<commit_before>package main

import (
	//	"encoding/binary"
	"fmt"
	"syscall"
	"unsafe"
)

const (
	MAX_AUDIT_MESSAGE_LENGTH = 8970
	AUDIT_GET                = 1000
	AUDIT_LIST               = 1002
	AUDIT_LIST_RULES         = 1013
)

/*
#define MAX_AUDIT_MESSAGE_LENGTH    8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1
struct audit_message {
	struct nlmsghdr nlh;
	char   data[MAX_AUDIT_MESSAGE_LENGTH];
};
*/
/*
struct audit_reply {
	int                      type;
	int                      len;
	struct nlmsghdr         *nlh;
	struct audit_message     msg;

	// Using a union to compress this structure since only one of
	 * the following should be valid for any packet. //
	union {
	struct audit_status     *status;
	struct audit_rule_data  *ruledata;
	struct audit_login      *login;
	const char              *message;
	struct nlmsgerr         *error;
	struct audit_sig_info   *signal_info;
	struct daemon_conf      *conf;
#if HAVE_DECL_AUDIT_FEATURE_VERSION
	struct audit_features	*features;
#endif
	};
};

*/
/*
func nativeEndian() binary.ByteOrder {
	var x uint32 = 0x01020304
	if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
		return binary.BigEndian
	}
	return binary.LittleEndian
}
*/

type NetlinkAuditRequest struct {
	Header syscall.NlMsghdr
	Data   string
}

type AuditReply struct {
	RepHeader syscall.NlMsghdr
	Message   NetlinkAuditRequest
}

func (rr *NetlinkAuditRequest) ToWireFormat() []byte {
	b := make([]byte, rr.Header.Len)
	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
	//	fmt.Printf("%+v,%+v\n", *(*uint16)(unsafe.Pointer(&b[4:6][0])), rr.Header.Type)
	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
	//	fmt.Printf("%+v,%+v\n", *(*uint16)(unsafe.Pointer(&b[6:8][0])), rr.Header.Flags)

	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
	//b[16] = byte(family)
	return b
}

func newNetlinkAuditRequest(proto, seq, family int) *NetlinkAuditRequest {
	rr := &NetlinkAuditRequest{}

	rr.Header.Len = uint32(syscall.NLMSG_HDRLEN) //
	rr.Header.Type = uint16(proto)
	rr.Header.Flags = syscall.NLM_F_REQUEST
	rr.Header.Seq = uint32(seq)
	return rr
	//	return rr.ToWireFormat()
}

// Round the length of a netlink message up to align it properly.
func nlmAlignOf(msglen int) int {
	return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1)
}

func ParseAuditNetlinkMessage(b []byte) ([]syscall.NetlinkMessage, error) {
	var msgs []syscall.NetlinkMessage
	for len(b) >= syscall.NLMSG_HDRLEN {
		h, dbuf, dlen, err := netlinkMessageHeaderAndData(b)
		if err != nil {
			fmt.Println("Error in parse")
			return nil, err
		}
		m := syscall.NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-syscall.NLMSG_HDRLEN]}
		msgs = append(msgs, m)
		b = b[dlen:]
	}
	return msgs, nil
}

func netlinkMessageHeaderAndData(b []byte) (*syscall.NlMsghdr, []byte, int, error) {

	h := (*syscall.NlMsghdr)(unsafe.Pointer(&b[0]))
	if int(h.Len) < syscall.NLMSG_HDRLEN || int(h.Len) > len(b) {
		fmt.Println("Error Here")
		fmt.Println(syscall.NLMSG_HDRLEN, h.Len, h.Len, len(b))
		return nil, nil, 0, syscall.EINVAL
	}
	return h, b[syscall.NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
}

/*
Inspired from Docker library

type NetlinkRequest struct {
	syscall.NlMsghdr
	Data []NetlinkRequestData
}

func (rr *NetlinkRequest) ToWireFormat() []byte {
	native := nativeEndian()

	length := rr.Len
	dataBytes := make([][]byte, len(rr.Data))
	for i, data := range rr.Data {
		dataBytes[i] = data.ToWireFormat()
		length += uint32(len(dataBytes[i]))
	}
	b := make([]byte, length)
	native.PutUint32(b[0:4], length)
	native.PutUint16(b[4:6], rr.Type)
	native.PutUint16(b[6:8], rr.Flags)
	native.PutUint32(b[8:12], rr.Seq)
	native.PutUint32(b[12:16], rr.Pid)

	next := 16
	for _, data := range dataBytes {
		copy(b[next:], data)
		next += len(data)
	}
	return b
}

func (rr *NetlinkRequest) AddData(data NetlinkRequestData) {
	if data != nil {
		rr.Data = append(rr.Data, data)
	}
}

func newNetlinkRequest(proto, flags int) *NetlinkRequest {
	return &NetlinkRequest{
		NlMsghdr: syscall.NlMsghdr{
			Len:   uint32(syscall.NLMSG_HDRLEN),
			Type:  uint16(proto),
			Flags: syscall.NLM_F_REQUEST | uint16(flags),
			Seq:   atomic.AddUint32(&nextSeqNr, 1),
		},
	}
}
*/
type NetlinkSocket struct {
	fd  int
	lsa syscall.SockaddrNetlink
}

func getNetlinkSocket() (*NetlinkSocket, error) {
	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_AUDIT)
	if err != nil {
		return nil, err
	}
	s := &NetlinkSocket{
		fd: fd,
	}
	s.lsa.Family = syscall.AF_NETLINK
	s.lsa.Groups = 0
	s.lsa.Pid = 0

	if err := syscall.Bind(fd, &s.lsa); err != nil {
		syscall.Close(fd)
		return nil, err
	}
	return s, nil
}

func (s *NetlinkSocket) Close() {
	syscall.Close(s.fd)
}

func (s *NetlinkSocket) Send(request *NetlinkAuditRequest) error {
	//fmt.Printf("Sent(Raw) %+v\n", wb)
	//Sending the request to kernel

	if err := syscall.Sendto(s.fd, request.ToWireFormat(), 0, &s.lsa); err != nil {
		return err
	}
	return nil
}

func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
	rb := make([]byte, syscall.Getpagesize())
	nr, _, err := syscall.Recvfrom(s.fd, rb, syscall.MSG_PEEK|syscall.MSG_DONTWAIT)
	//nr, _, err := syscall.Recvfrom(s, rb, syscall.MSG_PEEK|syscall.MSG_DONTWAIT)
	if err != nil {
		return nil, err
	}
	if nr < syscall.NLMSG_HDRLEN {
		return nil, syscall.EINVAL //ErrShortResponse
	}
	rb = rb[:nr]
	//var tab []byte
	//append(tab, rb...)
	//	fmt.Printf("Received (Raw)%v\n", rb)
	sd, _ := syscall.ParseNetlinkMessage(rb)
	//fmt.Printf("Received (Raw)%v\n", sd)
	for i, e := range sd {
		fmt.Println("index ", i)
		//fmt.Println(e.Data[:])
		b := e.Data[:]
		a := (*string)(unsafe.Pointer(&b[0])) //Conversion Success
		fmt.Println(a)
	}
	return ParseAuditNetlinkMessage(rb) //Or syscall.ParseNetlinkMessage(rb)
}

func AuditNetlink(proto, family int) ([]byte, error) {
	//native := nativeEndian()
	s, err := getNetlinkSocket()

	if err != nil {
		return nil, err
	}

	defer s.Close()

	wb := newNetlinkAuditRequest(proto, 1, family)

	if err := s.Send(wb); err != nil {
		return nil, err
	}

	/*
		if err := syscall.Sendto(s, wb, 0, lsa); err != nil {
			return nil, err
		}
	*/
	var tab []byte

	// done:
	//for {
	//Running for one time only
	/*rb := make([]byte, syscall.Getpagesize())

	nr, _, err := syscall.Recvfrom(s, rb, syscall.MSG_PEEK|syscall.MSG_DONTWAIT)

	if err != nil {
		fmt.Println("Error on Receiving")
		return nil, err
	}
	if nr < syscall.NLMSG_HDRLEN {
		return nil, syscall.EINVAL
	}
	rb = rb[:nr]
	*/
	//	tab = append(tab, rb...)
	msgs, err := s.Receive() //ParseAuditNetlinkMessage(rb)
	if err != nil {
		fmt.Println("Error in Parsing")
		return nil, err
	}

	for _, m := range msgs {
		lsa, err := syscall.Getsockname(s.fd)
		if err != nil {
			fmt.Println("Error in getting Sockaddr name")
			return nil, err
		}
		switch v := lsa.(type) {
		case *syscall.SockaddrNetlink:

			if m.Header.Seq != 1 || m.Header.Pid != v.Pid {
				fmt.Println("Messgage sequence or Pid didn't match")
				return nil, syscall.EINVAL
			}
		default:
			fmt.Println("foo4")
			return nil, syscall.EINVAL
			/*
				if m.Header.Seq != wb.seq {
					return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq)
				}
				if m.Header.Pid != pid {
					return fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
				}

			*/

		}

		if m.Header.Type == syscall.NLMSG_DONE {
			break //done
		}
		if m.Header.Type == syscall.NLMSG_ERROR {
			//error := int32(native.Uint32(m.Data[0:4]))
			fmt.Println("NLMSG_ERROR")
			return nil, syscall.EINVAL
		}
		if m.Header.Type == AUDIT_GET { //SHORT FOR AUDIT_GET
			fmt.Println("ENABLED")
			break
		}

	}
	//}
	return tab, nil

}

func main() {
	_, er := AuditNetlink(AUDIT_LIST_RULES, syscall.AF_NETLINK)
	//Types are defined in /usr/include/linux/audit.h
	//See https://www.redhat.com/archives/linux-audit/2011-January/msg00030.html
	if er != nil {
		fmt.Println("Got error on last")

		//fmt.Println(er)
	} else {
		//str := string(v[:])
		fmt.Println("Sucess!")
	}
	//	NetLinkListener()
}
<commit_msg>Added LIST_ALL_RULES | empty response<commit_after>package main

import (
	//	"encoding/binary"
	"fmt"
	"syscall"
	"unsafe"
)

const (
	MAX_AUDIT_MESSAGE_LENGTH = 8970
	AUDIT_GET                = 1000
	AUDIT_LIST               = 1002
	AUDIT_LIST_RULES         = 1013
	AUDIT_FIRST_USER_MSG     = 1100 /* Userspace messages mostly uninteresting to kernel */

)

/*
#define MAX_AUDIT_MESSAGE_LENGTH    8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1
struct audit_message {
	struct nlmsghdr nlh;
	char   data[MAX_AUDIT_MESSAGE_LENGTH];
};
*/
/*
struct audit_reply {
	int                      type;
	int                      len;
	struct nlmsghdr         *nlh;
	struct audit_message     msg;

	// Using a union to compress this structure since only one of
	 * the following should be valid for any packet. //
	union {
	struct audit_status     *status;
	struct audit_rule_data  *ruledata;
	struct audit_login      *login;
	const char              *message;
	struct nlmsgerr         *error;
	struct audit_sig_info   *signal_info;
	struct daemon_conf      *conf;
#if HAVE_DECL_AUDIT_FEATURE_VERSION
	struct audit_features	*features;
#endif
	};
};

*/
/*
func nativeEndian() binary.ByteOrder {
	var x uint32 = 0x01020304
	if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
		return binary.BigEndian
	}
	return binary.LittleEndian
}
*/

type NetlinkAuditRequest struct {
	Header syscall.NlMsghdr
	Data   []byte
}

type AuditReply struct {
	RepHeader syscall.NlMsghdr
	Message   NetlinkAuditRequest
}

//The recvfrom in go takes only a byte [] to put the data recieved from the kernel that removes the need
//for having a separate audit_reply Struct for recieving data from kernel.
func (rr *NetlinkAuditRequest) ToWireFormat() []byte {
	b := make([]byte, rr.Header.Len)
	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
	//	fmt.Printf("%+v,%+v\n", *(*uint16)(unsafe.Pointer(&b[4:6][0])), rr.Header.Type)
	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
	//	fmt.Printf("%+v,%+v\n", *(*uint16)(unsafe.Pointer(&b[6:8][0])), rr.Header.Flags)

	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
	//b[16] = byte(family)
	return b
}

func newNetlinkAuditRequest(proto, seq, family int) *NetlinkAuditRequest {
	rr := &NetlinkAuditRequest{}

	rr.Header.Len = uint32(syscall.NLMSG_HDRLEN) //
	rr.Header.Type = uint16(proto)
	rr.Header.Flags = syscall.NLM_F_REQUEST
	rr.Header.Seq = uint32(seq)
	return rr
	//	return rr.ToWireFormat()
}

// Round the length of a netlink message up to align it properly.
func nlmAlignOf(msglen int) int {
	return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1)
}

