<commit_before>package core

import (
	"strconv"
	"strings"

	"github.com/supergiant/guber"
	"github.com/supergiant/supergiant/types"
)

// kube_helpers.go is a collection of helper methods that convert a Supergiant
// resource definition into a Kubernetes resource defition.
// (and some other assorted things that should maybe be moved out...)

func kubeVolumeMounts(m *types.ContainerBlueprint) (volMounts []*guber.VolumeMount) {
	for _, mount := range m.Mounts {
		volMounts = append(volMounts, asKubeVolumeMount(mount))
	}
	return volMounts
}

func kubeContainerPorts(m *types.ContainerBlueprint) (cPorts []*guber.ContainerPort) {
	for _, port := range m.Ports {
		cPorts = append(cPorts, asKubeContainerPort(port))
	}
	return cPorts
}

func interpolatedEnvVars(m *types.ContainerBlueprint, instance *InstanceResource) (envVars []*guber.EnvVar) {
	for _, envVar := range m.Env {
		envVars = append(envVars, asKubeEnvVar(envVar, instance))
	}
	return envVars
}

func ImageRepoName(m *types.ContainerBlueprint) string {
	return strings.Split(m.Image, "/")[0]
}

func asKubeContainer(m *types.ContainerBlueprint, instance *InstanceResource) *guber.Container { // NOTE how instance must be passed here
	return &guber.Container{
		Name:  "container", // TODO this will fail with multiple containers ------------------------------------ TODO
		Image: m.Image,
		Env:   interpolatedEnvVars(m, instance),
		Resources: &guber.Resources{
			Requests: &guber.ResourceValues{
				Memory: types.BytesFromMiB(m.RAM.Min).ToKubeMebibytes(),
				CPU:    types.CoresFromMillicores(m.CPU.Min).ToKubeMillicores(),
			},
			Limits: &guber.ResourceValues{
				Memory: types.BytesFromMiB(m.RAM.Max).ToKubeMebibytes(),
				CPU:    types.CoresFromMillicores(m.CPU.Max).ToKubeMillicores(),
			},
		},
		VolumeMounts: kubeVolumeMounts(m),
		Ports:        kubeContainerPorts(m),

		// TODO this should be an option, enabled by default with volumes
		SecurityContext: &guber.SecurityContext{
			Privileged: true,
		},
	}
}

// EnvVar
//==============================================================================
func interpolatedValue(m *types.EnvVar, instance *InstanceResource) string {
	r := strings.NewReplacer(
		"{{ instance_id }}", *instance.ID,
		"{{ other_stuff }}", "TODO")
	return r.Replace(m.Value)
}

func asKubeEnvVar(m *types.EnvVar, instance *InstanceResource) *guber.EnvVar {
	return &guber.EnvVar{
		Name:  m.Name,
		Value: interpolatedValue(m, instance),
	}
}

// Volume
//==============================================================================
func asKubeVolume(m *AwsVolume) (*guber.Volume, error) {
	vol, err := m.awsVolume()
	if err != nil {
		return nil, err
	}

	return &guber.Volume{
		Name: *m.Blueprint.Name, // NOTE this is not the physical volume name
		AwsElasticBlockStore: &guber.AwsElasticBlockStore{
			VolumeID: *vol.VolumeId,
			FSType:   "ext4",
		},
	}, nil
}

// Mount
//==============================================================================
func asKubeVolumeMount(m *types.Mount) *guber.VolumeMount {
	return &guber.VolumeMount{
		Name:      *m.Volume,
		MountPath: m.Path,
	}
}

// Port
//==============================================================================
func portName(m *types.Port) string {
	return strconv.Itoa(m.Number)
}

func asKubeContainerPort(m *types.Port) *guber.ContainerPort {
	return &guber.ContainerPort{
		ContainerPort: m.Number,
	}
}

func asKubeServicePort(m *types.Port) *guber.ServicePort {
	return &guber.ServicePort{
		Name:     portName(m),
		Port:     m.Number,
		Protocol: "TCP", // this is default; only other option is UDP
	}
}

// ImageRepo
//==============================================================================
func asKubeImagePullSecret(m *ImageRepoResource) *guber.ImagePullSecret {
	return &guber.ImagePullSecret{
		Name: *m.Name,
	}
}

func asKubeSecret(m *ImageRepoResource) *guber.Secret {
	return &guber.Secret{
		Metadata: &guber.Metadata{
			Name: *m.Name,
		},
		Type: "kubernetes.io/dockercfg",
		Data: map[string]string{
			".dockercfg": m.Key,
		},
	}
}
<commit_msg>Do not pass ResourceValues when null<commit_after>package core

import (
	"strconv"
	"strings"

	"github.com/supergiant/guber"
	"github.com/supergiant/supergiant/types"
)

// kube_helpers.go is a collection of helper methods that convert a Supergiant
// resource definition into a Kubernetes resource defition.
// (and some other assorted things that should maybe be moved out...)

func kubeVolumeMounts(m *types.ContainerBlueprint) (volMounts []*guber.VolumeMount) {
	for _, mount := range m.Mounts {
		volMounts = append(volMounts, asKubeVolumeMount(mount))
	}
	return volMounts
}

func kubeContainerPorts(m *types.ContainerBlueprint) (cPorts []*guber.ContainerPort) {
	for _, port := range m.Ports {
		cPorts = append(cPorts, asKubeContainerPort(port))
	}
	return cPorts
}

func interpolatedEnvVars(m *types.ContainerBlueprint, instance *InstanceResource) (envVars []*guber.EnvVar) {
	for _, envVar := range m.Env {
		envVars = append(envVars, asKubeEnvVar(envVar, instance))
	}
	return envVars
}

func ImageRepoName(m *types.ContainerBlueprint) string {
	return strings.Split(m.Image, "/")[0]
}

func asKubeContainer(m *types.ContainerBlueprint, instance *InstanceResource) *guber.Container { // NOTE how instance must be passed here
	// TODO
	resources := new(guber.Resources)
	if m.RAM != nil {
		if m.RAM.Min != 0 {
			resources.Requests.Memory = types.BytesFromMiB(m.RAM.Min).ToKubeMebibytes()
		}
		if m.RAM.Max != 0 {
			resources.Limits.Memory = types.BytesFromMiB(m.RAM.Max).ToKubeMebibytes()
		}
	}
	if m.CPU != nil {
		if m.CPU.Min != 0 {
			resources.Requests.CPU = types.CoresFromMillicores(m.CPU.Min).ToKubeMillicores()
		}
		if m.CPU.Max != 0 {
			resources.Limits.CPU = types.CoresFromMillicores(m.CPU.Max).ToKubeMillicores()
		}
	}

	return &guber.Container{
		Name:         "container", // TODO this will fail with multiple containers ------------------------------------ TODO
		Image:        m.Image,
		Env:          interpolatedEnvVars(m, instance),
		Resources:    resources,
		VolumeMounts: kubeVolumeMounts(m),
		Ports:        kubeContainerPorts(m),

		// TODO this should be an option, enabled by default with volumes
		SecurityContext: &guber.SecurityContext{
			Privileged: true,
		},
	}
}

// EnvVar
//==============================================================================
func interpolatedValue(m *types.EnvVar, instance *InstanceResource) string {
	r := strings.NewReplacer(
		"{{ instance_id }}", *instance.ID,
		"{{ other_stuff }}", "TODO")
	return r.Replace(m.Value)
}

func asKubeEnvVar(m *types.EnvVar, instance *InstanceResource) *guber.EnvVar {
	return &guber.EnvVar{
		Name:  m.Name,
		Value: interpolatedValue(m, instance),
	}
}

// Volume
//==============================================================================
func asKubeVolume(m *AwsVolume) (*guber.Volume, error) {
	vol, err := m.awsVolume()
	if err != nil {
		return nil, err
	}

	return &guber.Volume{
		Name: *m.Blueprint.Name, // NOTE this is not the physical volume name
		AwsElasticBlockStore: &guber.AwsElasticBlockStore{
			VolumeID: *vol.VolumeId,
			FSType:   "ext4",
		},
	}, nil
}

// Mount
//==============================================================================
func asKubeVolumeMount(m *types.Mount) *guber.VolumeMount {
	return &guber.VolumeMount{
		Name:      *m.Volume,
		MountPath: m.Path,
	}
}

// Port
//==============================================================================
func portName(m *types.Port) string {
	return strconv.Itoa(m.Number)
}

func asKubeContainerPort(m *types.Port) *guber.ContainerPort {
	return &guber.ContainerPort{
		ContainerPort: m.Number,
	}
}

func asKubeServicePort(m *types.Port) *guber.ServicePort {
	return &guber.ServicePort{
		Name:     portName(m),
		Port:     m.Number,
		Protocol: "TCP", // this is default; only other option is UDP
	}
}

// ImageRepo
//==============================================================================
func asKubeImagePullSecret(m *ImageRepoResource) *guber.ImagePullSecret {
	return &guber.ImagePullSecret{
		Name: *m.Name,
	}
}

func asKubeSecret(m *ImageRepoResource) *guber.Secret {
	return &guber.Secret{
		Metadata: &guber.Metadata{
			Name: *m.Name,
		},
		Type: "kubernetes.io/dockercfg",
		Data: map[string]string{
			".dockercfg": m.Key,
		},
	}
}
<|endoftext|>


<commit_before>package form

import (
	"errors"
	"fmt"
	"net/url"
	"reflect"
	"strconv"
	"strings"
)

// ValidationError indicates that a field was not valid.
type ValidationError struct {
	Field, Message string
}

func (e ValidationError) Error() string {
	return e.Message
}

// CompoundValidationError represents a list of validation errors.
type CompoundValidationError struct {
	errs []*ValidationError
}

// Len returns the count of validation errors
func (c CompoundValidationError) Len() int {
	return len(c.errs)
}

// Errors returns all validation errors
func (c CompoundValidationError) Errors() []*ValidationError {
	return c.errs
}

func (c CompoundValidationError) Error() string {
	msg := make([]string, len(c.errs))
	for _, e := range c.errs {
		msg = append(msg, e.Error())
	}
	return fmt.Sprintf("multiple validation errors occurred: %s", strings.Join(msg, "; "))
}

// Validator indicates whether a form field is valid.
type Validator func(value []string) *ValidationError

// Setter decodes a value for a field.
type Setter func(value []string) error

// FieldUnmarshaler unmarshals a specific field.
type FieldUnmarshaler func(field string, value []string) (interface{}, error)

func Unmarshal(v url.Values, o interface{}) error {
	val := reflect.ValueOf(o)
	if val.Kind() != reflect.Ptr || val.IsNil() {
		return errors.New("unmarshal requires a pointer to a receiver")
	}

	return walk(val, v)
}

func walk(val reflect.Value, v url.Values) error {
	// Loop through values, top-down specificity
	verrs := []*ValidationError{}
	for key, vals := range v {
		e := findIn(val, key, vals)
		if e == nil {
			continue
		} else if ve, ok := e.(*ValidationError); ok {
			verrs = append(verrs, ve)
			continue
		}
		return e
	}
	if len(verrs) > 0 {
		return CompoundValidationError{errs: verrs}
	}
	return nil
}

func findIn(rv reflect.Value, key string, values []string) error {
	switch reflect.Indirect(rv).Kind() {
	case reflect.Map:
		// The map must take string keys.
		if _, ok := rv.Interface().(map[string]interface{}); ok {
			return assignToMap(rv, key, values)
		}
	case reflect.Struct:
		// Look for struct field named 'key'.
		//return assignToStruct(reflect.Indirect(rv), key, values)
		return assignToStruct(rv, key, values)
	}
	return fmt.Errorf("object %s cannot be used to store values", rv.Type().Name())
}

func assignToMap(rv reflect.Value, key string, values []string) error {
	var err error
	defer func() {
		if e := recover(); e != nil {
			fmt.Printf("Failed map assignment: %v\n", e)
			// FIXME: can't modify err in recover.
			err = fmt.Errorf("failed map assignment: %s", e)
		}
	}()
	// FIXME: There must be a way to find the destination type of a map and
	// appropriately convert to it.
	switch l := len(values); {
	case l == 1:
		rv.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(values[0]))
	case l > 1:
		rv.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(values))
	}
	return err
}

