<commit_before>// Package encoding converts arbitrary objects into byte slices, and vis
// versa. It also contains helper functions for reading and writing length-
// prefixed data. See doc/Encoding.md for the full encoding specification.
package encoding

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"reflect"
)

const (
	maxDecodeLen = 12e6 // 12 MB
	maxSliceLen  = 5e6  // 5 MB
)

var (
	errBadPointer = errors.New("cannot decode into invalid pointer")
)

type (
	// GenericMarshaler marshals objects into byte slices and unmarshals byte
	// slices into objects.
	GenericMarshaler interface {
		Marshal(interface{}) []byte
		Unmarshal([]byte, interface{}) error
	}

	// A SiaMarshaler can encode and write itself to a stream.
	SiaMarshaler interface {
		MarshalSia(io.Writer) error
	}

	// A SiaUnmarshaler can read and decode itself from a stream.
	SiaUnmarshaler interface {
		UnmarshalSia(io.Reader) error
	}

	// StdGenericMarshaler is an implementation of GenericMarshaler that uses
	// the encoding.Marshal and encoding.Unmarshal functions to perform
	// its marshaling/unmarshaling.
	StdGenericMarshaler struct{}

	// An Encoder writes objects to an output stream.
	Encoder struct {
		w io.Writer
	}
)

// Encode writes the encoding of v to the stream. For encoding details, see
// the package docstring.
func (e *Encoder) Encode(v interface{}) error {
	return e.encode(reflect.ValueOf(v))
}

// EncodeAll encodes a variable number of arguments.
func (e *Encoder) EncodeAll(vs ...interface{}) error {
	for _, v := range vs {
		if err := e.Encode(v); err != nil {
			return err
		}
	}
	return nil
}

// write catches instances where short writes do not return an error.
func (e *Encoder) write(p []byte) error {
	n, err := e.w.Write(p)
	if n != len(p) && err == nil {
		return io.ErrShortWrite
	}
	return err
}

// Encode writes the encoding of val to the stream. For encoding details, see
// the package docstring.
func (e *Encoder) encode(val reflect.Value) error {
	// check for MarshalSia interface first
	if val.CanInterface() {
		if m, ok := val.Interface().(SiaMarshaler); ok {
			return m.MarshalSia(e.w)
		}
	}

	switch val.Kind() {
	case reflect.Ptr:
		// write either a 1 or 0
		if err := e.Encode(!val.IsNil()); err != nil {
			return err
		}
		if !val.IsNil() {
			return e.encode(val.Elem())
		}
	case reflect.Bool:
		if val.Bool() {
			return e.write([]byte{1})
		} else {
			return e.write([]byte{0})
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return e.write(EncInt64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return e.write(EncUint64(val.Uint()))
	case reflect.String:
		return WritePrefix(e.w, []byte(val.String()))
	case reflect.Slice:
		// slices are variable length, so prepend the length and then fallthrough to array logic
		if err := e.write(EncUint64(uint64(val.Len()))); err != nil {
			return err
		}
		if val.Len() == 0 {
			return nil
		}
		fallthrough
	case reflect.Array:
		// special case for byte arrays
		if val.Type().Elem().Kind() == reflect.Uint8 {
			// if the array is addressable, we can optimize a bit here
			if val.CanAddr() {
				return e.write(val.Slice(0, val.Len()).Bytes())
			}
			// otherwise we have to copy into a newly allocated slice
			slice := reflect.MakeSlice(reflect.SliceOf(val.Type().Elem()), val.Len(), val.Len())
			reflect.Copy(slice, val)
			return e.write(slice.Bytes())
		}
		// normal slices/arrays are encoded by sequentially encoding their elements
		for i := 0; i < val.Len(); i++ {
			if err := e.encode(val.Index(i)); err != nil {
				return err
			}
		}
		return nil
	case reflect.Struct:
		for i := 0; i < val.NumField(); i++ {
			if err := e.encode(val.Field(i)); err != nil {
				return err
			}
		}
		return nil
	}

	// Marshalling should never fail. If it panics, you're doing something wrong,
	// like trying to encode a map or an unexported struct field.
	panic("could not marshal type " + val.Type().String())
}

// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

// Marshal returns the encoding of v. For encoding details, see the package
// docstring.
func Marshal(v interface{}) []byte {
	b := new(bytes.Buffer)
	NewEncoder(b).Encode(v) // no error possible when using a bytes.Buffer
	return b.Bytes()
}

// MarshalAll encodes all of its inputs and returns their concatenation.
func MarshalAll(vs ...interface{}) []byte {
	b := new(bytes.Buffer)
	enc := NewEncoder(b)
	// can't encode with EncodeAll (type information is lost)
	for _, v := range vs {
		enc.Encode(v)
	}
	return b.Bytes()
}

// WriteFile writes v to a file. The file will be created if it does not exist.
func WriteFile(filename string, v interface{}) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()
	err = NewEncoder(file).Encode(v)
	if err != nil {
		return errors.New("error while writing " + filename + ": " + err.Error())
	}
	return nil
}

// A Decoder reads and decodes values from an input stream.
type Decoder struct {
	r io.Reader
	n int
}

// Read implements the io.Reader interface. It also keeps track of the total
// number of bytes decoded, and panics if that number exceeds a global
// maximum.
func (d *Decoder) Read(p []byte) (int, error) {
	n, err := d.r.Read(p)
	// enforce an absolute maximum size limit
	if d.n += n; d.n > maxDecodeLen {
		panic("encoded type exceeds size limit")
	}
	return n, err
}

// Decode reads the next encoded value from its input stream and stores it in
// v, which must be a pointer. The decoding rules are the inverse of those
// specified in the package docstring.
func (d *Decoder) Decode(v interface{}) (err error) {
	// v must be a pointer
	pval := reflect.ValueOf(v)
	if pval.Kind() != reflect.Ptr || pval.IsNil() {
		return errBadPointer
	}

	// catch decoding panics and convert them to errors
	// note that this allows us to skip boundary checks during decoding
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("could not decode type %s: %v", pval.Elem().Type().String(), r)
		}
	}()

	// reset the read count
	d.n = 0

	d.decode(pval.Elem())
	return
}

// DecodeAll decodes a variable number of arguments.
func (d *Decoder) DecodeAll(vs ...interface{}) error {
	for _, v := range vs {
		if err := d.Decode(v); err != nil {
			return err
		}
	}
	return nil
}

// readN reads n bytes and panics if the read fails.
func (d *Decoder) readN(n int) []byte {
	b := make([]byte, n)
	_, err := io.ReadFull(d, b)
	if err != nil {
		panic(err)
	}
	return b
}

// readPrefix reads a length-prefixed byte slice and panics if the read fails.
func (d *Decoder) readPrefix() []byte {
	b, err := ReadPrefix(d, maxSliceLen)
	if err != nil {
		panic(err)
	}
	return b
}

// decode reads the next encoded value from its input stream and stores it in
// val. The decoding rules are the inverse of those specified in the package
// docstring.
func (d *Decoder) decode(val reflect.Value) {
	// check for UnmarshalSia interface first
	if val.CanAddr() && val.Addr().CanInterface() {
		if u, ok := val.Addr().Interface().(SiaUnmarshaler); ok {
			err := u.UnmarshalSia(d)
			if err != nil {
				panic(err)
			}
			return
		}
	}

	switch val.Kind() {
	case reflect.Ptr:
		var valid bool
		d.decode(reflect.ValueOf(&valid).Elem())
		// nil pointer, nothing to decode
		if !valid {
			return
		}
		// make sure we aren't decoding into nil
		if val.IsNil() {
			val.Set(reflect.New(val.Type().Elem()))
		}
		d.decode(val.Elem())
	case reflect.Bool:
		b := d.readN(1)
		if b[0] > 1 {
			panic("boolean value was not 0 or 1")
		}
		val.SetBool(b[0] == 1)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		val.SetInt(DecInt64(d.readN(8)))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		val.SetUint(DecUint64(d.readN(8)))
	case reflect.String:
		val.SetString(string(d.readPrefix()))
	case reflect.Slice:
		// slices are variable length, but otherwise the same as arrays.
		// just have to allocate them first, then we can fallthrough to the array logic.
		sliceLen := DecUint64(d.readN(8))
		// sanity-check the sliceLen, otherwise you can crash a peer by making
		// them allocate a massive slice
		if sliceLen > 1<<31-1 || sliceLen*uint64(val.Type().Elem().Size()) > maxSliceLen {
			panic("slice is too large")
		} else if sliceLen == 0 {
			return
		}
		val.Set(reflect.MakeSlice(val.Type(), int(sliceLen), int(sliceLen)))
		fallthrough
	case reflect.Array:
		// special case for byte arrays (e.g. hashes)
		if val.Type().Elem().Kind() == reflect.Uint8 {
			// convert val to a slice and read into it directly
			b := val.Slice(0, val.Len())
			_, err := io.ReadFull(d, b.Bytes())
			if err != nil {
				panic(err)
			}
			return
		}
		// arrays are unmarshalled by sequentially unmarshalling their elements
		for i := 0; i < val.Len(); i++ {
			d.decode(val.Index(i))
		}
		return
	case reflect.Struct:
		for i := 0; i < val.NumField(); i++ {
			d.decode(val.Field(i))
		}
		return
	default:
		panic("unknown type")
	}
}

// NewDecoder returns a new decoder that reads from r.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{r, 0}
}

// Unmarshal decodes the encoded value b and stores it in v, which must be a
// pointer. The decoding rules are the inverse of those specified in the
// package docstring for marshaling.
func Unmarshal(b []byte, v interface{}) error {
	r := bytes.NewReader(b)
	return NewDecoder(r).Decode(v)
}

// UnmarshalAll decodes the encoded values in b and stores them in vs, which
// must be pointers.
func UnmarshalAll(b []byte, vs ...interface{}) error {
	dec := NewDecoder(bytes.NewReader(b))
	// can't use DecodeAll (type information is lost)
	for _, v := range vs {
		if err := dec.Decode(v); err != nil {
			return err
		}
	}
	return nil
}

// ReadFile reads the contents of a file and decodes them into v.
func ReadFile(filename string, v interface{}) error {
	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer file.Close()
	err = NewDecoder(file).Decode(v)
	if err != nil {
		return errors.New("error while reading " + filename + ": " + err.Error())
	}
	return nil
}

// Marshal returns the encoding of v. For encoding details, see the package
// docstring.
func (m StdGenericMarshaler) Marshal(v interface{}) []byte {
	return Marshal(v)
}

// Unmarshal decodes the encoded value b and stores it in v, which must be a
// pointer. The decoding rules are the inverse of those specified in the
// package docstring for marshaling.
func (m StdGenericMarshaler) Unmarshal(b []byte, v interface{}) error {
	return Unmarshal(b, v)
}
<commit_msg>Use {En,De}codeAll in {M,Unm}arshalAll, respectively<commit_after>// Package encoding converts arbitrary objects into byte slices, and vis
// versa. It also contains helper functions for reading and writing length-
// prefixed data. See doc/Encoding.md for the full encoding specification.
package encoding

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"reflect"
)

const (
	maxDecodeLen = 12e6 // 12 MB
	maxSliceLen  = 5e6  // 5 MB
)

var (
	errBadPointer = errors.New("cannot decode into invalid pointer")
)

type (
	// GenericMarshaler marshals objects into byte slices and unmarshals byte
	// slices into objects.
	GenericMarshaler interface {
		Marshal(interface{}) []byte
		Unmarshal([]byte, interface{}) error
	}

	// A SiaMarshaler can encode and write itself to a stream.
	SiaMarshaler interface {
		MarshalSia(io.Writer) error
	}

	// A SiaUnmarshaler can read and decode itself from a stream.
	SiaUnmarshaler interface {
		UnmarshalSia(io.Reader) error
	}

	// StdGenericMarshaler is an implementation of GenericMarshaler that uses
	// the encoding.Marshal and encoding.Unmarshal functions to perform
	// its marshaling/unmarshaling.
	StdGenericMarshaler struct{}

	// An Encoder writes objects to an output stream.
	Encoder struct {
		w io.Writer
	}
)