func ParseAuditNetlinkMessage(b []byte) ([]syscall.NetlinkMessage, error) {
	var msgs []syscall.NetlinkMessage
	for len(b) >= syscall.NLMSG_HDRLEN {
		h, dbuf, dlen, err := netlinkMessageHeaderAndData(b)
		if err != nil {
			fmt.Println("Error in parse")
			return nil, err
		}
		m := syscall.NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-syscall.NLMSG_HDRLEN]}
		msgs = append(msgs, m)
		b = b[dlen:]
	}
	return msgs, nil
}

func netlinkMessageHeaderAndData(b []byte) (*syscall.NlMsghdr, []byte, int, error) {

	h := (*syscall.NlMsghdr)(unsafe.Pointer(&b[0]))
	if int(h.Len) < syscall.NLMSG_HDRLEN || int(h.Len) > len(b) {
		fmt.Println("Error Here")
		fmt.Println(syscall.NLMSG_HDRLEN, h.Len, h.Len, len(b))
		return nil, nil, 0, syscall.EINVAL
	}
	return h, b[syscall.NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
}

/*
Inspired from Docker library

type NetlinkRequest struct {
	syscall.NlMsghdr
	Data []NetlinkRequestData
}

func (rr *NetlinkRequest) ToWireFormat() []byte {
	native := nativeEndian()

	length := rr.Len
	dataBytes := make([][]byte, len(rr.Data))
	for i, data := range rr.Data {
		dataBytes[i] = data.ToWireFormat()
		length += uint32(len(dataBytes[i]))
	}
	b := make([]byte, length)
	native.PutUint32(b[0:4], length)
	native.PutUint16(b[4:6], rr.Type)
	native.PutUint16(b[6:8], rr.Flags)
	native.PutUint32(b[8:12], rr.Seq)
	native.PutUint32(b[12:16], rr.Pid)

	next := 16
	for _, data := range dataBytes {
		copy(b[next:], data)
		next += len(data)
	}
	return b
}

func (rr *NetlinkRequest) AddData(data NetlinkRequestData) {
	if data != nil {
		rr.Data = append(rr.Data, data)
	}
}

func newNetlinkRequest(proto, flags int) *NetlinkRequest {
	return &NetlinkRequest{
		NlMsghdr: syscall.NlMsghdr{
			Len:   uint32(syscall.NLMSG_HDRLEN),
			Type:  uint16(proto),
			Flags: syscall.NLM_F_REQUEST | uint16(flags),
			Seq:   atomic.AddUint32(&nextSeqNr, 1),
		},
	}
}
*/
type NetlinkSocket struct {
	fd  int
	lsa syscall.SockaddrNetlink
}

func getNetlinkSocket() (*NetlinkSocket, error) {
	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_AUDIT)
	if err != nil {
		return nil, err
	}
	s := &NetlinkSocket{
		fd: fd,
	}
	s.lsa.Family = syscall.AF_NETLINK
	s.lsa.Groups = 0
	s.lsa.Pid = 0

	if err := syscall.Bind(fd, &s.lsa); err != nil {
		syscall.Close(fd)
		return nil, err
	}
	return s, nil
}

func (s *NetlinkSocket) Close() {
	syscall.Close(s.fd)
}

func (s *NetlinkSocket) Send(request *NetlinkAuditRequest) error {
	//fmt.Printf("Sent(Raw) %+v\n", wb)
	//Sending the request to kernel

	if err := syscall.Sendto(s.fd, request.ToWireFormat(), 0, &s.lsa); err != nil {
		return err
	}
	return nil
}

func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
	rb := make([]byte, syscall.Getpagesize())
	nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
	//nr, _, err := syscall.Recvfrom(s, rb, syscall.MSG_PEEK|syscall.MSG_DONTWAIT)
	if err != nil {
		return nil, err
	}
	if nr < syscall.NLMSG_HDRLEN {
		return nil, syscall.EINVAL //ErrShortResponse
	}
	rb = rb[:nr]
	//var tab []byte
	//append(tab, rb...)
	//	fmt.Printf("Received (Raw)%v\n", rb)
	sd, _ := syscall.ParseNetlinkMessage(rb)

	//fmt.Printf("Received (Raw)%v\n", sd)

	for i, e := range sd {
		fmt.Println("index ", i)
		//fmt.Println(e.Data[:])
		if len(e.Data) == 0 {
			fmt.Println("0 DATA")
		} else {
			b := e.Data[:]
			//for i, _ := range b {
			a := (*string)(unsafe.Pointer(&b[0]))
			//d := *a
			fmt.Println(a)

		}
		//TO DO GET LIST DATA FROM KERNEL audit_rule_data ???
		//Represent the value in hex form
		//}
		//		a := (*string)(unsafe.Pointer(&b[0]))
		//		c := (*string)(unsafe.Pointer(&b[1])) //Conversion Success

	}

	return ParseAuditNetlinkMessage(rb) //Or syscall.ParseNetlinkMessage(rb)
}

func AuditNetlink(proto, family int) ([]byte, error) {
	//native := nativeEndian()
	s, err := getNetlinkSocket()

	if err != nil {
		return nil, err
	}

	defer s.Close()

	wb := newNetlinkAuditRequest(proto, 1, family)

	if err := s.Send(wb); err != nil {
		return nil, err
	}

	/*
		if err := syscall.Sendto(s, wb, 0, lsa); err != nil {
			return nil, err
		}
	*/
	var tab []byte

done:
	for {
		//Running for one time only
		/*rb := make([]byte, syscall.Getpagesize())

		nr, _, err := syscall.Recvfrom(s, rb, syscall.MSG_PEEK|syscall.MSG_DONTWAIT)

		if err != nil {
			fmt.Println("Error on Receiving")
			return nil, err
		}
		if nr < syscall.NLMSG_HDRLEN {
			return nil, syscall.EINVAL
		}
		rb = rb[:nr]
		*/
		//	tab = append(tab, rb...)
		msgs, err := s.Receive() //ParseAuditNetlinkMessage(rb)
		if err != nil {
			fmt.Println("Error in Parsing")
			return nil, err
		}

		for _, m := range msgs {
			lsa, err := syscall.Getsockname(s.fd)
			if err != nil {
				fmt.Println("Error in getting Sockaddr name")
				return nil, err
			}
			switch v := lsa.(type) {
			case *syscall.SockaddrNetlink:

				if m.Header.Seq != 1 || m.Header.Pid != v.Pid {
					fmt.Println("Messgage sequence or Pid didn't match")
					return nil, syscall.EINVAL
				}
			default:
				fmt.Println("foo4")
				return nil, syscall.EINVAL
				/*
					if m.Header.Seq != wb.seq {
						return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq)
					}
					if m.Header.Pid != pid {
						return fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
					}

				*/

			}

			if m.Header.Type == syscall.NLMSG_DONE {
				fmt.Println("Done")
				break done
			}
			if m.Header.Type == syscall.NLMSG_ERROR {
				//error := int32(native.Uint32(m.Data[0:4]))
				fmt.Println("NLMSG_ERROR")
				return nil, syscall.EINVAL
			}
			if m.Header.Type == AUDIT_GET { //SHORT FOR AUDIT_GET
				fmt.Println("ENABLED")
				break done
			}
			if m.Header.Type == AUDIT_FIRST_USER_MSG {
				fmt.Println("FFFF")
				break done
			}
			if m.Header.Type == AUDIT_LIST_RULES {
				fmt.Println("FOO")
				break done
			}
			if m.Header.Type == AUDIT_FIRST_USER_MSG {
				fmt.Println("HAA")
				break done
			}

		}
	}
	return tab, nil

}

func main() {
	_, er := AuditNetlink(AUDIT_LIST_RULES, syscall.AF_NETLINK)
	//Types are defined in /usr/include/linux/audit.h
	//See https://www.redhat.com/archives/linux-audit/2011-January/msg00030.html
	if er != nil {
		fmt.Println("Got error on last")

		//fmt.Println(er)
	} else {
		//str := string(v[:])
		fmt.Println("Sucess!")
	}
	//	NetLinkListener()
}
<|endoftext|>


<commit_before>// Copyright 2013 Julien Schmidt. All rights reserved.
// Copyright (c) 2015-2016, 招牌疯子
// Copyright (c) 2017, Kirill Danshin
// Use of this source code is governed by a BSD-style license that can be found
// in the 3rd-Party License/fasthttprouter file.

package gramework

import (
	"strings"

	"github.com/valyala/fasthttp"
)

var (
	// DefaultContentType cached to minimize memory allocations
	DefaultContentType = []byte("text/plain; charset=utf-8")
	// QuestionMark cached to minimize memory allocations
	QuestionMark = []byte("?")

	// SlashByte cached to minimize memory allocations
	SlashByte = byte('/')
)

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type router struct {
	Trees map[string]*node

	// Enables automatic redirection if the current route can't be matched but a
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301 for GET requests
	// and 307 for all other request methods.
	RedirectTrailingSlash bool

	// If enabled, the router tries to fix the current request path, if no
	// handle is registered for it.
	// First superfluous path elements like ../ or // are removed.
	// Afterwards the router does a case-insensitive lookup of the cleaned path.
	// If a handle can be found for this route, the router makes a redirection
	// to the corrected path with status code 301 for GET requests and 307 for
	// all other request methods.
	// For example /FOO and /..//Foo could be redirected to /foo.
	// RedirectTrailingSlash is independent of this option.
	RedirectFixedPath bool

	// If enabled, the router checks if another method is allowed for the
	// current route, if the current request can not be routed.
	// If this is the case, the request is answered with 'Method Not Allowed'
	// and HTTP status code 405.
	// If no other Method is allowed, the request is delegated to the NotFound
	// handler.
	HandleMethodNotAllowed bool

	// If enabled, the router automatically replies to OPTIONS requests.
	// Custom OPTIONS handlers take priority over automatic replies.
	HandleOPTIONS bool

	// Configurable http.Handler which is called when no matching route is
	// found. If it is not set, http.NotFound is used.
	NotFound RequestHandler

	// Configurable http.Handler which is called when a request
	// cannot be routed and HandleMethodNotAllowed is true.
	// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
	// The "Allow" header with allowed request methods is set before the handler
	// is called.
	MethodNotAllowed RequestHandler

	// Function to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// 500 (Internal Server Error).
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(*Context, interface{})

	cache *cache
}

// newRouter returns a new initialized Router.
// Path auto-correction, including trailing slashes, is enabled by default.
func newRouter() *router {
	r := &router{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
		HandleOPTIONS:          true,
		cache: &cache{
			v: make(map[string]*msc, 0),
		},
	}
	go r.cache.maintain()
	return r
}