func assignToStruct(rval reflect.Value, key string, values []string) error {
	ptrt := rval.Type()
	rv := reflect.Indirect(rval)
	rt := rv.Type()
	// Look for a Field on struct that matches the key name.
	for i := 0; i < rt.NumField(); i++ {
		f := rt.Field(i)
		tag := parseTag(f.Tag.Get("form"))
		if !tag.ignore && tag.name == "" {
			tag.name = f.Name
		}
		if tag.name == key {
			validator := "FormValidate" + f.Name
			setter := "FormSet" + f.Name

			// If there is a validator, call it.
			if m, ok := ptrt.MethodByName(validator); ok {
				// fmt.Printf("Validating %s against %v\n", key, m)
				if err := callFormMethod(m, rval, values); err != nil {
					return err
				}
			}

			// For assignment, if there is a setter, use it. Otherwise, do a
			// raw assignment.
			if m, ok := ptrt.MethodByName(setter); ok {
				//fmt.Printf("Setting %s with %v\n", key, m)
				return callFormMethod(m, rval, values)
			} else {
				assignToStructField(rv.FieldByName(f.Name), values)
				return nil
			}
		}
	}
	fmt.Printf("Skipped key %q", key)
	return nil
}

func callFormMethod(method reflect.Method, target reflect.Value, values []string) error {
	retvals := method.Func.Call([]reflect.Value{target, reflect.ValueOf(values)})
	if !retvals[0].IsNil() {
		// An error occurred
		return retvals[0].Interface().(error)
	}
	return nil
}

func assignToStructField(rv reflect.Value, val []string) error {
	// Basically, we need to convert from a string to the appropriate underlying
	// kind, then assign.
	switch rv.Kind() {
	case reflect.String:
		rv.Set(reflect.ValueOf(val[0]))
		return nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		vv := "0"
		if len(val) > 0 {
			vv = val[0]
		}
		return assignToInt(rv, vv)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		vv := "0"
		if len(val) > 0 {
			vv = val[0]
		}
		return assignToUint(rv, vv)
	case reflect.Float32, reflect.Float64:
		vv := "0"
		if len(val) > 0 {
			vv = val[0]
		}
		return assignToFloat(rv, vv)
	case reflect.Bool:
		b, err := strconv.ParseBool(val[0])
		reflect.Indirect(rv).Set(reflect.ValueOf(b))
		return err
	case reflect.Slice:
		if _, ok := rv.Interface().([]string); ok {
			reflect.Indirect(rv).Set(reflect.ValueOf(val))
			return nil
		}
		return fmt.Errorf("Only string slices are supported.")
	default:
		return fmt.Errorf("Unsupported kind")
	}
}

func assignToInt(rv reflect.Value, val string) error {
	rvv := reflect.Indirect(rv)
	if !rvv.CanSet() {
		return fmt.Errorf("cannot set %q (%s)", rv.Type().Name(), rv.Kind().String())
	}
	ival, err := strconv.ParseInt(val, 0, 0)
	if err != nil {
		return err
	}
	rvv.SetInt(ival)
	return nil
}
func assignToUint(rv reflect.Value, val string) error {
	rvv := reflect.Indirect(rv)
	if !rvv.CanSet() {
		return fmt.Errorf("cannot set %q (%s)", rv.Type().Name(), rv.Kind().String())
	}
	ival, err := strconv.ParseUint(val, 0, 0)
	if err != nil {
		return err
	}
	rvv.SetUint(ival)
	return nil
}
func assignToFloat(rv reflect.Value, val string) error {
	rvv := reflect.Indirect(rv)
	if !rvv.CanSet() {
		return fmt.Errorf("cannot set %q (%s)", rv.Type().Name(), rv.Kind().String())
	}
	ival, err := strconv.ParseFloat(val, 64)
	if err != nil {
		return err
	}
	rvv.SetFloat(ival)
	return nil
}

func parseTag(str string) *tag {
	parts := strings.Split(str, ",")
	if len(parts) == 1 && parts[0] == "" {
		return &tag{}
	}
	t := &tag{}
	switch n := parts[0]; n {
	case "+":
		t.group = true
	case "-":
		t.ignore = true
	default:
		t.name = n
	}

	for _, p := range parts[1:] {
		switch {
		case p == "omitempty":
			t.omit = true
		case strings.HasPrefix(p, "prefix="):
			t.prefix = strings.TrimPrefix(p, "prefix=")
		case strings.HasPrefix(p, "suffix="):
			t.suffix = strings.TrimPrefix(p, "suffix=")
		}
	}
	return t
}

// tag represents a 'form' tag.
//
//	Name string `form:name`
//	Date time.Time `form:date,omitempty`
//	Address *Address `form:+,omitempty,prefix=addr_
type tag struct {
	name           string
	prefix, suffix string //prefix=, suffix=
	omit           bool   // omitempty
	ignore         bool   // -
	group          bool   // +
	validator      Validator
	unmarshaler    FieldUnmarshaler
}
<commit_msg>Add API docs for Unmarshal<commit_after>package form

import (
	"errors"
	"fmt"
	"net/url"
	"reflect"
	"strconv"
	"strings"
)

// ValidationError indicates that a field was not valid.
type ValidationError struct {
	Field, Message string
}

func (e ValidationError) Error() string {
	return e.Message
}

// CompoundValidationError represents a list of validation errors.
type CompoundValidationError struct {
	errs []*ValidationError
}

// Len returns the count of validation errors
func (c CompoundValidationError) Len() int {
	return len(c.errs)
}

// Errors returns all validation errors
func (c CompoundValidationError) Errors() []*ValidationError {
	return c.errs
}

func (c CompoundValidationError) Error() string {
	msg := make([]string, len(c.errs))
	for _, e := range c.errs {
		msg = append(msg, e.Error())
	}
	return fmt.Sprintf("multiple validation errors occurred: %s", strings.Join(msg, "; "))
}

// Validator indicates whether a form field is valid.
type Validator func(value []string) *ValidationError

// Setter decodes a value for a field.
type Setter func(value []string) error

// FieldUnmarshaler unmarshals a specific field.
type FieldUnmarshaler func(field string, value []string) (interface{}, error)

// Unmarshal unmarshals values into the given interface{}.
//
// This walks the values and copies each value into the matching field on the
// interface. It is recommended that o be a pointer to a struct.
//
// Structs may be annotated with tags:
//
//	type Person struct {
//		First string `form:"first_name"`
//		Last string `form:"last_name"`
//	}
//
// Additionally, if a field has a matching Validator or Setter, that function
// will also be called. Validators and Setters are matched based on name.
// For example, given the First field above, the validators and setters would
// be:
//
//	func(p *Person) FormValidateFirst(v []string) *form.ValidationError {}
//	func(p *Person) FormSetFirst(v []string) error {}
//
// A Validator should not alter v or store any part of v.
//
// A Setter may set the field. If it does not, the field will remain unset.
//
// If a Validator fails, the field will not be set, but processing will continue.
// If a Setter fails, the field will not be set, and unmarshaling will be halter.
func Unmarshal(v url.Values, o interface{}) error {
	val := reflect.ValueOf(o)
	if val.Kind() != reflect.Ptr || val.IsNil() {
		return errors.New("unmarshal requires a pointer to a receiver")
	}

	return walk(val, v)
}

func walk(val reflect.Value, v url.Values) error {
	// Loop through values, top-down specificity
	verrs := []*ValidationError{}
	for key, vals := range v {
		e := findIn(val, key, vals)
		if e == nil {
			continue
		} else if ve, ok := e.(*ValidationError); ok {
			verrs = append(verrs, ve)
			continue
		}
		return e
	}
	if len(verrs) > 0 {
		return CompoundValidationError{errs: verrs}
	}
	return nil
}

func findIn(rv reflect.Value, key string, values []string) error {
	switch reflect.Indirect(rv).Kind() {
	case reflect.Map:
		// The map must take string keys.
		if _, ok := rv.Interface().(map[string]interface{}); ok {
			return assignToMap(rv, key, values)
		}
	case reflect.Struct:
		// Look for struct field named 'key'.
		//return assignToStruct(reflect.Indirect(rv), key, values)
		return assignToStruct(rv, key, values)
	}
	return fmt.Errorf("object %s cannot be used to store values", rv.Type().Name())
}

func assignToMap(rv reflect.Value, key string, values []string) error {
	var err error
	defer func() {
		if e := recover(); e != nil {
			fmt.Printf("Failed map assignment: %v\n", e)
			// FIXME: can't modify err in recover.
			err = fmt.Errorf("failed map assignment: %s", e)
		}
	}()
	// FIXME: There must be a way to find the destination type of a map and
	// appropriately convert to it.
	switch l := len(values); {
	case l == 1:
		rv.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(values[0]))
	case l > 1:
		rv.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(values))
	}
	return err
}

func assignToStruct(rval reflect.Value, key string, values []string) error {
	ptrt := rval.Type()
	rv := reflect.Indirect(rval)
	rt := rv.Type()
	// Look for a Field on struct that matches the key name.
	for i := 0; i < rt.NumField(); i++ {
		f := rt.Field(i)
		tag := parseTag(f.Tag.Get("form"))
		if !tag.ignore && tag.name == "" {
			tag.name = f.Name
		}
		if tag.name == key {
			validator := "FormValidate" + f.Name
			setter := "FormSet" + f.Name

			// If there is a validator, call it.
			if m, ok := ptrt.MethodByName(validator); ok {
				// fmt.Printf("Validating %s against %v\n", key, m)
				if err := callFormMethod(m, rval, values); err != nil {
					return err
				}
			}

			// For assignment, if there is a setter, use it. Otherwise, do a
			// raw assignment.
			if m, ok := ptrt.MethodByName(setter); ok {
				//fmt.Printf("Setting %s with %v\n", key, m)
				return callFormMethod(m, rval, values)
			} else {
				assignToStructField(rv.FieldByName(f.Name), values)
				return nil
			}
		}
	}
	fmt.Printf("Skipped key %q", key)
	return nil
}

func callFormMethod(method reflect.Method, target reflect.Value, values []string) error {
	retvals := method.Func.Call([]reflect.Value{target, reflect.ValueOf(values)})
	if !retvals[0].IsNil() {
		// An error occurred
		return retvals[0].Interface().(error)
	}
	return nil
}

func assignToStructField(rv reflect.Value, val []string) error {
	// Basically, we need to convert from a string to the appropriate underlying
	// kind, then assign.
	switch rv.Kind() {
	case reflect.String:
		rv.Set(reflect.ValueOf(val[0]))
		return nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		vv := "0"
		if len(val) > 0 {
			vv = val[0]
		}
		return assignToInt(rv, vv)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		vv := "0"
		if len(val) > 0 {
			vv = val[0]
		}
		return assignToUint(rv, vv)
	case reflect.Float32, reflect.Float64:
		vv := "0"
		if len(val) > 0 {
			vv = val[0]
		}
		return assignToFloat(rv, vv)
	case reflect.Bool:
		b, err := strconv.ParseBool(val[0])
		reflect.Indirect(rv).Set(reflect.ValueOf(b))
		return err
	case reflect.Slice:
		if _, ok := rv.Interface().([]string); ok {
			reflect.Indirect(rv).Set(reflect.ValueOf(val))
			return nil
		}
		return fmt.Errorf("Only string slices are supported.")
	default:
		return fmt.Errorf("Unsupported kind")
	}
}

func assignToInt(rv reflect.Value, val string) error {
	rvv := reflect.Indirect(rv)
	if !rvv.CanSet() {
		return fmt.Errorf("cannot set %q (%s)", rv.Type().Name(), rv.Kind().String())
	}
	ival, err := strconv.ParseInt(val, 0, 0)
	if err != nil {
		return err
	}
	rvv.SetInt(ival)
	return nil
}
func assignToUint(rv reflect.Value, val string) error {
	rvv := reflect.Indirect(rv)
	if !rvv.CanSet() {
		return fmt.Errorf("cannot set %q (%s)", rv.Type().Name(), rv.Kind().String())
	}
	ival, err := strconv.ParseUint(val, 0, 0)
	if err != nil {
		return err
	}
	rvv.SetUint(ival)
	return nil
}
func assignToFloat(rv reflect.Value, val string) error {
	rvv := reflect.Indirect(rv)
	if !rvv.CanSet() {
		return fmt.Errorf("cannot set %q (%s)", rv.Type().Name(), rv.Kind().String())
	}
	ival, err := strconv.ParseFloat(val, 64)
	if err != nil {
		return err
	}
	rvv.SetFloat(ival)
	return nil
}

