<commit_before>package sysvipc

/*
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*/
import "C"
import (
	"time"
	"unsafe"
)

// MessageQueue is a kernel-maintained queue.
type MessageQueue int64

// GetMsgQueue creates or retrieves a message queue id for a given IPC key.
// Useful flags are IPC_CREAT to create the queue if it doesn't already exist,
// and IPC_EXCL (in conjunction with IPC_CREAT) to fail with an error if it
// *does* already exists.
func GetMsgQueue(key, flag int64) (MessageQueue, error) {
	rc, err := C.msgget(C.key_t(key), C.int(flag))
	if rc == -1 {
		return -1, err
	}
	return MessageQueue(rc), nil
}

// Send places a new message onto the queue
func (mq MessageQueue) Send(mtyp int64, body []byte, flag int64) error {
	b := make([]byte, len(body)+8)
	copy(b[:8], serialize(mtyp))
	copy(b[8:], body)

	rc, err := C.msgsnd(
		C.int(mq),
		unsafe.Pointer(&b[0]),
		C.size_t(len(body)),
		C.int(flag),
	)
	if rc == -1 {
		return err
	}
	return nil
}

// Receive retrieves a message from the queue.
func (mq MessageQueue) Receive(maxlen uint, msgtyp, flag int64) ([]byte, int64, error) {
	b := make([]byte, maxlen+8)

	rc, err := C.msgrcv(
		C.int(mq),
		unsafe.Pointer(&b[0]),
		C.size_t(maxlen),
		C.long(msgtyp),
		C.int(flag),
	)
	if rc == -1 {
		return nil, 0, err
	}

	mtyp := deserialize(b[:8])
	return b[8 : rc+8], mtyp, nil
}

// Stat produces information about the queue.
func (mq MessageQueue) Stat() (*MQInfo, error) {
	mqds := C.struct_msqid_ds{}

	rc, err := C.msgctl(C.int(mq), C.IPC_STAT, &mqds)
	if rc == -1 {
		return nil, err
	}

	mqinf := MQInfo{
		Perms: IpcPerms{
			OwnerUID:   int(mqds.msg_perm.uid),
			OwnerGID:   int(mqds.msg_perm.gid),
			CreatorUID: int(mqds.msg_perm.cuid),
			CreatorGID: int(mqds.msg_perm.cgid),
			Mode:       uint16(mqds.msg_perm.mode),
		},
		LastSend:   time.Unix(int64(mqds.msg_stime), 0),
		LastRcv:    time.Unix(int64(mqds.msg_rtime), 0),
		LastChange: time.Unix(int64(mqds.msg_ctime), 0),
		MsgCount:   uint(mqds.msg_qnum),
		MaxBytes:   uint(mqds.msg_qbytes),
		LastSender: int(mqds.msg_lspid),
		LastRcver:  int(mqds.msg_lrpid),
	}
	return &mqinf, nil
}

// Set updates parameters of the queue.
func (mq MessageQueue) Set(mqi *MQInfo) error {
	mqds := &C.struct_msqid_ds{
		msg_perm: C.struct_ipc_perm{
			uid:  C.__uid_t(mqi.Perms.OwnerUID),
			gid:  C.__gid_t(mqi.Perms.OwnerGID),
			mode: C.ushort(mqi.Perms.Mode & 0x1FF),
		},
		msg_qbytes: C.msglen_t(mqi.MaxBytes),
	}

	rc, err := C.msgctl(C.int(mq), C.IPC_SET, mqds)
	if rc == -1 {
		return err
	}
	return nil
}

// Remove deletes the queue.
// This will also awake all waiting readers and writers with EIDRM.
func (mq MessageQueue) Remove() error {
	rc, err := C.msgctl(C.int(mq), C.IPC_RMID, nil)
	if rc == -1 {
		return err
	}
	return nil
}

// MQInfo holds meta information about a message queue.
type MQInfo struct {
	Perms      IpcPerms
	LastSend   time.Time
	LastRcv    time.Time
	LastChange time.Time

	MsgCount uint
	MaxBytes uint

	LastSender int
	LastRcver  int
}

// real c-style pointer casting
func serialize(num int64) []byte {
	b := make([]byte, 8)
	base := uintptr(unsafe.Pointer(&num))
	for i := 0; i < 8; i++ {
		b[i] = *(*byte)(unsafe.Pointer(base + uintptr(i)))
	}
	return b
}

func deserialize(b []byte) int64 {
	return *(*int64)(unsafe.Pointer(&b[0]))
}
<commit_msg>style for a *section* comment<commit_after>package sysvipc

/*
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*/
import "C"
import (
	"time"
	"unsafe"
)

// MessageQueue is a kernel-maintained queue.
type MessageQueue int64

// GetMsgQueue creates or retrieves a message queue id for a given IPC key.
// Useful flags are IPC_CREAT to create the queue if it doesn't already exist,
// and IPC_EXCL (in conjunction with IPC_CREAT) to fail with an error if it
// *does* already exists.
func GetMsgQueue(key, flag int64) (MessageQueue, error) {
	rc, err := C.msgget(C.key_t(key), C.int(flag))
	if rc == -1 {
		return -1, err
	}
	return MessageQueue(rc), nil
}

// Send places a new message onto the queue
func (mq MessageQueue) Send(mtyp int64, body []byte, flag int64) error {
	b := make([]byte, len(body)+8)
	copy(b[:8], serialize(mtyp))
	copy(b[8:], body)

	rc, err := C.msgsnd(
		C.int(mq),
		unsafe.Pointer(&b[0]),
		C.size_t(len(body)),
		C.int(flag),
	)
	if rc == -1 {
		return err
	}
	return nil
}

// Receive retrieves a message from the queue.
func (mq MessageQueue) Receive(maxlen uint, msgtyp, flag int64) ([]byte, int64, error) {
	b := make([]byte, maxlen+8)

	rc, err := C.msgrcv(
		C.int(mq),
		unsafe.Pointer(&b[0]),
		C.size_t(maxlen),
		C.long(msgtyp),
		C.int(flag),
	)
	if rc == -1 {
		return nil, 0, err
	}

	mtyp := deserialize(b[:8])
	return b[8 : rc+8], mtyp, nil
}

// Stat produces information about the queue.
func (mq MessageQueue) Stat() (*MQInfo, error) {
	mqds := C.struct_msqid_ds{}

	rc, err := C.msgctl(C.int(mq), C.IPC_STAT, &mqds)
	if rc == -1 {
		return nil, err
	}

	mqinf := MQInfo{
		Perms: IpcPerms{
			OwnerUID:   int(mqds.msg_perm.uid),
			OwnerGID:   int(mqds.msg_perm.gid),
			CreatorUID: int(mqds.msg_perm.cuid),
			CreatorGID: int(mqds.msg_perm.cgid),
			Mode:       uint16(mqds.msg_perm.mode),
		},
		LastSend:   time.Unix(int64(mqds.msg_stime), 0),
		LastRcv:    time.Unix(int64(mqds.msg_rtime), 0),
		LastChange: time.Unix(int64(mqds.msg_ctime), 0),
		MsgCount:   uint(mqds.msg_qnum),
		MaxBytes:   uint(mqds.msg_qbytes),
		LastSender: int(mqds.msg_lspid),
		LastRcver:  int(mqds.msg_lrpid),
	}
	return &mqinf, nil
}

// Set updates parameters of the queue.
func (mq MessageQueue) Set(mqi *MQInfo) error {
	mqds := &C.struct_msqid_ds{
		msg_perm: C.struct_ipc_perm{
			uid:  C.__uid_t(mqi.Perms.OwnerUID),
			gid:  C.__gid_t(mqi.Perms.OwnerGID),
			mode: C.ushort(mqi.Perms.Mode & 0x1FF),
		},
		msg_qbytes: C.msglen_t(mqi.MaxBytes),
	}

	rc, err := C.msgctl(C.int(mq), C.IPC_SET, mqds)
	if rc == -1 {
		return err
	}
	return nil
}

// Remove deletes the queue.
// This will also awake all waiting readers and writers with EIDRM.
func (mq MessageQueue) Remove() error {
	rc, err := C.msgctl(C.int(mq), C.IPC_RMID, nil)
	if rc == -1 {
		return err
	}
	return nil
}

// MQInfo holds meta information about a message queue.
type MQInfo struct {
	Perms      IpcPerms
	LastSend   time.Time
	LastRcv    time.Time
	LastChange time.Time

	MsgCount uint
	MaxBytes uint

	LastSender int
	LastRcver  int
}

/*
real c-style pointer casting
*/

func serialize(num int64) []byte {
	b := make([]byte, 8)
	base := uintptr(unsafe.Pointer(&num))
	for i := 0; i < 8; i++ {
		b[i] = *(*byte)(unsafe.Pointer(base + uintptr(i)))
	}
	return b
}

func deserialize(b []byte) int64 {
	return *(*int64)(unsafe.Pointer(&b[0]))
}
<|endoftext|>


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

package mux

import (
	"errors"
	"fmt"
	"net/http"
	"path"
	"regexp"

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}
	handler.ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

func (r *Router) buildVars(m map[string]string) map[string]string {
	if r.parent != nil {
		m = r.parent.buildVars(m)
	}
	return m
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// BuildVars registers a new route with a custom function for modifying
// route variables before building a URL.
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
	return r.NewRoute().BuildVarsFunc(f)
}

// Walk walks the router and all its sub-routers, calling walkFn for each route
// in the tree. The routes are walked in the order they were added. Sub-routers
// are explored depth-first.
func (r *Router) Walk(walkFn WalkFunc) error {
	return r.walk(walkFn, []*Route{})
}

// SkipRouter is used as a return value from WalkFuncs to indicate that the
// router that walk is about to descend down to should be skipped.
var SkipRouter = errors.New("skip this router")

// WalkFunc is the type of the function called for each route visited by Walk.
// At every invocation, it is given the current route, and the current router,
// and a list of ancestor routes that lead to the current route.
type WalkFunc func(route *Route, router *Router, ancestors []*Route) error

func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
	for _, t := range r.routes {
		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
			continue
		}

		err := walkFn(t, r, ancestors)
		if err == SkipRouter {
			continue
		}
		for _, sr := range t.matchers {
			if h, ok := sr.(*Router); ok {
				err := h.walk(walkFn, ancestors)
				if err != nil {
					return err
				}
			}
		}
		if h, ok := t.handler.(*Router); ok {
			ancestors = append(ancestors, t)
			err := h.walk(walkFn, ancestors)
			if err != nil {
				return err
			}
			ancestors = ancestors[:len(ancestors)-1]
		}
	}
	return nil
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
// Note: this only works when called inside the handler of the matched route
// because it uses context.Get() which will be cleared after executing the
// handler.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

func checkPairs(pairs ...string) (int, error) {
	length := len(pairs)
	if length%2 != 0 {
		return length, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	return length, nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]*regexp.Regexp, length/2)
	for i := 0; i < length; i += 2 {
		regex, err := regexp.Compile(pairs[i+1])
		if err != nil {
			return nil, err
		}
		m[pairs[i]] = regex
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMapWithString returns true if the given key/value pairs exist in a given map.
func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}

// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
// the given regex
func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != nil {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v.MatchString(value) {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<commit_msg>Update comment and specify KeepContext option.<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mux

import (
	"errors"
	"fmt"
	"net/http"
	"path"
	"regexp"

	"github.com/gorilla/context"
)

// NewRouter returns a new router instance.
func NewRouter() *Router {
	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}

// Router registers routes to be matched and dispatches a handler.
//
// It implements the http.Handler interface, so it can be registered to serve
// requests:
//
//     var router = mux.NewRouter()
//
//     func main() {
//         http.Handle("/", router)
//     }
//
// Or, for Google App Engine, register it in a init() function:
//
//     func init() {
//         http.Handle("/", router)
//     }
//
// This will send all incoming requests to the router.
type Router struct {
	// Configurable Handler to be used when no route matches.
	NotFoundHandler http.Handler
	// Parent route, if this is a subrouter.
	parent parentRoute
	// Routes to be matched, in order.
	routes []*Route
	// Routes by name for URL building.
	namedRoutes map[string]*Route
	// See Router.StrictSlash(). This defines the flag for new routes.
	strictSlash bool
	// If true, do not clear the request context after handling the request
	KeepContext bool
}

// Match matches registered routes against the request.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
	for _, route := range r.routes {
		if route.Match(req, match) {
			return true
		}
	}
	return false
}

// ServeHTTP dispatches the handler registered in the matched route.
//
// When there is a match, the route variables can be retrieved calling
// mux.Vars(request).
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	// Clean path to canonical form and redirect.
	if p := cleanPath(req.URL.Path); p != req.URL.Path {

		// Added 3 lines (Philip Schlump) - It was droping the query string and #whatever from query.
		// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
		// http://code.google.com/p/go/issues/detail?id=5252
		url := *req.URL
		url.Path = p
		p = url.String()

		w.Header().Set("Location", p)
		w.WriteHeader(http.StatusMovedPermanently)
		return
	}
	var match RouteMatch
	var handler http.Handler
	if r.Match(req, &match) {
		handler = match.Handler
		setVars(req, match.Vars)
		setCurrentRoute(req, match.Route)
	}
	if handler == nil {
		handler = r.NotFoundHandler
		if handler == nil {
			handler = http.NotFoundHandler()
		}
	}
	if !r.KeepContext {
		defer context.Clear(req)
	}
	handler.ServeHTTP(w, req)
}

// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
	return r.getNamedRoutes()[name]
}

// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
	return r.getNamedRoutes()[name]
}

// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
// When true, if the route path is "/path/", accessing "/path" will redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
// route inherit the original StrictSlash setting.
func (r *Router) StrictSlash(value bool) *Router {
	r.strictSlash = value
	return r
}

// ----------------------------------------------------------------------------
// parentRoute
// ----------------------------------------------------------------------------

// getNamedRoutes returns the map where named routes are registered.
func (r *Router) getNamedRoutes() map[string]*Route {
	if r.namedRoutes == nil {
		if r.parent != nil {
			r.namedRoutes = r.parent.getNamedRoutes()
		} else {
			r.namedRoutes = make(map[string]*Route)
		}
	}
	return r.namedRoutes
}

// getRegexpGroup returns regexp definitions from the parent route, if any.
func (r *Router) getRegexpGroup() *routeRegexpGroup {
	if r.parent != nil {
		return r.parent.getRegexpGroup()
	}
	return nil
}

func (r *Router) buildVars(m map[string]string) map[string]string {
	if r.parent != nil {
		m = r.parent.buildVars(m)
	}
	return m
}

// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------

// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
	route := &Route{parent: r, strictSlash: r.strictSlash}
	r.routes = append(r.routes, route)
	return route
}

// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
	return r.NewRoute().Path(path).Handler(handler)
}

// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
	*http.Request)) *Route {
	return r.NewRoute().Path(path).HandlerFunc(f)
}

// Headers registers a new route with a matcher for request header values.
// See Route.Headers().
func (r *Router) Headers(pairs ...string) *Route {
	return r.NewRoute().Headers(pairs...)
}

// Host registers a new route with a matcher for the URL host.
// See Route.Host().
func (r *Router) Host(tpl string) *Route {
	return r.NewRoute().Host(tpl)
}

// MatcherFunc registers a new route with a custom matcher function.
// See Route.MatcherFunc().
func (r *Router) MatcherFunc(f MatcherFunc) *Route {
	return r.NewRoute().MatcherFunc(f)
}

// Methods registers a new route with a matcher for HTTP methods.
// See Route.Methods().
func (r *Router) Methods(methods ...string) *Route {
	return r.NewRoute().Methods(methods...)
}

// Path registers a new route with a matcher for the URL path.
// See Route.Path().
func (r *Router) Path(tpl string) *Route {
	return r.NewRoute().Path(tpl)
}

// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {
	return r.NewRoute().PathPrefix(tpl)
}

// Queries registers a new route with a matcher for URL query values.
// See Route.Queries().
func (r *Router) Queries(pairs ...string) *Route {
	return r.NewRoute().Queries(pairs...)
}

// Schemes registers a new route with a matcher for URL schemes.
// See Route.Schemes().
func (r *Router) Schemes(schemes ...string) *Route {
	return r.NewRoute().Schemes(schemes...)
}

// BuildVars registers a new route with a custom function for modifying
// route variables before building a URL.
func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
	return r.NewRoute().BuildVarsFunc(f)
}

// Walk walks the router and all its sub-routers, calling walkFn for each route
// in the tree. The routes are walked in the order they were added. Sub-routers
// are explored depth-first.
func (r *Router) Walk(walkFn WalkFunc) error {
	return r.walk(walkFn, []*Route{})
}

// SkipRouter is used as a return value from WalkFuncs to indicate that the
// router that walk is about to descend down to should be skipped.
var SkipRouter = errors.New("skip this router")

// WalkFunc is the type of the function called for each route visited by Walk.
// At every invocation, it is given the current route, and the current router,
// and a list of ancestor routes that lead to the current route.
type WalkFunc func(route *Route, router *Router, ancestors []*Route) error

func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
	for _, t := range r.routes {
		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
			continue
		}

		err := walkFn(t, r, ancestors)
		if err == SkipRouter {
			continue
		}
		for _, sr := range t.matchers {
			if h, ok := sr.(*Router); ok {
				err := h.walk(walkFn, ancestors)
				if err != nil {
					return err
				}
			}
		}
		if h, ok := t.handler.(*Router); ok {
			ancestors = append(ancestors, t)
			err := h.walk(walkFn, ancestors)
			if err != nil {
				return err
			}
			ancestors = ancestors[:len(ancestors)-1]
		}
	}
	return nil
}

// ----------------------------------------------------------------------------
// Context
// ----------------------------------------------------------------------------

// RouteMatch stores information about a matched route.
type RouteMatch struct {
	Route   *Route
	Handler http.Handler
	Vars    map[string]string
}

type contextKey int

const (
	varsKey contextKey = iota
	routeKey
)

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
	if rv := context.Get(r, varsKey); rv != nil {
		return rv.(map[string]string)
	}
	return nil
}

// CurrentRoute returns the matched route for the current request, if any.
// This only works when called inside the handler of the matched route
// because the matched route is stored in the request context which is cleared
// after the handler returns, unless the KeepContext option is set on the
// Router.
func CurrentRoute(r *http.Request) *Route {
	if rv := context.Get(r, routeKey); rv != nil {
		return rv.(*Route)
	}
	return nil
}

func setVars(r *http.Request, val interface{}) {
	context.Set(r, varsKey, val)
}

func setCurrentRoute(r *http.Request, val interface{}) {
	context.Set(r, routeKey, val)
}

// ----------------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------------

// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
	if p == "" {
		return "/"
	}
	if p[0] != '/' {
		p = "/" + p
	}
	np := path.Clean(p)
	// path.Clean removes trailing slash except for root;
	// put the trailing slash back if necessary.
	if p[len(p)-1] == '/' && np != "/" {
		np += "/"
	}
	return np
}

// uniqueVars returns an error if two slices contain duplicated strings.
func uniqueVars(s1, s2 []string) error {
	for _, v1 := range s1 {
		for _, v2 := range s2 {
			if v1 == v2 {
				return fmt.Errorf("mux: duplicated route variable %q", v2)
			}
		}
	}
	return nil
}

func checkPairs(pairs ...string) (int, error) {
	length := len(pairs)
	if length%2 != 0 {
		return length, fmt.Errorf(
			"mux: number of parameters must be multiple of 2, got %v", pairs)
	}
	return length, nil
}

// mapFromPairs converts variadic string parameters to a string map.
func mapFromPairsToString(pairs ...string) (map[string]string, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]string, length/2)
	for i := 0; i < length; i += 2 {
		m[pairs[i]] = pairs[i+1]
	}
	return m, nil
}

func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
	length, err := checkPairs(pairs...)
	if err != nil {
		return nil, err
	}
	m := make(map[string]*regexp.Regexp, length/2)
	for i := 0; i < length; i += 2 {
		regex, err := regexp.Compile(pairs[i+1])
		if err != nil {
			return nil, err
		}
		m[pairs[i]] = regex
	}
	return m, nil
}

// matchInArray returns true if the given string value is in the array.
func matchInArray(arr []string, value string) bool {
	for _, v := range arr {
		if v == value {
			return true
		}
	}
	return false
}

// matchMapWithString returns true if the given key/value pairs exist in a given map.
func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != "" {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v == value {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}

// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
// the given regex
func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
	for k, v := range toCheck {
		// Check if key exists.
		if canonicalKey {
			k = http.CanonicalHeaderKey(k)
		}
		if values := toMatch[k]; values == nil {
			return false
		} else if v != nil {
			// If value was defined as an empty string we only check that the
			// key exists. Otherwise we also check for equality.
			valueExists := false
			for _, value := range values {
				if v.MatchString(value) {
					valueExists = true
					break
				}
			}
			if !valueExists {
				return false
			}
		}
	}
	return true
}
<|endoftext|>


<commit_before>// This file is part of fs1up.
// Copyright (C) 2014 Andreas Klauer <Andreas.Klauer@metamorpher.de>
// License: GPL-2

// Package nbd uses the Linux NBD layer to emulate a block device in user space
package nbd

import (
	"os"
	"runtime"
	"syscall"
)