// Encode writes the encoding of v to the stream. For encoding details, see
// the package docstring.
func (e *Encoder) Encode(v interface{}) error {
	return e.encode(reflect.ValueOf(v))
}

// EncodeAll encodes a variable number of arguments.
func (e *Encoder) EncodeAll(vs ...interface{}) error {
	for _, v := range vs {
		if err := e.Encode(v); err != nil {
			return err
		}
	}
	return nil
}

// write catches instances where short writes do not return an error.
func (e *Encoder) write(p []byte) error {
	n, err := e.w.Write(p)
	if n != len(p) && err == nil {
		return io.ErrShortWrite
	}
	return err
}

// Encode writes the encoding of val to the stream. For encoding details, see
// the package docstring.
func (e *Encoder) encode(val reflect.Value) error {
	// check for MarshalSia interface first
	if val.CanInterface() {
		if m, ok := val.Interface().(SiaMarshaler); ok {
			return m.MarshalSia(e.w)
		}
	}

	switch val.Kind() {
	case reflect.Ptr:
		// write either a 1 or 0
		if err := e.Encode(!val.IsNil()); err != nil {
			return err
		}
		if !val.IsNil() {
			return e.encode(val.Elem())
		}
	case reflect.Bool:
		if val.Bool() {
			return e.write([]byte{1})
		} else {
			return e.write([]byte{0})
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return e.write(EncInt64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return e.write(EncUint64(val.Uint()))
	case reflect.String:
		return WritePrefix(e.w, []byte(val.String()))
	case reflect.Slice:
		// slices are variable length, so prepend the length and then fallthrough to array logic
		if err := e.write(EncUint64(uint64(val.Len()))); err != nil {
			return err
		}
		if val.Len() == 0 {
			return nil
		}
		fallthrough
	case reflect.Array:
		// special case for byte arrays
		if val.Type().Elem().Kind() == reflect.Uint8 {
			// if the array is addressable, we can optimize a bit here
			if val.CanAddr() {
				return e.write(val.Slice(0, val.Len()).Bytes())
			}
			// otherwise we have to copy into a newly allocated slice
			slice := reflect.MakeSlice(reflect.SliceOf(val.Type().Elem()), val.Len(), val.Len())
			reflect.Copy(slice, val)
			return e.write(slice.Bytes())
		}
		// normal slices/arrays are encoded by sequentially encoding their elements
		for i := 0; i < val.Len(); i++ {
			if err := e.encode(val.Index(i)); err != nil {
				return err
			}
		}
		return nil
	case reflect.Struct:
		for i := 0; i < val.NumField(); i++ {
			if err := e.encode(val.Field(i)); err != nil {
				return err
			}
		}
		return nil
	}

	// Marshalling should never fail. If it panics, you're doing something wrong,
	// like trying to encode a map or an unexported struct field.
	panic("could not marshal type " + val.Type().String())
}

// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

// Marshal returns the encoding of v. For encoding details, see the package
// docstring.
func Marshal(v interface{}) []byte {
	b := new(bytes.Buffer)
	NewEncoder(b).Encode(v) // no error possible when using a bytes.Buffer
	return b.Bytes()
}

// MarshalAll encodes all of its inputs and returns their concatenation.
func MarshalAll(vs ...interface{}) []byte {
	b := new(bytes.Buffer)
	enc := NewEncoder(b)
	// Error from EncodeAll is ignored as encoding cannot fail when writing
	// to a bytes.Buffer.
	_ = enc.EncodeAll(vs...)
	return b.Bytes()
}

// WriteFile writes v to a file. The file will be created if it does not exist.
func WriteFile(filename string, v interface{}) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()
	err = NewEncoder(file).Encode(v)
	if err != nil {
		return errors.New("error while writing " + filename + ": " + err.Error())
	}
	return nil
}

// A Decoder reads and decodes values from an input stream.
type Decoder struct {
	r io.Reader
	n int
}

// Read implements the io.Reader interface. It also keeps track of the total
// number of bytes decoded, and panics if that number exceeds a global
// maximum.
func (d *Decoder) Read(p []byte) (int, error) {
	n, err := d.r.Read(p)
	// enforce an absolute maximum size limit
	if d.n += n; d.n > maxDecodeLen {
		panic("encoded type exceeds size limit")
	}
	return n, err
}

// Decode reads the next encoded value from its input stream and stores it in
// v, which must be a pointer. The decoding rules are the inverse of those
// specified in the package docstring.
func (d *Decoder) Decode(v interface{}) (err error) {
	// v must be a pointer
	pval := reflect.ValueOf(v)
	if pval.Kind() != reflect.Ptr || pval.IsNil() {
		return errBadPointer
	}

	// catch decoding panics and convert them to errors
	// note that this allows us to skip boundary checks during decoding
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("could not decode type %s: %v", pval.Elem().Type().String(), r)
		}
	}()

	// reset the read count
	d.n = 0

	d.decode(pval.Elem())
	return
}

// DecodeAll decodes a variable number of arguments.
func (d *Decoder) DecodeAll(vs ...interface{}) error {
	for _, v := range vs {
		if err := d.Decode(v); err != nil {
			return err
		}
	}
	return nil
}

// readN reads n bytes and panics if the read fails.
func (d *Decoder) readN(n int) []byte {
	b := make([]byte, n)
	_, err := io.ReadFull(d, b)
	if err != nil {
		panic(err)
	}
	return b
}

// readPrefix reads a length-prefixed byte slice and panics if the read fails.
func (d *Decoder) readPrefix() []byte {
	b, err := ReadPrefix(d, maxSliceLen)
	if err != nil {
		panic(err)
	}
	return b
}

// decode reads the next encoded value from its input stream and stores it in
// val. The decoding rules are the inverse of those specified in the package
// docstring.
func (d *Decoder) decode(val reflect.Value) {
	// check for UnmarshalSia interface first
	if val.CanAddr() && val.Addr().CanInterface() {
		if u, ok := val.Addr().Interface().(SiaUnmarshaler); ok {
			err := u.UnmarshalSia(d)
			if err != nil {
				panic(err)
			}
			return
		}
	}

	switch val.Kind() {
	case reflect.Ptr:
		var valid bool
		d.decode(reflect.ValueOf(&valid).Elem())
		// nil pointer, nothing to decode
		if !valid {
			return
		}
		// make sure we aren't decoding into nil
		if val.IsNil() {
			val.Set(reflect.New(val.Type().Elem()))
		}
		d.decode(val.Elem())
	case reflect.Bool:
		b := d.readN(1)
		if b[0] > 1 {
			panic("boolean value was not 0 or 1")
		}
		val.SetBool(b[0] == 1)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		val.SetInt(DecInt64(d.readN(8)))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		val.SetUint(DecUint64(d.readN(8)))
	case reflect.String:
		val.SetString(string(d.readPrefix()))
	case reflect.Slice:
		// slices are variable length, but otherwise the same as arrays.
		// just have to allocate them first, then we can fallthrough to the array logic.
		sliceLen := DecUint64(d.readN(8))
		// sanity-check the sliceLen, otherwise you can crash a peer by making
		// them allocate a massive slice
		if sliceLen > 1<<31-1 || sliceLen*uint64(val.Type().Elem().Size()) > maxSliceLen {
			panic("slice is too large")
		} else if sliceLen == 0 {
			return
		}
		val.Set(reflect.MakeSlice(val.Type(), int(sliceLen), int(sliceLen)))
		fallthrough
	case reflect.Array:
		// special case for byte arrays (e.g. hashes)
		if val.Type().Elem().Kind() == reflect.Uint8 {
			// convert val to a slice and read into it directly
			b := val.Slice(0, val.Len())
			_, err := io.ReadFull(d, b.Bytes())
			if err != nil {
				panic(err)
			}
			return
		}
		// arrays are unmarshalled by sequentially unmarshalling their elements
		for i := 0; i < val.Len(); i++ {
			d.decode(val.Index(i))
		}
		return
	case reflect.Struct:
		for i := 0; i < val.NumField(); i++ {
			d.decode(val.Field(i))
		}
		return
	default:
		panic("unknown type")
	}
}

// NewDecoder returns a new decoder that reads from r.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{r, 0}
}

// Unmarshal decodes the encoded value b and stores it in v, which must be a
// pointer. The decoding rules are the inverse of those specified in the
// package docstring for marshaling.
func Unmarshal(b []byte, v interface{}) error {
	r := bytes.NewReader(b)
	return NewDecoder(r).Decode(v)
}

// UnmarshalAll decodes the encoded values in b and stores them in vs, which
// must be pointers.
func UnmarshalAll(b []byte, vs ...interface{}) error {
	dec := NewDecoder(bytes.NewReader(b))
	return dec.DecodeAll(vs...)
}

// ReadFile reads the contents of a file and decodes them into v.
func ReadFile(filename string, v interface{}) error {
	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer file.Close()
	err = NewDecoder(file).Decode(v)
	if err != nil {
		return errors.New("error while reading " + filename + ": " + err.Error())
	}
	return nil
}

// Marshal returns the encoding of v. For encoding details, see the package
// docstring.
func (m StdGenericMarshaler) Marshal(v interface{}) []byte {
	return Marshal(v)
}

// Unmarshal decodes the encoded value b and stores it in v, which must be a
// pointer. The decoding rules are the inverse of those specified in the
// package docstring for marshaling.
func (m StdGenericMarshaler) Unmarshal(b []byte, v interface{}) error {
	return Unmarshal(b, v)
}
<|endoftext|>


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

package endpoints

import (
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"strings"
)

// errorResponse is SPI-compatible error response
type errorResponse struct {
	// Currently always "APPLICATION_ERROR"
	State string `json:"state"`
	Name  string `json:"error_name"`
	Msg   string `json:"error_message,omitempty"`
}

// errorNames is a slice of special error names (or better, their prefixes).
// First element is default error name.
// See newErrorResponse method for details.
var errorNames = []string{
	"Internal Server Error",
	"Bad Request",
	"Unauthorized",
	"Forbidden",
	"Not Found",
}

// Creates and initializes a new errorResponse.
// If msg contains any of errorNames then errorResponse.Name will be set
// to that name and the rest of the msg becomes errorResponse.Msg.
// Otherwise, a default error name is used and msg argument
// is errorResponse.Msg.
func newErrorResponse(msg string) *errorResponse {
	if msg == "" {
		return &errorResponse{State: "APPLICATION_ERROR", Name: errorNames[0]}
	}
	err := &errorResponse{State: "APPLICATION_ERROR"}
	for _, name := range errorNames {
		if strings.HasPrefix(msg, name) {
			err.Name = name
			err.Msg = msg[len(name):]
		}
	}
	if err.Name == "" {
		err.Name = errorNames[0]
		err.Msg = msg
	}
	return err
}

// Server serves registered RPC services using registered codecs.
type Server struct {
	root     string
	services *serviceMap
}

// NewServer returns a new RPC server.
func NewServer(root string) *Server {
	if root == "" {
		root = "/_ah/spi/"
	} else if root[len(root)-1] != '/' {
		root += "/"
	}

	server := &Server{root: root, services: new(serviceMap)}
	backend := newBackendService(server)
	server.services.register(backend, "BackendService", "", "", true, true)
	return server
}

// RegisterService adds a new service to the server.
//
// The name parameter is optional: if empty it will be inferred from
// the receiver type name.
//
// Methods from the receiver will be extracted if these rules are satisfied:
//
//    - The receiver is exported (begins with an upper case letter) or local
//      (defined in the package registering the service).
//    - The method name is exported.
//    - The method has three arguments: *http.Request, *args, *reply.
//    - All three arguments are pointers.
//    - The second and third arguments are exported or local.
//    - The method has return type error.
//
// All other methods are ignored.
func (s *Server) RegisterService(srv interface{}, name, ver, desc string, isDefault bool) (*RpcService, error) {
	return s.services.register(srv, name, ver, desc, isDefault, false)
}