func parseTag(str string) *tag {
	parts := strings.Split(str, ",")
	if len(parts) == 1 && parts[0] == "" {
		return &tag{}
	}
	t := &tag{}
	switch n := parts[0]; n {
	case "+":
		t.group = true
	case "-":
		t.ignore = true
	default:
		t.name = n
	}

	for _, p := range parts[1:] {
		switch {
		case p == "omitempty":
			t.omit = true
		case strings.HasPrefix(p, "prefix="):
			t.prefix = strings.TrimPrefix(p, "prefix=")
		case strings.HasPrefix(p, "suffix="):
			t.suffix = strings.TrimPrefix(p, "suffix=")
		}
	}
	return t
}

// tag represents a 'form' tag.
//
//	Name string `form:name`
//	Date time.Time `form:date,omitempty`
//	Address *Address `form:+,omitempty,prefix=addr_
type tag struct {
	name           string
	prefix, suffix string //prefix=, suffix=
	omit           bool   // omitempty
	ignore         bool   // -
	group          bool   // +
	validator      Validator
	unmarshaler    FieldUnmarshaler
}
<|endoftext|>


<commit_before>// +build !integration

package esapi

import (
	"testing"
)

func TestAPIHelpers(t *testing.T) {
	t.Run("BoolPtr", func(t *testing.T) {
		var v *bool

		v = BoolPtr(false)
		if v == nil || *v != false {
			t.Errorf("Expected false, got: %v", v)
		}

		v = BoolPtr(true)
		if v == nil || *v != true {
			t.Errorf("Expected true, got: %v", v)
		}
	})

	t.Run("IntPtr", func(t *testing.T) {
		var v *int

		v = IntPtr(0)
		if v == nil || *v != 0 {
			t.Errorf("Expected 0, got: %v", v)
		}
	})
}
<commit_msg>Simplify tests for API helpers<commit_after>// +build !integration

package esapi

import (
	"testing"
)

func TestAPIHelpers(t *testing.T) {
	t.Run("BoolPtr", func(t *testing.T) {
		v := BoolPtr(false)
		if v == nil || *v != false {
			t.Errorf("Expected false, got: %v", v)
		}

		v = BoolPtr(true)
		if v == nil || *v != true {
			t.Errorf("Expected true, got: %v", v)
		}
	})

	t.Run("IntPtr", func(t *testing.T) {
		v := IntPtr(0)
		if v == nil || *v != 0 {
			t.Errorf("Expected 0, got: %v", v)
		}
	})
}
<|endoftext|>


<commit_before>package app

import (
	"bytes"
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/go-martini/martini"
	"github.com/hashicorp/memberlist"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
	"net/http"
	"strconv"
	"time"
)

// TODO Should this live in the config package?
// Using pointers lets us differentiate between a natural 0, and an int-default 0
// omitempty tells it to ignore anything where the name was provided, but an empty value
// inside of a request body.
type ConfigRequest struct {
	VisibilityTimeout *float64 `json:"visibility_timeout,omitempty"`
	MinPartitions     *int     `json:"min_partitions,omitempty"`
	MaxPartitions     *int     `json:"max_partitions,omitempty"`
	MaxPartitionAge   *float64 `json:"max_partition_age,omitempty"`
}

// TODO make message definitions more explicit

func logrusLogger() martini.Handler {
	return func(res http.ResponseWriter, req *http.Request, c martini.Context, log *logrus.Logger) {
		start := time.Now()

		log.WithFields(logrus.Fields{
			"method": req.Method,
			"path":   req.URL.Path,
			"time":   time.Since(start),
		}).Info("Started a request")

		c.Next()
		rw := res.(martini.ResponseWriter)

		log.WithFields(logrus.Fields{
			"method": req.Method,
			"path":   req.URL.Path,
			"status": rw.Status(),
			"time":   time.Since(start),
		}).Info("Completed a request")
	}
}

func dynamiqMartini() *martini.ClassicMartini {
	r := martini.NewRouter()
	m := martini.New()

	m.Map(logrus.New())
	m.Use(logrusLogger())
	m.Use(martini.Recovery())
	m.Use(martini.Static("public"))
	m.MapTo(r, (*martini.Routes)(nil))
	m.Action(r.Handle)
	return &martini.ClassicMartini{m, r}
}

type HTTP_API_V1 struct {
}

func (h HTTP_API_V1) InitWebserver(list *memberlist.Memberlist, cfg *Config) {
	// tieing our Queue to HTTP interface == bad we should move this somewhere else
	// Queues.Queues is dumb. Need a better name-chain
	queues := cfg.Queues
	// also tieing topics this is next for refactor
	topics := InitTopics(cfg, queues)
	m := dynamiqMartini()
	m.Use(render.Renderer())

	// Group the routes underneath their version
	m.Group("/v1", func(r martini.Router) {
		// STATUS / STATISTICS API BLOCK
		m.Get("/status/servers", func() string {
			return_string := ""
			for _, member := range list.Members() {
				return_string += fmt.Sprintf("Member: %s %s\n", member.Name, member.Addr)
			}
			return return_string
		})
		// END STATUS / STATISTICS API BLOCK

		// CONFIGURATION API BLOCK

		m.Delete("/topics/:topic", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present == true {
				deleted := topics.DeleteTopic(params["topic"])
				r.JSON(200, map[string]interface{}{"Deleted": deleted})
			} else {
				r.JSON(404, map[string]interface{}{"error": "Topic did not exist."})
			}
		})

		m.Put("/queues/:queue", func(r render.Render, params martini.Params) {
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present != true {
				cfg.InitializeQueue(params["queue"])
				r.JSON(201, "created")
			} else {
				r.JSON(422, map[string]interface{}{"error": "Queue already exists."})
			}
		})

		m.Put("/topics/:topic", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
				r.JSON(201, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
			} else {
				r.JSON(422, map[string]interface{}{"error": "Topic already exists."})
			}
		})

		m.Put("/topics/:topic/queues/:queue", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				r.JSON(422, map[string]interface{}{"error": "Topic does not exist. Please create it first."})
			} else {
				_, present = queues.QueueMap[params["queue"]]
				if present != true {
					r.JSON(422, map[string]interface{}{"error": "Queue does not exist. Please create it first"})
				} else {
					topics.TopicMap[params["topic"]].AddQueue(cfg, params["queue"])
					r.JSON(200, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
				}
			}
		})

		// neeeds a little work....
		m.Delete("/topics/:topic/queues/:queue", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
			}
			topics.TopicMap[params["topic"]].DeleteQueue(cfg, params["queue"])
			r.JSON(200, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
		})

		m.Patch("/queues/:queue", binding.Json(ConfigRequest{}), func(configRequest ConfigRequest, r render.Render, params martini.Params) {
			// Not sure of better way to get the queue name from the request, but would be good to not
			// Have to reach into params - better to bind it

			// There is probably an optimal order to set these in, depending on if the values for min/max
			// have shrunk or grown, so the system can self-adjust in the correct fashion. Or, maybe it's fine to do it however

			// Should we detect and throw errors on incorrect configuration names? Would make debugging simpler

			// Likely all of this belongs in config, where we just pass in an interface to the request object, and it
			// returns the first error it runs across. Would simplify the code here greatly.
			var err error
			if configRequest.VisibilityTimeout != nil {
				err = cfg.SetVisibilityTimeout(params["queue"], *configRequest.VisibilityTimeout)
				// We really need a proper way to generalize error handling
				// Writing this out every time is going to be silly
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}

			if configRequest.MinPartitions != nil {
				err = cfg.SetMinPartitions(params["queue"], *configRequest.MinPartitions)
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}

			if configRequest.MaxPartitions != nil {
				err = cfg.SetMaxPartitions(params["queue"], *configRequest.MaxPartitions)
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}
			if configRequest.MaxPartitionAge != nil {
				err = cfg.SetMaxPartitionAge(params["queue"], *configRequest.MaxPartitionAge)
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}

			r.JSON(200, "ok")
		})

		// END CONFIGURATION API BLOCK

		// DATA INTERACTION API BLOCK

		m.Get("/topics", func(r render.Render) {
			topicList := make([]string, 0, 10)
			for topicName, _ := range topics.TopicMap {
				topicList = append(topicList, topicName)
			}
			r.JSON(200, map[string]interface{}{"topics": topicList})
		})

		m.Get("/topics/:topic", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
			}

			r.JSON(200, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
		})

		m.Put("/topics/:topic/message", func(r render.Render, params martini.Params, req *http.Request) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
			}
			var buf bytes.Buffer
			buf.ReadFrom(req.Body)

			response := topics.TopicMap[params["topic"]].Broadcast(cfg, buf.String())
			r.JSON(200, response)
		})

		m.Get("/queues", func(r render.Render, params martini.Params) {
			queueList := make([]string, 0, 10)
			for queueName, _ := range queues.QueueMap {
				queueList = append(queueList, queueName)
			}
			r.JSON(200, map[string]interface{}{"queues": queueList})
		})

		m.Get("/queues/:queue", func(r render.Render, params martini.Params) {
			//check if we've initialized this queue yet
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present == true {
				queueReturn := make(map[string]interface{})
				queueReturn["visibility_timeout"], _ = cfg.GetVisibilityTimeout(params["queue"])
				queueReturn["min_partitions"], _ = cfg.GetMinPartitions(params["queue"])
				queueReturn["max_partitions"], _ = cfg.GetMaxPartitions(params["queue"])
				queueReturn["max_partition_age"], _ = cfg.GetMaxPartitionAge(params["queue"])
				queueReturn["partitions"] = queues.QueueMap[params["queue"]].Parts.PartitionCount()
				r.JSON(200, queueReturn)
			} else {
				r.JSON(404, fmt.Sprintf("There is no queue named %s", params["queue"]))
			}
		})

		m.Get("/queues/:queue/messages/:batchSize", func(r render.Render, params martini.Params) {
			//check if we've initialized this queue yet
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present == true {
				batchSize, err := strconv.ParseInt(params["batchSize"], 10, 64)
				if err != nil {
					//log the error for unparsable input
					logrus.Error(err)
					r.JSON(422, err.Error())
				}
				if batchSize <= 0 {
					r.JSON(422, fmt.Sprint("Batchsizes must be non-negative integers greater than 0"))
				}
				messages, err := queues.QueueMap[params["queue"]].Get(cfg, list, batchSize)

				if err != nil && err.Error() != NOPARTITIONS {
					// We're choosing to ignore nopartitions issues for now and treat them as normal 200s
					// The only other error this could be is a riak related error but we're not going to
					// change the API at this point. Will review this during a future release
					r.JSON(204, err.Error())
				}
				//TODO move this into the Queue.Get code
				messageList := make([]map[string]interface{}, 0, 10)
				//Format response
				for _, object := range messages {
					message := make(map[string]interface{})
					message["id"] = object.Key
					message["body"] = string(object.Data[:])
					messageList = append(messageList, message)
				}
				if err != nil && err.Error() != NOPARTITIONS {
					logrus.Error(err)
					r.JSON(500, err.Error())
				} else {
					r.JSON(200, messageList)
				}
			} else {
				// What is a sane result here?
				r.JSON(404, fmt.Sprintf("There is no queue named %s", params["queue"]))
			}
		})

		m.Put("/queues/:queue/message", func(params martini.Params, req *http.Request) string {
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present == true {
				// parse the request body into a sting
				// TODO clean this up, full json api?
				var buf bytes.Buffer
				buf.ReadFrom(req.Body)
				uuid := queues.QueueMap[params["queue"]].Put(cfg, buf.String())

				return uuid
			} else {
				// What is a sane response to this?
				return ""
			}
		})

		m.Delete("/queues/:queue/message/:messageId", func(r render.Render, params martini.Params) {
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present != true {
				cfg.InitializeQueue(params["queue"])
			}

			r.JSON(200, queues.QueueMap[params["queue"]].Delete(cfg, params["messageId"]))
		})
		// DATA INTERACTION API BLOCK
	})
	logrus.Fatal(http.ListenAndServe(":"+strconv.Itoa(cfg.Core.HttpPort), m))
}
<commit_msg>Fixing logger in HTTP context not respecting log levels<commit_after>package app

import (
	"bytes"
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/go-martini/martini"
	"github.com/hashicorp/memberlist"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
	"net/http"
	"strconv"
	"time"
)