const (
	// Defined in <linux/fs.h>:
	BLKROSET = 4701
	// Defined in <linux/nbd.h>:
	NBD_SET_SOCK        = 43776
	NBD_SET_BLKSIZE     = 43777
	NBD_SET_SIZE        = 43778
	NBD_DO_IT           = 43779
	NBD_CLEAR_SOCK      = 43780
	NBD_CLEAR_QUE       = 43781
	NBD_PRINT_DEBUG     = 43782
	NBD_SET_SIZE_BLOCKS = 43782
	NBD_DISCONNECT      = 43783
	NBD_SET_TIMEOUT     = 43784
	NBD_SET_FLAGS       = 43785
	// enum
	NBD_CMD_READ  = 0
	NBD_CMD_WRITE = 1
	NBD_CMD_DISC  = 2
	NBD_CMD_FLUSH = 3
	NBD_CMD_TRIM  = 4
	// values for flags field
	NBD_FLAG_HAS_FLAGS  = (1 << 0) // nbd-server supports flags
	NBD_FLAG_READ_ONLY  = (1 << 1) // device is read-only
	NBD_FLAG_SEND_FLUSH = (1 << 2) // can flush writeback cache
	// there is a gap here to match userspace
	NBD_FLAG_SEND_TRIM = (1 << 5) // send trim/discard
	// These are sent over the network in the request/reply magic fields
	NBD_REQUEST_MAGIC = 0x25609513
	NBD_REPLY_MAGIC   = 0x67446698
	// Do *not* use magics: 0x12560953 0x96744668.
)

// DeviceInfo interface is a subset of os.FileInfo.
type DeviceInfo interface {
	Size() int64
}

// Device interface is a subset of os.File.
type Device interface {
	Stat() (di DeviceInfo, err error)
	ReadAt(b []byte, off int64) (n int, err error)
	WriteAt(b []byte, off int64) (n int, err error)
}

func Client(b Device) {
	runtime.LockOSThread()
	nbd := os.Open("/dev/nbd0") // TODO: find a free one
	fd, _ := Syscall.Socketpair(SOCK_STREAM, AF_UNIX, 0)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SOCK, fd[0])
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_BLKSIZE, 4096)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SIZE_BLOCKS, b.Stat().Size()/4096)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_FLAGS, 0)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), BLKROSET, 0)  // || 1
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DO_IT, 0) // doesn't return
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DISCONNECT, 0)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_CLEAR_SOCK, 0)
	runtime.UnlockOSThread()
}
<commit_msg>fix constants<commit_after>// This file is part of fs1up.
// Copyright (C) 2014 Andreas Klauer <Andreas.Klauer@metamorpher.de>
// License: GPL-2

// Package nbd uses the Linux NBD layer to emulate a block device in user space
package nbd

import (
	"os"
	"runtime"
	"syscall"
)

const (
	// Defined in <linux/fs.h>:
	BLKROSET = 4701
	// Defined in <linux/nbd.h>:
	NBD_SET_SOCK        = 43776
	NBD_SET_BLKSIZE     = 43777
	NBD_SET_SIZE        = 43778
	NBD_DO_IT           = 43779
	NBD_CLEAR_SOCK      = 43780
	NBD_CLEAR_QUE       = 43781
	NBD_PRINT_DEBUG     = 43782
	NBD_SET_SIZE_BLOCKS = 43783
	NBD_DISCONNECT      = 43784
	NBD_SET_TIMEOUT     = 43785
	NBD_SET_FLAGS       = 43786
	// enum
	NBD_CMD_READ  = 0
	NBD_CMD_WRITE = 1
	NBD_CMD_DISC  = 2
	NBD_CMD_FLUSH = 3
	NBD_CMD_TRIM  = 4
	// values for flags field
	NBD_FLAG_HAS_FLAGS  = (1 << 0) // nbd-server supports flags
	NBD_FLAG_READ_ONLY  = (1 << 1) // device is read-only
	NBD_FLAG_SEND_FLUSH = (1 << 2) // can flush writeback cache
	// there is a gap here to match userspace
	NBD_FLAG_SEND_TRIM = (1 << 5) // send trim/discard
	// These are sent over the network in the request/reply magic fields
	NBD_REQUEST_MAGIC = 0x25609513
	NBD_REPLY_MAGIC   = 0x67446698
	// Do *not* use magics: 0x12560953 0x96744668.
)

// Device interface is a subset of os.File.
type Device interface {
	ReadAt(b []byte, off int64) (n int, err error)
	WriteAt(b []byte, off int64) (n int, err error)
}

func handle(fd int) {
	buf := make([]byte, 1024)

	for {
		syscall.Read(fd, buf)
	}
}

func Client(d Device, offset int64, size int64) {
	nbd, _ := os.Open("/dev/nbd0") // TODO: find a free one
	fd, _ := syscall.Socketpair(syscall.SOCK_STREAM, syscall.AF_UNIX, 0)
	go handle(fd[1])
	runtime.LockOSThread()
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SOCK, uintptr(fd[0]))
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_BLKSIZE, 4096)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_SIZE_BLOCKS, uintptr(size/4096))
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_SET_FLAGS, 1)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), BLKROSET, 0)  // || 1
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DO_IT, 0) // doesn't return
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_DISCONNECT, 0)
	syscall.Syscall(syscall.SYS_IOCTL, nbd.Fd(), NBD_CLEAR_SOCK, 0)
	runtime.UnlockOSThread()
}
<|endoftext|>


<commit_before>package ncp

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
)

// NCp values:
// client http.Client with cookie
type NCp struct {
	client      http.Client
	baseAddress string
}

// Topic from forum
type Topic struct {
	Href    string
	Name    string
	Year    string
	Quality string
	Body    []byte
}

// Film all values
// Section       Раздел форума
// Name          Название
// EngName       Английское название
// Href          Ссылка
// Year          Год
// Genre         Жанр
// Country       Производство
// Director      Режиссер
// Producer      Продюсер
// Actors        Актеры
// Description   Описание
// Age           Возраст
// ReleaseDate   Дата мировой премьеры
// RussianDate   Дата премьеры в России
// Duration      Продолжительность
// Quality       Качество видео
// Translation   Перевод
// SubtitlesType Вид субтитров
// Subtitles     Субтитры
// Video         Видео
// Resolution    Разрешение видео
// Audio1        Аудио1
// Audio2        Аудио2
// Audio3        Аудио3
// Kinopoisk     Рейтинг кинопоиска
// Imdb          Рейтинг IMDb
// NNM           Рейтинг nnm-club
// Sound         Звук
// Size          Размер
// DateCreate    Дата создания раздачи
// Torrent       Ссылка на torrent
// Magnet        Ссылка на magnet
// Poster        Ссылка на постер
// Seeders       Количество раздающих
// Leechers      Количество скачивающих
type Film struct {
	Section       string
	Name          string
	EngName       string
	Href          string
	Year          int64
	Genre         []string
	Country       []string
	RawCountry    string
	Director      []string
	Producer      []string
	Actor         []string
	Description   string
	Age           string
	ReleaseDate   string
	RussianDate   string
	Duration      string
	Quality       string
	Translation   string
	SubtitlesType string
	Subtitles     string
	Video         string
	Resolution    string
	Audio1        string
	Audio2        string
	Audio3        string
	Kinopoisk     float64
	IMDb          float64
	NNM           float64
	Size          int64
	DateCreate    string
	Torrent       string
	Magnet        string
	Poster        string
	Seeders       int64
	Leechers      int64
}