// RegisterServiceWithDefaults will register provided service and will try to
// infer Endpoints config params from its method names and types.
// See RegisterService for details.
func (s *Server) RegisterServiceWithDefaults(srv interface{}) (*RpcService, error) {
	return s.RegisterService(srv, "", "", "", true)
}

// ServiceByName returns a registered service or nil if there's no service
// registered by that name.
func (s *Server) ServiceByName(serviceName string) *RpcService {
	return s.services.serviceByName(serviceName)
}

// HandleHttp adds Server s to specified http.ServeMux.
// If no mux is provided http.DefaultServeMux will be used.
func (s *Server) HandleHttp(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	mux.Handle(s.root, s)
}

// ServeHTTP is Server's implementation of http.ServiceByName interface.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Always respond with JSON, even when an error occurs
	// API server doesn't expect an encoding in Content-Type header.
	w.Header().Set("Content-Type", "application/json")

	if r.Method != "POST" {
		err := fmt.Errorf("rpc: POST method required, got %q", r.Method)
		writeError(w, err)
		return
	}

	// methodName has "ServiceName.MethodName" format.
	var methodName string
	if idx := strings.LastIndex(r.URL.Path, "/"); idx < 0 {
		writeError(w, fmt.Errorf("rpc: no method in path %q", r.URL.Path))
		return
	} else {
		methodName = r.URL.Path[idx+1:]
	}

	// Get service method specs
	serviceSpec, methodSpec, err := s.services.get(methodName)
	if err != nil {
		writeError(w, err)
		return
	}

	// Initialize RPC method request
	req := reflect.New(methodSpec.ReqType)

	if err := json.NewDecoder(r.Body).Decode(req.Interface()); err != nil {
		writeError(w, fmt.Errorf("Error while decoding JSON: %q", err))
		return
	}

	// Initialize RPC method response and call method's function
	resp := reflect.New(methodSpec.RespType)
	errValue := methodSpec.method.Func.Call([]reflect.Value{
		serviceSpec.rcvr,
		reflect.ValueOf(r),
		req,
		resp,
	})

	// Check if method returned an error
	if err := errValue[0].Interface(); err != nil {
		writeError(w, err.(error))
		return
	}

	// Encode non-error response
	json.NewEncoder(w).Encode(resp.Interface())
}

// writeError writes SPI-compatible error response.
func writeError(w http.ResponseWriter, err error) {
	errResp := newErrorResponse(err.Error())
	w.WriteHeader(400)
	json.NewEncoder(w).Encode(errResp)
}

// DefaultServer is the default RPC server, so you don't have to explicitly
// create one.
var DefaultServer *Server

// RegisterService registers a service using DefaultServer.
// See Server.RegisterService for details.
func RegisterService(srv interface{}, name, ver, desc string, isDefault bool) (
	*RpcService, error) {

	return DefaultServer.RegisterService(srv, name, ver, desc, isDefault)
}

// RegisterServiceWithDefaults registers a service using DefaultServer.
// See Server.RegisterServiceWithDefaults for details.
func RegisterServiceWithDefaults(srv interface{}) (*RpcService, error) {
	return DefaultServer.RegisterServiceWithDefaults(srv)
}

// HandleHttp calls DefaultServer's HandleHttp method using default serve mux.
func HandleHttp() {
	DefaultServer.HandleHttp(nil)
}

// TODO: var DefaultServer = NewServer("") won't work so it's in the init()
// function for now.
func init() {
	DefaultServer = NewServer("")
}
<commit_msg>Temporary logging SPI request body<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package endpoints

import (
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"strings"
	// Mainly for debug logging
	"appengine"
	"io/ioutil"
)

// errorResponse is SPI-compatible error response
type errorResponse struct {
	// Currently always "APPLICATION_ERROR"
	State string `json:"state"`
	Name  string `json:"error_name"`
	Msg   string `json:"error_message,omitempty"`
}

// errorNames is a slice of special error names (or better, their prefixes).
// First element is default error name.
// See newErrorResponse method for details.
var errorNames = []string{
	"Internal Server Error",
	"Bad Request",
	"Unauthorized",
	"Forbidden",
	"Not Found",
}

// Creates and initializes a new errorResponse.
// If msg contains any of errorNames then errorResponse.Name will be set
// to that name and the rest of the msg becomes errorResponse.Msg.
// Otherwise, a default error name is used and msg argument
// is errorResponse.Msg.
func newErrorResponse(msg string) *errorResponse {
	if msg == "" {
		return &errorResponse{State: "APPLICATION_ERROR", Name: errorNames[0]}
	}
	err := &errorResponse{State: "APPLICATION_ERROR"}
	for _, name := range errorNames {
		if strings.HasPrefix(msg, name) {
			err.Name = name
			err.Msg = msg[len(name):]
		}
	}
	if err.Name == "" {
		err.Name = errorNames[0]
		err.Msg = msg
	}
	return err
}

// Server serves registered RPC services using registered codecs.
type Server struct {
	root     string
	services *serviceMap
}

// NewServer returns a new RPC server.
func NewServer(root string) *Server {
	if root == "" {
		root = "/_ah/spi/"
	} else if root[len(root)-1] != '/' {
		root += "/"
	}

	server := &Server{root: root, services: new(serviceMap)}
	backend := newBackendService(server)
	server.services.register(backend, "BackendService", "", "", true, true)
	return server
}

// RegisterService adds a new service to the server.
//
// The name parameter is optional: if empty it will be inferred from
// the receiver type name.
//
// Methods from the receiver will be extracted if these rules are satisfied:
//
//    - The receiver is exported (begins with an upper case letter) or local
//      (defined in the package registering the service).
//    - The method name is exported.
//    - The method has three arguments: *http.Request, *args, *reply.
//    - All three arguments are pointers.
//    - The second and third arguments are exported or local.
//    - The method has return type error.
//
// All other methods are ignored.
func (s *Server) RegisterService(srv interface{}, name, ver, desc string, isDefault bool) (*RpcService, error) {
	return s.services.register(srv, name, ver, desc, isDefault, false)
}

// RegisterServiceWithDefaults will register provided service and will try to
// infer Endpoints config params from its method names and types.
// See RegisterService for details.
func (s *Server) RegisterServiceWithDefaults(srv interface{}) (*RpcService, error) {
	return s.RegisterService(srv, "", "", "", true)
}

// ServiceByName returns a registered service or nil if there's no service
// registered by that name.
func (s *Server) ServiceByName(serviceName string) *RpcService {
	return s.services.serviceByName(serviceName)
}

// HandleHttp adds Server s to specified http.ServeMux.
// If no mux is provided http.DefaultServeMux will be used.
func (s *Server) HandleHttp(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	mux.Handle(s.root, s)
}

// ServeHTTP is Server's implementation of http.ServiceByName interface.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Mainly for debug logging
	c := appengine.NewContext(r)

	// Always respond with JSON, even when an error occurs.
	// Note: API server doesn't expect an encoding in Content-Type header.
	w.Header().Set("Content-Type", "application/json")

	if r.Method != "POST" {
		err := fmt.Errorf("rpc: POST method required, got %q", r.Method)
		writeError(w, err)
		return
	}

	// methodName has "ServiceName.MethodName" format.
	var methodName string
	if idx := strings.LastIndex(r.URL.Path, "/"); idx < 0 {
		writeError(w, fmt.Errorf("rpc: no method in path %q", r.URL.Path))
		return
	} else {
		methodName = r.URL.Path[idx+1:]
	}

	// Get service method specs
	serviceSpec, methodSpec, err := s.services.get(methodName)
	if err != nil {
		writeError(w, err)
		return
	}

	// Initialize RPC method request
	req := reflect.New(methodSpec.ReqType)

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		writeError(w, err)
		return
	}
	c.Debugf("SPI request body: %s", body)

	// if err := json.NewDecoder(r.Body).Decode(req.Interface()); err != nil {
	// 	writeError(w, fmt.Errorf("Error while decoding JSON: %q", err))
	// 	return
	// }
	if err := json.Unmarshal(body, req.Interface()); err != nil {
		writeError(w, err)
		return
	}

	// Initialize RPC method response and call method's function
	resp := reflect.New(methodSpec.RespType)
	errValue := methodSpec.method.Func.Call([]reflect.Value{
		serviceSpec.rcvr,
		reflect.ValueOf(r),
		req,
		resp,
	})

	// Check if method returned an error
	if err := errValue[0].Interface(); err != nil {
		writeError(w, err.(error))
		return
	}

	// Encode non-error response
	json.NewEncoder(w).Encode(resp.Interface())
}

// writeError writes SPI-compatible error response.
func writeError(w http.ResponseWriter, err error) {
	errResp := newErrorResponse(err.Error())
	w.WriteHeader(400)
	json.NewEncoder(w).Encode(errResp)
}

// DefaultServer is the default RPC server, so you don't have to explicitly
// create one.
var DefaultServer *Server

// RegisterService registers a service using DefaultServer.
// See Server.RegisterService for details.
func RegisterService(srv interface{}, name, ver, desc string, isDefault bool) (
	*RpcService, error) {

	return DefaultServer.RegisterService(srv, name, ver, desc, isDefault)
}

// RegisterServiceWithDefaults registers a service using DefaultServer.
// See Server.RegisterServiceWithDefaults for details.
func RegisterServiceWithDefaults(srv interface{}) (*RpcService, error) {
	return DefaultServer.RegisterServiceWithDefaults(srv)
}

// HandleHttp calls DefaultServer's HandleHttp method using default serve mux.
func HandleHttp() {
	DefaultServer.HandleHttp(nil)
}

// TODO: var DefaultServer = NewServer("") won't work so it's in the init()
// function for now.
func init() {
	DefaultServer = NewServer("")
}
<|endoftext|>


<commit_before>package fake

import (
	"github.com/appscode/log"
	_ "github.com/k8sdb/apimachinery/api/install"
	"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
	"k8s.io/kubernetes/pkg/runtime"
)

type ClientSets struct {
	*fake.Clientset
	ACExtensionClient *FakeExtensionClient
}

func NewFakeClient(objects ...runtime.Object) *ClientSets {
	return &ClientSets{
		Clientset:         fake.NewSimpleClientset(objects...),
		ACExtensionClient: NewFakeExtensionClient(objects...),
	}
}
<commit_msg>Remove unused import<commit_after>package fake

import (
	_ "github.com/k8sdb/apimachinery/api/install"
	"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5/fake"
	"k8s.io/kubernetes/pkg/runtime"
)

type ClientSets struct {
	*fake.Clientset
	ACExtensionClient *FakeExtensionClient
}

func NewFakeClient(objects ...runtime.Object) *ClientSets {
	return &ClientSets{
		Clientset:         fake.NewSimpleClientset(objects...),
		ACExtensionClient: NewFakeExtensionClient(objects...),
	}
}
<|endoftext|>


<commit_before>package ovn

import (
	"fmt"
	"os/exec"
	"strings"
	"time"
	"unicode"

	"github.com/Sirupsen/logrus"
	kapi "k8s.io/client-go/pkg/api/v1"
)

func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string, error) {
	var gatewayIPMaskStr string
	var ok bool
	if gatewayIPMaskStr, ok = oc.gatewayCache[logicalSwitch]; !ok {
		gatewayIPBytes, err := exec.Command(OvnNbctl, "--if-exists", "get",
			"logical_switch", logicalSwitch,
			"external_ids:gateway_ip").Output()
		if err != nil {
			logrus.Debugf("Gateway IP:  %s, %v", string(gatewayIPBytes), err)
			return "", "", err
		}
		gatewayIPMaskStr = strings.TrimFunc(string(gatewayIPBytes), unicode.IsSpace)
		gatewayIPMaskStr = strings.Trim(gatewayIPMaskStr, `"`)
		oc.gatewayCache[logicalSwitch] = gatewayIPMaskStr
	}
	gatewayIPMask := strings.Split(gatewayIPMaskStr, "/")
	gatewayIP := gatewayIPMask[0]
	mask := gatewayIPMask[1]
	logrus.Debugf("Gateway IP: %s, Mask: %s", gatewayIP, mask)
	return gatewayIP, mask, nil
}