// TODO Should this live in the config package?
// Using pointers lets us differentiate between a natural 0, and an int-default 0
// omitempty tells it to ignore anything where the name was provided, but an empty value
// inside of a request body.
type ConfigRequest struct {
	VisibilityTimeout *float64 `json:"visibility_timeout,omitempty"`
	MinPartitions     *int     `json:"min_partitions,omitempty"`
	MaxPartitions     *int     `json:"max_partitions,omitempty"`
	MaxPartitionAge   *float64 `json:"max_partition_age,omitempty"`
}

// TODO make message definitions more explicit

func logrusLogger() martini.Handler {
	return func(res http.ResponseWriter, req *http.Request, c martini.Context, log *logrus.Logger) {
		start := time.Now()

		log.WithFields(logrus.Fields{
			"method": req.Method,
			"path":   req.URL.Path,
			"time":   time.Since(start),
		}).Info("Started a request")

		c.Next()
		rw := res.(martini.ResponseWriter)

		log.WithFields(logrus.Fields{
			"method": req.Method,
			"path":   req.URL.Path,
			"status": rw.Status(),
			"time":   time.Since(start),
		}).Info("Completed a request")
	}
}

func dynamiqMartini(cfg *Config) *martini.ClassicMartini {
	r := martini.NewRouter()
	m := martini.New()

	log := logrus.New()
	log.Level = cfg.Core.LogLevel

	m.Map(log)
	m.Use(logrusLogger())
	m.Use(martini.Recovery())
	m.Use(martini.Static("public"))
	m.MapTo(r, (*martini.Routes)(nil))
	m.Action(r.Handle)
	return &martini.ClassicMartini{m, r}
}

type HTTP_API_V1 struct {
}

func (h HTTP_API_V1) InitWebserver(list *memberlist.Memberlist, cfg *Config) {
	// tieing our Queue to HTTP interface == bad we should move this somewhere else
	// Queues.Queues is dumb. Need a better name-chain
	queues := cfg.Queues
	// also tieing topics this is next for refactor
	topics := InitTopics(cfg, queues)
	m := dynamiqMartini(cfg)
	m.Use(render.Renderer())

	// Group the routes underneath their version
	m.Group("/v1", func(r martini.Router) {
		// STATUS / STATISTICS API BLOCK
		m.Get("/status/servers", func() string {
			return_string := ""
			for _, member := range list.Members() {
				return_string += fmt.Sprintf("Member: %s %s\n", member.Name, member.Addr)
			}
			return return_string
		})
		// END STATUS / STATISTICS API BLOCK

		// CONFIGURATION API BLOCK

		m.Delete("/topics/:topic", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present == true {
				deleted := topics.DeleteTopic(params["topic"])
				r.JSON(200, map[string]interface{}{"Deleted": deleted})
			} else {
				r.JSON(404, map[string]interface{}{"error": "Topic did not exist."})
			}
		})

		m.Put("/queues/:queue", func(r render.Render, params martini.Params) {
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present != true {
				cfg.InitializeQueue(params["queue"])
				r.JSON(201, "created")
			} else {
				r.JSON(422, map[string]interface{}{"error": "Queue already exists."})
			}
		})

		m.Put("/topics/:topic", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
				r.JSON(201, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
			} else {
				r.JSON(422, map[string]interface{}{"error": "Topic already exists."})
			}
		})

		m.Put("/topics/:topic/queues/:queue", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				r.JSON(422, map[string]interface{}{"error": "Topic does not exist. Please create it first."})
			} else {
				_, present = queues.QueueMap[params["queue"]]
				if present != true {
					r.JSON(422, map[string]interface{}{"error": "Queue does not exist. Please create it first"})
				} else {
					topics.TopicMap[params["topic"]].AddQueue(cfg, params["queue"])
					r.JSON(200, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
				}
			}
		})

		// neeeds a little work....
		m.Delete("/topics/:topic/queues/:queue", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
			}
			topics.TopicMap[params["topic"]].DeleteQueue(cfg, params["queue"])
			r.JSON(200, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
		})

		m.Patch("/queues/:queue", binding.Json(ConfigRequest{}), func(configRequest ConfigRequest, r render.Render, params martini.Params) {
			// Not sure of better way to get the queue name from the request, but would be good to not
			// Have to reach into params - better to bind it

			// There is probably an optimal order to set these in, depending on if the values for min/max
			// have shrunk or grown, so the system can self-adjust in the correct fashion. Or, maybe it's fine to do it however

			// Should we detect and throw errors on incorrect configuration names? Would make debugging simpler

			// Likely all of this belongs in config, where we just pass in an interface to the request object, and it
			// returns the first error it runs across. Would simplify the code here greatly.
			var err error
			if configRequest.VisibilityTimeout != nil {
				err = cfg.SetVisibilityTimeout(params["queue"], *configRequest.VisibilityTimeout)
				// We really need a proper way to generalize error handling
				// Writing this out every time is going to be silly
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}

			if configRequest.MinPartitions != nil {
				err = cfg.SetMinPartitions(params["queue"], *configRequest.MinPartitions)
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}

			if configRequest.MaxPartitions != nil {
				err = cfg.SetMaxPartitions(params["queue"], *configRequest.MaxPartitions)
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}
			if configRequest.MaxPartitionAge != nil {
				err = cfg.SetMaxPartitionAge(params["queue"], *configRequest.MaxPartitionAge)
				if err != nil {
					logrus.Println(err)
					r.JSON(500, map[string]interface{}{"error": err.Error()})
					return
				}
			}

			r.JSON(200, "ok")
		})

		// END CONFIGURATION API BLOCK

		// DATA INTERACTION API BLOCK

		m.Get("/topics", func(r render.Render) {
			topicList := make([]string, 0, 10)
			for topicName, _ := range topics.TopicMap {
				topicList = append(topicList, topicName)
			}
			r.JSON(200, map[string]interface{}{"topics": topicList})
		})

		m.Get("/topics/:topic", func(r render.Render, params martini.Params) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
			}

			r.JSON(200, map[string]interface{}{"Queues": topics.TopicMap[params["topic"]].ListQueues()})
		})

		m.Put("/topics/:topic/message", func(r render.Render, params martini.Params, req *http.Request) {
			var present bool
			_, present = topics.TopicMap[params["topic"]]
			if present != true {
				topics.InitTopic(params["topic"])
			}
			var buf bytes.Buffer
			buf.ReadFrom(req.Body)

			response := topics.TopicMap[params["topic"]].Broadcast(cfg, buf.String())
			r.JSON(200, response)
		})

		m.Get("/queues", func(r render.Render, params martini.Params) {
			queueList := make([]string, 0, 10)
			for queueName, _ := range queues.QueueMap {
				queueList = append(queueList, queueName)
			}
			r.JSON(200, map[string]interface{}{"queues": queueList})
		})

		m.Get("/queues/:queue", func(r render.Render, params martini.Params) {
			//check if we've initialized this queue yet
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present == true {
				queueReturn := make(map[string]interface{})
				queueReturn["visibility_timeout"], _ = cfg.GetVisibilityTimeout(params["queue"])
				queueReturn["min_partitions"], _ = cfg.GetMinPartitions(params["queue"])
				queueReturn["max_partitions"], _ = cfg.GetMaxPartitions(params["queue"])
				queueReturn["max_partition_age"], _ = cfg.GetMaxPartitionAge(params["queue"])
				queueReturn["partitions"] = queues.QueueMap[params["queue"]].Parts.PartitionCount()
				r.JSON(200, queueReturn)
			} else {
				r.JSON(404, fmt.Sprintf("There is no queue named %s", params["queue"]))
			}
		})

		m.Get("/queues/:queue/messages/:batchSize", func(r render.Render, params martini.Params) {
			//check if we've initialized this queue yet
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present == true {
				batchSize, err := strconv.ParseInt(params["batchSize"], 10, 64)
				if err != nil {
					//log the error for unparsable input
					logrus.Error(err)
					r.JSON(422, err.Error())
				}
				if batchSize <= 0 {
					r.JSON(422, fmt.Sprint("Batchsizes must be non-negative integers greater than 0"))
				}
				messages, err := queues.QueueMap[params["queue"]].Get(cfg, list, batchSize)

				if err != nil && err.Error() != NOPARTITIONS {
					// We're choosing to ignore nopartitions issues for now and treat them as normal 200s
					// The only other error this could be is a riak related error but we're not going to
					// change the API at this point. Will review this during a future release
					r.JSON(204, err.Error())
				}
				//TODO move this into the Queue.Get code
				messageList := make([]map[string]interface{}, 0, 10)
				//Format response
				for _, object := range messages {
					message := make(map[string]interface{})
					message["id"] = object.Key
					message["body"] = string(object.Data[:])
					messageList = append(messageList, message)
				}
				if err != nil && err.Error() != NOPARTITIONS {
					logrus.Error(err)
					r.JSON(500, err.Error())
				} else {
					r.JSON(200, messageList)
				}
			} else {
				// What is a sane result here?
				r.JSON(404, fmt.Sprintf("There is no queue named %s", params["queue"]))
			}
		})

		m.Put("/queues/:queue/message", func(params martini.Params, req *http.Request) string {
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present == true {
				// parse the request body into a sting
				// TODO clean this up, full json api?
				var buf bytes.Buffer
				buf.ReadFrom(req.Body)
				uuid := queues.QueueMap[params["queue"]].Put(cfg, buf.String())

				return uuid
			} else {
				// What is a sane response to this?
				return ""
			}
		})

		m.Delete("/queues/:queue/message/:messageId", func(r render.Render, params martini.Params) {
			var present bool
			_, present = queues.QueueMap[params["queue"]]
			if present != true {
				cfg.InitializeQueue(params["queue"])
			}

			r.JSON(200, queues.QueueMap[params["queue"]].Delete(cfg, params["messageId"]))
		})
		// DATA INTERACTION API BLOCK
	})
	logrus.Fatal(http.ListenAndServe(":"+strconv.Itoa(cfg.Core.HttpPort), m))
}
<|endoftext|>


<commit_before>package pdft

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

type crawlResultFonts []crawlResultFont

// Split a font string like '/F1' or '/TT2' into the prefix and index
func splitFont(s string) (string, int, error) {
	prefix := ""
	for i, r := range s {
		if unicode.IsDigit(r) {
			val, err := strconv.Atoi(s[i:])
			if err != nil {
				return "", 0, err
			}
			return prefix, val, nil
		}
		prefix += string(r)
	}
	return "", 0, fmt.Errorf("No font index")
}

func (c *crawlResultFonts) parse(propVal *[]byte) error {
	var props PDFObjPropertiesData
	err := readProperties(propVal, &props)
	if err != nil {
		return err
	}

	for _, prop := range props {
		var crFont crawlResultFont

		prefix, fontIndex, err := splitFont(strings.TrimSpace(prop.key))
		fmt.Printf("splitFont %s: %s %d\n", prop.key, prefix, fontIndex)
		if err != nil {
			return err
		}
		objID, _, err := prop.asDictionary()
		if err != nil {
			return err
		}
		crFont.prefix = prefix
		crFont.fontIndex = fontIndex
		crFont.fontObjID = objID
		*c = append(*c, crFont)
	}
	return nil
}

func (c *crawlResultFonts) String() string {
	var buff bytes.Buffer
	for _, f := range *c {
		buff.WriteString(fmt.Sprintf("/%s%d %d 0 R\n", f.prefix, f.fontIndex, f.fontObjID))
	}
	return buff.String()
}

func (c *crawlResultFonts) append(fontIndex int, fontObjID int) {
	var crFont crawlResultFont
	crFont.fontIndex = fontIndex
	crFont.fontObjID = fontObjID
	crFont.prefix = "F"
	*c = append(*c, crFont)
}

func (c *crawlResultFonts) maxFontIndex() int {
	max := 0
	for _, f := range *c {
		if f.fontIndex > max {
			max = f.fontIndex
		}
	}
	return max
}

type crawlResultFont struct {
	fontIndex int
	fontObjID int
	prefix string
}
<commit_msg>Remove debugging<commit_after>package pdft

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

type crawlResultFonts []crawlResultFont