const (
	// GET method
	GET = "GET"
	// HEAD method
	HEAD = "HEAD"
	// OPTIONS method
	OPTIONS = "OPTIONS"
	// POST method
	POST = "POST"
	// PUT method
	PUT = "PUT"
	// PATCH method
	PATCH = "PATCH"
	// DELETE method
	DELETE = "DELETE"
	// CONNECT method
	CONNECT = "CONNECT"

	// PathAny used to minimize memory allocations
	PathAny = "*"
	// PathSlashAny used to minimize memory allocations
	PathSlashAny = "/*"
	// PathSlash used to minimize memory allocations
	PathSlash = "/"

	// HeaderAllow used to minimize memory allocations
	HeaderAllow = "Allow"
)

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *router) GET(path string, handle RequestHandler) {
	r.Handle(GET, path, handle)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (r *router) HEAD(path string, handle RequestHandler) {
	r.Handle(HEAD, path, handle)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (r *router) OPTIONS(path string, handle RequestHandler) {
	r.Handle(OPTIONS, path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *router) POST(path string, handle RequestHandler) {
	r.Handle(POST, path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *router) PUT(path string, handle RequestHandler) {
	r.Handle(PUT, path, handle)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (r *router) PATCH(path string, handle RequestHandler) {
	r.Handle(PATCH, path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *router) DELETE(path string, handle RequestHandler) {
	r.Handle(DELETE, path, handle)
}

// Handle registers a new request handle with the given path and method.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (r *router) Handle(method, path string, handle RequestHandler) {
	if path[0] != SlashByte {
		panic("path must begin with '/' in path '" + path + "'")
	}

	path = strings.TrimRight(path, Slash)

	if r.Trees == nil {
		r.Trees = make(map[string]*node)
	}

	root := r.Trees[method]
	if root == nil {
		root = new(node)
		root.router = r
		r.Trees[method] = root
	}

	root.addRoute(path, handle, r)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
//     router.ServeFiles("/src/*filepath", "/var/www")
func (r *router) ServeFiles(path string, rootPath string) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath in path '" + path + "'")
	}
	prefix := path[:len(path)-10]

	fileHandler := fasthttp.FSHandler(rootPath, strings.Count(prefix, PathSlash))

	r.GET(path, func(ctx *Context) {
		fileHandler(ctx.RequestCtx)
	})
}

// Recv used to recover after panic. Called if PanicHandler was set
func (r *router) Recv(ctx *Context) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(ctx, rcv)
	}
}

// Lookup allows the manual lookup of a method + path combo.
// This is e.g. useful to build a framework around this router.
// If the path was found, it returns the handle function and the path parameter
// values. Otherwise the third return value indicates whether a redirection to
// the same path with an extra / without the trailing slash should be performed.
func (r *router) Lookup(method, path string, ctx *Context) (RequestHandler, bool) {
	if root := r.Trees[method]; root != nil {
		return root.GetValue(path, ctx, method)
	}
	return nil, false
}

// Allowed returns Allow header's value used in OPTIONS responses
func (r *router) Allowed(path, reqMethod string) (allow string) {
	if path == PathAny || path == PathSlashAny { // server-wide
		for method := range r.Trees {
			if method == OPTIONS {
				continue
			}

			// add request method to list of allowed methods
			if len(allow) == 0 {
				allow = method
			} else {
				allow += ", " + method
			}
		}
	} else { // specific path
		for method := range r.Trees {
			// Skip the requested method - we already tried this one
			if method == reqMethod || method == OPTIONS {
				continue
			}

			handle, _ := r.Trees[method].GetValue(path, nil, reqMethod)
			if handle != nil {
				// add request method to list of allowed methods
				if len(allow) == 0 {
					allow = method
				} else {
					allow += ", " + method
				}
			}
		}
	}
	if len(allow) > 0 {
		allow += ", OPTIONS"
	}
	return
}

// // Handler makes the router implement the fasthttp.ListenAndServe interface.
// func (r *router) Handler(ctx *Context) {
// 	if r.PanicHandler != nil {
// 		defer r.Recv(ctx)
// 	}

// 	path := string(ctx.Path())
// 	method := string(ctx.Method())
// 	if root := r.Trees[method]; root != nil {
// 		if f, tsr := root.GetValue(path, ctx); f != nil {
// 			f(ctx)
// 			return
// 		} else if method != CONNECT && path != PathSlash {
// 			code := 301 // Permanent redirect, request with GET method
// 			if method != GET {
// 				// Temporary redirect, request with same method
// 				// As of Go 1.3, Go does not support status code 308.
// 				code = 307
// 			}

// 			if tsr && r.RedirectTrailingSlash {
// 				var uri string
// 				if len(path) > 1 && path[len(path)-1] == SlashByte {
// 					uri = path[:len(path)-1]
// 				} else {
// 					uri = path + PathSlash
// 				}
// 				ctx.Redirect(uri, code)
// 				return
// 			}

// 			// Try to fix the request path
// 			if r.RedirectFixedPath {
// 				fixedPath, found := root.FindCaseInsensitivePath(
// 					CleanPath(path),
// 					r.RedirectTrailingSlash,
// 				)

// 				if found {
// 					queryBuf := ctx.URI().QueryString()
// 					if len(queryBuf) > 0 {
// 						fixedPath = append(fixedPath, QuestionMark...)
// 						fixedPath = append(fixedPath, queryBuf...)
// 					}
// 					uri := string(fixedPath)
// 					ctx.Redirect(uri, code)
// 					return
// 				}
// 			}
// 		}
// 	}

// 	if method == OPTIONS {
// 		// Handle OPTIONS requests
// 		if r.HandleOPTIONS {
// 			if allow := r.Allowed(path, method); len(allow) > 0 {
// 				ctx.Response.Header.Set(HeaderAllow, allow)
// 				return
// 			}
// 		}
// 	} else {
// 		// Handle 405
// 		if r.HandleMethodNotAllowed {
// 			if allow := r.Allowed(path, method); len(allow) > 0 {
// 				ctx.Response.Header.Set(HeaderAllow, allow)
// 				if r.MethodNotAllowed != nil {
// 					r.MethodNotAllowed(ctx)
// 				} else {
// 					ctx.SetStatusCode(fasthttp.StatusMethodNotAllowed)
// 					ctx.SetContentTypeBytes(DefaultContentType)
// 					ctx.SetBodyString(fasthttp.StatusMessage(fasthttp.StatusMethodNotAllowed))
// 				}
// 				return
// 			}
// 		}
// 	}

// 	// Handle 404
// 	if r.NotFound != nil {
// 		r.NotFound(ctx)
// 	} else {
// 		ctx.Error(fasthttp.StatusMessage(fasthttp.StatusNotFound),
// 			fasthttp.StatusNotFound)
// 	}
// }
<commit_msg>router: #9 hotfix<commit_after>// Copyright 2013 Julien Schmidt. All rights reserved.
// Copyright (c) 2015-2016, 招牌疯子
// Copyright (c) 2017, Kirill Danshin
// Use of this source code is governed by a BSD-style license that can be found
// in the 3rd-Party License/fasthttprouter file.

package gramework

import (
	"strings"

	"github.com/valyala/fasthttp"
)

var (
	// DefaultContentType cached to minimize memory allocations
	DefaultContentType = []byte("text/plain; charset=utf-8")
	// QuestionMark cached to minimize memory allocations
	QuestionMark = []byte("?")

	// SlashByte cached to minimize memory allocations
	SlashByte = byte('/')
)

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type router struct {
	Trees map[string]*node

	// Enables automatic redirection if the current route can't be matched but a
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301 for GET requests
	// and 307 for all other request methods.
	RedirectTrailingSlash bool

	// If enabled, the router tries to fix the current request path, if no
	// handle is registered for it.
	// First superfluous path elements like ../ or // are removed.
	// Afterwards the router does a case-insensitive lookup of the cleaned path.
	// If a handle can be found for this route, the router makes a redirection
	// to the corrected path with status code 301 for GET requests and 307 for
	// all other request methods.
	// For example /FOO and /..//Foo could be redirected to /foo.
	// RedirectTrailingSlash is independent of this option.
	RedirectFixedPath bool

	// If enabled, the router checks if another method is allowed for the
	// current route, if the current request can not be routed.
	// If this is the case, the request is answered with 'Method Not Allowed'
	// and HTTP status code 405.
	// If no other Method is allowed, the request is delegated to the NotFound
	// handler.
	HandleMethodNotAllowed bool

	// If enabled, the router automatically replies to OPTIONS requests.
	// Custom OPTIONS handlers take priority over automatic replies.
	HandleOPTIONS bool

	// Configurable http.Handler which is called when no matching route is
	// found. If it is not set, http.NotFound is used.
	NotFound RequestHandler

	// Configurable http.Handler which is called when a request
	// cannot be routed and HandleMethodNotAllowed is true.
	// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
	// The "Allow" header with allowed request methods is set before the handler
	// is called.
	MethodNotAllowed RequestHandler

	// Function to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// 500 (Internal Server Error).
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(*Context, interface{})

	cache *cache
}

// newRouter returns a new initialized Router.
// Path auto-correction, including trailing slashes, is enabled by default.
func newRouter() *router {
	r := &router{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
		HandleOPTIONS:          true,
		cache: &cache{
			v: make(map[string]*msc, 0),
		},
	}
	go r.cache.maintain()
	return r
}

const (
	// GET method
	GET = "GET"
	// HEAD method
	HEAD = "HEAD"
	// OPTIONS method
	OPTIONS = "OPTIONS"
	// POST method
	POST = "POST"
	// PUT method
	PUT = "PUT"
	// PATCH method
	PATCH = "PATCH"
	// DELETE method
	DELETE = "DELETE"
	// CONNECT method
	CONNECT = "CONNECT"

	// PathAny used to minimize memory allocations
	PathAny = "*"
	// PathSlashAny used to minimize memory allocations
	PathSlashAny = "/*"
	// PathSlash used to minimize memory allocations
	PathSlash = "/"

	// HeaderAllow used to minimize memory allocations
	HeaderAllow = "Allow"
)

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *router) GET(path string, handle RequestHandler) {
	r.Handle(GET, path, handle)
}

// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (r *router) HEAD(path string, handle RequestHandler) {
	r.Handle(HEAD, path, handle)
}

// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (r *router) OPTIONS(path string, handle RequestHandler) {
	r.Handle(OPTIONS, path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *router) POST(path string, handle RequestHandler) {
	r.Handle(POST, path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *router) PUT(path string, handle RequestHandler) {
	r.Handle(PUT, path, handle)
}

// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (r *router) PATCH(path string, handle RequestHandler) {
	r.Handle(PATCH, path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *router) DELETE(path string, handle RequestHandler) {
	r.Handle(DELETE, path, handle)
}

// Handle registers a new request handle with the given path and method.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (r *router) Handle(method, path string, handle RequestHandler) {
	if path[0] != SlashByte {
		panic("path must begin with '/' in path '" + path + "'")
	}

	if path != "/" {
		path = strings.TrimRight(path, Slash)
	}

	if r.Trees == nil {
		r.Trees = make(map[string]*node)
	}

	root := r.Trees[method]
	if root == nil {
		root = new(node)
		root.router = r
		r.Trees[method] = root
	}

	root.addRoute(path, handle, r)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
//     router.ServeFiles("/src/*filepath", "/var/www")
func (r *router) ServeFiles(path string, rootPath string) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath in path '" + path + "'")
	}
	prefix := path[:len(path)-10]

	fileHandler := fasthttp.FSHandler(rootPath, strings.Count(prefix, PathSlash))

	r.GET(path, func(ctx *Context) {
		fileHandler(ctx.RequestCtx)
	})
}

// Recv used to recover after panic. Called if PanicHandler was set
func (r *router) Recv(ctx *Context) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(ctx, rcv)
	}
}

// Lookup allows the manual lookup of a method + path combo.
// This is e.g. useful to build a framework around this router.
// If the path was found, it returns the handle function and the path parameter
// values. Otherwise the third return value indicates whether a redirection to
// the same path with an extra / without the trailing slash should be performed.
func (r *router) Lookup(method, path string, ctx *Context) (RequestHandler, bool) {
	if root := r.Trees[method]; root != nil {
		return root.GetValue(path, ctx, method)
	}
	return nil, false
}

// Allowed returns Allow header's value used in OPTIONS responses
func (r *router) Allowed(path, reqMethod string) (allow string) {
	if path == PathAny || path == PathSlashAny { // server-wide
		for method := range r.Trees {
			if method == OPTIONS {
				continue
			}

			// add request method to list of allowed methods
			if len(allow) == 0 {
				allow = method
			} else {
				allow += ", " + method
			}
		}
	} else { // specific path
		for method := range r.Trees {
			// Skip the requested method - we already tried this one
			if method == reqMethod || method == OPTIONS {
				continue
			}

			handle, _ := r.Trees[method].GetValue(path, nil, reqMethod)
			if handle != nil {
				// add request method to list of allowed methods
				if len(allow) == 0 {
					allow = method
				} else {
					allow += ", " + method
				}
			}
		}
	}
	if len(allow) > 0 {
		allow += ", OPTIONS"
	}
	return
}

// // Handler makes the router implement the fasthttp.ListenAndServe interface.
// func (r *router) Handler(ctx *Context) {
// 	if r.PanicHandler != nil {
// 		defer r.Recv(ctx)
// 	}

// 	path := string(ctx.Path())
// 	method := string(ctx.Method())
// 	if root := r.Trees[method]; root != nil {
// 		if f, tsr := root.GetValue(path, ctx); f != nil {
// 			f(ctx)
// 			return
// 		} else if method != CONNECT && path != PathSlash {
// 			code := 301 // Permanent redirect, request with GET method
// 			if method != GET {
// 				// Temporary redirect, request with same method
// 				// As of Go 1.3, Go does not support status code 308.
// 				code = 307
// 			}

// 			if tsr && r.RedirectTrailingSlash {
// 				var uri string
// 				if len(path) > 1 && path[len(path)-1] == SlashByte {
// 					uri = path[:len(path)-1]
// 				} else {
// 					uri = path + PathSlash
// 				}
// 				ctx.Redirect(uri, code)
// 				return
// 			}

// 			// Try to fix the request path
// 			if r.RedirectFixedPath {
// 				fixedPath, found := root.FindCaseInsensitivePath(
// 					CleanPath(path),
// 					r.RedirectTrailingSlash,
// 				)

// 				if found {
// 					queryBuf := ctx.URI().QueryString()
// 					if len(queryBuf) > 0 {
// 						fixedPath = append(fixedPath, QuestionMark...)
// 						fixedPath = append(fixedPath, queryBuf...)
// 					}
// 					uri := string(fixedPath)
// 					ctx.Redirect(uri, code)
// 					return
// 				}
// 			}
// 		}
// 	}

// 	if method == OPTIONS {
// 		// Handle OPTIONS requests
// 		if r.HandleOPTIONS {
// 			if allow := r.Allowed(path, method); len(allow) > 0 {
// 				ctx.Response.Header.Set(HeaderAllow, allow)
// 				return
// 			}
// 		}
// 	} else {
// 		// Handle 405
// 		if r.HandleMethodNotAllowed {
// 			if allow := r.Allowed(path, method); len(allow) > 0 {
// 				ctx.Response.Header.Set(HeaderAllow, allow)
// 				if r.MethodNotAllowed != nil {
// 					r.MethodNotAllowed(ctx)
// 				} else {
// 					ctx.SetStatusCode(fasthttp.StatusMethodNotAllowed)
// 					ctx.SetContentTypeBytes(DefaultContentType)
// 					ctx.SetBodyString(fasthttp.StatusMessage(fasthttp.StatusMethodNotAllowed))
// 				}
// 				return
// 			}
// 		}
// 	}