func (oc *Controller) deleteLogicalPort(pod *kapi.Pod) {
	logrus.Debugf("Deleting pod: %s", pod.Name)
	out, err := exec.Command(OvnNbctl, "lsp-del", fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)).CombinedOutput()
	if err != nil {
		logrus.Errorf("Error in deleting pod network switch - %v(%v)", out, err)
	}
	return
}

func (oc *Controller) addLogicalPort(pod *kapi.Pod) {

	count := 30
	logicalSwitch := pod.Spec.NodeName
	for count > 0 {
		if logicalSwitch != "" {
			break
		}
		if count != 30 {
			time.Sleep(1 * time.Second)
		}
		count--
		p, err := oc.Kube.GetPod(pod.Namespace, pod.Name)
		if err != nil {
			logrus.Errorf("Could not get pod %s/%s for obtaining the logical switch it belongs to", pod.Namespace, pod.Name)
			continue
		}
		logicalSwitch = p.Spec.NodeName
	}
	if logicalSwitch == "" {
		logrus.Errorf("Could not find the logical switch that the pod %s/%s belongs to", pod.Namespace, pod.Name)
		return
	}

	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logrus.Debugf("Creating logical port for %s on switch %s", portName, logicalSwitch)

	out, err := exec.Command(OvnNbctl, "--wait=sb", "--", "--may-exist", "lsp-add",
		logicalSwitch, portName, "--", "lsp-set-addresses",
		portName, "dynamic", "--", "set",
		"logical_switch_port", portName,
		"external-ids:namespace="+pod.Namespace,
		"external-ids:pod=true").CombinedOutput()
	if err != nil {
		logrus.Errorf("Error while creating logical port %s - %v (%s)", portName, err, string(out))
		return
	}

	gatewayIP, mask, err := oc.getGatewayFromSwitch(logicalSwitch)
	if err != nil {
		logrus.Errorf("Error obtaining gateway address for switch %s", logicalSwitch)
		return
	}

	count = 30
	for count > 0 {
		out, err = exec.Command(OvnNbctl, "get", "logical_switch_port", portName, "dynamic_addresses").Output()
		if err == nil {
			break
		}
		logrus.Debugf("Error while obtaining addresses for %s - %v", portName, err)
		time.Sleep(time.Second)
		count--
	}
	if count == 0 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	outStr := strings.TrimFunc(string(out), unicode.IsSpace)
	outStr = strings.Trim(outStr, `"`)
	addresses := strings.Split(outStr, " ")
	if len(addresses) != 2 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	annotation := fmt.Sprintf(`{\"ip_address\":\"%s/%s\", \"mac_address\":\"%s\", \"gateway_ip\": \"%s\"}`, addresses[1], mask, addresses[0], gatewayIP)
	logrus.Debugf("Annotation values: ip=%s/%s ; mac=%s ; gw=%s\nAnnotation=%s", addresses[1], mask, addresses[0], gatewayIP, annotation)
	err = oc.Kube.SetAnnotationOnPod(pod, "ovn", annotation)
	if err != nil {
		logrus.Errorf("Failed to set annotation on pod %s - %v", pod.Name, err)
	}
	return
}
<commit_msg>pods.go: Use '--if-exists' while deleting logical port.<commit_after>package ovn

import (
	"fmt"
	"os/exec"
	"strings"
	"time"
	"unicode"

	"github.com/Sirupsen/logrus"
	kapi "k8s.io/client-go/pkg/api/v1"
)

func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string, error) {
	var gatewayIPMaskStr string
	var ok bool
	if gatewayIPMaskStr, ok = oc.gatewayCache[logicalSwitch]; !ok {
		gatewayIPBytes, err := exec.Command(OvnNbctl, "--if-exists", "get",
			"logical_switch", logicalSwitch,
			"external_ids:gateway_ip").Output()
		if err != nil {
			logrus.Debugf("Gateway IP:  %s, %v", string(gatewayIPBytes), err)
			return "", "", err
		}
		gatewayIPMaskStr = strings.TrimFunc(string(gatewayIPBytes), unicode.IsSpace)
		gatewayIPMaskStr = strings.Trim(gatewayIPMaskStr, `"`)
		oc.gatewayCache[logicalSwitch] = gatewayIPMaskStr
	}
	gatewayIPMask := strings.Split(gatewayIPMaskStr, "/")
	gatewayIP := gatewayIPMask[0]
	mask := gatewayIPMask[1]
	logrus.Debugf("Gateway IP: %s, Mask: %s", gatewayIP, mask)
	return gatewayIP, mask, nil
}

func (oc *Controller) deleteLogicalPort(pod *kapi.Pod) {
	logrus.Debugf("Deleting pod: %s", pod.Name)
	out, err := exec.Command(OvnNbctl, "--if-exists", "lsp-del",
		fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)).CombinedOutput()
	if err != nil {
		logrus.Errorf("Error in deleting pod network switch - %s (%v)",
			string(out), err)
	}
	return
}

func (oc *Controller) addLogicalPort(pod *kapi.Pod) {

	count := 30
	logicalSwitch := pod.Spec.NodeName
	for count > 0 {
		if logicalSwitch != "" {
			break
		}
		if count != 30 {
			time.Sleep(1 * time.Second)
		}
		count--
		p, err := oc.Kube.GetPod(pod.Namespace, pod.Name)
		if err != nil {
			logrus.Errorf("Could not get pod %s/%s for obtaining the logical switch it belongs to", pod.Namespace, pod.Name)
			continue
		}
		logicalSwitch = p.Spec.NodeName
	}
	if logicalSwitch == "" {
		logrus.Errorf("Could not find the logical switch that the pod %s/%s belongs to", pod.Namespace, pod.Name)
		return
	}

	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logrus.Debugf("Creating logical port for %s on switch %s", portName, logicalSwitch)

	out, err := exec.Command(OvnNbctl, "--wait=sb", "--", "--may-exist", "lsp-add",
		logicalSwitch, portName, "--", "lsp-set-addresses",
		portName, "dynamic", "--", "set",
		"logical_switch_port", portName,
		"external-ids:namespace="+pod.Namespace,
		"external-ids:pod=true").CombinedOutput()
	if err != nil {
		logrus.Errorf("Error while creating logical port %s - %v (%s)", portName, err, string(out))
		return
	}

	gatewayIP, mask, err := oc.getGatewayFromSwitch(logicalSwitch)
	if err != nil {
		logrus.Errorf("Error obtaining gateway address for switch %s", logicalSwitch)
		return
	}

	count = 30
	for count > 0 {
		out, err = exec.Command(OvnNbctl, "get", "logical_switch_port", portName, "dynamic_addresses").Output()
		if err == nil {
			break
		}
		logrus.Debugf("Error while obtaining addresses for %s - %v", portName, err)
		time.Sleep(time.Second)
		count--
	}
	if count == 0 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	outStr := strings.TrimFunc(string(out), unicode.IsSpace)
	outStr = strings.Trim(outStr, `"`)
	addresses := strings.Split(outStr, " ")
	if len(addresses) != 2 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	annotation := fmt.Sprintf(`{\"ip_address\":\"%s/%s\", \"mac_address\":\"%s\", \"gateway_ip\": \"%s\"}`, addresses[1], mask, addresses[0], gatewayIP)
	logrus.Debugf("Annotation values: ip=%s/%s ; mac=%s ; gw=%s\nAnnotation=%s", addresses[1], mask, addresses[0], gatewayIP, annotation)
	err = oc.Kube.SetAnnotationOnPod(pod, "ovn", annotation)
	if err != nil {
		logrus.Errorf("Failed to set annotation on pod %s - %v", pod.Name, err)
	}
	return
}
<|endoftext|>


<commit_before>package brands

import (
	"encoding/json"
	"fmt"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	log "github.com/Sirupsen/logrus"
	"github.com/jmcvetta/neoism"
)

//service maintains info about runners and index managers
type service struct {
	cypherRunner neoutils.CypherRunner
	indexManager neoutils.IndexManager
}

// NewCypherBrandsService provides functions for create, update, delete operations on brands in Neo4j,
// plus other utility functions needed for a service
func NewCypherBrandsService(cypherRunner neoutils.CypherRunner, indexManager neoutils.IndexManager) service {
	return service{cypherRunner, indexManager}
}

//Initialise the driver
func (s service) Initialise() error {
	entities := map[string]string{
		"Thing":   "uuid",
		"Concept": "uuid",
		"Brand":   "uuid",
	}
	if err := neoutils.EnsureConstraints(s.indexManager, entities); err != nil {
		return err
	}
	if err := neoutils.EnsureIndexes(s.indexManager, entities); err != nil {
		return err
	}
	return nil
}

func (s service) Read(uuid string) (interface{}, bool, error) {
	results := []struct {
		Brand
	}{}
	query := &neoism.CypherQuery{
		Statement: `
                        MATCH (n:Brand {uuid:{uuid}})
                        OPTIONAL MATCH (n:Brand {uuid:{uuid}})-[:HAS_PARENT]->(p:Thing)
                        OPTIONAL MATCH (n)<-[:IDENTIFIES]-(i:Identifier)
                        RETURN n.uuid AS uuid, n.prefLabel AS prefLabel,
                                n.strapline AS strapline, p.uuid as parentUUID,
                                n.descriptionXML AS descriptionXML,
                                n.description AS description, n.imageUrl AS _imageUrl,
                                collect({authority:i.authority, identifierValue:i.value}) as identifiers
                                `,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
		Result: &results,
	}
	err := s.cypherRunner.CypherBatch([]*neoism.CypherQuery{query})
	log.Infof("Read brand : %s returned %+v\n", uuid, results)
	if err != nil {
		return Brand{}, false, err
	}
	if len(results) == 0 {
		return Brand{}, false, nil
	}
	return results[0].Brand, true, nil
}

func (s service) Write(thing interface{}) error {
	brand := thing.(Brand)
	brandProps := map[string]string{
		"uuid":           brand.UUID,
		"prefLabel":      brand.PrefLabel,
		"strapline":      brand.Strapline,
		"descriptionXML": brand.DescriptionXML,
		"description":    brand.Description,
		"imageUrl":       brand.ImageURL,
	}
	stmt := `
                OPTIONAL MATCH (:Brand {uuid:{uuid}})-[r:HAS_PARENT]->(:Brand)
                DELETE r
                MERGE (n:Thing {uuid: {uuid}})
                SET n:Brand
                SET n:Concept
                SET n={props}
                `
	params := neoism.Props{
		"uuid":  brand.UUID,
		"props": brandProps,
	}
	parentUUID := brand.ParentUUID
	if parentUUID != "" {
		stmt += `
                        MERGE (p:Thing {uuid:{parentUUID}})
                        MERGE (n)-[:HAS_PARENT]->(p)
                        `
		params["parentUUID"] = brand.ParentUUID
	}

	deleteIdentifiers := &neoism.CypherQuery{
		Statement: `MATCH (t:Thing {uuid:{uuid}})
                                OPTIONAL MATCH (i:Identifier)-[ir:IDENTIFIES]->(t)
                                DELETE ir, i`,
		Parameters: map[string]interface{}{
			"uuid": brand.UUID,
		},
	}

	writeQuery := &neoism.CypherQuery{
		Statement:  stmt,
		Parameters: params,
	}

	queries := []*neoism.CypherQuery{deleteIdentifiers, writeQuery}

	for _, identifier := range brand.Identifiers {
		queries = append(queries, identifierMerge(identifier, brand.UUID))
	}
	return s.cypherRunner.CypherBatch(queries)

}

const (
	fsAuthority  = "http://api.ft.com/system/FACTSET-PPL"
	tmeAuthority = "http://api.ft.com/system/FT-TME"
)

var identifierLabels = map[string]string{
	fsAuthority:  "FactsetIdentifier",
	tmeAuthority: "TMEIdentifier",
}