// Split a font string like '/F1' or '/TT2' into the prefix and index
func splitFont(s string) (string, int, error) {
	prefix := ""
	for i, r := range s {
		if unicode.IsDigit(r) {
			val, err := strconv.Atoi(s[i:])
			if err != nil {
				return "", 0, err
			}
			return prefix, val, nil
		}
		prefix += string(r)
	}
	return "", 0, fmt.Errorf("No font index")
}

func (c *crawlResultFonts) parse(propVal *[]byte) error {
	var props PDFObjPropertiesData
	err := readProperties(propVal, &props)
	if err != nil {
		return err
	}

	for _, prop := range props {
		var crFont crawlResultFont

		prefix, fontIndex, err := splitFont(strings.TrimSpace(prop.key))
		if err != nil {
			return err
		}
		objID, _, err := prop.asDictionary()
		if err != nil {
			return err
		}
		crFont.prefix = prefix
		crFont.fontIndex = fontIndex
		crFont.fontObjID = objID
		*c = append(*c, crFont)
	}
	return nil
}

func (c *crawlResultFonts) String() string {
	var buff bytes.Buffer
	for _, f := range *c {
		buff.WriteString(fmt.Sprintf("/%s%d %d 0 R\n", f.prefix, f.fontIndex, f.fontObjID))
	}
	return buff.String()
}

func (c *crawlResultFonts) append(fontIndex int, fontObjID int) {
	var crFont crawlResultFont
	crFont.fontIndex = fontIndex
	crFont.fontObjID = fontObjID
	crFont.prefix = "F"
	*c = append(*c, crFont)
}

func (c *crawlResultFonts) maxFontIndex() int {
	max := 0
	for _, f := range *c {
		if f.fontIndex > max {
			max = f.fontIndex
		}
	}
	return max
}

type crawlResultFont struct {
	fontIndex int
	fontObjID int
	prefix string
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/ViBiOh/alcotest/alcotest"
	"github.com/ViBiOh/dashboard/auth"
	"github.com/ViBiOh/dashboard/docker"
)

const port = `1080`
const restPrefix = `/`
const websocketPrefix = `/ws/`

var restHandler = http.StripPrefix(restPrefix, docker.Handler{})
var websocketHandler = http.StripPrefix(websocketPrefix, docker.WebsocketHandler{})

func dashboardHandler(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, websocketPrefix) {
		websocketHandler.ServeHTTP(w, r)
	} else if strings.HasPrefix(r.URL.Path, restPrefix) {
		restHandler.ServeHTTP(w, r)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func handleGracefulClose(server *http.Server) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM)

	<-signals

	log.Printf(`SIGTERM received`)

	if server != nil {
		log.Print(`Shutting down http server`)
		if err := server.Shutdown(context.Background()); err != nil {
			log.Print(err)
		}
	}

	if docker.CanBeGracefullyClosed() {
		return
	}

	ticker := time.Tick(15 * time.Second)
	timeout := time.After(docker.DeployTimeout)

	for {
		select {
		case <-ticker:
			if docker.CanBeGracefullyClosed() {
				return
			}
		case <-timeout:
			os.Exit(1)
		}
	}
}

func main() {
	url := flag.String(`c`, ``, `URL to healthcheck (check and exit)`)
	authFile := flag.String(`auth`, ``, `Path of authentification configuration file`)
	websocketOrigin := flag.String(`ws`, `^dashboard`, `Allowed WebSocket Origin pattern`)
	flag.Parse()

	if *url != `` {
		alcotest.Do(url)
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	auth.Init(*authFile)
	docker.Init(*websocketOrigin)

	log.Print(`Starting server on port ` + port)

	server := &http.Server{
		Addr:    `:` + port,
		Handler: http.HandlerFunc(dashboardHandler),
	}

	go server.ListenAndServe()
	handleGracefulClose(server)
}
<commit_msg>Adding missing return<commit_after>package main

import (
	"context"
	"flag"
	"log"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/ViBiOh/alcotest/alcotest"
	"github.com/ViBiOh/dashboard/auth"
	"github.com/ViBiOh/dashboard/docker"
)

const port = `1080`
const restPrefix = `/`
const websocketPrefix = `/ws/`

var restHandler = http.StripPrefix(restPrefix, docker.Handler{})
var websocketHandler = http.StripPrefix(websocketPrefix, docker.WebsocketHandler{})

func dashboardHandler(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, websocketPrefix) {
		websocketHandler.ServeHTTP(w, r)
	} else if strings.HasPrefix(r.URL.Path, restPrefix) {
		restHandler.ServeHTTP(w, r)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func handleGracefulClose(server *http.Server) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM)

	<-signals

	log.Printf(`SIGTERM received`)

	if server != nil {
		log.Print(`Shutting down http server`)
		if err := server.Shutdown(context.Background()); err != nil {
			log.Print(err)
		}
	}

	if docker.CanBeGracefullyClosed() {
		return
	}

	ticker := time.Tick(15 * time.Second)
	timeout := time.After(docker.DeployTimeout)

	for {
		select {
		case <-ticker:
			if docker.CanBeGracefullyClosed() {
				return
			}
		case <-timeout:
			os.Exit(1)
		}
	}
}

func main() {
	url := flag.String(`c`, ``, `URL to healthcheck (check and exit)`)
	authFile := flag.String(`auth`, ``, `Path of authentification configuration file`)
	websocketOrigin := flag.String(`ws`, `^dashboard`, `Allowed WebSocket Origin pattern`)
	flag.Parse()

	if *url != `` {
		alcotest.Do(url)
		return
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	auth.Init(*authFile)
	docker.Init(*websocketOrigin)

	log.Print(`Starting server on port ` + port)

	server := &http.Server{
		Addr:    `:` + port,
		Handler: http.HandlerFunc(dashboardHandler),
	}

	go server.ListenAndServe()
	handleGracefulClose(server)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
)

func checkData(repoName string, dashboard string, blessed string) bool {

	data, err := ioutil.ReadFile("db/"+repoName+"/"+dashboard+".data")
	if err != nil {
		return false
	}
	lines := strings.Split(string(data), "\n")

	chErr := os.Chdir(blessed)
	if chErr != nil {
		return false
	}
	for _, line := range lines {
		if line != "\n" && line != "" {
			dt := strings.Split(line, "|")
			if len(dt) < 2 {
				return false
			}
			updateData("dashboards/"+dashboardPtr+"/dashboard.js", dt[0], dt[1])
		}
	}

	return true

}

func saveData(repoName string, dashboard string, vals ...string) {

	err := os.MkdirAll("db/"+repoName, 0644)
	check(err)

	data := ""
	for _, val := range vals {
		data += val+"\n"
	}
	d1 := []byte(data)

	err = ioutil.WriteFile("db/"+repoName+"/"+dashboard+".data", d1, 0644)
	check(err)

}

func updateData(filename string, varName string, data string) {

	input, err := ioutil.ReadFile(filename)
	check(err)

	lines := strings.Split(string(input), "\n")

	for i, line := range lines {
		if strings.Contains(line, "$"+varName) {
			lines[i] = "var "+varName+" = "+data
		}
	}
	output := strings.Join(lines, "\n")
	err = ioutil.WriteFile(filename, []byte(output), 0644)
	check(err)

}

func tableData(rows map[string]int) string {

	table := "["

	for key := range rows {
		table += "['"+strings.Replace(key, "'", "\\'", -1)+"', '"+strconv.Itoa(rows[key])+"'], "
	}
	table = table[0:len(table)-2]+"]"

	return table

}

func barChartData(bars map[string]int) (string, string) {

	x := "["
	y := "["

	for key := range bars {
		x += "'"+strings.Replace(key, "'", "\\'", -1)+"', "
		y += "'"+strconv.Itoa(bars[key])+"', "
	}
	x = x[0:len(x)-2]+"]"
	y = y[0:len(y)-2]+"]"

	return x, y

}

func updateDashboardData(uuidRepo string, repoPtr string, dashboard string) {

	// get data for dashboard
	languages, languageLines := barChartData(countLinesPerLanguage(uuidRepo))
	authors := tableData(countAuthorCommits(uuidRepo))

	// XXX cleanup line charts
	numLanguagesDataX := "x:["
	numLanguagesDataY := "y:["
	numLinesDataX := "x:["
	numLinesDataY := "y:["
	numAuthorsDataX := "x:["
	numAuthorsDataY := "y:["
	numFilesDataX := "x:["
	numFilesDataY := "y:["

	x, y := getCommits(uuidRepo)
	// XXX x needs to be reversed, note don't simply sort and reverse, order matters
	for i := len(x)-1; i >= 0; i-- {
		checkoutCommit(uuidRepo, x[i])

		lineCount := 0
		files := getFiles(uuidRepo)
		for _, file := range files {
			lineCount += countLines(file)
		}
		languageCount := 0
		langMap := countLanguages(uuidRepo)
		for key := range langMap {
			languageCount += langMap[key]
		}

		numLanguagesDataX += "'"+y[x[i]]["timestamp"]+"', "
		numLanguagesDataY += "'"+strconv.Itoa(languageCount)+"', "
		numLinesDataX += "'"+y[x[i]]["timestamp"]+"', "
		numLinesDataY += "'"+strconv.Itoa(lineCount)+"', "
		numAuthorsDataX += "'"+y[x[i]]["timestamp"]+"', "
		numAuthorsDataY += "'"+strconv.Itoa(countAuthorsByCommits(uuidRepo, x[i]))+"', "
		numFilesDataX += "'"+y[x[i]]["timestamp"]+"', "
		numFilesDataY += "'"+strconv.Itoa(countFiles(uuidRepo))+"', "
	}
	checkoutCommit(uuidRepo, x[0])

	numLanguagesData := "{"+numLanguagesDataX[0:len(numLanguagesDataX)-2]+"], "+numLanguagesDataY[0:len(numLanguagesDataY)-2]+"]"+"}"
	numLinesData := "{"+numLinesDataX[0:len(numLinesDataX)-2]+"], "+numLinesDataY[0:len(numLinesDataY)-2]+"]"+"}"
	numAuthorsData := "{"+numAuthorsDataX[0:len(numAuthorsDataX)-2]+"], "+numAuthorsDataY[0:len(numAuthorsDataY)-2]+"]"+"}"
	numFilesData := "{"+numFilesDataX[0:len(numFilesDataX)-2]+"], "+numFilesDataY[0:len(numFilesDataY)-2]+"]"+"}"

	saveData(repoPtr, dashboard, "languages|"+languages, "languageLines|"+languageLines, "authors|"+authors, "numLanguagesData|"+numLanguagesData, "numLinesData|"+numLinesData, "numAuthorsData|"+numAuthorsData, "numFilesData|"+numFilesData)

	chErr := os.Chdir(blessedPtr)
	check(chErr)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "languages", languages)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "languageLines", languageLines)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "authors", authors)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numLanguagesData", numLanguagesData)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numLinesData", numLinesData)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numAuthorsData", numAuthorsData)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numFilesData", numFilesData)

	binary, lookErr := exec.LookPath("node")
	check(lookErr)
	args := []string{"node", "./dashboards/"+dashboardPtr+"/dashboard.js"}
	env := os.Environ()
	execErr := syscall.Exec(binary, args, env)
	check(execErr)

}

func showDashboard() {

	chErr := os.Chdir(blessedPtr)
	check(chErr)
	binary, lookErr := exec.LookPath("node")
	check(lookErr)
	args := []string{"node", "./dashboards/"+dashboardPtr+"/dashboard.js"}
	env := os.Environ()
	execErr := syscall.Exec(binary, args, env)
	check(execErr)

}
<commit_msg>fixes #11<commit_after>package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
)

func checkData(repoName string, dashboard string, blessed string) bool {

	data, err := ioutil.ReadFile("db/"+repoName+"/"+dashboard+".data")
	if err != nil {
		return false
	}
	lines := strings.Split(string(data), "\n")

	chErr := os.Chdir(blessed)
	if chErr != nil {
		return false
	}
	for _, line := range lines {
		if line != "\n" && line != "" {
			dt := strings.Split(line, "|")
			if len(dt) < 2 {
				return false
			}
			updateData("dashboards/"+dashboardPtr+"/dashboard.js", dt[0], dt[1])
		}
	}

	return true

}

func saveData(repoName string, dashboard string, vals ...string) {

	err := os.MkdirAll("db/"+repoName, 0644)
	check(err)

	data := ""
	for _, val := range vals {
		data += val+"\n"
	}
	d1 := []byte(data)

	err = ioutil.WriteFile("db/"+repoName+"/"+dashboard+".data", d1, 0644)
	check(err)

}