// Init nnmc with login password
func Init(login string, password string, baseAddress string, proxy string) (*NCp, error) {
	var client http.Client
	if proxy != "" {
		os.Setenv("HTTP_PROXY", proxy)
	}
	cookieJar, _ := cookiejar.New(nil)
	client.Jar = cookieJar
	urlPost := baseAddress + "/forum/login.php"
	form := url.Values{}
	form.Set("username", login)
	form.Add("password", password)
	form.Add("redirect", "")
	form.Add("login", "âõîä")
	req, _ := http.NewRequest("POST", urlPost, bytes.NewBufferString(form.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
	_, err := client.Do(req)
	return &NCp{client: client, baseAddress: baseAddress}, err
}

// getHTML get body from href
func getHTML(href string, n *NCp, debug bool) ([]byte, error) {
	resp, err := n.client.Get(href)
	if err != nil {
		log.Println("client Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("ioutil.ReadAll error:", err)
	}
	buffer := bytes.NewBufferString("")
	for _, char := range body {
		var ch = toUtf(char)
		fmt.Fprintf(buffer, "%c", ch)
	}
	doc := buffer.Bytes()
	doc = replaceAll(doc, " ", " ")
	doc = replaceAll(doc, "&", "&")
	doc = replaceAll(doc, """, "'")
	doc = replaceAll(doc, "
", " ")
	doc = replaceAll(doc, ":", ":")
	doc = replaceAll(doc, "  ", " ")
	doc = removeTag(doc, `<span style="text-decoration:.+?">(.+?)</span>`)
	doc = removeTag(doc, `<span style="color:.+?">(.+?)</span>`)

	if debug == true {
		u, err := url.Parse(href)
		if err == nil {
			q := u.Query()
			t := q.Get("t")
			f := q.Get("f")
			if t != "" {
				ioutil.WriteFile(t+".html", doc, 0600)
			} else {
				if f != "" {
					ioutil.WriteFile(f+".html", doc, 0600)
				} else {
					ioutil.WriteFile(u.Path+".html", doc, 0600)
				}
			}
		}
	}
	return doc, nil
}

// ParseForumTree get topics from forumTree
func (n *NCp) ParseForumTree(href string, debug bool) ([]Topic, error) {
	var (
		topics []Topic
		reTree = regexp.MustCompile(`<a href="viewtopic.php\?t=(\d+).*?"class="topictitle">(.+?)\s\((\d{4})\)\s(.+?)</a>`)
	)
	body, err := getHTML(n.baseAddress+href, n, debug)
	if err != nil {
		return topics, err
	}
	if reTree.Match(body) == false {
		return topics, fmt.Errorf("No topic in body")
	}
	findResult := reTree.FindAllSubmatch(body, -1)
	for _, v := range findResult {
		var t Topic
		t.Href = string(v[1])
		t.Name = string(v[2])
		t.Year = string(v[3])
		t.Quality = string(v[4])
		topics = append(topics, t)
	}
	return topics, nil
}

// ParseTopic get film from topic
func (n *NCp) ParseTopic(topic Topic, debug bool) (Film, error) {
	var (
		film Film
	)
	name := strings.Split(topic.Name, " / ")
	switch len(name) {
	case 1:
		film.Name = strings.Trim(name[0], " ")
	case 2:
		film.Name = strings.Trim(name[0], " ")
		film.EngName = strings.Trim(name[1], " ")
	case 3:
		film.Name = strings.Trim(name[0], " ")
		film.EngName = strings.Trim(name[1], " ")
	case 4:
		film.Name = strings.Trim(name[0], " ")
		film.EngName = strings.Trim(name[2], " ")
	}
	film.Name = strings.Replace(film.Name, ":", ": ", -1)
	film.Name = strings.Replace(film.Name, "  ", " ", -1)
	film.EngName = strings.Replace(film.EngName, ":", ": ", -1)
	film.EngName = strings.Replace(film.EngName, "  ", " ", -1)
	film.Href = topic.Href
	if year64, err := strconv.ParseInt(topic.Year, 10, 64); err == nil {
		film.Year = year64
	}
	body, err := getHTML(n.baseAddress+"/forum/viewtopic.php?t="+film.Href, n, debug)
	if err != nil {
		return film, err
	}
	topic.Body = body
	film.Section = topic.getSection()
	film.Country, film.RawCountry = topic.getCountry()
	film.Genre = topic.getGenre()
	film.Director = topic.getDirector()
	film.Producer = topic.getProducer()
	film.Actor = topic.getActor()
	film.Description = topic.getDescription()
	film.Age = topic.getAge()
	film.ReleaseDate = topic.getReleaseDate()
	film.RussianDate = topic.getRussianDate()
	film.Duration = topic.getDuration()
	film.Quality = topic.getQuality()
	film.Translation = topic.getTranslation()
	film.SubtitlesType = topic.getSubtitlesType()
	film.Subtitles = topic.getSubtitles()
	film.Video = topic.getVideo()
	film.Resolution = getResolution(film.Video)
	film.Audio1 = topic.getAudio1()
	film.Audio2 = topic.getAudio2()
	film.Audio3 = topic.getAudio3()
	film.Torrent = topic.getTorrent()
	film.Magnet = topic.getMagnet()
	film.DateCreate = topic.getDate()
	film.Size = topic.getSize()
	film.NNM = topic.getRating()
	film.Poster = topic.getPoster()
	film.Seeders = topic.getSeeds()
	film.Leechers = topic.getLeechs()
	return film, nil
}

func replaceAll(body []byte, from string, to string) []byte {
	var reStr = regexp.MustCompile(from)
	if reStr.Match(body) == false {
		return body
	}
	return reStr.ReplaceAll(body, []byte(to))
}

func replaceDate(s string) string {
	s = strings.Replace(s, " Янв ", ".01.", -1)
	s = strings.Replace(s, " января ", ".01.", -1)
	s = strings.Replace(s, " Фев ", ".02.", -1)
	s = strings.Replace(s, " февраля ", ".02.", -1)
	s = strings.Replace(s, " Мар ", ".03.", -1)
	s = strings.Replace(s, " марта ", ".03.", -1)
	s = strings.Replace(s, " Апр ", ".04.", -1)
	s = strings.Replace(s, " апреля ", ".04.", -1)
	s = strings.Replace(s, " Май ", ".05.", -1)
	s = strings.Replace(s, " мая ", ".05.", -1)
	s = strings.Replace(s, " Июн ", ".06.", -1)
	s = strings.Replace(s, " июня ", ".06.", -1)
	s = strings.Replace(s, " Июл ", ".07.", -1)
	s = strings.Replace(s, " июля ", ".07.", -1)
	s = strings.Replace(s, " Авг ", ".08.", -1)
	s = strings.Replace(s, " августа ", ".08.", -1)
	s = strings.Replace(s, " Сен ", ".09.", -1)
	s = strings.Replace(s, " сентября ", ".09.", -1)
	s = strings.Replace(s, " Окт ", ".10.", -1)
	s = strings.Replace(s, " октября ", ".10.", -1)
	s = strings.Replace(s, " Ноя ", ".11.", -1)
	s = strings.Replace(s, " ноября ", ".11.", -1)
	s = strings.Replace(s, " Дек ", ".12.", -1)
	s = strings.Replace(s, " декабря ", ".12.", -1)
	split := strings.Split(s, ".")
	if len(split[0]) == 1 {
		s = "0" + s
	}
	return s
}

func caseInsensitiveContains(s, substr string) bool {
	s, substr = strings.ToUpper(s), strings.ToUpper(substr)
	return strings.Contains(s, substr)
}

func cleanStr(str string) string {
	var reSpan = regexp.MustCompile("")
	str = reSpan.ReplaceAllString(str, "")
	str = strings.Trim(str, " ")
	return str
}

func removeTag(body []byte, tag string) []byte {
	var reTag = regexp.MustCompile(tag)
	if reTag.Match(body) == false {
		return body
	}
	tags := reTag.FindAllSubmatch(body, -1)
	for _, item := range tags {
		body = bytes.Replace(body, item[0], item[1], 1)
	}
	return body
}

func stringToStruct(in string) []string {
	var out []string
	itemsArray := strings.Split(in, ",")
	for _, item := range itemsArray {
		trimItem := strings.Trim(item, " ")
		if item != "" {
			out = append(out, trimItem)
		}
	}
	return out
}
<commit_msg>add missing comment<commit_after>package ncp

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
)

// NCp values:
// client http.Client with cookie
type NCp struct {
	client      http.Client
	baseAddress string
}

// Topic from forum
type Topic struct {
	Href    string
	Name    string
	Year    string
	Quality string
	Body    []byte
}

// Film all values
// Section       Раздел форума
// Name          Название
// EngName       Английское название
// Href          Ссылка
// Year          Год
// Genre         Жанр
// Country       Производство
// RawCountry    Производство (оригинальная строка)
// Director      Режиссер
// Producer      Продюсер
// Actors        Актеры
// Description   Описание
// Age           Возраст
// ReleaseDate   Дата мировой премьеры
// RussianDate   Дата премьеры в России
// Duration      Продолжительность
// Quality       Качество видео
// Translation   Перевод
// SubtitlesType Вид субтитров
// Subtitles     Субтитры
// Video         Видео
// Resolution    Разрешение видео
// Audio1        Аудио1
// Audio2        Аудио2
// Audio3        Аудио3
// Kinopoisk     Рейтинг кинопоиска
// Imdb          Рейтинг IMDb
// NNM           Рейтинг nnm-club
// Sound         Звук
// Size          Размер
// DateCreate    Дата создания раздачи
// Torrent       Ссылка на torrent
// Magnet        Ссылка на magnet
// Poster        Ссылка на постер
// Seeders       Количество раздающих
// Leechers      Количество скачивающих
type Film struct {
	Section       string
	Name          string
	EngName       string
	Href          string
	Year          int64
	Genre         []string
	Country       []string
	RawCountry    string
	Director      []string
	Producer      []string
	Actor         []string
	Description   string
	Age           string
	ReleaseDate   string
	RussianDate   string
	Duration      string
	Quality       string
	Translation   string
	SubtitlesType string
	Subtitles     string
	Video         string
	Resolution    string
	Audio1        string
	Audio2        string
	Audio3        string
	Kinopoisk     float64
	IMDb          float64
	NNM           float64
	Size          int64
	DateCreate    string
	Torrent       string
	Magnet        string
	Poster        string
	Seeders       int64
	Leechers      int64
}

// Init nnmc with login password
func Init(login string, password string, baseAddress string, proxy string) (*NCp, error) {
	var client http.Client
	if proxy != "" {
		os.Setenv("HTTP_PROXY", proxy)
	}
	cookieJar, _ := cookiejar.New(nil)
	client.Jar = cookieJar
	urlPost := baseAddress + "/forum/login.php"
	form := url.Values{}
	form.Set("username", login)
	form.Add("password", password)
	form.Add("redirect", "")
	form.Add("login", "âõîä")
	req, _ := http.NewRequest("POST", urlPost, bytes.NewBufferString(form.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
	_, err := client.Do(req)
	return &NCp{client: client, baseAddress: baseAddress}, err
}

// getHTML get body from href
func getHTML(href string, n *NCp, debug bool) ([]byte, error) {
	resp, err := n.client.Get(href)
	if err != nil {
		log.Println("client Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println("ioutil.ReadAll error:", err)
	}
	buffer := bytes.NewBufferString("")
	for _, char := range body {
		var ch = toUtf(char)
		fmt.Fprintf(buffer, "%c", ch)
	}
	doc := buffer.Bytes()
	doc = replaceAll(doc, " ", " ")
	doc = replaceAll(doc, "&", "&")
	doc = replaceAll(doc, """, "'")
	doc = replaceAll(doc, "
", " ")
	doc = replaceAll(doc, ":", ":")
	doc = replaceAll(doc, "  ", " ")
	doc = removeTag(doc, `<span style="text-decoration:.+?">(.+?)</span>`)
	doc = removeTag(doc, `<span style="color:.+?">(.+?)</span>`)

	if debug == true {
		u, err := url.Parse(href)
		if err == nil {
			q := u.Query()
			t := q.Get("t")
			f := q.Get("f")
			if t != "" {
				ioutil.WriteFile(t+".html", doc, 0600)
			} else {
				if f != "" {
					ioutil.WriteFile(f+".html", doc, 0600)
				} else {
					ioutil.WriteFile(u.Path+".html", doc, 0600)
				}
			}
		}
	}
	return doc, nil
}

// ParseForumTree get topics from forumTree
func (n *NCp) ParseForumTree(href string, debug bool) ([]Topic, error) {
	var (
		topics []Topic
		reTree = regexp.MustCompile(`<a href="viewtopic.php\?t=(\d+).*?"class="topictitle">(.+?)\s\((\d{4})\)\s(.+?)</a>`)
	)
	body, err := getHTML(n.baseAddress+href, n, debug)
	if err != nil {
		return topics, err
	}
	if reTree.Match(body) == false {
		return topics, fmt.Errorf("No topic in body")
	}
	findResult := reTree.FindAllSubmatch(body, -1)
	for _, v := range findResult {
		var t Topic
		t.Href = string(v[1])
		t.Name = string(v[2])
		t.Year = string(v[3])
		t.Quality = string(v[4])
		topics = append(topics, t)
	}
	return topics, nil
}

// ParseTopic get film from topic
func (n *NCp) ParseTopic(topic Topic, debug bool) (Film, error) {
	var (
		film Film
	)
	name := strings.Split(topic.Name, " / ")
	switch len(name) {
	case 1:
		film.Name = strings.Trim(name[0], " ")
	case 2:
		film.Name = strings.Trim(name[0], " ")
		film.EngName = strings.Trim(name[1], " ")
	case 3:
		film.Name = strings.Trim(name[0], " ")
		film.EngName = strings.Trim(name[1], " ")
	case 4:
		film.Name = strings.Trim(name[0], " ")
		film.EngName = strings.Trim(name[2], " ")
	}
	film.Name = strings.Replace(film.Name, ":", ": ", -1)
	film.Name = strings.Replace(film.Name, "  ", " ", -1)
	film.EngName = strings.Replace(film.EngName, ":", ": ", -1)
	film.EngName = strings.Replace(film.EngName, "  ", " ", -1)
	film.Href = topic.Href
	if year64, err := strconv.ParseInt(topic.Year, 10, 64); err == nil {
		film.Year = year64
	}
	body, err := getHTML(n.baseAddress+"/forum/viewtopic.php?t="+film.Href, n, debug)
	if err != nil {
		return film, err
	}
	topic.Body = body
	film.Section = topic.getSection()
	film.Country, film.RawCountry = topic.getCountry()
	film.Genre = topic.getGenre()
	film.Director = topic.getDirector()
	film.Producer = topic.getProducer()
	film.Actor = topic.getActor()
	film.Description = topic.getDescription()
	film.Age = topic.getAge()
	film.ReleaseDate = topic.getReleaseDate()
	film.RussianDate = topic.getRussianDate()
	film.Duration = topic.getDuration()
	film.Quality = topic.getQuality()
	film.Translation = topic.getTranslation()
	film.SubtitlesType = topic.getSubtitlesType()
	film.Subtitles = topic.getSubtitles()
	film.Video = topic.getVideo()
	film.Resolution = getResolution(film.Video)
	film.Audio1 = topic.getAudio1()
	film.Audio2 = topic.getAudio2()
	film.Audio3 = topic.getAudio3()
	film.Torrent = topic.getTorrent()
	film.Magnet = topic.getMagnet()
	film.DateCreate = topic.getDate()
	film.Size = topic.getSize()
	film.NNM = topic.getRating()
	film.Poster = topic.getPoster()
	film.Seeders = topic.getSeeds()
	film.Leechers = topic.getLeechs()
	return film, nil
}

func replaceAll(body []byte, from string, to string) []byte {
	var reStr = regexp.MustCompile(from)
	if reStr.Match(body) == false {
		return body
	}
	return reStr.ReplaceAll(body, []byte(to))
}

func replaceDate(s string) string {
	s = strings.Replace(s, " Янв ", ".01.", -1)
	s = strings.Replace(s, " января ", ".01.", -1)
	s = strings.Replace(s, " Фев ", ".02.", -1)
	s = strings.Replace(s, " февраля ", ".02.", -1)
	s = strings.Replace(s, " Мар ", ".03.", -1)
	s = strings.Replace(s, " марта ", ".03.", -1)
	s = strings.Replace(s, " Апр ", ".04.", -1)
	s = strings.Replace(s, " апреля ", ".04.", -1)
	s = strings.Replace(s, " Май ", ".05.", -1)
	s = strings.Replace(s, " мая ", ".05.", -1)
	s = strings.Replace(s, " Июн ", ".06.", -1)
	s = strings.Replace(s, " июня ", ".06.", -1)
	s = strings.Replace(s, " Июл ", ".07.", -1)
	s = strings.Replace(s, " июля ", ".07.", -1)
	s = strings.Replace(s, " Авг ", ".08.", -1)
	s = strings.Replace(s, " августа ", ".08.", -1)
	s = strings.Replace(s, " Сен ", ".09.", -1)
	s = strings.Replace(s, " сентября ", ".09.", -1)
	s = strings.Replace(s, " Окт ", ".10.", -1)
	s = strings.Replace(s, " октября ", ".10.", -1)
	s = strings.Replace(s, " Ноя ", ".11.", -1)
	s = strings.Replace(s, " ноября ", ".11.", -1)
	s = strings.Replace(s, " Дек ", ".12.", -1)
	s = strings.Replace(s, " декабря ", ".12.", -1)
	split := strings.Split(s, ".")
	if len(split[0]) == 1 {
		s = "0" + s
	}
	return s
}

func caseInsensitiveContains(s, substr string) bool {
	s, substr = strings.ToUpper(s), strings.ToUpper(substr)
	return strings.Contains(s, substr)
}

func cleanStr(str string) string {
	var reSpan = regexp.MustCompile("")
	str = reSpan.ReplaceAllString(str, "")
	str = strings.Trim(str, " ")
	return str
}

func removeTag(body []byte, tag string) []byte {
	var reTag = regexp.MustCompile(tag)
	if reTag.Match(body) == false {
		return body
	}
	tags := reTag.FindAllSubmatch(body, -1)
	for _, item := range tags {
		body = bytes.Replace(body, item[0], item[1], 1)
	}
	return body
}

func stringToStruct(in string) []string {
	var out []string
	itemsArray := strings.Split(in, ",")
	for _, item := range itemsArray {
		trimItem := strings.Trim(item, " ")
		if item != "" {
			out = append(out, trimItem)
		}
	}
	return out
}
<|endoftext|>


<commit_before>package missinggo

import (
	"net"
)

type HostPort struct {
	Host string // Just the host, with no port.
	Port string // May be empty if no port was given.
	Err  error  // The error returned from net.SplitHostPort.
}

// Parse a "hostport" string, a concept that floats around the stdlib a lot
// and is painful to work with. If no port is present, what's usually present
// is just the host.
func ParseHostPort(hostPort string) (ret HostPort) {
	ret.Host, ret.Port, ret.Err = net.SplitHostPort(hostPort)
	if ret.Err != nil {
		ret.Host = hostPort
	}
	return
}

func (me *HostPort) Join() string {
	return net.JoinHostPort(me.Host, me.Port)
}
<commit_msg>Joining a host port with no port should not put a dangling ':'<commit_after>package missinggo

import (
	"net"
)

type HostPort struct {
	Host string // Just the host, with no port.
	Port string // May be empty if no port was given.
	Err  error  // The error returned from net.SplitHostPort.
}

// Parse a "hostport" string, a concept that floats around the stdlib a lot
// and is painful to work with. If no port is present, what's usually present
// is just the host.
func ParseHostPort(hostPort string) (ret HostPort) {
	ret.Host, ret.Port, ret.Err = net.SplitHostPort(hostPort)
	if ret.Err != nil {
		ret.Host = hostPort
	}
	return
}

func (me *HostPort) Join() string {
	if me.Port == "" {
		return me.Host
	}
	return net.JoinHostPort(me.Host, me.Port)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/facebookgo/parse"
	"github.com/facebookgo/stackerr"
	"github.com/spf13/cobra"
)

type newCmd struct {
	addApplication bool

	noCode       bool   // do not set up/download code
	createNewApp bool   // create a new app
	parseAppName string // name of parse app
	codeLocation string // location of cloud code project
}

var newProjectFiles = []struct {
	dirname, filename, content string
}{
	{"cloud", "main.js", sampleSource},
	{"public", "index.html", sampleHTML},
}

func (n *newCmd) curlCommand(app *app) string {
	return fmt.Sprintf(
		`curl -X POST \
 -H "X-Parse-Application-Id: %s" \
 -H "X-Parse-REST-API-Key: %s" \
 -H "Content-Type: application/json" \
 -d '{}' \
 https://api.parse.com/1/functions/hello
`,
		app.ApplicationID,
		app.RestKey,
	)
}

func (n *newCmd) cloudCodeHelpMessage(e *env, app *app) string {
	return fmt.Sprintf(
		`Your Cloud Code has been created at %s.
Next, you might want to deploy this code with "parse deploy".
This includes a "Hello world" cloud function, so once you deploy
you can test that it works, with:

%s
`,
		e.Root,
		n.curlCommand(app),
	)
}

func (n *newCmd) getCloudCodeDir(e *env, appName string, isNew bool) (string, error) {
	var cloudCodeDir string
	if isNew {
		fmt.Fprintf(e.Out,
			`Awesome! Now it's time to set up some Cloud Code for the app: %q,
Next we will create a directory to hold your Cloud Code.
Please enter the name to use for this directory,
or hit ENTER to use %q as the directory name.

Directory Name: `,
			appName,
			appName,
		)
	} else {
		fmt.Fprintf(e.Out,
			`Please enter the name of the folder where we can download the latest deployed
Cloud Code for your app %q

Directory Name: `,
			appName,
		)
	}

	fmt.Fscanf(e.In, "%s\n", &cloudCodeDir)
	cloudCodeDir = strings.TrimSpace(cloudCodeDir)
	if cloudCodeDir == "" {
		cloudCodeDir = appName
	}

	helpMsg := "Next time, please select the same app you selected now."
	if isNew {
		helpMsg = `Next time, please select to add Cloud Code to an 'existing' app
and select the app you just created.`
	}

	configFile := filepath.Join(e.Root, cloudCodeDir, legacyConfigFile)
	if _, err := os.Lstat(configFile); err == nil {
		return "", stackerr.Newf(
			`Sorry, we are unable to create Cloud Code at %s.
It seems that you already have Cloud Code at %s.
Please run "parse new" again.
%s
Please choose a different name for your Cloud Code directory,
so it does not conflict with any other Cloud Code in the current directory.
`,
			cloudCodeDir,
			cloudCodeDir,
			helpMsg,
		)
	}

	cloudCodeDirInfo, err := os.Stat(filepath.Join(e.Root, cloudCodeDir))
	if err == nil {
		if !cloudCodeDirInfo.IsDir() {
			return "", stackerr.Newf(`Sorry, we are unable to create Cloud Code at %s.
In the current directory a file named: %s already exists.
Please run "parse new" again.
%s
Please choose a different name for your Cloud Code directory,
so it does not conflict with any other Cloud Code in the current directory.
`,
				cloudCodeDir,
				cloudCodeDir,
				helpMsg,
			)

		}
		return "", nil
	}
	if !os.IsNotExist(err) {
		return "", stackerr.Wrap(err)
	}
	return cloudCodeDir, nil
}

func (n *newCmd) createConfigWithContent(path, content string) error {
	file, err := os.OpenFile(
		path,
		os.O_RDWR|os.O_CREATE|os.O_TRUNC,
		0600,
	)
	if err != nil && !os.IsExist(err) {
		return stackerr.Wrap(err)
	}
	defer file.Close()
	if _, err := file.WriteString(content); err != nil {
		return stackerr.Wrap(err)
	}
	if err := file.Close(); err != nil {
		return stackerr.Wrap(err)
	}
	return nil
}

func (n *newCmd) promptCreateNewApp(e *env, nonInteractive bool) (string, error) {
	if nonInteractive {
		if n.createNewApp {
			return "new", nil
		}
		return "existing", nil
	}

	msg := `"new" and "existing" are the only valid options.
Please try again ...`

	var decision string
	for i := 0; i < 3; i++ {
		fmt.Fprintf(e.Out,
			`Would you like to create a new app, or add Cloud Code to an existing app?
Type "(n)ew" or "(e)xisting": `,
		)
		fmt.Fscanf(e.In, "%s\n", &decision)
		decision = strings.ToLower(decision)

		if decision == "new" || decision == "n" || decision == "existing" || decision == "e" {
			return decision, nil
		}
		fmt.Fprintln(e.Err, msg)
	}
	return "", stackerr.New(msg)
}

func (n *newCmd) setupSample(
	e *env,
	name string,
	appConfig appConfig,
	isNew bool,
	nonInteractive bool,
) (bool, error) {
	found := isProjectDir(getProjectRoot(e, e.Root))
	if !found {
		root := getLegacyProjectRoot(e, e.Root)
		_, err := os.Lstat(filepath.Join(root, legacyConfigFile))
		found = err == nil
	}
	if found {
		return false, stackerr.New(
			`Detected that you are already inside a Parse project.
Please refrain from creating a Parse project inside another Parse project.
`,
		)
	}

	var (
		cloudCodeDir string
		err          error
	)

	if nonInteractive {
		cloudCodeDir = n.codeLocation
	} else if n.noCode {
		cloudCodeDir = "" // ensures that "parse new --init" inits the current directory
	} else {
		cloudCodeDir, err = n.getCloudCodeDir(e, name, isNew)
		if err != nil {
			return false, err
		}
	}
	e.Root = filepath.Join(e.Root, cloudCodeDir)

	switch e.Type {
	case parseFormat:
		dumpTemplate := false
		if !isNew && !n.noCode {
			// if parse app was already created try to fetch cloud code and populate dir
			masterKey, err := appConfig.getMasterKey(e)
			if err != nil {
				return false, err
			}
			e.ParseAPIClient = e.ParseAPIClient.WithCredentials(
				parse.MasterKey{
					ApplicationID: appConfig.getApplicationID(),
					MasterKey:     masterKey,
				},
			)

			d := &downloadCmd{destination: e.Root}
			err = d.run(e, nil)
			if err != nil {
				if err == errNoFiles {
					dumpTemplate = true
				} else {
					fmt.Fprintln(
						e.Out,
						`
NOTE: If you like to fetch the latest deployed Cloud Code from Parse,
you can use the "parse download" command after finishing the set up.
This will download Cloud Code to a temporary location.
`,
					)
				}
			}
		}
		dumpTemplate = (isNew || dumpTemplate) && !n.noCode
		return dumpTemplate, n.cloneSampleCloudCode(e, dumpTemplate)
	}
	return false, stackerr.Newf("Unknown project type: %d", e.Type)
}

func (n *newCmd) configureSample(
	add *addCmd,
	name string,
	appConfig appConfig,
	args []string,
	e *env,
) error {
	if err := add.addSelectedApp(name, appConfig, args, e); err != nil {
		return err
	}

	masterKey, err := appConfig.getMasterKey(e)
	if err != nil {
		return err
	}
	e.ParseAPIClient = e.ParseAPIClient.WithCredentials(
		parse.MasterKey{
			ApplicationID: appConfig.getApplicationID(),
			MasterKey:     masterKey,
		},
	)

	if e.Type == parseFormat {
		return useLatestJSSDK(e)
	}
	return nil
}

func (n *newCmd) run(e *env) error {
	apps := &apps{}
	addCmd := &addCmd{MakeDefault: true, apps: apps}

	if err := apps.login.authUser(e); err != nil {
		return err
	}
	var (
		app *app
		err error
	)

	nonInteractive := n.parseAppName != "" && n.codeLocation != ""
	decision, err := n.promptCreateNewApp(e, nonInteractive)
	if err != nil {
		return err
	}
	isNew := false

	switch decision {
	case "new", "n":
		isNew = true
		app, err = apps.createApp(e, n.parseAppName)
		if err != nil {
			return err
		}
	case "existing", "e":
		app, err = addCmd.selectApp(e, n.parseAppName)
		if err != nil {
			return err
		}
	}

	e.Type = parseFormat
	appConfig := addCmd.getParseAppConfig(app)

	dumpTemplate, err := n.setupSample(e, app.Name, appConfig, isNew, nonInteractive)
	if err != nil {
		return err
	}
	if err := n.configureSample(addCmd, app.Name, appConfig, nil, e); err != nil {
		return err
	}
	if token := apps.login.credentials.token; token != "" {
		email, err := apps.login.authToken(e, token)
		if err != nil {
			return err
		}
		if err := (&configureCmd{}).parserEmail(e, []string{email}); err != nil {
			return err
		}
	}

	if dumpTemplate {
		fmt.Fprintf(e.Out, n.cloudCodeHelpMessage(e, app))
	}

	return nil
}

func newNewCmd(e *env) *cobra.Command {
	nc := newCmd{addApplication: true}
	cmd := &cobra.Command{
		Use:   "new",
		Short: "Adds Cloud Code to an existing Parse app, additional can create a new Parse app",
		Long: `Adds Cloud Code to an existing Parse app, additional can create a new Parse app.
You can also use it in non-interactive mode by using the various flags available.
`,
		Run: runNoArgs(e, nc.run),
	}
	cmd.Flags().BoolVarP(&nc.noCode, "init", "i", nc.noCode,
		"Create a Cloud Code project only with configuration, no code.")
	cmd.Flags().BoolVarP(&nc.createNewApp, "create", "c", nc.createNewApp,
		"Set this flag to true if you want to create a new Parse app.")
	cmd.Flags().StringVarP(&nc.parseAppName, "app", "a", nc.parseAppName,
		"Name of the Parse app you want to create or set up Cloud Code project for.")
	cmd.Flags().StringVarP(&nc.codeLocation, "loc", "l", nc.codeLocation,
		"Location at which the Cloud Code project will be set up.")
	return cmd
}
<commit_msg>[new] clairfy documentation of new cmd<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/facebookgo/parse"
	"github.com/facebookgo/stackerr"
	"github.com/spf13/cobra"
)

type newCmd struct {
	addApplication bool

	noCode       bool   // do not set up/download code
	createNewApp bool   // create a new app
	parseAppName string // name of parse app
	codeLocation string // location of cloud code project
}

var newProjectFiles = []struct {
	dirname, filename, content string
}{
	{"cloud", "main.js", sampleSource},
	{"public", "index.html", sampleHTML},
}

func (n *newCmd) curlCommand(app *app) string {
	return fmt.Sprintf(
		`curl -X POST \
 -H "X-Parse-Application-Id: %s" \
 -H "X-Parse-REST-API-Key: %s" \
 -H "Content-Type: application/json" \
 -d '{}' \
 https://api.parse.com/1/functions/hello
`,
		app.ApplicationID,
		app.RestKey,
	)
}

func (n *newCmd) cloudCodeHelpMessage(e *env, app *app) string {
	return fmt.Sprintf(
		`Your Cloud Code has been created at %s.
Next, you might want to deploy this code with "parse deploy".
This includes a "Hello world" cloud function, so once you deploy
you can test that it works, with:

%s
`,
		e.Root,
		n.curlCommand(app),
	)
}

func (n *newCmd) getCloudCodeDir(e *env, appName string, isNew bool) (string, error) {
	var cloudCodeDir string
	if isNew {
		fmt.Fprintf(e.Out,
			`Awesome! Now it's time to set up some Cloud Code for the app: %q,
Next we will create a directory to hold your Cloud Code.
Please enter the name to use for this directory,
or hit ENTER to use %q as the directory name.

Directory Name: `,
			appName,
			appName,
		)
	} else {
		fmt.Fprintf(e.Out,
			`Please enter the name of the folder where we can download the latest deployed
Cloud Code for your app %q

Directory Name: `,
			appName,
		)
	}

	fmt.Fscanf(e.In, "%s\n", &cloudCodeDir)
	cloudCodeDir = strings.TrimSpace(cloudCodeDir)
	if cloudCodeDir == "" {
		cloudCodeDir = appName
	}

	helpMsg := "Next time, please select the same app you selected now."
	if isNew {
		helpMsg = `Next time, please select to add Cloud Code to an 'existing' app
and select the app you just created.`
	}

	configFile := filepath.Join(e.Root, cloudCodeDir, legacyConfigFile)
	if _, err := os.Lstat(configFile); err == nil {
		return "", stackerr.Newf(
			`Sorry, we are unable to create Cloud Code at %s.
It seems that you already have Cloud Code at %s.
Please run "parse new" again.
%s
Please choose a different name for your Cloud Code directory,
so it does not conflict with any other Cloud Code in the current directory.
`,
			cloudCodeDir,
			cloudCodeDir,
			helpMsg,
		)
	}

	cloudCodeDirInfo, err := os.Stat(filepath.Join(e.Root, cloudCodeDir))
	if err == nil {
		if !cloudCodeDirInfo.IsDir() {
			return "", stackerr.Newf(`Sorry, we are unable to create Cloud Code at %s.
In the current directory a file named: %s already exists.
Please run "parse new" again.
%s
Please choose a different name for your Cloud Code directory,
so it does not conflict with any other Cloud Code in the current directory.
`,
				cloudCodeDir,
				cloudCodeDir,
				helpMsg,
			)

		}
		return "", nil
	}
	if !os.IsNotExist(err) {
		return "", stackerr.Wrap(err)
	}
	return cloudCodeDir, nil
}

func (n *newCmd) createConfigWithContent(path, content string) error {
	file, err := os.OpenFile(
		path,
		os.O_RDWR|os.O_CREATE|os.O_TRUNC,
		0600,
	)
	if err != nil && !os.IsExist(err) {
		return stackerr.Wrap(err)
	}
	defer file.Close()
	if _, err := file.WriteString(content); err != nil {
		return stackerr.Wrap(err)
	}
	if err := file.Close(); err != nil {
		return stackerr.Wrap(err)
	}
	return nil
}

func (n *newCmd) promptCreateNewApp(e *env, nonInteractive bool) (string, error) {
	if nonInteractive {
		if n.createNewApp {
			return "new", nil
		}
		return "existing", nil
	}

	msg := `"new" and "existing" are the only valid options.
Please try again ...`

	var decision string
	for i := 0; i < 3; i++ {
		fmt.Fprintf(e.Out,
			`Would you like to create a new app, or add Cloud Code to an existing app?
Type "(n)ew" or "(e)xisting": `,
		)
		fmt.Fscanf(e.In, "%s\n", &decision)
		decision = strings.ToLower(decision)

		if decision == "new" || decision == "n" || decision == "existing" || decision == "e" {
			return decision, nil
		}
		fmt.Fprintln(e.Err, msg)
	}
	return "", stackerr.New(msg)
}

func (n *newCmd) setupSample(
	e *env,
	name string,
	appConfig appConfig,
	isNew bool,
	nonInteractive bool,
) (bool, error) {
	found := isProjectDir(getProjectRoot(e, e.Root))
	if !found {
		root := getLegacyProjectRoot(e, e.Root)
		_, err := os.Lstat(filepath.Join(root, legacyConfigFile))
		found = err == nil
	}
	if found {
		return false, stackerr.New(
			`Detected that you are already inside a Parse project.
Please refrain from creating a Parse project inside another Parse project.
`,
		)
	}

	var (
		cloudCodeDir string
		err          error
	)

	if nonInteractive {
		cloudCodeDir = n.codeLocation
	} else if n.noCode {
		cloudCodeDir = "" // ensures that "parse new --init" inits the current directory
	} else {
		cloudCodeDir, err = n.getCloudCodeDir(e, name, isNew)
		if err != nil {
			return false, err
		}
	}
	e.Root = filepath.Join(e.Root, cloudCodeDir)

	switch e.Type {
	case parseFormat:
		dumpTemplate := false
		if !isNew && !n.noCode {
			// if parse app was already created try to fetch cloud code and populate dir
			masterKey, err := appConfig.getMasterKey(e)
			if err != nil {
				return false, err
			}
			e.ParseAPIClient = e.ParseAPIClient.WithCredentials(
				parse.MasterKey{
					ApplicationID: appConfig.getApplicationID(),
					MasterKey:     masterKey,
				},
			)

			d := &downloadCmd{destination: e.Root}
			err = d.run(e, nil)
			if err != nil {
				if err == errNoFiles {
					dumpTemplate = true
				} else {
					fmt.Fprintln(
						e.Out,
						`
NOTE: If you like to fetch the latest deployed Cloud Code from Parse,
you can use the "parse download" command after finishing the set up.
This will download Cloud Code to a temporary location.
`,
					)
				}
			}
		}
		dumpTemplate = (isNew || dumpTemplate) && !n.noCode
		return dumpTemplate, n.cloneSampleCloudCode(e, dumpTemplate)
	}
	return false, stackerr.Newf("Unknown project type: %d", e.Type)
}

func (n *newCmd) configureSample(
	add *addCmd,
	name string,
	appConfig appConfig,
	args []string,
	e *env,
) error {
	if err := add.addSelectedApp(name, appConfig, args, e); err != nil {
		return err
	}

	masterKey, err := appConfig.getMasterKey(e)
	if err != nil {
		return err
	}
	e.ParseAPIClient = e.ParseAPIClient.WithCredentials(
		parse.MasterKey{
			ApplicationID: appConfig.getApplicationID(),
			MasterKey:     masterKey,
		},
	)

	if e.Type == parseFormat {
		return useLatestJSSDK(e)
	}
	return nil
}

func (n *newCmd) run(e *env) error {
	apps := &apps{}
	addCmd := &addCmd{MakeDefault: true, apps: apps}

	if err := apps.login.authUser(e); err != nil {
		return err
	}
	var (
		app *app
		err error
	)

	nonInteractive := n.parseAppName != "" && n.codeLocation != ""
	decision, err := n.promptCreateNewApp(e, nonInteractive)
	if err != nil {
		return err
	}
	isNew := false

	switch decision {
	case "new", "n":
		isNew = true
		app, err = apps.createApp(e, n.parseAppName)
		if err != nil {
			return err
		}
	case "existing", "e":
		app, err = addCmd.selectApp(e, n.parseAppName)
		if err != nil {
			return err
		}
	}

	e.Type = parseFormat
	appConfig := addCmd.getParseAppConfig(app)

	dumpTemplate, err := n.setupSample(e, app.Name, appConfig, isNew, nonInteractive)
	if err != nil {
		return err
	}
	if err := n.configureSample(addCmd, app.Name, appConfig, nil, e); err != nil {
		return err
	}
	if token := apps.login.credentials.token; token != "" {
		email, err := apps.login.authToken(e, token)
		if err != nil {
			return err
		}
		if err := (&configureCmd{}).parserEmail(e, []string{email}); err != nil {
			return err
		}
	}

	if dumpTemplate {
		fmt.Fprintf(e.Out, n.cloudCodeHelpMessage(e, app))
	}

	return nil
}

func newNewCmd(e *env) *cobra.Command {
	nc := newCmd{addApplication: true}
	cmd := &cobra.Command{
		Use:   "new",
		Short: "Adds Cloud Code to an existing Parse app, additional can create a new Parse app",
		Long: `Adds Cloud Code to an existing Parse app, additional can create a new Parse app.
You can also use it in non-interactive mode by using the various flags available.
`,
		Run: runNoArgs(e, nc.run),
	}
	cmd.Flags().BoolVarP(&nc.noCode, "init", "i", nc.noCode,
		"Create a Cloud Code project only with configuration, no code.")
	cmd.Flags().BoolVarP(&nc.createNewApp, "create", "c", nc.createNewApp,
		"Set this flag to true if you want to create a new Parse app.")
	cmd.Flags().StringVarP(&nc.parseAppName, "app", "a", nc.parseAppName,
		"Name of the Parse app you want to create or set up Cloud Code project for.")
	cmd.Flags().StringVarP(&nc.codeLocation, "loc", "l", nc.codeLocation,
		"Location, relative to the current directory, at which the Cloud Code project will be set up.")
	return cmd
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// NpmRegistry is the npm registry to use
var NpmRegistry = npmRegistry()

// NpmPackage represents an npm package.
type NpmPackage struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

// Packages returns a list of npm packages installed.
func (p *Plugins) Packages() ([]NpmPackage, error) {
	stdout, stderr, err := p.execNpm("list", "--json", "--depth=0")
	if err != nil {
		return nil, errors.New(stderr)
	}
	var response map[string]map[string]NpmPackage
	if err := json.Unmarshal([]byte(stdout), &response); err != nil {
		return nil, errors.New(stderr)
	}
	packages := make([]NpmPackage, 0, len(response["dependencies"]))
	for name, p := range response["dependencies"] {
		p.Name = name
		packages = append(packages, p)
	}
	return packages, nil
}

// installPackages installs a npm packages.
func (p *Plugins) installPackages(packages ...string) error {
	args := append([]string{"install"}, packages...)
	_, stderr, err := p.execNpm(args...)
	if err != nil {
		return errors.New("Error installing package. \n" + stderr + "\nTry running again with HEROKU_DEBUG=1 to see more output.")
	}
	return nil
}

// RemovePackages removes a npm packages.
func (p *Plugins) RemovePackages(packages ...string) error {
	installedPackages, err := p.Packages()
	if err != nil {
		return err
	}
	toRemove := make([]string, 0, len(installedPackages))
	for _, a := range installedPackages {
		for _, b := range packages {
			if a.Name == b {
				toRemove = append(toRemove, b)
			}
		}
	}
	if len(toRemove) == 0 {
		return nil
	}
	args := append([]string{"remove"}, toRemove...)
	_, stderr, err := p.execNpm(args...)
	if err != nil {
		return errors.New(stderr)
	}
	return nil
}

// OutdatedPackages returns a map of packages and their latest version
func (p *Plugins) OutdatedPackages(names ...string) (map[string]string, error) {
	args := append([]string{"outdated", "--json"}, names...)
	stdout, stderr, err := p.execNpm(args...)
	if err != nil {
		return nil, errors.New(stderr)
	}
	var outdated map[string]struct{ Latest string }
	json.Unmarshal([]byte(stdout), &outdated)
	packages := make(map[string]string, len(outdated))
	for name, versions := range outdated {
		packages[name] = versions.Latest
	}
	return packages, nil
}

// ClearCache clears the npm cache
func (p *Plugins) ClearCache() error {
	cmd, err := p.npmCmd("cache", "clean")
	if err != nil {
		return err
	}
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (p *Plugins) npmCmd(args ...string) (*exec.Cmd, error) {
	if err := os.MkdirAll(p.modulesPath(), 0755); err != nil {
		return nil, err
	}
	args = append([]string{npmBinPath()}, args...)
	if Debugging {
		level := os.Getenv("GODE_DEBUG")
		if level == "" {
			level = "info"
		}
		args = append(args, "--loglevel="+level)
	}
	cmd := exec.Command(nodeBinPath(), args...)
	cmd.Dir = p.Path
	cmd.Env = p.environ()
	return cmd, nil
}

func (p *Plugins) execNpm(args ...string) (string, string, error) {
	cmd, err := p.npmCmd(args...)
	if err != nil {
		return "", "", err
	}
	var stdout, stderr bytes.Buffer
	if Debugging {
		log.Printf("running npm from %s: %s\n", cmd.Dir, strings.Join(cmd.Args, " "))
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr
	}
	err = cmd.Run()
	return stdout.String(), stderr.String(), err
}

func (p *Plugins) environ() []string {
	env := []string{
		"NPM_CONFIG_ALWAYS_AUTH=false",
		"NPM_CONFIG_CACHE=" + filepath.Join(CacheHome, "npm"),
		"NPM_CONFIG_REGISTRY=" + NpmRegistry,
		"NPM_CONFIG_GLOBAL=false",
		"NPM_CONFIG_ONLOAD_SCRIPT=false",
	}
	return append(env, os.Environ()...)
}

func npmRegistry() string {
	registry := os.Getenv("HEROKU_NPM_REGISTRY")
	if registry == "" {
		registry = "https://cli-npm.heroku.com"
	}
	return registry
}

func npmBinPath() string {
	return filepath.Join(AppDir, "lib", "npm", "cli.js")
}
<commit_msg>Add NPM_CONFIG_CAFILE=$SSL_CERT_FILE to npm cmd (#269)<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// NpmRegistry is the npm registry to use
var NpmRegistry = npmRegistry()

// NpmPackage represents an npm package.
type NpmPackage struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

// Packages returns a list of npm packages installed.
func (p *Plugins) Packages() ([]NpmPackage, error) {
	stdout, stderr, err := p.execNpm("list", "--json", "--depth=0")
	if err != nil {
		return nil, errors.New(stderr)
	}
	var response map[string]map[string]NpmPackage
	if err := json.Unmarshal([]byte(stdout), &response); err != nil {
		return nil, errors.New(stderr)
	}
	packages := make([]NpmPackage, 0, len(response["dependencies"]))
	for name, p := range response["dependencies"] {
		p.Name = name
		packages = append(packages, p)
	}
	return packages, nil
}

// installPackages installs a npm packages.
func (p *Plugins) installPackages(packages ...string) error {
	args := append([]string{"install"}, packages...)
	_, stderr, err := p.execNpm(args...)
	if err != nil {
		return errors.New("Error installing package. \n" + stderr + "\nTry running again with HEROKU_DEBUG=1 to see more output.")
	}
	return nil
}

// RemovePackages removes a npm packages.
func (p *Plugins) RemovePackages(packages ...string) error {
	installedPackages, err := p.Packages()
	if err != nil {
		return err
	}
	toRemove := make([]string, 0, len(installedPackages))
	for _, a := range installedPackages {
		for _, b := range packages {
			if a.Name == b {
				toRemove = append(toRemove, b)
			}
		}
	}
	if len(toRemove) == 0 {
		return nil
	}
	args := append([]string{"remove"}, toRemove...)
	_, stderr, err := p.execNpm(args...)
	if err != nil {
		return errors.New(stderr)
	}
	return nil
}

// OutdatedPackages returns a map of packages and their latest version
func (p *Plugins) OutdatedPackages(names ...string) (map[string]string, error) {
	args := append([]string{"outdated", "--json"}, names...)
	stdout, stderr, err := p.execNpm(args...)
	if err != nil {
		return nil, errors.New(stderr)
	}
	var outdated map[string]struct{ Latest string }
	json.Unmarshal([]byte(stdout), &outdated)
	packages := make(map[string]string, len(outdated))
	for name, versions := range outdated {
		packages[name] = versions.Latest
	}
	return packages, nil
}

// ClearCache clears the npm cache
func (p *Plugins) ClearCache() error {
	cmd, err := p.npmCmd("cache", "clean")
	if err != nil {
		return err
	}
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (p *Plugins) npmCmd(args ...string) (*exec.Cmd, error) {
	if err := os.MkdirAll(p.modulesPath(), 0755); err != nil {
		return nil, err
	}
	args = append([]string{npmBinPath()}, args...)
	if Debugging {
		level := os.Getenv("GODE_DEBUG")
		if level == "" {
			level = "info"
		}
		args = append(args, "--loglevel="+level)
	}
	cmd := exec.Command(nodeBinPath(), args...)
	cmd.Dir = p.Path
	cmd.Env = p.environ()
	return cmd, nil
}

func (p *Plugins) execNpm(args ...string) (string, string, error) {
	cmd, err := p.npmCmd(args...)
	if err != nil {
		return "", "", err
	}
	var stdout, stderr bytes.Buffer
	if Debugging {
		log.Printf("running npm from %s: %s\n", cmd.Dir, strings.Join(cmd.Args, " "))
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr
	}
	err = cmd.Run()
	return stdout.String(), stderr.String(), err
}

func (p *Plugins) environ() []string {
	env := []string{
		"NPM_CONFIG_ALWAYS_AUTH=false",
		"NPM_CONFIG_CACHE=" + filepath.Join(CacheHome, "npm"),
		"NPM_CONFIG_REGISTRY=" + NpmRegistry,
		"NPM_CONFIG_GLOBAL=false",
		"NPM_CONFIG_ONLOAD_SCRIPT=false",
	}
	if file := os.Getenv("SSL_CERT_FILE"); file != "" {
		env = append(env, "NPM_CONFIG_CAFILE="+file)
	}
	return append(env, os.Environ()...)
}

func npmRegistry() string {
	registry := os.Getenv("HEROKU_NPM_REGISTRY")
	if registry == "" {
		registry = "https://cli-npm.heroku.com"
	}
	return registry
}

func npmBinPath() string {
	return filepath.Join(AppDir, "lib", "npm", "cli.js")
}
<|endoftext|>


<commit_before>package kube2iam

import (
	"fmt"

	log "github.com/sirupsen/logrus"
	"k8s.io/client-go/pkg/api/unversioned"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/tools/cache"
)

// PodHandler represents a pod handler.
type PodHandler struct {
	iamRoleKey string
}

func (p *PodHandler) podFields(pod *v1.Pod) log.Fields {
	return log.Fields{
		"pod.name":         pod.GetName(),
		"pod.namespace":    pod.GetNamespace(),
		"pod.status.ip":    pod.Status.PodIP,
		"pod.status.phase": pod.Status.Phase,
		"pod.iam.role":     pod.GetAnnotations()[p.iamRoleKey],
	}
}

// OnAdd is called when a pod is added.
func (p *PodHandler) OnAdd(obj interface{}) {
	pod, ok := obj.(*v1.Pod)
	if !ok {
		log.Errorf("Expected Pod but OnAdd handler received %+v", obj)
		return
	}

	//TODO JRN: Should we be filtering this by the `isPodActive` to reduce chatter and confusion about
	// what is actually being indexed by the indexer? This gets a little tricky with the OnUpdate piece
	// of cronjobs that stick around in Completed/Succeeded status
	logger := log.WithFields(p.podFields(pod))
	logger.Debug("Pod OnAdd")
}

// OnUpdate is called when a pod is modified.
func (p *PodHandler) OnUpdate(oldObj, newObj interface{}) {
	_, ok1 := oldObj.(*v1.Pod)
	newPod, ok2 := newObj.(*v1.Pod)
	if !ok1 || !ok2 {
		log.Errorf("Expected Pod but OnUpdate handler received %+v %+v", oldObj, newObj)
		return
	}

	logger := log.WithFields(p.podFields(newPod))
	logger.Debug("Pod OnUpdate")
}

// OnDelete is called when a pod is deleted.
func (p *PodHandler) OnDelete(obj interface{}) {
	pod, ok := obj.(*v1.Pod)
	if !ok {
		deletedObj, dok := obj.(cache.DeletedFinalStateUnknown)
		if dok {
			pod, ok = deletedObj.Obj.(*v1.Pod)
		}
	}

	if !ok {
		log.Errorf("Expected Pod but OnDelete handler received %+v", obj)
		return
	}

	logger := log.WithFields(p.podFields(pod))
	logger.Debug("Pod OnDelete")
}

func isPodActive(p *v1.Pod) bool {
	podDeleted := false
	if p.DeletionTimestamp != nil {
		podDeleted = p.DeletionTimestamp.Before(unversioned.Now())
	}
	return p.Status.PodIP != "" &&
		v1.PodSucceeded != p.Status.Phase &&
		v1.PodFailed != p.Status.Phase &&
		!podDeleted
}

// PodIPIndexFunc maps a given Pod to it's IP for caching.
func PodIPIndexFunc(obj interface{}) ([]string, error) {
	pod, ok := obj.(*v1.Pod)
	if !ok {
		return nil, fmt.Errorf("obj not pod: %+v", obj)
	}
	if isPodActive(pod) {
		return []string{pod.Status.PodIP}, nil
	}
	return nil, nil
}

// NewPodHandler constructs a pod handler given the relevant IAM Role Key
func NewPodHandler(iamRoleKey string) *PodHandler {
	return &PodHandler{iamRoleKey: iamRoleKey}
}
<commit_msg>Do not check the pod's deletionTimestamp (#203)<commit_after>package kube2iam

import (
	"fmt"

	log "github.com/sirupsen/logrus"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/tools/cache"
)

// PodHandler represents a pod handler.
type PodHandler struct {
	iamRoleKey string
}

func (p *PodHandler) podFields(pod *v1.Pod) log.Fields {
	return log.Fields{
		"pod.name":         pod.GetName(),
		"pod.namespace":    pod.GetNamespace(),
		"pod.status.ip":    pod.Status.PodIP,
		"pod.status.phase": pod.Status.Phase,
		"pod.iam.role":     pod.GetAnnotations()[p.iamRoleKey],
	}
}

// OnAdd is called when a pod is added.
func (p *PodHandler) OnAdd(obj interface{}) {
	pod, ok := obj.(*v1.Pod)
	if !ok {
		log.Errorf("Expected Pod but OnAdd handler received %+v", obj)
		return
	}

	//TODO JRN: Should we be filtering this by the `isPodActive` to reduce chatter and confusion about
	// what is actually being indexed by the indexer? This gets a little tricky with the OnUpdate piece
	// of cronjobs that stick around in Completed/Succeeded status
	logger := log.WithFields(p.podFields(pod))
	logger.Debug("Pod OnAdd")
}

// OnUpdate is called when a pod is modified.
func (p *PodHandler) OnUpdate(oldObj, newObj interface{}) {
	_, ok1 := oldObj.(*v1.Pod)
	newPod, ok2 := newObj.(*v1.Pod)
	if !ok1 || !ok2 {
		log.Errorf("Expected Pod but OnUpdate handler received %+v %+v", oldObj, newObj)
		return
	}

	logger := log.WithFields(p.podFields(newPod))
	logger.Debug("Pod OnUpdate")
}

// OnDelete is called when a pod is deleted.
func (p *PodHandler) OnDelete(obj interface{}) {
	pod, ok := obj.(*v1.Pod)
	if !ok {
		deletedObj, dok := obj.(cache.DeletedFinalStateUnknown)
		if dok {
			pod, ok = deletedObj.Obj.(*v1.Pod)
		}
	}

	if !ok {
		log.Errorf("Expected Pod but OnDelete handler received %+v", obj)
		return
	}

	logger := log.WithFields(p.podFields(pod))
	logger.Debug("Pod OnDelete")
}

func isPodActive(p *v1.Pod) bool {
	return p.Status.PodIP != "" &&
		v1.PodSucceeded != p.Status.Phase &&
		v1.PodFailed != p.Status.Phase
}

// PodIPIndexFunc maps a given Pod to it's IP for caching.
func PodIPIndexFunc(obj interface{}) ([]string, error) {
	pod, ok := obj.(*v1.Pod)
	if !ok {
		return nil, fmt.Errorf("obj not pod: %+v", obj)
	}
	if isPodActive(pod) {
		return []string{pod.Status.PodIP}, nil
	}
	return nil, nil
}

// NewPodHandler constructs a pod handler given the relevant IAM Role Key
func NewPodHandler(iamRoleKey string) *PodHandler {
	return &PodHandler{iamRoleKey: iamRoleKey}
}
<|endoftext|>


<commit_before>package pty

import (
	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data"
	"io"
	"os"
	"os/exec"
	"syscall"
	"unsafe"
)

/*
#include <pty.h>
#cgo LDFLAGS: -lutil
*/
import "C"

type PTY struct {
	Master        *os.File
	MasterEncoded io.WriteCloser
	Slave         *os.File
}

func New() *PTY {
	var master, slave C.int
	C.openpty(&master, &slave, nil, nil, nil)
	masterFile := os.NewFile(uintptr(master), "")
	slaveFile := os.NewFile(uintptr(slave), "")
	encodedMaster, err := charset.NewWriter("ISO-8859-1", masterFile)
	if err != nil {
		panic(err)
	}
	return &PTY{masterFile, encodedMaster, slaveFile}
}

func (pty *PTY) AdaptCommand(cmd *exec.Cmd) {
	pty.Slave.Chown(int(cmd.SysProcAttr.Credential.Uid), -1)
	cmd.Stdin = pty.Slave
	cmd.Stdout = pty.Slave
	cmd.Stderr = pty.Slave
	cmd.SysProcAttr.Setsid = true
}

type winsize struct {
	ws_row, ws_col, ws_xpixel, ws_ypixel C.ushort
}

func (pty *PTY) SetSize(x, y uint16) {
	winsize := winsize{
		ws_col: C.ushort(x),
		ws_row: C.ushort(y),
	}
	syscall.Syscall(syscall.SYS_IOCTL, pty.Slave.Fd(), syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(&winsize)))
}
<commit_msg>let's get web term working.<commit_after>package pty

import (
	"code.google.com/p/go-charset/charset"
	_ "code.google.com/p/go-charset/data"
	"io"
	"os"
	"os/exec"
	"syscall"
	"unsafe"
)

/*
#ifdef __APPLE__
#include <util.h>
#else
#include <pty.h>
#endif
#cgo LDFLAGS: -lutil
*/
import "C"

type PTY struct {
	Master        *os.File
	MasterEncoded io.WriteCloser
	Slave         *os.File
}

func New() *PTY {
	var master, slave C.int
	C.openpty(&master, &slave, nil, nil, nil)
	masterFile := os.NewFile(uintptr(master), "")
	slaveFile := os.NewFile(uintptr(slave), "")
	encodedMaster, err := charset.NewWriter("ISO-8859-1", masterFile)
	if err != nil {
		panic(err)
	}
	return &PTY{masterFile, encodedMaster, slaveFile}
}

func (pty *PTY) AdaptCommand(cmd *exec.Cmd) {
	pty.Slave.Chown(int(cmd.SysProcAttr.Credential.Uid), -1)
	cmd.Stdin = pty.Slave
	cmd.Stdout = pty.Slave
	cmd.Stderr = pty.Slave
	cmd.SysProcAttr.Setsid = true
}

type winsize struct {
	ws_row, ws_col, ws_xpixel, ws_ypixel C.ushort
}

func (pty *PTY) SetSize(x, y uint16) {
	winsize := winsize{
		ws_col: C.ushort(x),
		ws_row: C.ushort(y),
	}
	syscall.Syscall(syscall.SYS_IOCTL, pty.Slave.Fd(), syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(&winsize)))
}
<|endoftext|>