// 	// Handle 404
// 	if r.NotFound != nil {
// 		r.NotFound(ctx)
// 	} else {
// 		ctx.Error(fasthttp.StatusMessage(fasthttp.StatusNotFound),
// 			fasthttp.StatusNotFound)
// 	}
// }
<|endoftext|>


<commit_before>package testrunner

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

	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

type Runner struct {
	binPath    string
	Session    *gexec.Session
	StartCheck string
	config     Config
}

type Config struct {
	PreloadedRootFSes      []string
	RootFSProviders        []string
	CellID                 string
	EtcdCluster            string
	ServerPort             int
	GardenAddr             string
	LogLevel               string
	ConsulCluster          string
	ReceptorTaskHandlerURL string
	PollingInterval        time.Duration
	EvacuationTimeout      time.Duration
	ClientCert             string
	ClientKey              string
	CACert                 string
}

func New(binPath string, config Config) *Runner {
	return &Runner{
		binPath:    binPath,
		StartCheck: "rep.started",
		config:     config,
	}
}

func (r *Runner) Start() {
	if r.Session != nil && r.Session.ExitCode() == -1 {
		panic("starting more than one rep!!!")
	}

	args := []string{
		"-cellID", r.config.CellID,
		"-listenAddr", fmt.Sprintf("0.0.0.0:%d", r.config.ServerPort),
		"-etcdCluster", r.config.EtcdCluster,
		"-logLevel", r.config.LogLevel,
		"-pollingInterval", r.config.PollingInterval.String(),
		"-evacuationTimeout", r.config.EvacuationTimeout.String(),
		"-lockRetryInterval", "1s",
		"-consulCluster", r.config.ConsulCluster,
		"-receptorTaskHandlerURL", r.config.ReceptorTaskHandlerURL,
		"-containerMaxCpuShares", "1024",
		"-gardenNetwork", "tcp",
		"-gardenAddr", r.config.GardenAddr,
		"-certFile", r.config.ClientCert,
		"-keyFile", r.config.ClientKey,
		"-caFile", r.config.CACert,
	}
	for _, rootfs := range r.config.PreloadedRootFSes {
		args = append(args, "-preloadedRootFS", rootfs)
	}
	for _, provider := range r.config.RootFSProviders {
		args = append(args, "-rootFSProvider", provider)
	}

	repSession, err := gexec.Start(
		exec.Command(
			r.binPath,
			args...,
		),
		gexec.NewPrefixedWriter("\x1b[32m[o]\x1b[32m[rep]\x1b[0m ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("\x1b[91m[e]\x1b[32m[rep]\x1b[0m ", ginkgo.GinkgoWriter),
	)

	Expect(err).NotTo(HaveOccurred())
	r.Session = repSession

	Eventually(r.Session.Buffer(), 2).Should(gbytes.Say(r.StartCheck))
}

func (r *Runner) Stop() {
	if r.Session != nil {
		r.Session.Interrupt().Wait(5 * time.Second)
	}
}

func (r *Runner) KillWithFire() {
	if r.Session != nil {
		r.Session.Kill().Wait(5 * time.Second)
	}
}
<commit_msg>Use etcd specific flags for etcd ssl config<commit_after>package testrunner

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

	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

type Runner struct {
	binPath    string
	Session    *gexec.Session
	StartCheck string
	config     Config
}

type Config struct {
	PreloadedRootFSes      []string
	RootFSProviders        []string
	CellID                 string
	EtcdCluster            string
	ServerPort             int
	GardenAddr             string
	LogLevel               string
	ConsulCluster          string
	ReceptorTaskHandlerURL string
	PollingInterval        time.Duration
	EvacuationTimeout      time.Duration
	EtcdClientCert         string
	EtcdClientKey          string
	EtcdCACert             string
}

func New(binPath string, config Config) *Runner {
	return &Runner{
		binPath:    binPath,
		StartCheck: "rep.started",
		config:     config,
	}
}

func (r *Runner) Start() {
	if r.Session != nil && r.Session.ExitCode() == -1 {
		panic("starting more than one rep!!!")
	}

	args := []string{
		"-cellID", r.config.CellID,
		"-listenAddr", fmt.Sprintf("0.0.0.0:%d", r.config.ServerPort),
		"-etcdCluster", r.config.EtcdCluster,
		"-logLevel", r.config.LogLevel,
		"-pollingInterval", r.config.PollingInterval.String(),
		"-evacuationTimeout", r.config.EvacuationTimeout.String(),
		"-lockRetryInterval", "1s",
		"-consulCluster", r.config.ConsulCluster,
		"-receptorTaskHandlerURL", r.config.ReceptorTaskHandlerURL,
		"-containerMaxCpuShares", "1024",
		"-gardenNetwork", "tcp",
		"-gardenAddr", r.config.GardenAddr,
		"-etcdCertFile", r.config.EtcdClientCert,
		"-etcdKeyFile", r.config.EtcdClientKey,
		"-etcdCaFile", r.config.EtcdCACert,
	}
	for _, rootfs := range r.config.PreloadedRootFSes {
		args = append(args, "-preloadedRootFS", rootfs)
	}
	for _, provider := range r.config.RootFSProviders {
		args = append(args, "-rootFSProvider", provider)
	}

	repSession, err := gexec.Start(
		exec.Command(
			r.binPath,
			args...,
		),
		gexec.NewPrefixedWriter("\x1b[32m[o]\x1b[32m[rep]\x1b[0m ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("\x1b[91m[e]\x1b[32m[rep]\x1b[0m ", ginkgo.GinkgoWriter),
	)

	Expect(err).NotTo(HaveOccurred())
	r.Session = repSession

	Eventually(r.Session.Buffer(), 2).Should(gbytes.Say(r.StartCheck))
}

func (r *Runner) Stop() {
	if r.Session != nil {
		r.Session.Interrupt().Wait(5 * time.Second)
	}
}

func (r *Runner) KillWithFire() {
	if r.Session != nil {
		r.Session.Kill().Wait(5 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"github.com/semantic-release/go-semantic-release"
	"github.com/semantic-release/go-semantic-release/condition"
	"io/ioutil"
	"log"
	"os"
)

var SRVERSION string

func errorHandler(logger *log.Logger) func(error) {
	return func(err error) {
		if err != nil {
			logger.Println(err)
			os.Exit(1)
		}
	}
}

func main() {
	token := flag.String("token", os.Getenv("GITHUB_TOKEN"), "github token")
	slug := flag.String("slug", os.Getenv("TRAVIS_REPO_SLUG"), "slug of the repository")
	ghr := flag.Bool("ghr", false, "create a .ghr file with the parameters for ghr")
	noci := flag.Bool("noci", false, "run semantic-release locally")
	dry := flag.Bool("dry", false, "do not create release")
	vFile := flag.Bool("vf", false, "create a .version file")
	showVersion := flag.Bool("version", false, "outputs the semantic-release version")
	flag.Parse()

	if *showVersion {
		fmt.Printf("semantic-release v%s", SRVERSION)
		return
	}

	logger := log.New(os.Stderr, "[semantic-release]: ", 0)
	exitIfError := errorHandler(logger)

	if *token == "" {
		exitIfError(errors.New("github token missing"))
	}
	if *slug == "" {
		exitIfError(errors.New("slug missing"))
	}

	repo, nerr := semrel.NewRepository(context.TODO(), *slug, *token)
	exitIfError(nerr)

	logger.Println("getting default branch...")
	defaultBranch, isPrivate, derr := repo.GetInfo()
	exitIfError(derr)
	logger.Println("found default branch: " + defaultBranch)

	if !*noci {
		logger.Println("running CI condition...")
		exitIfError(condition.Travis(*token, defaultBranch, isPrivate))
	}

	logger.Println("getting latest release...")
	release, rerr := repo.GetLatestRelease()
	exitIfError(rerr)
	logger.Println("found version: " + release.Version.String())

	logger.Println("getting commits...")
	commits, cerr := repo.GetCommits()
	exitIfError(cerr)

	logger.Println("calculating new version...")
	newVer := semrel.GetNewVersion(commits, release)
	if newVer == nil {
		exitIfError(errors.New("no change"))
	}
	logger.Println("new version: " + newVer.String())

	if *dry {
		exitIfError(errors.New("DRY RUN: no release was created"))
	}

	logger.Println("creating release...")
	exitIfError(repo.CreateRelease(commits, release, newVer))

	if *ghr {
		exitIfError(ioutil.WriteFile(".ghr", []byte(fmt.Sprintf("-u %s -r %s v%s", repo.Owner, repo.Repo, newVer.String())), 0644))
	}

	if *vFile {
		exitIfError(ioutil.WriteFile(".version", []byte(newVer.String()), 0644))
	}

	logger.Println("done.")
}
<commit_msg>refactor: use simpler variable names<commit_after>package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"github.com/semantic-release/go-semantic-release"
	"github.com/semantic-release/go-semantic-release/condition"
	"io/ioutil"
	"log"
	"os"
)

var SRVERSION string

func errorHandler(logger *log.Logger) func(error) {
	return func(err error) {
		if err != nil {
			logger.Println(err)
			os.Exit(1)
		}
	}
}

func main() {
	token := flag.String("token", os.Getenv("GITHUB_TOKEN"), "github token")
	slug := flag.String("slug", os.Getenv("TRAVIS_REPO_SLUG"), "slug of the repository")
	ghr := flag.Bool("ghr", false, "create a .ghr file with the parameters for ghr")
	noci := flag.Bool("noci", false, "run semantic-release locally")
	dry := flag.Bool("dry", false, "do not create release")
	vFile := flag.Bool("vf", false, "create a .version file")
	showVersion := flag.Bool("version", false, "outputs the semantic-release version")
	flag.Parse()

	if *showVersion {
		fmt.Printf("semantic-release v%s", SRVERSION)
		return
	}

	logger := log.New(os.Stderr, "[semantic-release]: ", 0)
	exitIfError := errorHandler(logger)

	if *token == "" {
		exitIfError(errors.New("github token missing"))
	}
	if *slug == "" {
		exitIfError(errors.New("slug missing"))
	}

	repo, err := semrel.NewRepository(context.TODO(), *slug, *token)
	exitIfError(err)

	logger.Println("getting default branch...")
	defaultBranch, isPrivate, err := repo.GetInfo()
	exitIfError(err)
	logger.Println("found default branch: " + defaultBranch)

	if !*noci {
		logger.Println("running CI condition...")
		exitIfError(condition.Travis(*token, defaultBranch, isPrivate))
	}

	logger.Println("getting latest release...")
	release, err := repo.GetLatestRelease()
	exitIfError(err)
	logger.Println("found version: " + release.Version.String())

	logger.Println("getting commits...")
	commits, err := repo.GetCommits()
	exitIfError(err)

	logger.Println("calculating new version...")
	newVer := semrel.GetNewVersion(commits, release)
	if newVer == nil {
		exitIfError(errors.New("no change"))
	}
	logger.Println("new version: " + newVer.String())

	if *dry {
		exitIfError(errors.New("DRY RUN: no release was created"))
	}

	logger.Println("creating release...")
	exitIfError(repo.CreateRelease(commits, release, newVer))

	if *ghr {
		exitIfError(ioutil.WriteFile(".ghr", []byte(fmt.Sprintf("-u %s -r %s v%s", repo.Owner, repo.Repo, newVer.String())), 0644))
	}

	if *vFile {
		exitIfError(ioutil.WriteFile(".version", []byte(newVer.String()), 0644))
	}

	logger.Println("done.")
}
<|endoftext|>


<commit_before>package revel

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"reflect"
)

type Hotel struct {
	HotelId          int
	Name, Address    string
	City, State, Zip string
	Country          string
	Price            int
}

type Hotels struct {
	*Controller
}

type Static struct {
	*Controller
}

func (c Hotels) Show(id int) Result {
	title := "View Hotel"
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.Render(title, hotel)
}

func (c Hotels) Book(id int) Result {
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.RenderJson(hotel)
}

func (c Hotels) Index() Result {
	return c.RenderText("Hello, World!")
}

func (c Static) Serve(prefix, filepath string) Result {
	var basePath, dirName string

	if !filepath.IsAbs(dirName) {
		basePath = BasePath
	}

	fname := filepath.Join(basePath, prefix, filepath)
	file, err := os.Open(fname)
	if os.IsNotExist(err) {
		return c.NotFound("")
	} else if err != nil {
		WARN.Printf("Problem opening file (%s): %s ", fname, err)
		return c.NotFound("This was found but not sure why we couldn't open it.")
	}
	return c.RenderFile(file, "")
}

func startFakeBookingApp() {
	Init("prod", "github.com/revel/revel/testdata", "")

	// Disable logging.
	TRACE = log.New(ioutil.Discard, "", 0)
	INFO = TRACE
	WARN = TRACE
	ERROR = TRACE

	MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, filepath.Join(RevelPath, "templates")})
	MainTemplateLoader.Refresh()

	RegisterController((*Hotels)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Index",
			},
			&MethodType{
				Name: "Show",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
				RenderArgNames: map[int][]string{30: []string{"title", "hotel"}},
			},
			&MethodType{
				Name: "Book",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
			},
		})

	RegisterController((*Static)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Serve",
				Args: []*MethodArg{
					&MethodArg{Name: "prefix", Type: reflect.TypeOf((*string)(nil))},
					&MethodArg{Name: "filepath", Type: reflect.TypeOf((*string)(nil))},
				},
				RenderArgNames: map[int][]string{},
			},
		})

	runStartupHooks()
}
<commit_msg>test case update<commit_after>package revel

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"reflect"
)

type Hotel struct {
	HotelId          int
	Name, Address    string
	City, State, Zip string
	Country          string
	Price            int
}

type Hotels struct {
	*Controller
}

type Static struct {
	*Controller
}

func (c Hotels) Show(id int) Result {
	title := "View Hotel"
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.Render(title, hotel)
}

func (c Hotels) Book(id int) Result {
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.RenderJson(hotel)
}

func (c Hotels) Index() Result {
	return c.RenderText("Hello, World!")
}

func (c Static) Serve(prefix, path string) Result {
	var basePath, dirName string

	if !filepath.IsAbs(dirName) {
		basePath = BasePath
	}

	fname := filepath.Join(basePath, prefix, path)
	file, err := os.Open(fname)
	if os.IsNotExist(err) {
		return c.NotFound("")
	} else if err != nil {
		WARN.Printf("Problem opening file (%s): %s ", fname, err)
		return c.NotFound("This was found but not sure why we couldn't open it.")
	}
	return c.RenderFile(file, "")
}

func startFakeBookingApp() {
	Init("prod", "github.com/revel/revel/testdata", "")

	// Disable logging.
	TRACE = log.New(ioutil.Discard, "", 0)
	INFO = TRACE
	WARN = TRACE
	ERROR = TRACE

	MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, filepath.Join(RevelPath, "templates")})
	MainTemplateLoader.Refresh()

	RegisterController((*Hotels)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Index",
			},
			&MethodType{
				Name: "Show",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
				RenderArgNames: map[int][]string{30: []string{"title", "hotel"}},
			},
			&MethodType{
				Name: "Book",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
			},
		})

	RegisterController((*Static)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Serve",
				Args: []*MethodArg{
					&MethodArg{Name: "prefix", Type: reflect.TypeOf((*string)(nil))},
					&MethodArg{Name: "filepath", Type: reflect.TypeOf((*string)(nil))},
				},
				RenderArgNames: map[int][]string{},
			},
		})

	runStartupHooks()
}
<|endoftext|>