func updateData(filename string, varName string, data string) {

	input, err := ioutil.ReadFile(filename)
	check(err)

	lines := strings.Split(string(input), "\n")

	for i, line := range lines {
		if strings.Contains(line, "$"+varName) {
			lines[i] = "var "+varName+" = "+data
		}
	}
	output := strings.Join(lines, "\n")
	err = ioutil.WriteFile(filename, []byte(output), 0644)
	check(err)

}

func tableData(rowVals []int, invRows map[int]string) string {

	table := "["

	for i := len(rowVals)-1; i >= 0; i-- {
		table += "['"+strings.Replace(invRows[rowVals[i]], "'", "\\'", -1)+"', '"+strconv.Itoa(rowVals[i])+"'], "
	}
	table = table[0:len(table)-2]+"]"

	return table

}

func barChartData(barVals []int, invBars map[int]string) (string, string) {

	x := "["
	y := "["

	for _, k := range barVals {
		x += "'"+strings.Replace(invBars[k], "'", "\\'", -1)+"', "
		y += "'"+strconv.Itoa(k)+"', "
	}
	x = x[0:len(x)-2]+"]"
	y = y[0:len(y)-2]+"]"

	return x, y

}

func bubbleSort(arr[] int) []int {

	for i:=1; i< len(arr); i++ {
		for j:=0; j < len(arr)-i; j++ {
			if (arr[j] > arr[j+1]) {
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
	}

	return arr

}

func sortMap(m map[string]int) ([]int, map[int]string) {

	// inverting map
	invMap := make(map[int]string, len(m))
	for k,v := range m {
		invMap[v] = k
	}

	// sorting
	sortedKeys := make([]int, len(invMap))
	var i int = 0
	for k := range invMap {
		sortedKeys[i] = k
		i++
	}

	return bubbleSort(sortedKeys), invMap

}

func updateDashboardData(uuidRepo string, repoPtr string, dashboard string) {

	// get data for dashboard
	languages, languageLines := barChartData(sortMap(countLinesPerLanguage(uuidRepo)))
	authors := tableData(sortMap(countAuthorCommits(uuidRepo)))

	// XXX cleanup line charts
	numLanguagesDataX := "x:["
	numLanguagesDataY := "y:["
	numLinesDataX := "x:["
	numLinesDataY := "y:["
	numAuthorsDataX := "x:["
	numAuthorsDataY := "y:["
	numFilesDataX := "x:["
	numFilesDataY := "y:["

	x, y := getCommits(uuidRepo)
	for i := len(x)-1; i >= 0; i-- {
		checkoutCommit(uuidRepo, x[i])

		lineCount := 0
		files := getFiles(uuidRepo)
		for _, file := range files {
			lineCount += countLines(file)
		}
		languageCount := 0
		langMap := countLanguages(uuidRepo)
		for key := range langMap {
			languageCount += langMap[key]
		}

		numLanguagesDataX += "'"+y[x[i]]["timestamp"]+"', "
		numLanguagesDataY += "'"+strconv.Itoa(languageCount)+"', "
		numLinesDataX += "'"+y[x[i]]["timestamp"]+"', "
		numLinesDataY += "'"+strconv.Itoa(lineCount)+"', "
		numAuthorsDataX += "'"+y[x[i]]["timestamp"]+"', "
		numAuthorsDataY += "'"+strconv.Itoa(countAuthorsByCommits(uuidRepo, x[i]))+"', "
		numFilesDataX += "'"+y[x[i]]["timestamp"]+"', "
		numFilesDataY += "'"+strconv.Itoa(countFiles(uuidRepo))+"', "
	}
	checkoutCommit(uuidRepo, x[0])

	numLanguagesData := "{"+numLanguagesDataX[0:len(numLanguagesDataX)-2]+"], "+numLanguagesDataY[0:len(numLanguagesDataY)-2]+"]"+"}"
	numLinesData := "{"+numLinesDataX[0:len(numLinesDataX)-2]+"], "+numLinesDataY[0:len(numLinesDataY)-2]+"]"+"}"
	numAuthorsData := "{"+numAuthorsDataX[0:len(numAuthorsDataX)-2]+"], "+numAuthorsDataY[0:len(numAuthorsDataY)-2]+"]"+"}"
	numFilesData := "{"+numFilesDataX[0:len(numFilesDataX)-2]+"], "+numFilesDataY[0:len(numFilesDataY)-2]+"]"+"}"

	saveData(repoPtr, dashboard, "languages|"+languages, "languageLines|"+languageLines, "authors|"+authors, "numLanguagesData|"+numLanguagesData, "numLinesData|"+numLinesData, "numAuthorsData|"+numAuthorsData, "numFilesData|"+numFilesData)

	chErr := os.Chdir(blessedPtr)
	check(chErr)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "languages", languages)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "languageLines", languageLines)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "authors", authors)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numLanguagesData", numLanguagesData)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numLinesData", numLinesData)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numAuthorsData", numAuthorsData)
	updateData("dashboards/"+dashboardPtr+"/dashboard.js", "numFilesData", numFilesData)

	binary, lookErr := exec.LookPath("node")
	check(lookErr)
	args := []string{"node", "./dashboards/"+dashboardPtr+"/dashboard.js"}
	env := os.Environ()
	execErr := syscall.Exec(binary, args, env)
	check(execErr)

}

func showDashboard() {

	chErr := os.Chdir(blessedPtr)
	check(chErr)
	binary, lookErr := exec.LookPath("node")
	check(lookErr)
	args := []string{"node", "./dashboards/"+dashboardPtr+"/dashboard.js"}
	env := os.Environ()
	execErr := syscall.Exec(binary, args, env)
	check(execErr)

}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

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

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

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

import (
	"knative.dev/pkg/apis"
)

var conditions = apis.NewLivingConditionSet(
	DeploymentsAvailable,
	InstallSucceeded,
)

// GetConditions implements apis.ConditionsAccessor
func (is *KnativeServingStatus) GetConditions() apis.Conditions {
	return is.Conditions
}

// SetConditions implements apis.ConditionsAccessor
func (is *KnativeServingStatus) SetConditions(c apis.Conditions) {
	is.Conditions = c
}

func (is *KnativeServingStatus) IsReady() bool {
	return conditions.Manage(is).IsHappy()
}

func (is *KnativeServingStatus) IsInstalled() bool {
	return is.GetCondition(InstallSucceeded).IsTrue()
}

func (is *KnativeServingStatus) IsAvailable() bool {
	return is.GetCondition(DeploymentsAvailable).IsTrue()
}

func (is *KnativeServingStatus) IsDeploying() bool {
	return is.IsInstalled() && !is.IsAvailable()
}

func (is *KnativeServingStatus) GetCondition(t apis.ConditionType) *apis.Condition {
	return conditions.Manage(is).GetCondition(t)
}

func (is *KnativeServingStatus) InitializeConditions() {
	conditions.Manage(is).InitializeConditions()
}

func (is *KnativeServingStatus) MarkInstallFailed(msg string) {
	conditions.Manage(is).MarkFalse(
		InstallSucceeded,
		"Error",
		"Install failed with message: %s", msg)
}

func (is *KnativeServingStatus) MarkIgnored(msg string) {
	conditions.Manage(is).MarkFalse(
		InstallSucceeded,
		"Ignored",
		"Install not attempted: %s", msg)
}

func (is *KnativeServingStatus) MarkInstallSucceeded() {
	conditions.Manage(is).MarkTrue(InstallSucceeded)
}

func (is *KnativeServingStatus) MarkDeploymentsAvailable() {
	conditions.Manage(is).MarkTrue(DeploymentsAvailable)
}

func (is *KnativeServingStatus) MarkDeploymentsNotReady() {
	conditions.Manage(is).MarkFalse(
		DeploymentsAvailable,
		"NotReady",
		"Waiting on deployments")
}
<commit_msg>Remove unused MarkIgnored lifecycle function (#141)<commit_after>/*
Copyright 2019 The Knative Authors

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

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

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

import (
	"knative.dev/pkg/apis"
)

var conditions = apis.NewLivingConditionSet(
	DeploymentsAvailable,
	InstallSucceeded,
)

// GetConditions implements apis.ConditionsAccessor
func (is *KnativeServingStatus) GetConditions() apis.Conditions {
	return is.Conditions
}

// SetConditions implements apis.ConditionsAccessor
func (is *KnativeServingStatus) SetConditions(c apis.Conditions) {
	is.Conditions = c
}

func (is *KnativeServingStatus) IsReady() bool {
	return conditions.Manage(is).IsHappy()
}

func (is *KnativeServingStatus) IsInstalled() bool {
	return is.GetCondition(InstallSucceeded).IsTrue()
}

func (is *KnativeServingStatus) IsAvailable() bool {
	return is.GetCondition(DeploymentsAvailable).IsTrue()
}

func (is *KnativeServingStatus) IsDeploying() bool {
	return is.IsInstalled() && !is.IsAvailable()
}

func (is *KnativeServingStatus) GetCondition(t apis.ConditionType) *apis.Condition {
	return conditions.Manage(is).GetCondition(t)
}

func (is *KnativeServingStatus) InitializeConditions() {
	conditions.Manage(is).InitializeConditions()
}

func (is *KnativeServingStatus) MarkInstallFailed(msg string) {
	conditions.Manage(is).MarkFalse(
		InstallSucceeded,
		"Error",
		"Install failed with message: %s", msg)
}

func (is *KnativeServingStatus) MarkInstallSucceeded() {
	conditions.Manage(is).MarkTrue(InstallSucceeded)
}

func (is *KnativeServingStatus) MarkDeploymentsAvailable() {
	conditions.Manage(is).MarkTrue(DeploymentsAvailable)
}

func (is *KnativeServingStatus) MarkDeploymentsNotReady() {
	conditions.Manage(is).MarkFalse(
		DeploymentsAvailable,
		"NotReady",
		"Waiting on deployments")
}
<|endoftext|>


<commit_before>package ipam

import (
	"context"
	"fmt"
	"net"

	"github.com/giantswarm/microerror"
	"github.com/giantswarm/micrologger"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha3"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/giantswarm/azure-operator/v5/pkg/helpers"
)

type AzureMachinePoolSubnetReleaserConfig struct {
	CtrlClient client.Client
	Logger     micrologger.Logger
}

// AzureMachinePoolSubnetReleaser is a Releaser implementation that releases an
// allocated subnet for a node pool by removing it from AzureCluster CR.
type AzureMachinePoolSubnetReleaser struct {
	ctrlClient client.Client
	logger     micrologger.Logger
}

func NewAzureMachinePoolSubnetReleaser(config AzureMachinePoolSubnetReleaserConfig) (*AzureMachinePoolSubnetReleaser, error) {
	if config.CtrlClient == nil {
		return nil, microerror.Maskf(invalidConfigError, "%T.CtrlClient must not be empty", config)
	}
	if config.Logger == nil {
		return nil, microerror.Maskf(invalidConfigError, "%T.Logger must not be empty", config)
	}

	p := &AzureMachinePoolSubnetReleaser{
		ctrlClient: config.CtrlClient,
		logger:     config.Logger,
	}

	return p, nil
}

func (r *AzureMachinePoolSubnetReleaser) Release(ctx context.Context, subnet net.IPNet, namespace, name string) error {
	r.logger.Debugf(ctx, "releasing allocated subnet from AzureCluster CR")

	azureMachinePool := &v1alpha3.AzureMachinePool{}
	err := r.ctrlClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, azureMachinePool)
	if err != nil {
		return microerror.Mask(err)
	}

	err = r.removeSubnetFromAzureCluster(ctx, subnet, azureMachinePool)
	if err != nil {
		return microerror.Mask(err)
	}

	r.logger.Debugf(ctx, "released allocated subnet from AzureCluster CR")
	return nil
}