func identifierMerge(identifier identifier, uuid string) *neoism.CypherQuery {
	statementTemplate := fmt.Sprintf(`MERGE (o:Thing {uuid:{uuid}})
                                          MERGE (i:Identifier {value:{value} , authority:{authority}})
                                          MERGE (o)<-[:IDENTIFIES]-(i)
                                          set i:%s`, identifierLabels[identifier.Authority])

	query := &neoism.CypherQuery{
		Statement: statementTemplate,
		Parameters: map[string]interface{}{
			"uuid":      uuid,
			"value":     identifier.IdentifierValue,
			"authority": identifier.Authority,
		},
	}
	return query
}

func (s service) Delete(uuid string) (bool, error) {
	deleteIdentifiers := &neoism.CypherQuery{
		Statement: `MATCH (t:Thing {uuid:{uuid}})
                                OPTIONAL MATCH (i:Identifier)-[ir:IDENTIFIES]->(t)
                                DELETE ir
                                WITH i
                                MATCH (i)-[ir2:IDENTIFIES]->(:Thing)
                                WITH i, count(ir2) as c
                                WHERE c = 0
                                DELETE i
                                `,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
	}

	clearNode := &neoism.CypherQuery{
		Statement: `
			MATCH (n:Thing {uuid: {uuid}})
			REMOVE n:Brand
			SET n={props}
		`,
		Parameters: neoism.Props{
			"uuid": uuid,
			"props": neoism.Props{
				"uuid": uuid,
			},
		},
		IncludeStats: true,
	}

	removeNodeIfUnused := &neoism.CypherQuery{
		Statement: `
			MATCH (p:Thing {uuid: {uuid}})
			OPTIONAL MATCH (p)-[a]-(x)
			WITH p, count(a) AS relCount
			WHERE relCount = 0
			DELETE p
		`,
		Parameters: neoism.Props{
			"uuid": uuid,
		},
	}

	err := s.cypherRunner.CypherBatch([]*neoism.CypherQuery{deleteIdentifiers, clearNode, removeNodeIfUnused})

	s1, err := clearNode.Stats()
	if err != nil {
		return false, err
	}

	var deleted bool
	if s1.ContainsUpdates && s1.LabelsRemoved > 0 {
		deleted = true
	}

	return deleted, err
}

func (s service) DecodeJSON(dec *json.Decoder) (interface{}, string, error) {
	brand := Brand{}
	err := dec.Decode(&brand)
	return brand, brand.UUID, err
}

func (s service) Check() error {
	return neoutils.Check(s.cypherRunner)
}

func (s service) Count() (int, error) {

	results := []struct {
		Count int `json:"c"`
	}{}

	query := &neoism.CypherQuery{
		Statement: `MATCH (n:Brand) return count(n) as c`,
		Result:    &results,
	}

	err := s.cypherRunner.CypherBatch([]*neoism.CypherQuery{query})

	if err != nil {
		return 0, err
	}

	return results[0].Count, nil
}
<commit_msg>Fix Identifier cleanup when deleting Brands<commit_after>package brands

import (
	"encoding/json"
	"fmt"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	log "github.com/Sirupsen/logrus"
	"github.com/jmcvetta/neoism"
)

//service maintains info about runners and index managers
type service struct {
	cypherRunner neoutils.CypherRunner
	indexManager neoutils.IndexManager
}

// NewCypherBrandsService provides functions for create, update, delete operations on brands in Neo4j,
// plus other utility functions needed for a service
func NewCypherBrandsService(cypherRunner neoutils.CypherRunner, indexManager neoutils.IndexManager) service {
	return service{cypherRunner, indexManager}
}

//Initialise the driver
func (s service) Initialise() error {
	entities := map[string]string{
		"Thing":      "uuid",
		"Concept":    "uuid",
		"Brand":      "uuid",
		"Identifier": "uuid",
	}
	if err := neoutils.EnsureConstraints(s.indexManager, entities); err != nil {
		return err
	}
	if err := neoutils.EnsureIndexes(s.indexManager, entities); err != nil {
		return err
	}
	return nil
}

func (s service) Read(uuid string) (interface{}, bool, error) {
	results := []struct {
		Brand
	}{}
	query := &neoism.CypherQuery{
		Statement: `
                        MATCH (n:Brand {uuid:{uuid}})
                        OPTIONAL MATCH (n:Brand {uuid:{uuid}})-[:HAS_PARENT]->(p:Thing)
                        OPTIONAL MATCH (n)<-[:IDENTIFIES]-(i:Identifier)
                        RETURN n.uuid AS uuid, n.prefLabel AS prefLabel,
                                n.strapline AS strapline, p.uuid as parentUUID,
                                n.descriptionXML AS descriptionXML,
                                n.description AS description, n.imageUrl AS _imageUrl,
                                collect({authority:i.authority, identifierValue:i.value}) as identifiers
                                `,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
		Result: &results,
	}
	err := s.cypherRunner.CypherBatch([]*neoism.CypherQuery{query})
	log.Infof("Read brand : %s returned %+v\n", uuid, results)
	if err != nil {
		return Brand{}, false, err
	}
	if len(results) == 0 {
		return Brand{}, false, nil
	}
	return results[0].Brand, true, nil
}

func (s service) Write(thing interface{}) error {
	brand := thing.(Brand)
	brandProps := map[string]string{
		"uuid":           brand.UUID,
		"prefLabel":      brand.PrefLabel,
		"strapline":      brand.Strapline,
		"descriptionXML": brand.DescriptionXML,
		"description":    brand.Description,
		"imageUrl":       brand.ImageURL,
	}
	stmt := `
                OPTIONAL MATCH (:Brand {uuid:{uuid}})-[r:HAS_PARENT]->(:Brand)
                DELETE r
                MERGE (n:Thing {uuid: {uuid}})
                SET n:Brand
                SET n:Concept
                SET n={props}
                `
	params := neoism.Props{
		"uuid":  brand.UUID,
		"props": brandProps,
	}
	parentUUID := brand.ParentUUID
	if parentUUID != "" {
		stmt += `
                        MERGE (p:Thing {uuid:{parentUUID}})
                        MERGE (n)-[:HAS_PARENT]->(p)
                        `
		params["parentUUID"] = brand.ParentUUID
	}

	deleteIdentifiers := &neoism.CypherQuery{
		Statement: `MATCH (t:Thing {uuid:{uuid}})
                                OPTIONAL MATCH (i:Identifier)-[ir:IDENTIFIES]->(t)
                                DELETE ir, i`,
		Parameters: map[string]interface{}{
			"uuid": brand.UUID,
		},
	}

	writeQuery := &neoism.CypherQuery{
		Statement:  stmt,
		Parameters: params,
	}

	queries := []*neoism.CypherQuery{deleteIdentifiers, writeQuery}

	for _, identifier := range brand.Identifiers {
		queries = append(queries, identifierMerge(identifier, brand.UUID))
	}
	return s.cypherRunner.CypherBatch(queries)

}

const (
	fsAuthority  = "http://api.ft.com/system/FACTSET-PPL"
	tmeAuthority = "http://api.ft.com/system/FT-TME"
)

var identifierLabels = map[string]string{
	fsAuthority:  "FactsetIdentifier",
	tmeAuthority: "TMEIdentifier",
}

func identifierMerge(identifier identifier, uuid string) *neoism.CypherQuery {
	statementTemplate := fmt.Sprintf(`MERGE (o:Thing {uuid:{uuid}})
                                          MERGE (i:Identifier {value:{value} , authority:{authority}})
                                          MERGE (o)<-[:IDENTIFIES]-(i)
                                          set i:%s`, identifierLabels[identifier.Authority])

	query := &neoism.CypherQuery{
		Statement: statementTemplate,
		Parameters: map[string]interface{}{
			"uuid":      uuid,
			"value":     identifier.IdentifierValue,
			"authority": identifier.Authority,
		},
	}
	return query
}

func (s service) Delete(uuid string) (bool, error) {
	deleteIdentifiers := &neoism.CypherQuery{
		Statement: `MATCH (t:Thing {uuid:{uuid}})
                                OPTIONAL MATCH (i:Identifier)-[ir:IDENTIFIES]->(t)
                                WITH i, count(ir) as c, ir, t
                                WHERE c = 1
                                DELETE ir, i
                                `,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
	}

	deleteOwnedRelationships := &neoism.CypherQuery{
		Statement: `
                        MATCH (n:Thing {uuid: {uuid}})-[p:HAS_PARENT]->(t:Thing)
                        DELETE p
                `,
		Parameters: neoism.Props{
			"uuid": uuid,
		},
		IncludeStats: true,
	}

	clearNode := &neoism.CypherQuery{
		Statement: `
			MATCH (n:Thing {uuid: {uuid}})
			REMOVE n:Brand
			SET n={props}
		`,
		Parameters: neoism.Props{
			"uuid": uuid,
			"props": neoism.Props{
				"uuid": uuid,
			},
		},
		IncludeStats: true,
	}

	removeNodeIfUnused := &neoism.CypherQuery{
		Statement: `
			MATCH (p:Thing {uuid: {uuid}})
			OPTIONAL MATCH (p)-[a]-(x)
			WITH p, count(a) AS relCount
			WHERE relCount = 0
			DELETE p
		`,
		Parameters: neoism.Props{
			"uuid": uuid,
		},
	}

	err := s.cypherRunner.CypherBatch([]*neoism.CypherQuery{deleteIdentifiers, deleteOwnedRelationships, clearNode, removeNodeIfUnused})

	s1, err := clearNode.Stats()
	if err != nil {
		return false, err
	}

	var deleted bool
	if s1.ContainsUpdates && s1.LabelsRemoved > 0 {
		deleted = true
	}

	return deleted, err
}

func (s service) DecodeJSON(dec *json.Decoder) (interface{}, string, error) {
	brand := Brand{}
	err := dec.Decode(&brand)
	return brand, brand.UUID, err
}

func (s service) Check() error {
	return neoutils.Check(s.cypherRunner)
}

func (s service) Count() (int, error) {

	results := []struct {
		Count int `json:"c"`
	}{}

	query := &neoism.CypherQuery{
		Statement: `MATCH (n:Brand) return count(n) as c`,
		Result:    &results,
	}

	err := s.cypherRunner.CypherBatch([]*neoism.CypherQuery{query})

	if err != nil {
		return 0, err
	}

	return results[0].Count, nil
}
<|endoftext|>


<commit_before>package testserver

import (
	"net/http"
	"net/http/httptest"
	"sync"
	"testing"
)

type request struct {
	method        string
	url           string
	responseCode  int
	responseBytes string
	shouldHang    bool
	next          *request
}

// TestServer wraps around httptest.Server to support expectations and timeout tests.
// Use ExpectAndRespond and ExpectAndHang methods to indicate expected requests in the order they
// should arrive.
//
// Currently, parallel requests are not supported.
type TestServer struct {
	reqChain     *request
	t            *testing.T
	s            *httptest.Server
	URL          string
	waiter       *sync.Cond
	reqChainLock sync.Mutex
}

// NewTestServer creates a new TestServer associate with given testing.T instance
func NewTestServer(t *testing.T) *TestServer {
	var m sync.Mutex
	ts := &TestServer{t: t, waiter: sync.NewCond(&m)}
	ts.run()
	ts.URL = ts.s.URL
	return ts
}

// ExpectAndRespond specifies the next request to be expected (using request method and url) and
// specifies what response needs to be provided.
func (ts *TestServer) ExpectAndRespond(method string, url string, responseCode int, responseBytes string) *TestServer {
	return ts.insertNextReq(request{
		method:        method,
		url:           url,
		responseCode:  responseCode,
		responseBytes: responseBytes,
		shouldHang:    false,
	})
}

// ExpectAndHang specifies the next request expected, the server hangs and the request will not be
// responded to. This is useful to test client timeouts. To stop the hanging server, call
// CloseAndAssertExpectations.
func (ts *TestServer) ExpectAndHang(method string, url string) *TestServer {
	return ts.insertNextReq(request{
		method:     method,
		url:        url,
		shouldHang: true,
	})
}