<commit_before>package runtime

// Version is the current version of the buffalo binary
// const Version = "v0.11.1"
const Version = "development"
<commit_msg>version bump<commit_after>package runtime

// Version is the current version of the buffalo binary
const Version = "v0.12.0"

// const Version = "development"
<|endoftext|>


<commit_before>package runtime

import (
	"fmt"
	"github.com/dotcloud/docker/archive"
	"github.com/dotcloud/docker/runtime/execdriver"
	"github.com/dotcloud/docker/utils"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

type BindMap struct {
	SrcPath string
	DstPath string
	Mode    string
}

func prepareVolumesForContainer(container *Container) error {
	if container.Volumes == nil || len(container.Volumes) == 0 {
		container.Volumes = make(map[string]string)
		container.VolumesRW = make(map[string]bool)
		if err := applyVolumesFrom(container); err != nil {
			return err
		}
	}

	if err := createVolumes(container); err != nil {
		return err
	}
	return nil
}

func setupMountsForContainer(container *Container, envPath string) error {
	mounts := []execdriver.Mount{
		{container.runtime.sysInitPath, "/.dockerinit", false, true},
		{envPath, "/.dockerenv", false, true},
		{container.ResolvConfPath, "/etc/resolv.conf", false, true},
	}

	if container.HostnamePath != "" && container.HostsPath != "" {
		mounts = append(mounts, execdriver.Mount{container.HostnamePath, "/etc/hostname", false, true})
		mounts = append(mounts, execdriver.Mount{container.HostsPath, "/etc/hosts", false, true})
	}

	// Mount user specified volumes
	// Note, these are not private because you may want propagation of (un)mounts from host
	// volumes. For instance if you use -v /usr:/usr and the host later mounts /usr/share you
	// want this new mount in the container
	for r, v := range container.Volumes {
		mounts = append(mounts, execdriver.Mount{v, r, container.VolumesRW[r], false})
	}

	container.command.Mounts = mounts

	return nil
}

func applyVolumesFrom(container *Container) error {
	if container.Config.VolumesFrom != "" {
		for _, containerSpec := range strings.Split(container.Config.VolumesFrom, ",") {
			var (
				mountRW   = true
				specParts = strings.SplitN(containerSpec, ":", 2)
			)

			switch len(specParts) {
			case 0:
				return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
			case 2:
				switch specParts[1] {
				case "ro":
					mountRW = false
				case "rw": // mountRW is already true
				default:
					return fmt.Errorf("Malformed volumes-from specification: %s", containerSpec)
				}
			}

			c := container.runtime.Get(specParts[0])
			if c == nil {
				return fmt.Errorf("Container %s not found. Impossible to mount its volumes", specParts[0])
			}

			if err := c.Mount(); err != nil {
				return fmt.Errorf("Container %s failed to mount. Impossible to mount its volumes", specParts[0])
			}
			defer c.Unmount()

			for volPath, id := range c.Volumes {
				if _, exists := container.Volumes[volPath]; exists {
					continue
				}
				stat, err := os.Stat(filepath.Join(c.basefs, volPath))
				if err != nil {
					return err
				}
				if err := createIfNotExists(filepath.Join(container.basefs, volPath), stat.IsDir()); err != nil {
					return err
				}
				container.Volumes[volPath] = id
				if isRW, exists := c.VolumesRW[volPath]; exists {
					container.VolumesRW[volPath] = isRW && mountRW
				}
			}

		}
	}
	return nil
}

func getBindMap(container *Container) (map[string]BindMap, error) {
	var (
		// Create the requested bind mounts
		binds = make(map[string]BindMap)
		// Define illegal container destinations
		illegalDsts = []string{"/", "."}
	)

	for _, bind := range container.hostConfig.Binds {
		// FIXME: factorize bind parsing in parseBind
		var (
			src, dst, mode string
			arr            = strings.Split(bind, ":")
		)

		if len(arr) == 2 {
			src = arr[0]
			dst = arr[1]
			mode = "rw"
		} else if len(arr) == 3 {
			src = arr[0]
			dst = arr[1]
			mode = arr[2]
		} else {
			return nil, fmt.Errorf("Invalid bind specification: %s", bind)
		}

		// Bail if trying to mount to an illegal destination
		for _, illegal := range illegalDsts {
			if dst == illegal {
				return nil, fmt.Errorf("Illegal bind destination: %s", dst)
			}
		}

		bindMap := BindMap{
			SrcPath: src,
			DstPath: dst,
			Mode:    mode,
		}
		binds[filepath.Clean(dst)] = bindMap
	}
	return binds, nil
}

func createVolumes(container *Container) error {
	binds, err := getBindMap(container)
	if err != nil {
		return err
	}

	volumesDriver := container.runtime.volumes.Driver()
	// Create the requested volumes if they don't exist
	for volPath := range container.Config.Volumes {
		volPath = filepath.Clean(volPath)
		volIsDir := true
		// Skip existing volumes
		if _, exists := container.Volumes[volPath]; exists {
			continue
		}
		var srcPath string
		var isBindMount bool
		srcRW := false
		// If an external bind is defined for this volume, use that as a source
		if bindMap, exists := binds[volPath]; exists {
			isBindMount = true
			srcPath = bindMap.SrcPath
			srcAbs, err := filepath.Abs(srcPath)
			if err != nil {
				return err
			}
			if srcPath != srcAbs {
				return fmt.Errorf("%s should be an absolute path", srcPath)
			}
			if strings.ToLower(bindMap.Mode) == "rw" {
				srcRW = true
			}
			if stat, err := os.Stat(bindMap.SrcPath); err != nil {
				return err
			} else {
				volIsDir = stat.IsDir()
			}
			// Otherwise create an directory in $ROOT/volumes/ and use that
		} else {

			// Do not pass a container as the parameter for the volume creation.
			// The graph driver using the container's information ( Image ) to
			// create the parent.
			c, err := container.runtime.volumes.Create(nil, "", "", "", "", nil, nil)
			if err != nil {
				return err
			}
			srcPath, err = volumesDriver.Get(c.ID)
			if err != nil {
				return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
			}
			srcRW = true // RW by default
		}

		if p, err := filepath.EvalSymlinks(srcPath); err != nil {
			return err
		} else {
			srcPath = p
		}

		container.Volumes[volPath] = srcPath
		container.VolumesRW[volPath] = srcRW

		// Create the mountpoint
		volPath = filepath.Join(container.basefs, volPath)
		rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.basefs)
		if err != nil {
			return err
		}
		if err := createIfNotExists(rootVolPath, volIsDir); err != nil {
			return err
		}

		// Do not copy or change permissions if we are mounting from the host
		if srcRW && !isBindMount {
			volList, err := ioutil.ReadDir(rootVolPath)
			if err != nil {
				return err
			}
			if len(volList) > 0 {
				srcList, err := ioutil.ReadDir(srcPath)
				if err != nil {
					return err
				}
				if len(srcList) == 0 {
					// If the source volume is empty copy files from the root into the volume
					if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
						return err
					}

					var stat syscall.Stat_t
					if err := syscall.Stat(rootVolPath, &stat); err != nil {
						return err
					}
					var srcStat syscall.Stat_t
					if err := syscall.Stat(srcPath, &srcStat); err != nil {
						return err
					}
					// Change the source volume's ownership if it differs from the root
					// files that were just copied
					if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
						if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
							return err
						}
					}
				}
			}
		}
	}
	return nil
}

func createIfNotExists(path string, isDir bool) error {
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			if isDir {
				if err := os.MkdirAll(path, 0755); err != nil {
					return err
				}
			} else {
				if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
					return err
				}
				f, err := os.OpenFile(path, os.O_CREATE, 0755)
				if err != nil {
					return err
				}
				defer f.Close()
			}
		}
	}
	return nil
}
<commit_msg>Fix edge case in bind mount absolute path detection<commit_after>package runtime