func (r *AzureMachinePoolSubnetReleaser) removeSubnetFromAzureCluster(ctx context.Context, subnet net.IPNet, azureMachinePool *v1alpha3.AzureMachinePool) error {
	azureCluster, err := helpers.GetAzureClusterFromMetadata(ctx, r.ctrlClient, azureMachinePool.ObjectMeta)
	if err != nil {
		errorMessage := fmt.Sprint("error while getting AzureCluster CR from AzureMachinePool CR metadata")
		r.logger.LogCtx(ctx, "level", "warning", "message", errorMessage)
		return microerror.Mask(err)
	}

	for i, subnet := range azureCluster.Spec.NetworkSpec.Subnets {
		if subnet.Name == azureMachinePool.Name {
			azureCluster.Spec.NetworkSpec.Subnets = append(azureCluster.Spec.NetworkSpec.Subnets[:i], azureCluster.Spec.NetworkSpec.Subnets[i+1:]...)
			break
		}
	}

	err = r.ctrlClient.Update(ctx, azureCluster)
	if apierrors.IsConflict(err) {
		r.logger.Debugf(ctx, "conflict trying to save object in k8s API concurrently", "stack", microerror.JSON(microerror.Mask(err)))
		r.logger.Debugf(ctx, "cancelling resource")
	} else if err != nil {
		return microerror.Mask(err)
	}

	return nil
}
<commit_msg>Fix debugf logging (#1320)<commit_after>package ipam

import (
	"context"
	"fmt"
	"net"

	"github.com/giantswarm/microerror"
	"github.com/giantswarm/micrologger"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha3"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/giantswarm/azure-operator/v5/pkg/helpers"
)

type AzureMachinePoolSubnetReleaserConfig struct {
	CtrlClient client.Client
	Logger     micrologger.Logger
}

// AzureMachinePoolSubnetReleaser is a Releaser implementation that releases an
// allocated subnet for a node pool by removing it from AzureCluster CR.
type AzureMachinePoolSubnetReleaser struct {
	ctrlClient client.Client
	logger     micrologger.Logger
}

func NewAzureMachinePoolSubnetReleaser(config AzureMachinePoolSubnetReleaserConfig) (*AzureMachinePoolSubnetReleaser, error) {
	if config.CtrlClient == nil {
		return nil, microerror.Maskf(invalidConfigError, "%T.CtrlClient must not be empty", config)
	}
	if config.Logger == nil {
		return nil, microerror.Maskf(invalidConfigError, "%T.Logger must not be empty", config)
	}

	p := &AzureMachinePoolSubnetReleaser{
		ctrlClient: config.CtrlClient,
		logger:     config.Logger,
	}

	return p, nil
}

func (r *AzureMachinePoolSubnetReleaser) Release(ctx context.Context, subnet net.IPNet, namespace, name string) error {
	r.logger.Debugf(ctx, "releasing allocated subnet from AzureCluster CR")

	azureMachinePool := &v1alpha3.AzureMachinePool{}
	err := r.ctrlClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, azureMachinePool)
	if err != nil {
		return microerror.Mask(err)
	}

	err = r.removeSubnetFromAzureCluster(ctx, subnet, azureMachinePool)
	if err != nil {
		return microerror.Mask(err)
	}

	r.logger.Debugf(ctx, "released allocated subnet from AzureCluster CR")
	return nil
}

func (r *AzureMachinePoolSubnetReleaser) removeSubnetFromAzureCluster(ctx context.Context, subnet net.IPNet, azureMachinePool *v1alpha3.AzureMachinePool) error {
	azureCluster, err := helpers.GetAzureClusterFromMetadata(ctx, r.ctrlClient, azureMachinePool.ObjectMeta)
	if err != nil {
		errorMessage := fmt.Sprint("error while getting AzureCluster CR from AzureMachinePool CR metadata")
		r.logger.LogCtx(ctx, "level", "warning", "message", errorMessage)
		return microerror.Mask(err)
	}

	for i, subnet := range azureCluster.Spec.NetworkSpec.Subnets {
		if subnet.Name == azureMachinePool.Name {
			azureCluster.Spec.NetworkSpec.Subnets = append(azureCluster.Spec.NetworkSpec.Subnets[:i], azureCluster.Spec.NetworkSpec.Subnets[i+1:]...)
			break
		}
	}

	err = r.ctrlClient.Update(ctx, azureCluster)
	if apierrors.IsConflict(err) {
		r.logger.Debugf(ctx, "conflict trying to save object in k8s API concurrently")
		r.logger.Debugf(ctx, "cancelling resource")
	} else if err != nil {
		return microerror.Mask(err)
	}

	return nil
}
<|endoftext|>


<commit_before>package rsync

import (
	"bitbucket.org/kardianos/rsync"
	"bitbucket.org/kardianos/rsync/proto"
)

func getRsync() *rsync.RSync {
	return &rsync.RSync{
		MaxDataOp: 1024 * 16,
	}
}

func signature(basis, signature string, blockSizeKiB int) error {
	rs := getRsync()
	rs.BlockSize = 1024 * blockSizeKiB

	basisFile, err := os.Open(basis)
	if err != nil {
		return err
	}
	defer basisFile.Close()

	sigFile, err := os.Create(signature)
	if err != nil {
		return err
	}
	defer sigFile.Close()

	sigEncode := &proto.Writer{Writer: sigFile}

	err = sigEncode.Header(proto.TypeSignature, proto.CompNone, rs.BlockSize)
	if err != nil {
		return err
	}
	defer sigEncode.Close()

	return rs.CreateSignature(basisFile, sigEncode.SignatureWriter())
}

func delta(signature, newfile, delta string, checkFile bool, comp proto.Comp) error {
	rs := getRsync()
	sigFile, err := os.Open(signature)
	if err != nil {
		return err
	}
	defer sigFile.Close()

	nfFile, err := os.Open(newfile)
	if err != nil {
		return err
	}
	defer nfFile.Close()

	deltaFile, err := os.Create(delta)
	if err != nil {
		return err
	}
	defer deltaFile.Close()

	// Load signature hash list.
	sigDecode := &proto.Reader{Reader: sigFile}
	rs.BlockSize, err = sigDecode.Header(proto.TypeSignature)
	if err != nil {
		if err == io.EOF {
			return io.ErrUnexpectedEOF
		}
		return err
	}
	defer sigDecode.Close()

	hl, err := sigDecode.ReadAllSignatures()
	if err != nil {
		return err
	}
	if *verbose {
		fmt.Printf("Signature Count: %d\n", len(hl))
	}

	// Save operations to file.
	opsEncode := &proto.Writer{Writer: deltaFile}
	err = opsEncode.Header(proto.TypeDelta, comp, rs.BlockSize)
	if err != nil {
		return err
	}
	defer opsEncode.Close()

	var hasher hash.Hash
	if checkFile {
		hasher = md5.New()
	}
	opF := opsEncode.OperationWriter()
	err = rs.CreateDelta(nfFile, hl, opF, hasher)
	if err != nil {
		return err
	}
	if checkFile {
		return opF(rsync.Operation{
			Type: rsync.OpHash,
			Data: hasher.Sum(nil),
		})
	}
	return nil
}

func patch(basis, delta, newfile string, checkFile bool) error {
	rs := getRsync()
	basisFile, err := os.Open(basis)
	if err != nil {
		return err
	}
	defer basisFile.Close()

	deltaFile, err := os.Open(delta)
	if err != nil {
		return err
	}
	defer deltaFile.Close()

	fsFile, err := os.Create(newfile)
	if err != nil {
		return err
	}
	defer fsFile.Close()

	deltaDecode := proto.Reader{Reader: deltaFile}
	rs.BlockSize, err = deltaDecode.Header(proto.TypeDelta)
	if err != nil {
		if err == io.EOF {
			return io.ErrUnexpectedEOF
		}
		return err
	}
	defer deltaDecode.Close()

	hashOps := make(chan rsync.Operation, 2)
	ops := make(chan rsync.Operation)
	// Load operations from file.
	var decodeError error
	go func() {
		defer close(ops)
		decodeError = deltaDecode.ReadOperations(ops, hashOps)
	}()

	var hasher hash.Hash
	if checkFile {
		hasher = md5.New()
	}
	err = rs.ApplyDelta(fsFile, basisFile, ops, hasher)
	if err != nil {
		return err
	}
	if decodeError != nil {
		return decodeError
	}
	if checkFile == false {
		return nil
	}
	hashOp := <-hashOps
	if hashOp.Data == nil {
		return NoTargetSumError
	}
	if bytes.Equal(hashOp.Data, hasher.Sum(nil)) == false {
		return HashNoMatchError
	}

	return nil
}
<commit_msg>added `os` as a dependency in `rsync/delta.go`<commit_after>package rsync

import (
	"os"

	"bitbucket.org/kardianos/rsync"
	"bitbucket.org/kardianos/rsync/proto"
)

func getRsync() *rsync.RSync {
	return &rsync.RSync{
		MaxDataOp: 1024 * 16,
	}
}

func signature(basis, signature string, blockSizeKiB int) error {
	rs := getRsync()
	rs.BlockSize = 1024 * blockSizeKiB

	basisFile, err := os.Open(basis)
	if err != nil {
		return err
	}
	defer basisFile.Close()

	sigFile, err := os.Create(signature)
	if err != nil {
		return err
	}
	defer sigFile.Close()

	sigEncode := &proto.Writer{Writer: sigFile}

	err = sigEncode.Header(proto.TypeSignature, proto.CompNone, rs.BlockSize)
	if err != nil {
		return err
	}
	defer sigEncode.Close()

	return rs.CreateSignature(basisFile, sigEncode.SignatureWriter())
}

func delta(signature, newfile, delta string, checkFile bool, comp proto.Comp) error {
	rs := getRsync()
	sigFile, err := os.Open(signature)
	if err != nil {
		return err
	}
	defer sigFile.Close()

	nfFile, err := os.Open(newfile)
	if err != nil {
		return err
	}
	defer nfFile.Close()

	deltaFile, err := os.Create(delta)
	if err != nil {
		return err
	}
	defer deltaFile.Close()

	// Load signature hash list.
	sigDecode := &proto.Reader{Reader: sigFile}
	rs.BlockSize, err = sigDecode.Header(proto.TypeSignature)
	if err != nil {
		if err == io.EOF {
			return io.ErrUnexpectedEOF
		}
		return err
	}
	defer sigDecode.Close()

	hl, err := sigDecode.ReadAllSignatures()
	if err != nil {
		return err
	}
	if *verbose {
		fmt.Printf("Signature Count: %d\n", len(hl))
	}

	// Save operations to file.
	opsEncode := &proto.Writer{Writer: deltaFile}
	err = opsEncode.Header(proto.TypeDelta, comp, rs.BlockSize)
	if err != nil {
		return err
	}
	defer opsEncode.Close()

	var hasher hash.Hash
	if checkFile {
		hasher = md5.New()
	}
	opF := opsEncode.OperationWriter()
	err = rs.CreateDelta(nfFile, hl, opF, hasher)
	if err != nil {
		return err
	}
	if checkFile {
		return opF(rsync.Operation{
			Type: rsync.OpHash,
			Data: hasher.Sum(nil),
		})
	}
	return nil
}

func patch(basis, delta, newfile string, checkFile bool) error {
	rs := getRsync()
	basisFile, err := os.Open(basis)
	if err != nil {
		return err
	}
	defer basisFile.Close()

	deltaFile, err := os.Open(delta)
	if err != nil {
		return err
	}
	defer deltaFile.Close()

	fsFile, err := os.Create(newfile)
	if err != nil {
		return err
	}
	defer fsFile.Close()

	deltaDecode := proto.Reader{Reader: deltaFile}
	rs.BlockSize, err = deltaDecode.Header(proto.TypeDelta)
	if err != nil {
		if err == io.EOF {
			return io.ErrUnexpectedEOF
		}
		return err
	}
	defer deltaDecode.Close()

	hashOps := make(chan rsync.Operation, 2)
	ops := make(chan rsync.Operation)
	// Load operations from file.
	var decodeError error
	go func() {
		defer close(ops)
		decodeError = deltaDecode.ReadOperations(ops, hashOps)
	}()

	var hasher hash.Hash
	if checkFile {
		hasher = md5.New()
	}
	err = rs.ApplyDelta(fsFile, basisFile, ops, hasher)
	if err != nil {
		return err
	}
	if decodeError != nil {
		return decodeError
	}
	if checkFile == false {
		return nil
	}
	hashOp := <-hashOps
	if hashOp.Data == nil {
		return NoTargetSumError
	}
	if bytes.Equal(hashOp.Data, hasher.Sum(nil)) == false {
		return HashNoMatchError
	}

	return nil
}
<|endoftext|>


<commit_before>package gist5645828