func (ts *TestServer) insertNextReq(nextReq request) *TestServer {
	defer ts.reqChainLock.Unlock()
	ts.reqChainLock.Lock()

	if ts.reqChain == nil {
		ts.reqChain = &nextReq
	} else {
		req := ts.reqChain

		for req.next != nil {
			req = req.next
		}

		req.next = &nextReq
	}

	return ts
}

func (ts *TestServer) run() {
	ts.s = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ts.t.Logf("Received request: %s %s\n", r.Method, r.URL)

		ts.reqChainLock.Lock()
		nextReq := ts.reqChain
		ts.reqChain = ts.reqChain.next
		ts.reqChainLock.Unlock()

		if nextReq == nil {
			w.WriteHeader(http.StatusExpectationFailed)
			ts.t.Errorf("Unexpected request %s %s\n", r.Method, r.URL)
			return
		}

		if nextReq.method != r.Method || nextReq.url != r.URL.String() {
			w.WriteHeader(http.StatusExpectationFailed)
			ts.t.Errorf("Expected request: %s %s\nGot request: %s %s", nextReq.method, nextReq.url, r.Method, r.URL)
			return
		}

		if nextReq.shouldHang {
			ts.t.Log("Hanging on response")
			ts.waiter.L.Lock()
			ts.waiter.Wait()
			ts.waiter.L.Unlock()
		} else {
			ts.t.Logf("Responding with status %d\n", nextReq.responseCode)
			w.WriteHeader(nextReq.responseCode)
			w.Write([]byte(nextReq.responseBytes))
		}
	}))

	ts.t.Logf("Running httptest server on %s\n", ts.s.URL)
}

// CloseAndAssertExpectations will stop any hanging requests and shutdown the test server. Any
// remaining expectations will flag a test error.
func (ts *TestServer) CloseAndAssertExpectations() {
	ts.reqChainLock.Lock()
	if ts.reqChain != nil {
		ts.t.Errorf("Some expected requests were never called, next one being %s %s",
			ts.reqChain.method, ts.reqChain.url)
	}
	ts.reqChainLock.Unlock()

	ts.waiter.L.Lock()
	ts.waiter.Broadcast()
	ts.waiter.L.Unlock()
	ts.s.Close()
}
<commit_msg>Verify reqChain is not nil before reqChain.next.<commit_after>package testserver

import (
	"net/http"
	"net/http/httptest"
	"sync"
	"testing"
)

type request struct {
	method        string
	url           string
	responseCode  int
	responseBytes string
	shouldHang    bool
}

// TestServer wraps around httptest.Server to support expectations and timeout tests.
// Use ExpectAndRespond and ExpectAndHang methods to indicate expected requests in the order they
// should arrive.
//
// Currently, parallel requests are not supported.
type TestServer struct {
	reqChain     []request
	t            *testing.T
	s            *httptest.Server
	URL          string
	waiter       *sync.Cond
	reqChainLock sync.Mutex
}

// NewTestServer creates a new TestServer associate with given testing.T instance
func NewTestServer(t *testing.T) *TestServer {
	var m sync.Mutex
	ts := &TestServer{t: t, waiter: sync.NewCond(&m)}
	ts.run()
	ts.URL = ts.s.URL
	return ts
}

// ExpectAndRespond specifies the next request to be expected (using request method and url) and
// specifies what response needs to be provided.
func (ts *TestServer) ExpectAndRespond(method string, url string, responseCode int, responseBytes string) *TestServer {
	return ts.insertNextReq(request{
		method:        method,
		url:           url,
		responseCode:  responseCode,
		responseBytes: responseBytes,
		shouldHang:    false,
	})
}

// ExpectAndHang specifies the next request expected, the server hangs and the request will not be
// responded to. This is useful to test client timeouts. To stop the hanging server, call
// CloseAndAssertExpectations.
func (ts *TestServer) ExpectAndHang(method string, url string) *TestServer {
	return ts.insertNextReq(request{
		method:     method,
		url:        url,
		shouldHang: true,
	})
}

func (ts *TestServer) insertNextReq(nextReq request) *TestServer {
	defer ts.reqChainLock.Unlock()
	ts.reqChainLock.Lock()
	ts.reqChain = append(ts.reqChain, nextReq)

	return ts
}

func (ts *TestServer) popNextReq() (nextReq request, ok bool) {
	defer ts.reqChainLock.Unlock()
	ts.reqChainLock.Lock()

	if len(ts.reqChain) > 0 {
		nextReq, ts.reqChain = ts.reqChain[0], ts.reqChain[1:]
		ok = true
	} else {
		ok = false
	}

	return
}

func (ts *TestServer) run() {
	ts.s = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ts.t.Logf("Received request: %s %s\n", r.Method, r.URL)

		nextReq, ok := ts.popNextReq()

		if !ok {
			w.WriteHeader(http.StatusExpectationFailed)
			ts.t.Errorf("Unexpected request %s %s\n", r.Method, r.URL)
			return
		}

		if nextReq.method != r.Method || nextReq.url != r.URL.String() {
			w.WriteHeader(http.StatusExpectationFailed)
			ts.t.Errorf("Expected request: %s %s\nGot request: %s %s", nextReq.method, nextReq.url, r.Method, r.URL)
			return
		}

		if nextReq.shouldHang {
			ts.t.Log("Hanging on response")
			ts.waiter.L.Lock()
			ts.waiter.Wait()
			ts.waiter.L.Unlock()
		} else {
			ts.t.Logf("Responding with status %d\n", nextReq.responseCode)
			w.WriteHeader(nextReq.responseCode)
			w.Write([]byte(nextReq.responseBytes))
		}
	}))

	ts.t.Logf("Running httptest server on %s\n", ts.s.URL)
}

// CloseAndAssertExpectations will stop any hanging requests and shutdown the test server. Any
// remaining expectations will flag a test error.
func (ts *TestServer) CloseAndAssertExpectations() {
	ts.reqChainLock.Lock()
	if len(ts.reqChain) != 0 {
		ts.t.Errorf("Some expected requests were never called, next one being %s %s",
			ts.reqChain[0].method, ts.reqChain[0].url)
	}
	ts.reqChainLock.Unlock()

	ts.waiter.L.Lock()
	ts.waiter.Broadcast()
	ts.waiter.L.Unlock()
	ts.s.Close()
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 rollout

import (
	"context"
	"fmt"
	"time"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/resource"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/cache"
	watchtools "k8s.io/client-go/tools/watch"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/polymorphichelpers"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/completion"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/interrupt"
	"k8s.io/kubectl/pkg/util/templates"
)

var (
	statusLong = templates.LongDesc(i18n.T(`
		Show the status of the rollout.

		By default 'rollout status' will watch the status of the latest rollout
		until it's done. If you don't want to wait for the rollout to finish then
		you can use --watch=false. Note that if a new rollout starts in-between, then
		'rollout status' will continue watching the latest revision. If you want to
		pin to a specific revision and abort if it is rolled over by another revision,
		use --revision=N where N is the revision you need to watch for.`))

	statusExample = templates.Examples(`
		# Watch the rollout status of a deployment
		kubectl rollout status deployment/nginx`)
)

// RolloutStatusOptions holds the command-line options for 'rollout status' sub command
type RolloutStatusOptions struct {
	PrintFlags *genericclioptions.PrintFlags

	Namespace        string
	EnforceNamespace bool
	BuilderArgs      []string
	LabelSelector    string

	Watch    bool
	Revision int64
	Timeout  time.Duration

	StatusViewerFn func(*meta.RESTMapping) (polymorphichelpers.StatusViewer, error)
	Builder        func() *resource.Builder
	DynamicClient  dynamic.Interface

	FilenameOptions *resource.FilenameOptions
	genericclioptions.IOStreams
}

// NewRolloutStatusOptions returns an initialized RolloutStatusOptions instance
func NewRolloutStatusOptions(streams genericclioptions.IOStreams) *RolloutStatusOptions {
	return &RolloutStatusOptions{
		PrintFlags:      genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
		FilenameOptions: &resource.FilenameOptions{},
		IOStreams:       streams,
		Watch:           true,
		Timeout:         0,
	}
}

// NewCmdRolloutStatus returns a Command instance for the 'rollout status' sub command
func NewCmdRolloutStatus(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := NewRolloutStatusOptions(streams)

	validArgs := []string{"deployment", "daemonset", "statefulset"}

	cmd := &cobra.Command{
		Use:                   "status (TYPE NAME | TYPE/NAME) [flags]",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Show the status of the rollout"),
		Long:                  statusLong,
		Example:               statusExample,
		ValidArgsFunction:     completion.SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(f, validArgs),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}

	usage := "identifying the resource to get from a server."
	cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
	cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "Watch the status of the rollout until it's done.")
	cmd.Flags().Int64Var(&o.Revision, "revision", o.Revision, "Pin to a specific revision for showing its status. Defaults to 0 (last revision).")
	cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "The length of time to wait before ending watch, zero means never. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
	cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)

	return cmd
}

// Complete completes all the required options
func (o *RolloutStatusOptions) Complete(f cmdutil.Factory, args []string) error {
	o.Builder = f.NewBuilder

	var err error
	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	o.BuilderArgs = args
	o.StatusViewerFn = polymorphichelpers.StatusViewerFn

	clientConfig, err := f.ToRESTConfig()
	if err != nil {
		return err
	}

	o.DynamicClient, err = dynamic.NewForConfig(clientConfig)
	if err != nil {
		return err
	}

	return nil
}

// Validate makes sure all the provided values for command-line options are valid
func (o *RolloutStatusOptions) Validate() error {
	if len(o.BuilderArgs) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
		return fmt.Errorf("required resource not specified")
	}

	if o.Revision < 0 {
		return fmt.Errorf("revision must be a positive integer: %v", o.Revision)
	}

	return nil
}