import (
	"fmt"
	"github.com/dotcloud/docker/archive"
	"github.com/dotcloud/docker/runtime/execdriver"
	"github.com/dotcloud/docker/utils"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

type BindMap struct {
	SrcPath string
	DstPath string
	Mode    string
}

func prepareVolumesForContainer(container *Container) error {
	if container.Volumes == nil || len(container.Volumes) == 0 {
		container.Volumes = make(map[string]string)
		container.VolumesRW = make(map[string]bool)
		if err := applyVolumesFrom(container); err != nil {
			return err
		}
	}

	if err := createVolumes(container); err != nil {
		return err
	}
	return nil
}

func setupMountsForContainer(container *Container, envPath string) error {
	mounts := []execdriver.Mount{
		{container.runtime.sysInitPath, "/.dockerinit", false, true},
		{envPath, "/.dockerenv", false, true},
		{container.ResolvConfPath, "/etc/resolv.conf", false, true},
	}

	if container.HostnamePath != "" && container.HostsPath != "" {
		mounts = append(mounts, execdriver.Mount{container.HostnamePath, "/etc/hostname", false, true})
		mounts = append(mounts, execdriver.Mount{container.HostsPath, "/etc/hosts", false, true})
	}

	// Mount user specified volumes
	// Note, these are not private because you may want propagation of (un)mounts from host
	// volumes. For instance if you use -v /usr:/usr and the host later mounts /usr/share you
	// want this new mount in the container
	for r, v := range container.Volumes {
		mounts = append(mounts, execdriver.Mount{v, r, container.VolumesRW[r], false})
	}

	container.command.Mounts = mounts

	return nil
}

func applyVolumesFrom(container *Container) error {
	if container.Config.VolumesFrom != "" {
		for _, containerSpec := range strings.Split(container.Config.VolumesFrom, ",") {
			var (
				mountRW   = true
				specParts = strings.SplitN(containerSpec, ":", 2)
			)

			switch len(specParts) {
			case 0:
				return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
			case 2:
				switch specParts[1] {
				case "ro":
					mountRW = false
				case "rw": // mountRW is already true
				default:
					return fmt.Errorf("Malformed volumes-from specification: %s", containerSpec)
				}
			}

			c := container.runtime.Get(specParts[0])
			if c == nil {
				return fmt.Errorf("Container %s not found. Impossible to mount its volumes", specParts[0])
			}

			if err := c.Mount(); err != nil {
				return fmt.Errorf("Container %s failed to mount. Impossible to mount its volumes", specParts[0])
			}
			defer c.Unmount()

			for volPath, id := range c.Volumes {
				if _, exists := container.Volumes[volPath]; exists {
					continue
				}
				stat, err := os.Stat(filepath.Join(c.basefs, volPath))
				if err != nil {
					return err
				}
				if err := createIfNotExists(filepath.Join(container.basefs, volPath), stat.IsDir()); err != nil {
					return err
				}
				container.Volumes[volPath] = id
				if isRW, exists := c.VolumesRW[volPath]; exists {
					container.VolumesRW[volPath] = isRW && mountRW
				}
			}

		}
	}
	return nil
}

func getBindMap(container *Container) (map[string]BindMap, error) {
	var (
		// Create the requested bind mounts
		binds = make(map[string]BindMap)
		// Define illegal container destinations
		illegalDsts = []string{"/", "."}
	)

	for _, bind := range container.hostConfig.Binds {
		// FIXME: factorize bind parsing in parseBind
		var (
			src, dst, mode string
			arr            = strings.Split(bind, ":")
		)

		if len(arr) == 2 {
			src = arr[0]
			dst = arr[1]
			mode = "rw"
		} else if len(arr) == 3 {
			src = arr[0]
			dst = arr[1]
			mode = arr[2]
		} else {
			return nil, fmt.Errorf("Invalid bind specification: %s", bind)
		}

		// Bail if trying to mount to an illegal destination
		for _, illegal := range illegalDsts {
			if dst == illegal {
				return nil, fmt.Errorf("Illegal bind destination: %s", dst)
			}
		}

		bindMap := BindMap{
			SrcPath: src,
			DstPath: dst,
			Mode:    mode,
		}
		binds[filepath.Clean(dst)] = bindMap
	}
	return binds, nil
}

func createVolumes(container *Container) error {
	binds, err := getBindMap(container)
	if err != nil {
		return err
	}

	volumesDriver := container.runtime.volumes.Driver()
	// Create the requested volumes if they don't exist
	for volPath := range container.Config.Volumes {
		volPath = filepath.Clean(volPath)
		volIsDir := true
		// Skip existing volumes
		if _, exists := container.Volumes[volPath]; exists {
			continue
		}
		var srcPath string
		var isBindMount bool
		srcRW := false
		// If an external bind is defined for this volume, use that as a source
		if bindMap, exists := binds[volPath]; exists {
			isBindMount = true
			srcPath = bindMap.SrcPath
			if !filepath.IsAbs(srcPath) {
				return fmt.Errorf("%s must be an absolute path", srcPath)
			}
			if strings.ToLower(bindMap.Mode) == "rw" {
				srcRW = true
			}
			if stat, err := os.Stat(bindMap.SrcPath); err != nil {
				return err
			} else {
				volIsDir = stat.IsDir()
			}
			// Otherwise create an directory in $ROOT/volumes/ and use that
		} else {

			// Do not pass a container as the parameter for the volume creation.
			// The graph driver using the container's information ( Image ) to
			// create the parent.
			c, err := container.runtime.volumes.Create(nil, "", "", "", "", nil, nil)
			if err != nil {
				return err
			}
			srcPath, err = volumesDriver.Get(c.ID)
			if err != nil {
				return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
			}
			srcRW = true // RW by default
		}

		if p, err := filepath.EvalSymlinks(srcPath); err != nil {
			return err
		} else {
			srcPath = p
		}

		container.Volumes[volPath] = srcPath
		container.VolumesRW[volPath] = srcRW

		// Create the mountpoint
		volPath = filepath.Join(container.basefs, volPath)
		rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.basefs)
		if err != nil {
			return err
		}
		if err := createIfNotExists(rootVolPath, volIsDir); err != nil {
			return err
		}

		// Do not copy or change permissions if we are mounting from the host
		if srcRW && !isBindMount {
			volList, err := ioutil.ReadDir(rootVolPath)
			if err != nil {
				return err
			}
			if len(volList) > 0 {
				srcList, err := ioutil.ReadDir(srcPath)
				if err != nil {
					return err
				}
				if len(srcList) == 0 {
					// If the source volume is empty copy files from the root into the volume
					if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
						return err
					}

					var stat syscall.Stat_t
					if err := syscall.Stat(rootVolPath, &stat); err != nil {
						return err
					}
					var srcStat syscall.Stat_t
					if err := syscall.Stat(srcPath, &srcStat); err != nil {
						return err
					}
					// Change the source volume's ownership if it differs from the root
					// files that were just copied
					if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
						if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
							return err
						}
					}
				}
			}
		}
	}
	return nil
}