import (
	"fmt"
	"go/ast"
	"go/doc"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	. "github.com/shurcooL/go/gists/gist5504644"
	. "github.com/shurcooL/go/gists/gist5639599"
)

func PrintPackageFullSummary(dpkg *doc.Package) {
	FprintPackageFullSummary(os.Stdout, dpkg)
}

func FprintPackageFullSummary(w io.Writer, dpkg *doc.Package) {
	for _, v := range dpkg.Vars {
		for _, spec := range v.Decl.Specs {
			spec.(*ast.ValueSpec).Comment = nil
		}
		fmt.Fprintln(w, SprintAstBare(v.Decl))
	}
	for _, t := range dpkg.Types {
		for _, v := range t.Vars {
			for _, spec := range v.Decl.Specs {
				spec.(*ast.ValueSpec).Comment = nil
			}
			fmt.Fprintln(w, SprintAstBare(v.Decl))
		}
	}
	fmt.Fprintln(w)
	for _, f := range dpkg.Funcs {
		fmt.Fprintln(w, SprintAstBare(f.Decl))
	}
	for _, t := range dpkg.Types {
		for _, f := range t.Funcs {
			fmt.Fprintln(w, SprintAstBare(f.Decl))
		}
		for _, m := range t.Methods {
			fmt.Fprintln(w, SprintAstBare(m.Decl))
		}
	}
	fmt.Fprintln(w)
	for _, c := range dpkg.Consts {
		for _, spec := range c.Decl.Specs {
			spec.(*ast.ValueSpec).Values = nil
			spec.(*ast.ValueSpec).Comment = nil
		}
		fmt.Fprintln(w, SprintAstBare(c.Decl))
		//fmt.Fprintln(w, "const", strings.Join(c.Names, "\n"))
	}
	for _, t := range dpkg.Types {
		for _, c := range t.Consts {
			for _, spec := range c.Decl.Specs {
				spec.(*ast.ValueSpec).Values = nil
				spec.(*ast.ValueSpec).Comment = nil
			}
			fmt.Fprintln(w, SprintAstBare(c.Decl))
			//fmt.Fprintln(w, "const", strings.Join(c.Names, "\n"))
		}
	}
	fmt.Fprintln(w)
	for _, t := range dpkg.Types {
		//fmt.Fprintln(w, SprintAstBare(t.Decl))
		fmt.Fprintln(w, "type", t.Name)
	}
}

func printPackageSummary(dpkg *doc.Package) {
	fmt.Println(`import . "` + dpkg.ImportPath + `"`)
	for _, f := range dpkg.Funcs {
		fmt.Print("\t")
		PrintlnAstBare(f.Decl)
	}
	for _, t := range dpkg.Types {
		for _, f := range t.Funcs {
			fmt.Print("\t")
			PrintlnAstBare(f.Decl)
		}
		// THINK: Do I want to include methods?
		/*for _, m := range t.Methods {
			fmt.Print("\t")
			PrintlnAstBare(m.Decl)
		}*/
	}
	fmt.Println()
}

func hasAnyFuncs(dpkg *doc.Package) bool {
	if len(dpkg.Funcs) > 0 {
		return true
	}

	for _, t := range dpkg.Types {
		if len(t.Funcs) > 0 {
			return true
		}
	}

	return false
}

func PrintPackageSummary(ImportPath string) {
	dpkg, err := GetDocPackage(BuildPackageFromImportPath(ImportPath))
	if err != nil {
		return
	}
	if !hasAnyFuncs(dpkg) {
		return
	}
	printPackageSummary(dpkg)
}

func PrintPackageSummaryWithPath(ImportPath, fullPath string) {
	dpkg, err := GetDocPackage(BuildPackageFromImportPath(ImportPath))
	if err != nil {
		return
	}
	if !hasAnyFuncs(dpkg) {
		return
	}
	fmt.Println(filepath.Join(fullPath, dpkg.Filenames[0]))
	printPackageSummary(dpkg)
}

func PrintPackageSummariesInDir(dirname string) {
	gopathEntries := filepath.SplitList(os.Getenv("GOPATH"))
	for _, gopathEntry := range gopathEntries {
		path0 := filepath.Join(gopathEntry, "src")
		entries, err := ioutil.ReadDir(filepath.Join(path0, dirname))
		//CheckError(err)
		if err != nil {
			continue
		}
		//for _, v := range entries {
		for i := len(entries) - 1; i >= 0; i-- {
			v := entries[i]
			if v.IsDir() { // TODO: Build a build.Package to figure out if this is a valid Go package; rather than assuming all dirs are
				//PrintPackageSummaryWithPath(filepath.Join(dirname, v.Name()), filepath.Join(path0, dirname, v.Name()))
				PrintPackageSummary(filepath.Join(dirname, v.Name()))
			}
		}
	}
}

func main() {
	//PrintPackageSummary("gist.github.com/5639599.git"); return
	//PrintPackageSummariesInDir("gist.github.com")
	dpkg, err := GetDocPackageAll(BuildPackageFromImportPath("github.com/shurcooL/Conception-go"))
	if err != nil {
		panic(err)
	}
	PrintPackageFullSummary(dpkg)
}
<commit_msg>FprintPackageFullSummary: Avoid unintended comment blocks.<commit_after>package gist5645828

import (
	"fmt"
	"go/ast"
	"go/doc"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	. "github.com/shurcooL/go/gists/gist5504644"
	. "github.com/shurcooL/go/gists/gist5639599"
)

func PrintPackageFullSummary(dpkg *doc.Package) {
	FprintPackageFullSummary(os.Stdout, dpkg)
}

func FprintPackageFullSummary(w io.Writer, dpkg *doc.Package) {
	for _, v := range dpkg.Vars {
		for _, spec := range v.Decl.Specs {
			spec.(*ast.ValueSpec).Doc = nil
			spec.(*ast.ValueSpec).Comment = nil
		}
		fmt.Fprintln(w, SprintAstBare(v.Decl))
	}
	for _, t := range dpkg.Types {
		for _, v := range t.Vars {
			for _, spec := range v.Decl.Specs {
				spec.(*ast.ValueSpec).Doc = nil
				spec.(*ast.ValueSpec).Comment = nil
			}
			fmt.Fprintln(w, SprintAstBare(v.Decl))
		}
	}
	fmt.Fprintln(w)
	for _, f := range dpkg.Funcs {
		fmt.Fprintln(w, SprintAstBare(f.Decl))
	}
	for _, t := range dpkg.Types {
		for _, f := range t.Funcs {
			fmt.Fprintln(w, SprintAstBare(f.Decl))
		}
		for _, m := range t.Methods {
			fmt.Fprintln(w, SprintAstBare(m.Decl))
		}
	}
	fmt.Fprintln(w)
	for _, c := range dpkg.Consts {
		for _, spec := range c.Decl.Specs {
			spec.(*ast.ValueSpec).Values = nil
			spec.(*ast.ValueSpec).Doc = nil
			spec.(*ast.ValueSpec).Comment = nil
		}
		fmt.Fprintln(w, SprintAstBare(c.Decl))
		//fmt.Fprintln(w, "const", strings.Join(c.Names, "\n"))
	}
	for _, t := range dpkg.Types {
		for _, c := range t.Consts {
			for _, spec := range c.Decl.Specs {
				spec.(*ast.ValueSpec).Values = nil
				spec.(*ast.ValueSpec).Doc = nil
				spec.(*ast.ValueSpec).Comment = nil
			}
			fmt.Fprintln(w, SprintAstBare(c.Decl))
			//fmt.Fprintln(w, "const", strings.Join(c.Names, "\n"))
		}
	}
	fmt.Fprintln(w)
	for _, t := range dpkg.Types {
		//fmt.Fprintln(w, SprintAstBare(t.Decl))
		fmt.Fprintln(w, "type", t.Name)
	}
}

func printPackageSummary(dpkg *doc.Package) {
	fmt.Println(`import . "` + dpkg.ImportPath + `"`)
	for _, f := range dpkg.Funcs {
		fmt.Print("\t")
		PrintlnAstBare(f.Decl)
	}
	for _, t := range dpkg.Types {
		for _, f := range t.Funcs {
			fmt.Print("\t")
			PrintlnAstBare(f.Decl)
		}
		// THINK: Do I want to include methods?
		/*for _, m := range t.Methods {
			fmt.Print("\t")
			PrintlnAstBare(m.Decl)
		}*/
	}
	fmt.Println()
}

func hasAnyFuncs(dpkg *doc.Package) bool {
	if len(dpkg.Funcs) > 0 {
		return true
	}

	for _, t := range dpkg.Types {
		if len(t.Funcs) > 0 {
			return true
		}
	}

	return false
}

func PrintPackageSummary(ImportPath string) {
	dpkg, err := GetDocPackage(BuildPackageFromImportPath(ImportPath))
	if err != nil {
		return
	}
	if !hasAnyFuncs(dpkg) {
		return
	}
	printPackageSummary(dpkg)
}

func PrintPackageSummaryWithPath(ImportPath, fullPath string) {
	dpkg, err := GetDocPackage(BuildPackageFromImportPath(ImportPath))
	if err != nil {
		return
	}
	if !hasAnyFuncs(dpkg) {
		return
	}
	fmt.Println(filepath.Join(fullPath, dpkg.Filenames[0]))
	printPackageSummary(dpkg)
}

func PrintPackageSummariesInDir(dirname string) {
	gopathEntries := filepath.SplitList(os.Getenv("GOPATH"))
	for _, gopathEntry := range gopathEntries {
		path0 := filepath.Join(gopathEntry, "src")
		entries, err := ioutil.ReadDir(filepath.Join(path0, dirname))
		//CheckError(err)
		if err != nil {
			continue
		}
		//for _, v := range entries {
		for i := len(entries) - 1; i >= 0; i-- {
			v := entries[i]
			if v.IsDir() { // TODO: Build a build.Package to figure out if this is a valid Go package; rather than assuming all dirs are
				//PrintPackageSummaryWithPath(filepath.Join(dirname, v.Name()), filepath.Join(path0, dirname, v.Name()))
				PrintPackageSummary(filepath.Join(dirname, v.Name()))
			}
		}
	}
}

func main() {
	//PrintPackageSummary("gist.github.com/5639599.git"); return
	//PrintPackageSummariesInDir("gist.github.com")
	dpkg, err := GetDocPackageAll(BuildPackageFromImportPath("github.com/microcosm-cc/bluemonday"))
	if err != nil {
		panic(err)
	}
	PrintPackageFullSummary(dpkg)
}
<|endoftext|>


<commit_before>package reset
<commit_msg>Added unit test for Start<commit_after>package reset

import (
	"context"
	"testing"

	"github.com/google/gnxi/gnoi/reset/pb"
)

func TestStart(t *testing.T) {
	testSettings := []Settings{
		{false, false},
		{false, true},
		{true, false},
		{true, true},
	}

	testRequests := []pb.StartRequest{
		{ZeroFill: true},
		{ZeroFill: true, FactoryOs: true},
		{FactoryOs: true},
		{},
	}

	for _, test := range testSettings {
		s := NewServer(&test)
		for _, testReq := range testRequests {
			resp, _ := s.Start(context.Background(), &testReq)
			switch response := resp.Response.(type) {
			case *pb.StartResponse_ResetSuccess:
				if test.errorIfZero && testReq.ZeroFill || test.osUnsupported && testReq.FactoryOs {
					t.Errorf(
						"Error occured on case: \nSettings{errIfZero:%v,osUnsupported:%v}\nRequest{ZeroFill:%v,FactoryOs:%v} \nResponseSuccess{%v},",
						test.errorIfZero,
						test.osUnsupported,
						testReq.ZeroFill,
						testReq.FactoryOs,
						response)
				}
			case *pb.StartResponse_ResetError:
				if response.ResetError.ZeroFillUnsupported != (test.errorIfZero && testReq.ZeroFill) ||
					response.ResetError.FactoryOsUnsupported != (test.osUnsupported && testReq.FactoryOs) {
					t.Errorf(
						"Error occured on case: \nSettings{errIfZero:%v,osUnsupported:%v}\nRequest{ZeroFill:%v,FactoryOs:%v} \nResponseError{%v},",
						test.errorIfZero,
						test.osUnsupported,
						testReq.ZeroFill,
						testReq.FactoryOs,
						response)
				}
			}
		}
	}
}
<|endoftext|>