// Run performs the execution of 'rollout status' sub command
func (o *RolloutStatusOptions) Run() error {
	r := o.Builder().
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		NamespaceParam(o.Namespace).DefaultNamespace().
		LabelSelectorParam(o.LabelSelector).
		FilenameParam(o.EnforceNamespace, o.FilenameOptions).
		ResourceTypeOrNameArgs(true, o.BuilderArgs...).
		SingleResourceType().
		Latest().
		Do()
	err := r.Err()
	if err != nil {
		return err
	}

	infos, err := r.Infos()
	if err != nil {
		return err
	}
	if len(infos) != 1 {
		return fmt.Errorf("rollout status is only supported on individual resources and resource collections - %d resources were found", len(infos))
	}
	info := infos[0]
	mapping := info.ResourceMapping()

	statusViewer, err := o.StatusViewerFn(mapping)
	if err != nil {
		return err
	}

	fieldSelector := fields.OneTermEqualSelector("metadata.name", info.Name).String()
	lw := &cache.ListWatch{
		ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
			options.FieldSelector = fieldSelector
			return o.DynamicClient.Resource(info.Mapping.Resource).Namespace(info.Namespace).List(context.TODO(), options)
		},
		WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
			options.FieldSelector = fieldSelector
			return o.DynamicClient.Resource(info.Mapping.Resource).Namespace(info.Namespace).Watch(context.TODO(), options)
		},
	}

	// if the rollout isn't done yet, keep watching deployment status
	ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), o.Timeout)
	intr := interrupt.New(nil, cancel)
	return intr.Run(func() error {
		_, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, nil, func(e watch.Event) (bool, error) {
			switch t := e.Type; t {
			case watch.Added, watch.Modified:
				status, done, err := statusViewer.Status(e.Object.(runtime.Unstructured), o.Revision)
				if err != nil {
					return false, err
				}
				fmt.Fprintf(o.Out, "%s", status)
				// Quit waiting if the rollout is done
				if done {
					return true, nil
				}

				shouldWatch := o.Watch
				if !shouldWatch {
					return true, nil
				}

				return false, nil

			case watch.Deleted:
				// We need to abort to avoid cases of recreation and not to silently watch the wrong (new) object
				return true, fmt.Errorf("object has been deleted")

			default:
				return true, fmt.Errorf("internal error: unexpected event %#v", e)
			}
		})
		return err
	})
}
<commit_msg>kubectl rollout: support recursive flag for rollout status<commit_after>/*
Copyright 2016 The Kubernetes 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 rollout

import (
	"context"
	"fmt"
	"time"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/resource"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/cache"
	watchtools "k8s.io/client-go/tools/watch"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/polymorphichelpers"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/completion"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/interrupt"
	"k8s.io/kubectl/pkg/util/templates"
)

var (
	statusLong = templates.LongDesc(i18n.T(`
		Show the status of the rollout.

		By default 'rollout status' will watch the status of the latest rollout
		until it's done. If you don't want to wait for the rollout to finish then
		you can use --watch=false. Note that if a new rollout starts in-between, then
		'rollout status' will continue watching the latest revision. If you want to
		pin to a specific revision and abort if it is rolled over by another revision,
		use --revision=N where N is the revision you need to watch for.`))

	statusExample = templates.Examples(`
		# Watch the rollout status of a deployment
		kubectl rollout status deployment/nginx`)
)

// RolloutStatusOptions holds the command-line options for 'rollout status' sub command
type RolloutStatusOptions struct {
	PrintFlags *genericclioptions.PrintFlags

	Namespace        string
	EnforceNamespace bool
	BuilderArgs      []string
	LabelSelector    string

	Watch    bool
	Revision int64
	Timeout  time.Duration

	StatusViewerFn func(*meta.RESTMapping) (polymorphichelpers.StatusViewer, error)
	Builder        func() *resource.Builder
	DynamicClient  dynamic.Interface

	FilenameOptions *resource.FilenameOptions
	genericclioptions.IOStreams
}

// NewRolloutStatusOptions returns an initialized RolloutStatusOptions instance
func NewRolloutStatusOptions(streams genericclioptions.IOStreams) *RolloutStatusOptions {
	return &RolloutStatusOptions{
		PrintFlags:      genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
		FilenameOptions: &resource.FilenameOptions{},
		IOStreams:       streams,
		Watch:           true,
		Timeout:         0,
	}
}

// NewCmdRolloutStatus returns a Command instance for the 'rollout status' sub command
func NewCmdRolloutStatus(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := NewRolloutStatusOptions(streams)

	validArgs := []string{"deployment", "daemonset", "statefulset"}

	cmd := &cobra.Command{
		Use:                   "status (TYPE NAME | TYPE/NAME) [flags]",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Show the status of the rollout"),
		Long:                  statusLong,
		Example:               statusExample,
		ValidArgsFunction:     completion.SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(f, validArgs),
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}

	usage := "identifying the resource to get from a server."
	cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, usage)
	cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "Watch the status of the rollout until it's done.")
	cmd.Flags().Int64Var(&o.Revision, "revision", o.Revision, "Pin to a specific revision for showing its status. Defaults to 0 (last revision).")
	cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "The length of time to wait before ending watch, zero means never. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
	cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)

	return cmd
}

// Complete completes all the required options
func (o *RolloutStatusOptions) Complete(f cmdutil.Factory, args []string) error {
	o.Builder = f.NewBuilder

	var err error
	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	o.BuilderArgs = args
	o.StatusViewerFn = polymorphichelpers.StatusViewerFn

	clientConfig, err := f.ToRESTConfig()
	if err != nil {
		return err
	}

	o.DynamicClient, err = dynamic.NewForConfig(clientConfig)
	if err != nil {
		return err
	}

	return nil
}

// Validate makes sure all the provided values for command-line options are valid
func (o *RolloutStatusOptions) Validate() error {
	if len(o.BuilderArgs) == 0 && cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames, o.FilenameOptions.Kustomize) {
		return fmt.Errorf("required resource not specified")
	}

	if o.Revision < 0 {
		return fmt.Errorf("revision must be a positive integer: %v", o.Revision)
	}

	return nil
}

// Run performs the execution of 'rollout status' sub command
func (o *RolloutStatusOptions) Run() error {
	r := o.Builder().
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		NamespaceParam(o.Namespace).DefaultNamespace().
		LabelSelectorParam(o.LabelSelector).
		FilenameParam(o.EnforceNamespace, o.FilenameOptions).
		ResourceTypeOrNameArgs(true, o.BuilderArgs...).
		ContinueOnError().
		Latest().
		Do()

	err := r.Err()
	if err != nil {
		return err
	}

	return r.Visit(func(info *resource.Info, err error) error {
		mapping := info.ResourceMapping()
		statusViewer, err := o.StatusViewerFn(mapping)
		if err != nil {
			return err
		}

		fieldSelector := fields.OneTermEqualSelector("metadata.name", info.Name).String()
		lw := &cache.ListWatch{
			ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
				options.FieldSelector = fieldSelector
				return o.DynamicClient.Resource(info.Mapping.Resource).Namespace(info.Namespace).List(context.TODO(), options)
			},
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				options.FieldSelector = fieldSelector
				return o.DynamicClient.Resource(info.Mapping.Resource).Namespace(info.Namespace).Watch(context.TODO(), options)
			},
		}

		// if the rollout isn't done yet, keep watching deployment status
		ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), o.Timeout)
		intr := interrupt.New(nil, cancel)
		return intr.Run(func() error {
			_, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, nil, func(e watch.Event) (bool, error) {
				switch t := e.Type; t {
				case watch.Added, watch.Modified:
					status, done, err := statusViewer.Status(e.Object.(runtime.Unstructured), o.Revision)
					if err != nil {
						return false, err
					}
					fmt.Fprintf(o.Out, "%s", status)
					// Quit waiting if the rollout is done
					if done {
						return true, nil
					}

					shouldWatch := o.Watch
					if !shouldWatch {
						return true, nil
					}

					return false, nil

				case watch.Deleted:
					// We need to abort to avoid cases of recreation and not to silently watch the wrong (new) object
					return true, fmt.Errorf("object has been deleted")

				default:
					return true, fmt.Errorf("internal error: unexpected event %#v", e)
				}
			})
			return err
		})
	})
}
<|endoftext|>


<commit_before>package main

import(
    "fmt"
    "github.com/mattn/go-sqlite3"
)

func main() {
    fmt.Println("hello")

    db, err := sql.Open("sqlite3", "./foo.db")
    if err != nil {
            log.Fatal(err)
    }

    fmt.Println(db)
}
<commit_msg>test that generates some data and stores it in an sqlite db.<commit_after>package main

import(
    "fmt"
    "log"
    "os"
    "database/sql"
    _ "github.com/mattn/go-sqlite3"

)

func main() {

    os.Remove("./foo.db")

    db, err := sql.Open("sqlite3", "./foo.db")
    if err != nil {
            log.Panic(err)
    }

    defer db.Close()

    sql := `
        create table foo (id integer not null primary key, name text, age integer);
        delete from foo;
        `
    _, err = db.Exec(sql)
    if err != nil {
            log.Printf("%q: %s\n", err, sql)
            return
    }

    tx, err := db.Begin()
    if err != nil{
        log.Panic(err)
    }

    stmt, err := tx.Prepare("insert into foo(id,name,age) values(?,?,?)")
    if err != nil {
        log.Panic(err)
    }

    defer stmt.Close()

    for i := 0; i < 100; i ++ {
        _, err = stmt.Exec(i, fmt.Sprintf("item %d",i), i*2)
        if err != nil{
            log.Panic(err)
        }
    }

    tx.Commit()

    rows, err := db.Query("select id, name, age from foo")
    if err != nil {
        log.Panic(err)
    }

    fmt.Println("Extracting from db:")
    for rows.Next() {
        var id int
        var name string
        var age int
        rows.Scan(&id, &name, &age)
        fmt.Println("id =",id,"name =",name,"age =",age)
    }

    rows.Close()

}
<|endoftext|>


<commit_before>package schema

import (
	"fmt"
	"reflect"
	"sort"
	"sync"

	"github.com/hashicorp/terraform/helper/hashcode"
)

// HashString hashes strings. If you want a Set of strings, this is the
// SchemaSetFunc you want.
func HashString(v interface{}) int {
	return hashcode.String(v.(string))
}

// Set is a set data structure that is returned for elements of type
// TypeSet.
type Set struct {
	F SchemaSetFunc

	m    map[int]interface{}
	once sync.Once
}

// NewSet is a convenience method for creating a new set with the given
// items.
func NewSet(f SchemaSetFunc, items []interface{}) *Set {
	s := &Set{F: f}
	for _, i := range items {
		s.Add(i)
	}

	return s
}

// Add adds an item to the set if it isn't already in the set.
func (s *Set) Add(item interface{}) {
	s.add(item)
}

// Contains checks if the set has the given item.
func (s *Set) Contains(item interface{}) bool {
	_, ok := s.m[s.hash(item)]
	return ok
}

// Len returns the amount of items in the set.
func (s *Set) Len() int {
	return len(s.m)
}

// List returns the elements of this set in slice format.
//
// The order of the returned elements is deterministic. Given the same
// set, the order of this will always be the same.
func (s *Set) List() []interface{} {
	result := make([]interface{}, len(s.m))
	for i, k := range s.listCode() {
		result[i] = s.m[k]
	}

	return result
}

// Differences performs a set difference of the two sets, returning
// a new third set that has only the elements unique to this set.
func (s *Set) Difference(other *Set) *Set {
	result := &Set{F: s.F}
	result.once.Do(result.init)

	for k, v := range s.m {
		if _, ok := other.m[k]; !ok {
			result.m[k] = v
		}
	}

	return result
}

// Intersection performs the set intersection of the two sets
// and returns a new third set.
func (s *Set) Intersection(other *Set) *Set {
	result := &Set{F: s.F}
	result.once.Do(result.init)

	for k, v := range s.m {
		if _, ok := other.m[k]; ok {
			result.m[k] = v
		}
	}

	return result
}

// Union performs the set union of the two sets and returns a new third
// set.
func (s *Set) Union(other *Set) *Set {
	result := &Set{F: s.F}
	result.once.Do(result.init)

	for k, v := range s.m {
		result.m[k] = v
	}
	for k, v := range other.m {
		result.m[k] = v
	}

	return result
}

func (s *Set) Equal(raw interface{}) bool {
	other, ok := raw.(*Set)
	if !ok {
		return false
	}

	return reflect.DeepEqual(s.m, other.m)
}

func (s *Set) GoString() string {
	return fmt.Sprintf("*Set(%#v)", s.m)
}

func (s *Set) init() {
	s.m = make(map[int]interface{})
}

func (s *Set) add(item interface{}) int {
	s.once.Do(s.init)

	code := s.hash(item)
	if _, ok := s.m[code]; !ok {
		s.m[code] = item
	}

	return code
}

func (s *Set) hash(item interface{}) int {
	code := s.F(item)
	// Always return a nonnegative hashcode.
	if code < 0 {
		return -code
	}
	return code
}

func (s *Set) index(item interface{}) int {
	return sort.SearchInts(s.listCode(), s.hash(item))
}

func (s *Set) listCode() []int {
	// Sort the hash codes so the order of the list is deterministic
	keys := make([]int, 0, len(s.m))
	for k, _ := range s.m {
		keys = append(keys, k)
	}
	sort.Sort(sort.IntSlice(keys))
	return keys
}
<commit_msg>Implement AWS IAM resources<commit_after>package schema

import (
	"fmt"
	"reflect"
	"sort"
	"sync"

	"github.com/hashicorp/terraform/helper/hashcode"
)

// HashString hashes strings. If you want a Set of strings, this is the
// SchemaSetFunc you want.
func HashString(v interface{}) int {
	return hashcode.String(v.(string))
}

// Set is a set data structure that is returned for elements of type
// TypeSet.
type Set struct {
	F SchemaSetFunc

	m    map[int]interface{}
	once sync.Once
}

// NewSet is a convenience method for creating a new set with the given
// items.
func NewSet(f SchemaSetFunc, items []interface{}) *Set {
	s := &Set{F: f}
	for _, i := range items {
		s.Add(i)
	}

	return s
}

// CopySet returns a copy of another set.
func CopySet(otherSet *Set) *Set {
	return NewSet(otherSet.F, otherSet.List())
}

// Add adds an item to the set if it isn't already in the set.
func (s *Set) Add(item interface{}) {
	s.add(item)
}

// Remove removes an item if it's already in the set. Idempotent.
func (s *Set) Remove(item interface{}) {
	s.remove(item)
}

// Contains checks if the set has the given item.
func (s *Set) Contains(item interface{}) bool {
	_, ok := s.m[s.hash(item)]
	return ok
}

// Len returns the amount of items in the set.
func (s *Set) Len() int {
	return len(s.m)
}

// List returns the elements of this set in slice format.
//
// The order of the returned elements is deterministic. Given the same
// set, the order of this will always be the same.
func (s *Set) List() []interface{} {
	result := make([]interface{}, len(s.m))
	for i, k := range s.listCode() {
		result[i] = s.m[k]
	}

	return result
}

// Differences performs a set difference of the two sets, returning
// a new third set that has only the elements unique to this set.
func (s *Set) Difference(other *Set) *Set {
	result := &Set{F: s.F}
	result.once.Do(result.init)

	for k, v := range s.m {
		if _, ok := other.m[k]; !ok {
			result.m[k] = v
		}
	}

	return result
}

// Intersection performs the set intersection of the two sets
// and returns a new third set.
func (s *Set) Intersection(other *Set) *Set {
	result := &Set{F: s.F}
	result.once.Do(result.init)

	for k, v := range s.m {
		if _, ok := other.m[k]; ok {
			result.m[k] = v
		}
	}

	return result
}

// Union performs the set union of the two sets and returns a new third
// set.
func (s *Set) Union(other *Set) *Set {
	result := &Set{F: s.F}
	result.once.Do(result.init)

	for k, v := range s.m {
		result.m[k] = v
	}
	for k, v := range other.m {
		result.m[k] = v
	}

	return result
}

func (s *Set) Equal(raw interface{}) bool {
	other, ok := raw.(*Set)
	if !ok {
		return false
	}

	return reflect.DeepEqual(s.m, other.m)
}

func (s *Set) GoString() string {
	return fmt.Sprintf("*Set(%#v)", s.m)
}

func (s *Set) init() {
	s.m = make(map[int]interface{})
}

func (s *Set) add(item interface{}) int {
	s.once.Do(s.init)

	code := s.hash(item)
	if _, ok := s.m[code]; !ok {
		s.m[code] = item
	}

	return code
}

func (s *Set) hash(item interface{}) int {
	code := s.F(item)
	// Always return a nonnegative hashcode.
	if code < 0 {
		return -code
	}
	return code
}

func (s *Set) remove(item interface{}) int {
	s.once.Do(s.init)

	code := s.F(item)
	delete(s.m, code)

	return code
}

func (s *Set) index(item interface{}) int {
	return sort.SearchInts(s.listCode(), s.hash(item))
}

func (s *Set) listCode() []int {
	// Sort the hash codes so the order of the list is deterministic
	keys := make([]int, 0, len(s.m))
	for k, _ := range s.m {
		keys = append(keys, k)
	}
	sort.Sort(sort.IntSlice(keys))
	return keys
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/kjelly/jscli/lib/libvm"
	"github.com/kjelly/jscli/lib/utils"
	"github.com/robertkrimen/otto"
	"gopkg.in/alecthomas/kingpin.v2"
	"io/ioutil"
	"os"
	"sort"
)

var (
	codeListPtr  = ArgsStrList(kingpin.Arg("code", "the js code you want to run").Required())
	lineSeqPtr   = kingpin.Flag("line-seq", "the char used for split line").Short('l').Default("\n").String()
	columnSeqPtr = kingpin.Flag("column-seq", "the char used for split column").Short('c').Default(" +").String()
	funcListPtr  = ArgsStrList(kingpin.Flag("funcion", "function").Short('f'))
	pathListPtr  = ArgsStrList(kingpin.Flag("path", "command search path").Short('p'))
	jsListPtr    = ArgsStrList(kingpin.Flag("js", "Javascript file").Short('j'))
	reversePtr   = kingpin.Flag("reverse", "execute code with reverse order").Short('r').Bool()
	nostdinPtr   = kingpin.Flag("nostdin", "Dont't read from stdin").Bool()
)

type argsStrList []string

func (i *argsStrList) Set(value string) error {
	*i = append(*i, value)
	return nil
}

func (i *argsStrList) String() string {
	return ""
}

func (i *argsStrList) IsCumulative() bool {
	return true
}

func ArgsStrList(s kingpin.Settings) (target *[]string) {
	target = new([]string)
	s.SetValue((*argsStrList)(target))
	return
}

func readAll() string {
	bytes, err := ioutil.ReadAll(os.Stdin)
	if err == nil {
		return string(bytes)
	} else {
		panic("Failed to read stdin")
	}
}

type Matrix [][]string

func addPATHEnv(path string) {
	oldEnv := os.Getenv("PATH")
	newEnv := path + ":" + oldEnv
	os.Setenv("PATH", newEnv)
}

func getWd() string {
	cwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return cwd
}

func main() {
	addPATHEnv(getWd())
	fmt.Printf("")
	kingpin.Parse()

	var stdin string

	if *nostdinPtr {
		stdin = ""
	} else {
		stdin = readAll()
	}

	lines, matrixPtr := utils.ParseStdin(stdin, *columnSeqPtr, *lineSeqPtr)

	vm := otto.New()

	vm.Set("stdin", stdin)
	vm.Set("stdout", "")
	vm.Set("lines", lines)
	vm.Set("matrix", *matrixPtr)
	vm.Run("println = console.log")
	libvm.SetBuiltinFunc(vm)

	for i := 0; i < len(*funcListPtr); i += 1 {
		libvm.InitExternelFunc(vm, (*funcListPtr)[i])
	}

	for i := 0; i < len(*pathListPtr); i += 1 {
		addPATHEnv((*pathListPtr)[i])
	}

	for i := 0; i < len(*jsListPtr); i += 1 {
		libvm.ReadJSFile(vm, (*jsListPtr)[i])
	}

	codeList := sort.StringSlice(*codeListPtr)

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

	for i := 0; i < len(codeList); i += 1 {
		_, err := vm.Run(codeList[i])
		if err != nil {
			panic(err)
		}
	}

}
<commit_msg>use go-arg instead of kingpin.v2 for cli<commit_after>package main

import (
	"fmt"
	"github.com/alexflint/go-arg"
	"github.com/kjelly/jscli/lib/libvm"
	"github.com/kjelly/jscli/lib/utils"
	"github.com/robertkrimen/otto"
	"io/ioutil"
	"os"
	"sort"
)

func readAll() string {
	bytes, err := ioutil.ReadAll(os.Stdin)
	if err == nil {
		return string(bytes)
	} else {
		panic("Failed to read stdin")
	}
}

type Matrix [][]string

func addPATHEnv(path string) {
	oldEnv := os.Getenv("PATH")
	newEnv := path + ":" + oldEnv
	os.Setenv("PATH", newEnv)
}

func getWd() string {
	cwd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return cwd
}

func main() {
	addPATHEnv(getWd())
	fmt.Printf("")

	var args struct {
		CodeList  []string `arg:"positional"`
		LineSeq   string   `arg:"-l"`
		ColumnSeq string   `arg:"-c"`
		FuncList  []string `arg:"-f"`
		JSList    []string `arg:"-j"`
		PathList  []string `arg:"-p"`
		Reverse   bool     `arg:"-r"`
		NoStdin   bool     `arg:"--nostdin"`
	}
	args.LineSeq = "\n"
	args.ColumnSeq = " +"
	arg.MustParse(&args)

	var stdin string

	if args.NoStdin {
		stdin = ""
	} else {
		stdin = readAll()
	}

	lines, matrixPtr := utils.ParseStdin(stdin, args.ColumnSeq, args.LineSeq)

	vm := otto.New()

	vm.Set("stdin", stdin)
	vm.Set("stdout", "")
	vm.Set("lines", lines)
	vm.Set("matrix", *matrixPtr)
	vm.Run("println = console.log")
	libvm.SetBuiltinFunc(vm)

	for i := 0; i < len(args.FuncList); i += 1 {
		libvm.InitExternelFunc(vm, (args.FuncList)[i])
	}

	for i := 0; i < len(args.PathList); i += 1 {
		addPATHEnv((args.PathList)[i])
	}

	for i := 0; i < len(args.JSList); i += 1 {
		libvm.ReadJSFile(vm, (args.JSList)[i])
	}

	codeList := sort.StringSlice(args.CodeList)

	if args.Reverse {
		for i, j := 0, len(codeList)-1; i < j; i, j = i+1, j-1 {
			codeList[i], codeList[j] = codeList[j], codeList[i]
		}
	}

	for i := 0; i < len(codeList); i += 1 {
		_, err := vm.Run(codeList[i])
		if err != nil {
			panic(err)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"
	"log"
	"net/url"
	"path"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

type Link struct {
	NodeName string
	Text     string
	URL      string
}

func NormalizeString(s string) string {
	return strings.Join(strings.Fields(s), " ")
}

func ImageText(s *goquery.Selection) string {
	alt, _ := s.Attr("alt")
	if alt != "" {
		return alt
	}

	title, _ := s.Attr("title")
	if title != "" {
		return title
	}

	src, ok := s.Attr("src")
	if !ok {
		return "NO TEXT"
	}

	imageURL, err := url.Parse(src)
	if err != nil {
		log.Fatal(err)
	}

	return path.Base(imageURL.Path)
}

func FindLinks(file io.Reader) ([]Link, error) {
	doc, err := goquery.NewDocumentFromReader(file)
	if err != nil {
		return nil, err
	}

	var links []Link
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		node := goquery.NodeName(s)
		text := NormalizeString(s.Text())
		if text == "" {
			s.Children().Each(func(i int, s *goquery.Selection) {
				node = goquery.NodeName(s)
				if node == "img" {
					text = ImageText(s)
				}
			})
		}
		if text == "" {
			text = "NO TEXT"
		}
		url, _ := s.Attr("href")
		links = append(links, Link{node, text, url})
	})

	if len(links) == 0 {
		return nil, errors.New("no links found")
	}

	return links, nil
}
<commit_msg>Only add links that have a href attribute<commit_after>package main

import (
	"errors"
	"io"
	"log"
	"net/url"
	"path"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

type Link struct {
	NodeName string
	Text     string
	URL      string
}

func NormalizeString(s string) string {
	return strings.Join(strings.Fields(s), " ")
}

func ImageText(s *goquery.Selection) string {
	alt, _ := s.Attr("alt")
	if alt != "" {
		return alt
	}

	title, _ := s.Attr("title")
	if title != "" {
		return title
	}

	src, ok := s.Attr("src")
	if !ok {
		return "NO TEXT"
	}

	imageURL, err := url.Parse(src)
	if err != nil {
		log.Fatal(err)
	}

	return path.Base(imageURL.Path)
}

func FindLinks(file io.Reader) ([]Link, error) {
	doc, err := goquery.NewDocumentFromReader(file)
	if err != nil {
		return nil, err
	}

	var links []Link
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		url, ok := s.Attr("href")
		if !ok {
			return
		}

		node := goquery.NodeName(s)
		text := NormalizeString(s.Text())
		if text == "" {
			s.Children().Each(func(i int, s *goquery.Selection) {
				node = goquery.NodeName(s)
				if node == "img" {
					text = ImageText(s)
				}
			})
		}

		if text == "" {
			text = "NO TEXT"
		}

		links = append(links, Link{node, text, url})
	})

	if len(links) == 0 {
		return nil, errors.New("no links found")
	}

	return links, nil
}
<|endoftext|>