func createIfNotExists(path string, isDir bool) error {
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			if isDir {
				if err := os.MkdirAll(path, 0755); err != nil {
					return err
				}
			} else {
				if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
					return err
				}
				f, err := os.OpenFile(path, os.O_CREATE, 0755)
				if err != nil {
					return err
				}
				defer f.Close()
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 grumpy

import (
	"fmt"
	"os"
	"reflect"
	"runtime"
	"sync"
	"sync/atomic"
	"unsafe"
)

var (
	// WeakRefType is the object representing the Python 'weakref' type.
	WeakRefType = newBasisType("weakref", reflect.TypeOf(WeakRef{}), toWeakRefUnsafe, ObjectType)
)

type weakRefState int

const (
	weakRefStateNew weakRefState = iota
	weakRefStateUsed
	weakRefStateDead
)

// WeakRef represents Python 'weakref' objects.
type WeakRef struct {
	Object
	ptr       uintptr
	mutex     sync.Mutex
	state     weakRefState
	callbacks []*Object
	hash      *Object
}

func toWeakRefUnsafe(o *Object) *WeakRef {
	return (*WeakRef)(o.toPointer())
}

// get returns r's referent, or nil if r is "dead".
func (r *WeakRef) get() *Object {
	if r.state == weakRefStateDead {
		return nil
	}
	r.state = weakRefStateUsed
	return (*Object)(unsafe.Pointer(r.ptr))
}

// ToObject upcasts r to an Object.
func (r *WeakRef) ToObject() *Object {
	return &r.Object
}

func weakRefCall(f *Frame, callable *Object, args Args, _ KWArgs) (*Object, *BaseException) {
	if raised := checkFunctionArgs(f, "__call__", args); raised != nil {
		return nil, raised
	}
	r := toWeakRefUnsafe(callable)
	r.mutex.Lock()
	o := r.get()
	r.mutex.Unlock()
	if o == nil {
		o = None
	}
	return o, nil
}

func weakRefHash(f *Frame, o *Object) (result *Object, raised *BaseException) {
	r := toWeakRefUnsafe(o)
	var referent *Object
	r.mutex.Lock()
	if r.hash != nil {
		result = r.hash
	} else {
		referent = r.get()
	}
	r.mutex.Unlock()
	if referent != nil {
		var hash *Int
		hash, raised = Hash(f, referent)
		if raised == nil {
			result = hash.ToObject()
			r.mutex.Lock()
			r.hash = result
			r.mutex.Unlock()
		}
	} else if result == nil {
		raised = f.RaiseType(TypeErrorType, "weak object has gone away")
	}
	return result, raised
}

func weakRefNew(f *Frame, t *Type, args Args, _ KWArgs) (*Object, *BaseException) {
	if raised := checkFunctionVarArgs(f, "__new__", args, ObjectType); raised != nil {
		return nil, raised
	}
	argc := len(args)
	if argc > 2 {
		format := "__new__ expected at most 2 arguments, got %d"
		return nil, f.RaiseType(TypeErrorType, fmt.Sprintf(format, argc))
	}
	o := args[0]
	nilPtr := unsafe.Pointer(nil)
	addr := (*unsafe.Pointer)(unsafe.Pointer(&o.ref))
	var r *WeakRef
	// Atomically fetch or initialize o.ref.
	for {
		p := atomic.LoadPointer(addr)
		if p != nilPtr {
			r = (*WeakRef)(p)
			break
		} else {
			r = &WeakRef{Object: Object{typ: WeakRefType}, ptr: uintptr(o.toPointer())}
			if atomic.CompareAndSwapPointer(addr, nilPtr, r.toPointer()) {
				runtime.SetFinalizer(o, weakRefFinalizeReferent)
				break
			}
		}
	}
	if argc > 1 {
		r.mutex.Lock()
		r.callbacks = append(r.callbacks, args[1])
		r.mutex.Unlock()
	}
	return r.ToObject(), nil
}

func weakRefRepr(f *Frame, o *Object) (*Object, *BaseException) {
	r := toWeakRefUnsafe(o)
	r.mutex.Lock()
	p := r.get()
	r.mutex.Unlock()
	s := "dead"
	if p != nil {
		s = fmt.Sprintf("to '%s' at %p", p.Type().Name(), p)
	}
	return NewStr(fmt.Sprintf("<weakref at %p; %s>", r, s)).ToObject(), nil
}

func initWeakRefType(map[string]*Object) {
	WeakRefType.flags &= ^typeFlagBasetype
	WeakRefType.slots.Call = &callSlot{weakRefCall}
	WeakRefType.slots.Hash = &unaryOpSlot{weakRefHash}
	WeakRefType.slots.New = &newSlot{weakRefNew}
	WeakRefType.slots.Repr = &unaryOpSlot{weakRefRepr}
}

func weakRefFinalizeReferent(o *Object) {
	// Note that although o should be the last reference to that object
	// (since this is its finalizer), in the time between the runtime
	// scheduling this finalizer and the Lock() call below, r may have
	// handed out another reference to o. So we can't simply mark r "dead".
	addr := (*unsafe.Pointer)(unsafe.Pointer(&o.ref))
	r := (*WeakRef)(atomic.LoadPointer(addr))
	numCallbacks := 0
	var callbacks []*Object
	r.mutex.Lock()
	switch r.state {
	case weakRefStateNew:
		// State "new" means that no references have been handed out by
		// r and therefore o is the only live reference.
		r.state = weakRefStateDead
		numCallbacks = len(r.callbacks)
		callbacks = make([]*Object, numCallbacks)
		copy(callbacks, r.callbacks)
	case weakRefStateUsed:
		// Most likely it's safe to mark r "dead" at this point, but
		// because a reference was handed out at some point, play it
		// safe and reset the finalizer. If no more references are
		// handed out before the next finalize then it will be "dead".
		r.state = weakRefStateNew
		runtime.SetFinalizer(o, weakRefFinalizeReferent)
	}
	r.mutex.Unlock()
	// Don't hold r.mutex while invoking callbacks in case they access r
	// and attempt to acquire the mutex.
	for i := numCallbacks - 1; i >= 0; i-- {
		f := newFrame(nil)
		if _, raised := callbacks[i].Call(f, Args{r.ToObject()}, nil); raised != nil {
			s, raised := FormatException(f, raised)
			if raised != nil {
				s = raised.String()
			}
			fmt.Fprint(os.Stderr, s)
		}
	}
}
<commit_msg>Weak ref type can be a base class.<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 grumpy

import (
	"fmt"
	"os"
	"reflect"
	"runtime"
	"sync"
	"sync/atomic"
	"unsafe"
)

var (
	// WeakRefType is the object representing the Python 'weakref' type.
	WeakRefType = newBasisType("weakref", reflect.TypeOf(WeakRef{}), toWeakRefUnsafe, ObjectType)
)

type weakRefState int

const (
	weakRefStateNew weakRefState = iota
	weakRefStateUsed
	weakRefStateDead
)

// WeakRef represents Python 'weakref' objects.
type WeakRef struct {
	Object
	ptr       uintptr
	mutex     sync.Mutex
	state     weakRefState
	callbacks []*Object
	hash      *Object
}

func toWeakRefUnsafe(o *Object) *WeakRef {
	return (*WeakRef)(o.toPointer())
}

// get returns r's referent, or nil if r is "dead".
func (r *WeakRef) get() *Object {
	if r.state == weakRefStateDead {
		return nil
	}
	r.state = weakRefStateUsed
	return (*Object)(unsafe.Pointer(r.ptr))
}

// ToObject upcasts r to an Object.
func (r *WeakRef) ToObject() *Object {
	return &r.Object
}

func weakRefCall(f *Frame, callable *Object, args Args, _ KWArgs) (*Object, *BaseException) {
	if raised := checkFunctionArgs(f, "__call__", args); raised != nil {
		return nil, raised
	}
	r := toWeakRefUnsafe(callable)
	r.mutex.Lock()
	o := r.get()
	r.mutex.Unlock()
	if o == nil {
		o = None
	}
	return o, nil
}

func weakRefHash(f *Frame, o *Object) (result *Object, raised *BaseException) {
	r := toWeakRefUnsafe(o)
	var referent *Object
	r.mutex.Lock()
	if r.hash != nil {
		result = r.hash
	} else {
		referent = r.get()
	}
	r.mutex.Unlock()
	if referent != nil {
		var hash *Int
		hash, raised = Hash(f, referent)
		if raised == nil {
			result = hash.ToObject()
			r.mutex.Lock()
			r.hash = result
			r.mutex.Unlock()
		}
	} else if result == nil {
		raised = f.RaiseType(TypeErrorType, "weak object has gone away")
	}
	return result, raised
}

func weakRefNew(f *Frame, t *Type, args Args, _ KWArgs) (*Object, *BaseException) {
	if raised := checkFunctionVarArgs(f, "__new__", args, ObjectType); raised != nil {
		return nil, raised
	}
	argc := len(args)
	if argc > 2 {
		format := "__new__ expected at most 2 arguments, got %d"
		return nil, f.RaiseType(TypeErrorType, fmt.Sprintf(format, argc))
	}
	o := args[0]
	nilPtr := unsafe.Pointer(nil)
	addr := (*unsafe.Pointer)(unsafe.Pointer(&o.ref))
	var r *WeakRef
	// Atomically fetch or initialize o.ref.
	for {
		p := atomic.LoadPointer(addr)
		if p != nilPtr {
			r = (*WeakRef)(p)
			break
		} else {
			r = &WeakRef{Object: Object{typ: WeakRefType}, ptr: uintptr(o.toPointer())}
			if atomic.CompareAndSwapPointer(addr, nilPtr, r.toPointer()) {
				runtime.SetFinalizer(o, weakRefFinalizeReferent)
				break
			}
		}
	}
	if argc > 1 {
		r.mutex.Lock()
		r.callbacks = append(r.callbacks, args[1])
		r.mutex.Unlock()
	}
	return r.ToObject(), nil
}

func weakRefRepr(f *Frame, o *Object) (*Object, *BaseException) {
	r := toWeakRefUnsafe(o)
	r.mutex.Lock()
	p := r.get()
	r.mutex.Unlock()
	s := "dead"
	if p != nil {
		s = fmt.Sprintf("to '%s' at %p", p.Type().Name(), p)
	}
	return NewStr(fmt.Sprintf("<weakref at %p; %s>", r, s)).ToObject(), nil
}

func initWeakRefType(map[string]*Object) {
	WeakRefType.slots.Call = &callSlot{weakRefCall}
	WeakRefType.slots.Hash = &unaryOpSlot{weakRefHash}
	WeakRefType.slots.New = &newSlot{weakRefNew}
	WeakRefType.slots.Repr = &unaryOpSlot{weakRefRepr}
}

func weakRefFinalizeReferent(o *Object) {
	// Note that although o should be the last reference to that object
	// (since this is its finalizer), in the time between the runtime
	// scheduling this finalizer and the Lock() call below, r may have
	// handed out another reference to o. So we can't simply mark r "dead".
	addr := (*unsafe.Pointer)(unsafe.Pointer(&o.ref))
	r := (*WeakRef)(atomic.LoadPointer(addr))
	numCallbacks := 0
	var callbacks []*Object
	r.mutex.Lock()
	switch r.state {
	case weakRefStateNew:
		// State "new" means that no references have been handed out by
		// r and therefore o is the only live reference.
		r.state = weakRefStateDead
		numCallbacks = len(r.callbacks)
		callbacks = make([]*Object, numCallbacks)
		copy(callbacks, r.callbacks)
	case weakRefStateUsed:
		// Most likely it's safe to mark r "dead" at this point, but
		// because a reference was handed out at some point, play it
		// safe and reset the finalizer. If no more references are
		// handed out before the next finalize then it will be "dead".
		r.state = weakRefStateNew
		runtime.SetFinalizer(o, weakRefFinalizeReferent)
	}
	r.mutex.Unlock()
	// Don't hold r.mutex while invoking callbacks in case they access r
	// and attempt to acquire the mutex.
	for i := numCallbacks - 1; i >= 0; i-- {
		f := newFrame(nil)
		if _, raised := callbacks[i].Call(f, Args{r.ToObject()}, nil); raised != nil {
			s, raised := FormatException(f, raised)
			if raised != nil {
				s = raised.String()
			}
			fmt.Fprint(os.Stderr, s)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 Jeremy Wall (jeremy@marzhillstudios.com)
// Use of this source code is governed by the Artistic License 2.0.
// That License is included in the LICENSE file.
/*

The html transform package implements a html css selector and transformer.

An html doc can be inspected and queried using css selectors as well as
transformed.

 	doc := NewDoc(str)
 	sel1 := NewSelector("li.menuitem")
 	sel2 := NewSelector("a")
	t := NewTransform(doc)
 	t.Apply(CopyAnd(myModifiers...), sel1)
  t..Apply(Replace(Text("my new text"), sel2)
  newDoc := t.Doc()
*/
package transform

// TODO(jwall): Documentation...
import (
	. "go-html-transform.googlecode.com/hg/h5"
	"log"
)

// The TransformFunc type is the type of a Node transformation function.
type TransformFunc func(*Node)

// Transformer encapsulates a document under transformation.
type Transformer struct {
	doc *Node
}

// Constructor for a Transformer. It makes a copy of the document
// and transforms that instead of the original.
func NewTransform(d *Node) *Transformer {
	return &Transformer{doc: d.Clone()}
}

// The Doc method returns the document under transformation.
func (t *Transformer) Doc() *Node {
	return t.doc
}

func (t *Transformer) String() string {
	return t.doc.String()
}

// The Apply method applies a TransformFunc to the nodes returned from
// the Selector query
func (t *Transformer) Apply(f TransformFunc, sel ...string) *Transformer {
	// TODO come up with a way to walk tree once?
	sq := NewSelectorQuery(sel...)
	nodes := sq.Apply(t.doc)
	for _, n := range nodes {
		f(n)
	}
	return t
}

// Compose a set of TransformFuncs into a single TransformFunc
func Compose(fs ...TransformFunc) TransformFunc {
	return func(n *Node) {
		for _, f := range fs {
			f(n)
		}
	}
}

// AppendChildren creates a TransformFunc that appends the Children passed in.
func AppendChildren(cs ...*Node) TransformFunc {
	return func(n *Node) {
		sz := len(n.Children)
		newChild := make([]*Node, sz+len(cs))
		copy(newChild, n.Children)
		copy(newChild[sz:], cs)
		n.Children = newChild
	}
}

// PrependChildren creates a TransformFunc that prepends the Children passed in.
func PrependChildren(cs ...*Node) TransformFunc {
	return func(n *Node) {
		sz := len(n.Children)
		sz2 := len(cs)
		newChild := make([]*Node, sz+len(cs))
		copy(newChild[sz2:], n.Children)
		copy(newChild[0:sz2], cs)
		n.Children = newChild
	}
}

// RemoveChildren creates a TransformFunc that removes the Children of the node
// it operates on.
func RemoveChildren() TransformFunc {
	return func(n *Node) {
		n.Children = make([]*Node, 0)
	}
}

// ReplaceChildren creates a TransformFunc that replaces the Children of the
// node it operates on with the Children passed in.
func ReplaceChildren(ns ...*Node) TransformFunc {
	return func(n *Node) {
		n.Children = ns
	}
}

func Replace(ns ...*Node) TransformFunc {
	return func(n *Node) {
		p := n.Parent
		// TODO(jwall): splice the new nodes into the spot the current node is
		for i, c := range p.Children {
			if c == n {
				n := i - 1
				if n < 0 {
					n = 0
				}
				var newChild []*Node
				pre := p.Children[:n]
				post := p.Children[i+1:]
				newChild = append(pre, ns...)
				p.Children = append(newChild, post...)
			}
		}
	}
}

// ModifyAttrb creates a TransformFunc that modifies the attributes
// of the node it operates on.
func ModifyAttrib(key string, val string) TransformFunc {
	return func(n *Node) {
		found := false
		for i, attr := range n.Attr {
			if attr.Name == key {
				n.Attr[i].Value = val
				found = true
			}
		}
		if !found {
			newAttr := make([]*Attribute, len(n.Attr)+1)
			newAttr[len(n.Attr)] = &Attribute{Name: key, Value: val}
			n.Attr = newAttr
		}
	}
}

func TransformAttrib(key string, f func(string) string) TransformFunc {
	return func(n *Node) {
		for i, attr := range n.Attr {
			if attr.Name == key {
				n.Attr[i].Value = f(n.Attr[i].Value)
			}
		}
	}
}

func DoAll(fs ...TransformFunc) TransformFunc {
	return func(n *Node) {
		for _, f := range fs {
			f(n)
		}
	}
}

// ForEach takes a function and a list of Nodes and performs that
// function for each node in the list.
// The function should be of a type either func(...*Node) TransformFunc
// or func(*Node) TransformFunc. Any other type will panic.
// Returns a TransformFunc.
func ForEach(f interface{}, ns ...*Node) TransformFunc {
	switch t := f.(type) {
	case func(...*Node) TransformFunc:
		return func(n *Node) {
			for _, n2 := range ns {
				f1 := f.(func(...*Node) TransformFunc)
				f2 := f1(n2)
				f2(n)
			}
		}
	case func(*Node) TransformFunc:
		return func(n *Node) {
			for _, n2 := range ns {
				f1 := f.(func(*Node) TransformFunc)
				f2 := f1(n2)
				f2(n)
			}
		}
	default:
		log.Panicf("Wrong function type passed to ForEach %s", t)
	}
	return nil
}

// CopyAnd will construct a TransformFunc that will
// make a copy of the node for each passed in TransformFunc
// And replace the passed in node with the resulting transformed
// Nodes.
// Returns a TransformFunc
func CopyAnd(fns ...TransformFunc) TransformFunc {
	return func(n *Node) {
		newNodes := make([]*Node, len(fns))
		for i, fn := range fns {
			node := n.Clone()
			fn(node)
			newNodes[i] = node
		}
		replaceFn := Replace(newNodes...)
		replaceFn(n)
	}
}
<commit_msg>Move the copyright statement to the bottom.<commit_after>/*

The html transform package implements a html css selector and transformer.

An html doc can be inspected and queried using css selectors as well as
transformed.

 	doc := NewDoc(str)
 	sel1 := NewSelector("li.menuitem")
 	sel2 := NewSelector("a")
	t := NewTransform(doc)
 	t.Apply(CopyAnd(myModifiers...), sel1)
  t..Apply(Replace(Text("my new text"), sel2)
  newDoc := t.Doc()
*/
package transform

// TODO(jwall): Documentation...
import (
	. "go-html-transform.googlecode.com/hg/h5"
	"log"
)

// The TransformFunc type is the type of a Node transformation function.
type TransformFunc func(*Node)

// Transformer encapsulates a document under transformation.
type Transformer struct {
	doc *Node
}

// Constructor for a Transformer. It makes a copy of the document
// and transforms that instead of the original.
func NewTransform(d *Node) *Transformer {
	return &Transformer{doc: d.Clone()}
}

// The Doc method returns the document under transformation.
func (t *Transformer) Doc() *Node {
	return t.doc
}

func (t *Transformer) String() string {
	return t.doc.String()
}

// The Apply method applies a TransformFunc to the nodes returned from
// the Selector query
func (t *Transformer) Apply(f TransformFunc, sel ...string) *Transformer {
	// TODO come up with a way to walk tree once?
	sq := NewSelectorQuery(sel...)
	nodes := sq.Apply(t.doc)
	for _, n := range nodes {
		f(n)
	}
	return t
}

// Compose a set of TransformFuncs into a single TransformFunc
func Compose(fs ...TransformFunc) TransformFunc {
	return func(n *Node) {
		for _, f := range fs {
			f(n)
		}
	}
}

// AppendChildren creates a TransformFunc that appends the Children passed in.
func AppendChildren(cs ...*Node) TransformFunc {
	return func(n *Node) {
		sz := len(n.Children)
		newChild := make([]*Node, sz+len(cs))
		copy(newChild, n.Children)
		copy(newChild[sz:], cs)
		n.Children = newChild
	}
}

// PrependChildren creates a TransformFunc that prepends the Children passed in.
func PrependChildren(cs ...*Node) TransformFunc {
	return func(n *Node) {
		sz := len(n.Children)
		sz2 := len(cs)
		newChild := make([]*Node, sz+len(cs))
		copy(newChild[sz2:], n.Children)
		copy(newChild[0:sz2], cs)
		n.Children = newChild
	}
}

// RemoveChildren creates a TransformFunc that removes the Children of the node
// it operates on.
func RemoveChildren() TransformFunc {
	return func(n *Node) {
		n.Children = make([]*Node, 0)
	}
}

// ReplaceChildren creates a TransformFunc that replaces the Children of the
// node it operates on with the Children passed in.
func ReplaceChildren(ns ...*Node) TransformFunc {
	return func(n *Node) {
		n.Children = ns
	}
}

func Replace(ns ...*Node) TransformFunc {
	return func(n *Node) {
		p := n.Parent
		// TODO(jwall): splice the new nodes into the spot the current node is
		for i, c := range p.Children {
			if c == n {
				n := i - 1
				if n < 0 {
					n = 0
				}
				var newChild []*Node
				pre := p.Children[:n]
				post := p.Children[i+1:]
				newChild = append(pre, ns...)
				p.Children = append(newChild, post...)
			}
		}
	}
}

// ModifyAttrb creates a TransformFunc that modifies the attributes
// of the node it operates on.
func ModifyAttrib(key string, val string) TransformFunc {
	return func(n *Node) {
		found := false
		for i, attr := range n.Attr {
			if attr.Name == key {
				n.Attr[i].Value = val
				found = true
			}
		}
		if !found {
			newAttr := make([]*Attribute, len(n.Attr)+1)
			newAttr[len(n.Attr)] = &Attribute{Name: key, Value: val}
			n.Attr = newAttr
		}
	}
}

func TransformAttrib(key string, f func(string) string) TransformFunc {
	return func(n *Node) {
		for i, attr := range n.Attr {
			if attr.Name == key {
				n.Attr[i].Value = f(n.Attr[i].Value)
			}
		}
	}
}

func DoAll(fs ...TransformFunc) TransformFunc {
	return func(n *Node) {
		for _, f := range fs {
			f(n)
		}
	}
}

// ForEach takes a function and a list of Nodes and performs that
// function for each node in the list.
// The function should be of a type either func(...*Node) TransformFunc
// or func(*Node) TransformFunc. Any other type will panic.
// Returns a TransformFunc.
func ForEach(f interface{}, ns ...*Node) TransformFunc {
	switch t := f.(type) {
	case func(...*Node) TransformFunc:
		return func(n *Node) {
			for _, n2 := range ns {
				f1 := f.(func(...*Node) TransformFunc)
				f2 := f1(n2)
				f2(n)
			}
		}
	case func(*Node) TransformFunc:
		return func(n *Node) {
			for _, n2 := range ns {
				f1 := f.(func(*Node) TransformFunc)
				f2 := f1(n2)
				f2(n)
			}
		}
	default:
		log.Panicf("Wrong function type passed to ForEach %s", t)
	}
	return nil
}

// CopyAnd will construct a TransformFunc that will
// make a copy of the node for each passed in TransformFunc
// And replace the passed in node with the resulting transformed
// Nodes.
// Returns a TransformFunc
func CopyAnd(fns ...TransformFunc) TransformFunc {
	return func(n *Node) {
		newNodes := make([]*Node, len(fns))
		for i, fn := range fns {
			node := n.Clone()
			fn(node)
			newNodes[i] = node
		}
		replaceFn := Replace(newNodes...)
		replaceFn(n)
	}
}
// Copyright 2010 Jeremy Wall (jeremy@marzhillstudios.com)
// Use of this source code is governed by the Artistic License 2.0.
// That License is included in the LICENSE file.
<|endoftext|>


<commit_before>package nyb

import (
	"encoding/json"
	"fmt"
	"log"
	"sort"
	"sync"
	"time"

	"github.com/hako/durafmt"
	"github.com/ugjka/dumbirc"
)

//Settings for bot
type Settings struct {
	IrcNick    string
	IrcChans   []string
	IrcServer  string
	IrcTrigger string
	IrcUseTLS  bool
	Bot        *dumbirc.Connection
	LogChan    LogChan
	Stopper    chan bool
	Email      string
	Nominatim  string
	extra
}

type extra struct {
	zones           TZS
	last            TZ
	next            TZ
	nominatimResult NominatimResults
	//We close this when we get WELCOME msg on join in irc
	start chan bool
	//This is used to prevent sending ping before we
	//have response from previous ping (any activity on irc)
	//pingpong(pp) sends a signal to ping timer
	pp chan bool
	sync.Once
	sync.WaitGroup
}

//New creates new bot
func New(nick string, chans []string, trigger string, server string,
	tls bool, email string, nominatim string) *Settings {
	return &Settings{
		nick,
		chans,
		server,
		trigger,
		tls,
		dumbirc.New(nick, "nyebot", server, tls),
		newLogChan(),
		make(chan bool),
		email,
		nominatim,
		extra{
			start: make(chan bool),
			pp:    make(chan bool, 1),
		},
	}
}

var stFinished = "That's it, Year %d is here AoE"

//Start starts the bot
func (s *Settings) Start() {
	log.SetOutput(s.LogChan)
	log.Println("Starting the bot...")
	defer s.Wait()
	//
	//Set up irc
	//
	bot := s.Bot
	s.addCallbacks()
	s.addTriggers()

	s.Add(1)
	go s.ircControl()

	bot.Start()

	select {
	case <-s.start:
		log.Println("Got start...")
	case <-s.Stopper:
		return
	}

	s.decodeZones(Zones)
	for {
		s.loopTimeZones()
		select {
		case <-s.Stopper:
			return
		default:
		}
		bot.PrivMsgBulk(s.IrcChans, fmt.Sprintf(stFinished, target.Year()))
		log.Println("All zones finished...")
		target = target.AddDate(1, 0, 0)
		log.Printf("Wrapping the target date around to %d\n", target.Year())
	}
}

func (s *Settings) decodeZones(z []byte) {
	if err := json.Unmarshal(z, &s.zones); err != nil {
		log.Println("Fatal error:", err)
		close(s.Stopper)
		return
	}
	sort.Sort(sort.Reverse(s.zones))
}

//Stop stops the bot
func (s *Settings) Stop() {
	select {
	case <-s.Stopper:
		return
	default:
		close(s.Stopper)
	}
}

var reconnectInterval = time.Second * 30
var pingInterval = time.Minute * 1

func (s *Settings) ircControl() {
	bot := s.Bot
	defer s.Done()
	for {
		timer := time.NewTimer(pingInterval)
		select {
		case err := <-bot.Errchan:
			log.Println("Error:", err)
			log.Printf("Reconnecting to irc in %s...\n", reconnectInterval)
			time.AfterFunc(reconnectInterval, func() {
				select {
				case <-s.Stopper:
					return
				default:
					bot.Start()
				}
			})
		case <-s.Stopper:
			timer.Stop()
			log.Println("Stopping the bot...")
			log.Println("Disconnecting...")
			bot.Disconnect()
			return
		case <-timer.C:
			timer.Stop()
			//pingpong stuff
			select {
			case <-s.pp:
				log.Println("Sending PING...")
				bot.Ping()
			default:
				log.Println("Got no PONG...")
			}
		}

	}
}

var stNextNewYear = "Next New Year in %s in %s"
var stHappyNewYear = "Happy New Year in %s"

func (s *Settings) loopTimeZones() {
	zones := s.zones
	bot := s.Bot
	for i := 0; i < len(zones); i++ {
		dur := time.Minute * time.Duration(zones[i].Offset*60)
		s.next = zones[i]
		if i == 0 {
			s.last = zones[len(zones)-1]
		} else {
			s.last = zones[i-1]
		}
		if timeNow().UTC().Add(dur).Before(target) {
			time.Sleep(time.Second * 2)
			log.Println("Zone pending:", zones[i].Offset)
			humandur := durafmt.Parse(target.Sub(timeNow().UTC().Add(dur)))
			msg := fmt.Sprintf(stNextNewYear, removeMilliseconds(humandur), zones[i])
			bot.PrivMsgBulk(s.IrcChans, msg)
			//Wait till Target in Timezone
			timer := NewTimer(target.Sub(timeNow().UTC().Add(dur)))
			select {
			case <-timer.C:
				timer.Stop()
				msg = fmt.Sprintf(stHappyNewYear, zones[i])
				bot.PrivMsgBulk(s.IrcChans, msg)
				log.Println("Announcing zone:", zones[i].Offset)
			case <-s.Stopper:
				timer.Stop()
				return
			}
		}
	}
}
<commit_msg>fix api change<commit_after>package nyb

import (
	"encoding/json"
	"fmt"
	"log"
	"sort"
	"sync"
	"time"

	"github.com/hako/durafmt"
	"github.com/ugjka/dumbirc"
)

//Settings for bot
type Settings struct {
	IrcNick    string
	IrcChans   []string
	IrcServer  string
	IrcTrigger string
	IrcUseTLS  bool
	Bot        *dumbirc.Connection
	LogChan    LogChan
	Stopper    chan bool
	Email      string
	Nominatim  string
	extra
}

type extra struct {
	zones           TZS
	last            TZ
	next            TZ
	nominatimResult NominatimResults
	//We close this when we get WELCOME msg on join in irc
	start chan bool
	//This is used to prevent sending ping before we
	//have response from previous ping (any activity on irc)
	//pingpong(pp) sends a signal to ping timer
	pp chan bool
	sync.Once
	sync.WaitGroup
}

//New creates new bot
func New(nick string, chans []string, trigger string, server string,
	tls bool, email string, nominatim string) *Settings {
	return &Settings{
		nick,
		chans,
		server,
		trigger,
		tls,
		dumbirc.New(nick, "nyebot", server, tls),
		newLogChan(),
		make(chan bool),
		email,
		nominatim,
		extra{
			start: make(chan bool),
			pp:    make(chan bool, 1),
		},
	}
}

var stFinished = "That's it, Year %d is here AoE"

//Start starts the bot
func (s *Settings) Start() {
	log.SetOutput(s.LogChan)
	log.Println("Starting the bot...")
	defer s.Wait()
	//
	//Set up irc
	//
	bot := s.Bot
	s.addCallbacks()
	s.addTriggers()

	s.Add(1)
	go s.ircControl()

	bot.Start()

	select {
	case <-s.start:
		log.Println("Got start...")
	case <-s.Stopper:
		return
	}

	s.decodeZones(Zones)
	for {
		s.loopTimeZones()
		select {
		case <-s.Stopper:
			return
		default:
		}
		bot.MsgBulk(s.IrcChans, fmt.Sprintf(stFinished, target.Year()))
		log.Println("All zones finished...")
		target = target.AddDate(1, 0, 0)
		log.Printf("Wrapping the target date around to %d\n", target.Year())
	}
}

func (s *Settings) decodeZones(z []byte) {
	if err := json.Unmarshal(z, &s.zones); err != nil {
		log.Println("Fatal error:", err)
		close(s.Stopper)
		return
	}
	sort.Sort(sort.Reverse(s.zones))
}

//Stop stops the bot
func (s *Settings) Stop() {
	select {
	case <-s.Stopper:
		return
	default:
		close(s.Stopper)
	}
}

var reconnectInterval = time.Second * 30
var pingInterval = time.Minute * 1

func (s *Settings) ircControl() {
	bot := s.Bot
	defer s.Done()
	for {
		timer := time.NewTimer(pingInterval)
		select {
		case err := <-bot.Errchan:
			log.Println("Error:", err)
			log.Printf("Reconnecting to irc in %s...\n", reconnectInterval)
			time.AfterFunc(reconnectInterval, func() {
				select {
				case <-s.Stopper:
					return
				default:
					bot.Start()
				}
			})
		case <-s.Stopper:
			timer.Stop()
			log.Println("Stopping the bot...")
			log.Println("Disconnecting...")
			bot.Disconnect()
			return
		case <-timer.C:
			timer.Stop()
			//pingpong stuff
			select {
			case <-s.pp:
				log.Println("Sending PING...")
				bot.Ping()
			default:
				log.Println("Got no PONG...")
			}
		}

	}
}

var stNextNewYear = "Next New Year in %s in %s"
var stHappyNewYear = "Happy New Year in %s"

func (s *Settings) loopTimeZones() {
	zones := s.zones
	bot := s.Bot
	for i := 0; i < len(zones); i++ {
		dur := time.Minute * time.Duration(zones[i].Offset*60)
		s.next = zones[i]
		if i == 0 {
			s.last = zones[len(zones)-1]
		} else {
			s.last = zones[i-1]
		}
		if timeNow().UTC().Add(dur).Before(target) {
			time.Sleep(time.Second * 2)
			log.Println("Zone pending:", zones[i].Offset)
			humandur := durafmt.Parse(target.Sub(timeNow().UTC().Add(dur)))
			msg := fmt.Sprintf(stNextNewYear, removeMilliseconds(humandur), zones[i])
			bot.MsgBulk(s.IrcChans, msg)
			//Wait till Target in Timezone
			timer := NewTimer(target.Sub(timeNow().UTC().Add(dur)))
			select {
			case <-timer.C:
				timer.Stop()
				msg = fmt.Sprintf(stHappyNewYear, zones[i])
				bot.MsgBulk(s.IrcChans, msg)
				log.Println("Announcing zone:", zones[i].Offset)
			case <-s.Stopper:
				timer.Stop()
				return
			}
		}
	}
}
<|endoftext|>