<commit_before>package descriptions

import "fmt"
import "log"
import "github.com/jbowtie/gokogiri/xml"
import "github.com/gosuri/uitable"

import "github.com/nlewo/contrail-introspect-cli/utils"
import "github.com/nlewo/contrail-introspect-cli/collection"

func CtrlIfmap() collection.DescCollection {
	return collection.DescCollection{
		BaseXpath: "IFMapTableShowResp/ifmap_db/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "node_name/text()",
			LongDetail:       collection.LongFormatFn(ifmapNeighbors),
		},
		PageArgs: []string{"controller-fqdn", "table-name", "search-string"},
		PageBuilder: func(args []string) collection.Sourcer {
			path := fmt.Sprintf("Snh_IFMapTableShowReq?table_name=%s&search_string=%s", args[1], args[2])
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8083}
		},
		PrimaryField: "node_name",
	}
}

func ifmapNeighbors(t *uitable.Table, e collection.Element) {
	t.AddRow("Node name", "Neighbors")
	nodeName, _ := e.Node.Search("node_name/text()")
	t.AddRow(fmt.Sprintf("%s", nodeName[0]))
	neighbors, _ := e.Node.Search("neighbors/list/element/text()")
	for _, n := range neighbors {
		t.AddRow("", fmt.Sprintf("%s", n))
	}
	t.AddRow("", "")
}

func Interface() collection.DescCollection {
	return collection.DescCollection{
		BaseXpath: "__ItfResp_list/ItfResp/itf_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"uuid", "name", "vrf_name", "vm_uuid", "ip_addr", "mdata_ip_addr"}),
		},
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.interface.0", VrouterUrl: args[0], Port: 8085}
		},
		PrimaryField: "name",
	}
}

func Peering() collection.DescCollection {
	return collection.DescCollection{
		PageArgs:  []string{"vrouter-fqdn"},
		BaseXpath: "AgentXmppConnectionStatus/peer/list",
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Webui{Path: "Snh_AgentXmppConnectionStatusReq", VrouterUrl: args[0], Port: 8085}
		},
		DescElt: collection.DescElement{
			ShortDetailXpath: "controller_ip/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"controller_ip", "state", "flap_count", "cfg_controller"}),
		},
		PrimaryField: "name",
	}
}

func Si() collection.DescCollection {
	return collection.DescCollection{
		BaseXpath: "__ServiceInstanceResp_list/ServiceInstanceResp/service_instance_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "uuid/text()",
			// LongDetailHelp: []string{"Service instance uuid", "Type of service instance", "Virtual machine uuid"},
			LongDetail: collection.LongFormatXpaths([]string{"uuid", "service_type", "instance_id"}),
		},
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.service-instance.0", VrouterUrl: args[0], Port: 8085}
		},
		PrimaryField: "uuid",
	}
}

func Route() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn", "vrf-name"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{VrouterUrl: args[0], Table: args[1] + ".uc.route.0,", Port: 8085}
		},
		BaseXpath: "__Inet4UcRouteResp_list/Inet4UcRouteResp/route_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "src_ip/text()",
			LongDetail:       collection.LongFormatFn(routeDetail)},
		PrimaryField: "src_ip",
	}
}
func Vrf() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.vrf.0", VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__VrfListResp_list/VrfListResp/vrf_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "uc_index"}),
		},
		PrimaryField: "name",
	}
}
func Vn() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.vn.0", VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__VnListResp_list/VnListResp/vn_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "vrf_name"}),
		},
		PrimaryField: "name",
	}
}

func RiSummary() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"controller-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Webui{Path: "Snh_ShowRoutingInstanceSummaryReq?search_string=", VrouterUrl: args[0], Port: 8083}
		},
		BaseXpath: "ShowRoutingInstanceSummaryResp/instances/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "virtual_network"}),
		},
		PrimaryField: "name",
	}
}

func CtrlRouteSummary() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"controller-fqdn", "search"},
		PageBuilder: func(args []string) collection.Sourcer {
			path := fmt.Sprintf("Snh_ShowRouteSummaryReq?search_string=%s", args[1])
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8083}
		},
		BaseXpath: "ShowRouteSummaryResp/tables/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "prefixes", "paths", "primary_paths", "secondary_paths", "pending_updates"}),
		},
		PrimaryField: "name",
	}
}

func CtrlRoute() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"controller-fqdn", "routing-instance"},
		PageBuilder: func(args []string) collection.Sourcer {
			path := fmt.Sprintf("Snh_ShowRouteReq?x=%s.inet.0", args[1])
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8083}
		},
		BaseXpath: "ShowRouteResp/tables/list/ShowRouteTable/routes/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "prefix/text()",
			LongDetail:       collection.LongFormatFn(controllerRoutePath),
		},
		PrimaryField: "prefix",
	}
}

func Mpls() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.mpls.0", VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__MplsResp_list/MplsResp/mpls_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "label/text()",
			LongDetail:       collection.LongFormatFn(mplsDetail),
		},
		PrimaryField: "label",
	}
}

func routeDetail(t *uitable.Table, e collection.Element) {
	srcIp, _ := e.Node.Search("src_ip/text()")
	t.AddRow(fmt.Sprintf("Src %s", srcIp[0]))
	paths, _ := e.Node.Search("path_list/list/PathSandeshData")

	t.AddRow("    Dst", "Peers", "MPLS label", "Interface", "Dest VN")
	for _, path := range paths {
		nhs, _ := path.Search("nh/NhSandeshData//dip/text()")
		peers, _ := path.Search("peer/text()")
		label, _ := path.Search("label/text()")
		destvn, _ := path.Search("dest_vn/text()")
		itf, _ := path.Search("nh/NhSandeshData/itf/text()")
		t.AddRow("    "+utils.Pretty(nhs), utils.Pretty(peers), utils.Pretty(label), utils.Pretty(itf), utils.Pretty(destvn))
	}
	t.AddRow("")
}

func mplsDetail(t *uitable.Table, e collection.Element) {
	label, err := e.GetField("label")
	if err != nil {
		log.Fatal(err)
	}
	t.AddRow(fmt.Sprintf("Label: %s", label))
	nexthopDetail(t, e.Node)
	t.AddRow("")
}

func nexthopDetail(t *uitable.Table, node xml.Node) {
	t.AddRow("    Type", "Interface", "Nexthop index")
	nhs, _ := node.Search("nh/NhSandeshData/type/text()")
	itf, _ := node.Search("nh/NhSandeshData/itf/text()")
	nhIdx, _ := node.Search("nh/NhSandeshData/nh_index/text()")
	t.AddRow("    "+utils.Pretty(nhs), utils.Pretty(itf), utils.Pretty(nhIdx))
}

func controllerRoutePath(t *uitable.Table, e collection.Element) {
	srcIp, _ := e.Node.Search("prefix/text()")
	t.AddRow(fmt.Sprintf("Prefix %s", srcIp[0]))
	paths, _ := e.Node.Search("paths/list/ShowRoutePath")

	t.AddRow("    Protocol", "Nexthop", "Local Pref", "Peers", "MPLS label")
	for _, path := range paths {
		protocol, _ := path.Search("protocol/text()")
		nhs, _ := path.Search("next_hop/text()")
		peers, _ := path.Search("source/text()")
		label, _ := path.Search("label/text()")
		localPref, _ := path.Search("local_preference/text()")
		t.AddRow("    "+utils.Pretty(protocol), utils.Pretty(nhs), utils.Pretty(localPref), utils.Pretty(peers), utils.Pretty(label))
	}
	t.AddRow("")
}

func AgentPing() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn", "vrf-name", "source-ip", "source-port", "dest-ip", "dest-port"},
		PageBuilder: func(args []string) collection.Sourcer {
			sourceIp := args[2]
			sourcePort := args[3]
			destIp := args[4]
			destPort := args[5]
			vrfName := args[1]

			path := fmt.Sprintf("Snh_PingReq?source_ip=%s&source_port=%s&dest_ip=%s&dest_port=%s&protocol=6&vrf_name=%s&packet_size=&count=1&interval=",
				sourceIp, sourcePort, destIp, destPort, vrfName)
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__PingResp_list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "resp/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"resp", "rtt"}),
		},
	}
}
<commit_msg>uc_index -> ucindex key<commit_after>package descriptions

import "fmt"
import "log"
import "github.com/jbowtie/gokogiri/xml"
import "github.com/gosuri/uitable"

import "github.com/nlewo/contrail-introspect-cli/utils"
import "github.com/nlewo/contrail-introspect-cli/collection"

func CtrlIfmap() collection.DescCollection {
	return collection.DescCollection{
		BaseXpath: "IFMapTableShowResp/ifmap_db/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "node_name/text()",
			LongDetail:       collection.LongFormatFn(ifmapNeighbors),
		},
		PageArgs: []string{"controller-fqdn", "table-name", "search-string"},
		PageBuilder: func(args []string) collection.Sourcer {
			path := fmt.Sprintf("Snh_IFMapTableShowReq?table_name=%s&search_string=%s", args[1], args[2])
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8083}
		},
		PrimaryField: "node_name",
	}
}

func ifmapNeighbors(t *uitable.Table, e collection.Element) {
	t.AddRow("Node name", "Neighbors")
	nodeName, _ := e.Node.Search("node_name/text()")
	t.AddRow(fmt.Sprintf("%s", nodeName[0]))
	neighbors, _ := e.Node.Search("neighbors/list/element/text()")
	for _, n := range neighbors {
		t.AddRow("", fmt.Sprintf("%s", n))
	}
	t.AddRow("", "")
}

func Interface() collection.DescCollection {
	return collection.DescCollection{
		BaseXpath: "__ItfResp_list/ItfResp/itf_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"uuid", "name", "vrf_name", "vm_uuid", "ip_addr", "mdata_ip_addr"}),
		},
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.interface.0", VrouterUrl: args[0], Port: 8085}
		},
		PrimaryField: "name",
	}
}

func Peering() collection.DescCollection {
	return collection.DescCollection{
		PageArgs:  []string{"vrouter-fqdn"},
		BaseXpath: "AgentXmppConnectionStatus/peer/list",
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Webui{Path: "Snh_AgentXmppConnectionStatusReq", VrouterUrl: args[0], Port: 8085}
		},
		DescElt: collection.DescElement{
			ShortDetailXpath: "controller_ip/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"controller_ip", "state", "flap_count", "cfg_controller"}),
		},
		PrimaryField: "name",
	}
}

func Si() collection.DescCollection {
	return collection.DescCollection{
		BaseXpath: "__ServiceInstanceResp_list/ServiceInstanceResp/service_instance_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "uuid/text()",
			// LongDetailHelp: []string{"Service instance uuid", "Type of service instance", "Virtual machine uuid"},
			LongDetail: collection.LongFormatXpaths([]string{"uuid", "service_type", "instance_id"}),
		},
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.service-instance.0", VrouterUrl: args[0], Port: 8085}
		},
		PrimaryField: "uuid",
	}
}

func Route() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn", "vrf-name"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{VrouterUrl: args[0], Table: args[1] + ".uc.route.0,", Port: 8085}
		},
		BaseXpath: "__Inet4UcRouteResp_list/Inet4UcRouteResp/route_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "src_ip/text()",
			LongDetail:       collection.LongFormatFn(routeDetail)},
		PrimaryField: "src_ip",
	}
}
func Vrf() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.vrf.0", VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__VrfListResp_list/VrfListResp/vrf_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "ucindex"}),
		},
		PrimaryField: "name",
	}
}
func Vn() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.vn.0", VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__VnListResp_list/VnListResp/vn_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "vrf_name"}),
		},
		PrimaryField: "name",
	}
}

func RiSummary() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"controller-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Webui{Path: "Snh_ShowRoutingInstanceSummaryReq?search_string=", VrouterUrl: args[0], Port: 8083}
		},
		BaseXpath: "ShowRoutingInstanceSummaryResp/instances/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "virtual_network"}),
		},
		PrimaryField: "name",
	}
}

func CtrlRouteSummary() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"controller-fqdn", "search"},
		PageBuilder: func(args []string) collection.Sourcer {
			path := fmt.Sprintf("Snh_ShowRouteSummaryReq?search_string=%s", args[1])
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8083}
		},
		BaseXpath: "ShowRouteSummaryResp/tables/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "name/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"name", "prefixes", "paths", "primary_paths", "secondary_paths", "pending_updates"}),
		},
		PrimaryField: "name",
	}
}

func CtrlRoute() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"controller-fqdn", "routing-instance"},
		PageBuilder: func(args []string) collection.Sourcer {
			path := fmt.Sprintf("Snh_ShowRouteReq?x=%s.inet.0", args[1])
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8083}
		},
		BaseXpath: "ShowRouteResp/tables/list/ShowRouteTable/routes/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "prefix/text()",
			LongDetail:       collection.LongFormatFn(controllerRoutePath),
		},
		PrimaryField: "prefix",
	}
}

func Mpls() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) collection.Sourcer {
			return collection.Remote{Table: "db.mpls.0", VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__MplsResp_list/MplsResp/mpls_list/list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "label/text()",
			LongDetail:       collection.LongFormatFn(mplsDetail),
		},
		PrimaryField: "label",
	}
}

func routeDetail(t *uitable.Table, e collection.Element) {
	srcIp, _ := e.Node.Search("src_ip/text()")
	t.AddRow(fmt.Sprintf("Src %s", srcIp[0]))
	paths, _ := e.Node.Search("path_list/list/PathSandeshData")

	t.AddRow("    Dst", "Peers", "MPLS label", "Interface", "Dest VN")
	for _, path := range paths {
		nhs, _ := path.Search("nh/NhSandeshData//dip/text()")
		peers, _ := path.Search("peer/text()")
		label, _ := path.Search("label/text()")
		destvn, _ := path.Search("dest_vn/text()")
		itf, _ := path.Search("nh/NhSandeshData/itf/text()")
		t.AddRow("    "+utils.Pretty(nhs), utils.Pretty(peers), utils.Pretty(label), utils.Pretty(itf), utils.Pretty(destvn))
	}
	t.AddRow("")
}

func mplsDetail(t *uitable.Table, e collection.Element) {
	label, err := e.GetField("label")
	if err != nil {
		log.Fatal(err)
	}
	t.AddRow(fmt.Sprintf("Label: %s", label))
	nexthopDetail(t, e.Node)
	t.AddRow("")
}

func nexthopDetail(t *uitable.Table, node xml.Node) {
	t.AddRow("    Type", "Interface", "Nexthop index")
	nhs, _ := node.Search("nh/NhSandeshData/type/text()")
	itf, _ := node.Search("nh/NhSandeshData/itf/text()")
	nhIdx, _ := node.Search("nh/NhSandeshData/nh_index/text()")
	t.AddRow("    "+utils.Pretty(nhs), utils.Pretty(itf), utils.Pretty(nhIdx))
}

func controllerRoutePath(t *uitable.Table, e collection.Element) {
	srcIp, _ := e.Node.Search("prefix/text()")
	t.AddRow(fmt.Sprintf("Prefix %s", srcIp[0]))
	paths, _ := e.Node.Search("paths/list/ShowRoutePath")

	t.AddRow("    Protocol", "Nexthop", "Local Pref", "Peers", "MPLS label")
	for _, path := range paths {
		protocol, _ := path.Search("protocol/text()")
		nhs, _ := path.Search("next_hop/text()")
		peers, _ := path.Search("source/text()")
		label, _ := path.Search("label/text()")
		localPref, _ := path.Search("local_preference/text()")
		t.AddRow("    "+utils.Pretty(protocol), utils.Pretty(nhs), utils.Pretty(localPref), utils.Pretty(peers), utils.Pretty(label))
	}
	t.AddRow("")
}

func AgentPing() collection.DescCollection {
	return collection.DescCollection{
		PageArgs: []string{"vrouter-fqdn", "vrf-name", "source-ip", "source-port", "dest-ip", "dest-port"},
		PageBuilder: func(args []string) collection.Sourcer {
			sourceIp := args[2]
			sourcePort := args[3]
			destIp := args[4]
			destPort := args[5]
			vrfName := args[1]

			path := fmt.Sprintf("Snh_PingReq?source_ip=%s&source_port=%s&dest_ip=%s&dest_port=%s&protocol=6&vrf_name=%s&packet_size=&count=1&interval=",
				sourceIp, sourcePort, destIp, destPort, vrfName)
			return collection.Webui{Path: path, VrouterUrl: args[0], Port: 8085}
		},
		BaseXpath: "__PingResp_list",
		DescElt: collection.DescElement{
			ShortDetailXpath: "resp/text()",
			LongDetail:       collection.LongFormatXpaths([]string{"resp", "rtt"}),
		},
	}
}
<|endoftext|>


<commit_before>// Package bit provides a bit array implementation and some utility functions.
package bit

import (
	"bytes"
	"fmt"
	"strings"
)

// Array represents a bit array.
type Array struct {
	bits   []uint64
	length int
}

// NewArray creates a new bit array
// with an initial bit capacity of n.
func NewArray(n int) *Array {
	if n < 0 {
		panic("bit: array size must be greater than or equal 0")
	}

	b := make([]uint64, 1, (n>>6)+1)
	return &Array{b, 0}
}

// Add appends the bits given its size to the array.
func (a *Array) Add(bits uint64, size int) {
	if size <= 0 || size > 64 {
		panic("bit: bit size must be in range [1,64]")
	}

	// Extend bits if necessary
	lenbits := len(a.bits)
	freespace := (lenbits << 6) - a.length
	overflow := size - freespace
	if overflow > 0 {
		a.bits = append(a.bits, 0)
	}

	// Append bits
	idx := lenbits - 1
	if freespace > 0 {
		a.bits[idx] |= bits << uint(a.length&63)
	}

	if overflow > 0 {
		a.bits[idx+1] |= bits >> uint(freespace)
	}

	// Increment size
	a.length += size
}

// Insert inserts bits to index idx overwriting its contents.
func (a *Array) Insert(idx int, bits uint64, size int) {
	if idx > a.length {
		panic("bit: index out of bounds")
	} else if size <= 0 || size > 64 {
		panic("bit: bit size must be in range [1,64]")
	}

	// Extend bits if necessary
	overflow := idx + size - a.length
	if overflow > 0 {
		lenbits := len(a.bits)
		freespace := (lenbits << 6) - a.length
		if overflow > freespace {
			a.bits = append(a.bits, 0)
		}

		a.length += overflow
	}

	bitIdx := idx & 63
	arrayIdx := idx >> 6
	lowBitSz := 64 - bitIdx
	overflow = size - lowBitSz

	ba := a.bits[arrayIdx]
	bb := bits << uint(bitIdx)
	mask := uint64(1<<uint(size)) - 1

	// Use bit twiddling hacks (merging bits)
	// https://graphics.stanford.edu/~seander/bithacks.html
	a.bits[arrayIdx] = ba ^ ((ba ^ bb) & (mask << uint(bitIdx)))

	if overflow > 0 {
		arrayIdx++
		ba = a.bits[arrayIdx]
		bb = bits >> uint(lowBitSz)

		a.bits[arrayIdx] = ba ^ ((ba ^ bb) & (mask >> uint(lowBitSz)))
	}
}

// Get returns the uint64 representation of
// bits starting from index idx given the bit size.
func (a *Array) Get(idx, size int) uint64 {
	if idx > a.length {
		panic("bit: index out of bounds")
	} else if size <= 0 || size > 64 {
		panic("bit: bit size must be in range [1,64]")
	}

	bitIdx := idx & 63
	arrayIdx := idx >> 6
	lowBitSz := 64 - bitIdx
	overflow := size - lowBitSz

	res := a.bits[arrayIdx] >> uint(bitIdx)
	if overflow > 0 {
		res |= a.bits[arrayIdx+1] << uint(lowBitSz)
	}

	return res & ((1 << uint(size)) - 1)
}

// Reset resets the array
// to its initial state.
func (a *Array) Reset() {
	for i := range a.bits {
		a.bits[i] = 0
	}

	a.bits = a.bits[0:1]
	a.length = 0
}

// Len returns the number
// of bits stored in the array.
func (a *Array) Len() int {
	return a.length
}

// Size returns the size
// of the array in bytes.
func (a *Array) Size() int {
	return len(a.bits) * 8
}

// String returns a hexadecimal
// string representation of the array.
func (a *Array) String() string {
	buf := new(bytes.Buffer)
	for i := len(a.bits) - 1; i >= 0; i-- {
		bits := fmt.Sprintf("%16X", a.bits[i])
		bits = strings.Replace(bits, " ", "0", -1)
		fmt.Fprintf(buf, "%s [%d-%d] ", bits, (i<<6)+63, i<<6)
	}

	return buf.String()
}
<commit_msg>Allows the underlying array to be accessed<commit_after>// Package bit provides a bit array implementation and some utility functions.
package bit

import (
	"bytes"
	"fmt"
	"strings"
)

// Array represents a bit array.
type Array struct {
	bits   []uint64
	length int
}

// NewArray creates a new bit array
// with an initial bit capacity of n.
func NewArray(n int) *Array {
	if n < 0 {
		panic("bit: array size must be greater than or equal 0")
	}

	b := make([]uint64, 1, (n>>6)+1)
	return &Array{b, 0}
}

// Add appends the bits given its size to the array.
func (a *Array) Add(bits uint64, size int) {
	if size <= 0 || size > 64 {
		panic("bit: bit size must be in range [1,64]")
	}

	// Extend bits if necessary
	lenbits := len(a.bits)
	freespace := (lenbits << 6) - a.length
	overflow := size - freespace
	if overflow > 0 {
		a.bits = append(a.bits, 0)
	}

	// Append bits
	idx := lenbits - 1
	if freespace > 0 {
		a.bits[idx] |= bits << uint(a.length&63)
	}

	if overflow > 0 {
		a.bits[idx+1] |= bits >> uint(freespace)
	}

	// Increment size
	a.length += size
}

// Insert inserts bits to index idx overwriting its contents.
func (a *Array) Insert(idx int, bits uint64, size int) {
	if idx > a.length {
		panic("bit: index out of bounds")
	} else if size <= 0 || size > 64 {
		panic("bit: bit size must be in range [1,64]")
	}

	// Extend bits if necessary
	overflow := idx + size - a.length
	if overflow > 0 {
		lenbits := len(a.bits)
		freespace := (lenbits << 6) - a.length
		if overflow > freespace {
			a.bits = append(a.bits, 0)
		}

		a.length += overflow
	}

	bitIdx := idx & 63
	arrayIdx := idx >> 6
	lowBitSz := 64 - bitIdx
	overflow = size - lowBitSz

	ba := a.bits[arrayIdx]
	bb := bits << uint(bitIdx)
	mask := uint64(1<<uint(size)) - 1

	// Use bit twiddling hacks (merging bits)
	// https://graphics.stanford.edu/~seander/bithacks.html
	a.bits[arrayIdx] = ba ^ ((ba ^ bb) & (mask << uint(bitIdx)))

	if overflow > 0 {
		arrayIdx++
		ba = a.bits[arrayIdx]
		bb = bits >> uint(lowBitSz)

		a.bits[arrayIdx] = ba ^ ((ba ^ bb) & (mask >> uint(lowBitSz)))
	}
}

// Get returns the uint64 representation of
// bits starting from index idx given the bit size.
func (a *Array) Get(idx, size int) uint64 {
	if idx > a.length {
		panic("bit: index out of bounds")
	} else if size <= 0 || size > 64 {
		panic("bit: bit size must be in range [1,64]")
	}

	bitIdx := idx & 63
	arrayIdx := idx >> 6
	lowBitSz := 64 - bitIdx
	overflow := size - lowBitSz

	res := a.bits[arrayIdx] >> uint(bitIdx)
	if overflow > 0 {
		res |= a.bits[arrayIdx+1] << uint(lowBitSz)
	}

	return res & ((1 << uint(size)) - 1)
}

// Bits returns the underlying array.
func (a *Array) Bits() []uint64 {
	return a.bits
}

// Reset resets the array
// to its initial state.
func (a *Array) Reset() {
	for i := range a.bits {
		a.bits[i] = 0
	}

	a.bits = a.bits[0:1]
	a.length = 0
}

// Len returns the number
// of bits stored in the array.
func (a *Array) Len() int {
	return a.length
}

// Size returns the size
// of the array in bytes.
func (a *Array) Size() int {
	return len(a.bits) * 8
}

// String returns a hexadecimal
// string representation of the array.
func (a *Array) String() string {
	buf := new(bytes.Buffer)
	for i := len(a.bits) - 1; i >= 0; i-- {
		bits := fmt.Sprintf("%16X", a.bits[i])
		bits = strings.Replace(bits, " ", "0", -1)
		fmt.Fprintf(buf, "%s [%d-%d] ", bits, (i<<6)+63, i<<6)
	}

	return buf.String()
}
<|endoftext|>


<commit_before>package appcli

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/rliebz/tusk/ui"
)

const zshInstallDir = "/usr/local/share/zsh/site-functions"

// InstallCompletions installs command line completions for a given shell.
func InstallCompletions(shell string) error {
	switch shell {
	case "bash":
		return installBashCompletion()
	case "zsh":
		return installZshCompletion(zshInstallDir)
	default:
		return fmt.Errorf("tab completion for %q is not supported", shell)
	}
}

// UninstallCompletions uninstalls command line completions for a given shell.
func UninstallCompletions(shell string) error {
	switch shell {
	case "bash":
		return uninstallBashCompletion()
	case "zsh":
		return uninstallZshCompletion(zshInstallDir)
	default:
		return fmt.Errorf("tab completion for %q is not supported", shell)
	}
}

// TODO: Write the real command
const bashCommand = `echo "Hello, world"`

var bashRCFiles = []string{".bashrc", ".bash_profile", ".profile"}

func installBashCompletion() error {
	rcfile, err := getBashRCFile()
	if err != nil {
		return err
	}

	return appendIfAbsent(rcfile, bashCommand)
}

func getBashRCFile() (string, error) {
	homedir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}

	for _, rcfile := range bashRCFiles {
		path := filepath.Join(homedir, rcfile)
		if _, err := os.Stat(path); err != nil {
			if os.IsNotExist(err) {
				continue
			}

			return "", err
		}

		return path, nil
	}

	return filepath.Join(homedir, ".bashrc"), nil
}

func appendIfAbsent(path, text string) error {
	// nolint: gosec
	f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		return err
	}
	defer f.Close() // nolint: errcheck

	scanner := bufio.NewScanner(f)

	isEmpty := true
	for scanner.Scan() {
		isEmpty = false
		if scanner.Text() == text {
			return nil
		}
	}
	if serr := scanner.Err(); serr != nil {
		return serr
	}

	if !isEmpty {
		text = "\n" + text
	}

	_, err = fmt.Fprintln(f, text)
	return err
}

func uninstallBashCompletion() error {
	rcfile, err := getBashRCFile()
	if err != nil {
		return err
	}

	return removeLineInFile(rcfile, bashCommand)
}

func removeLineInFile(path, text string) error {
	rf, err := os.OpenFile(path, os.O_RDONLY, 0644) // nolint: gosec
	if err != nil {
		return err
	}
	defer rf.Close() // nolint: errcheck

	wf, err := ioutil.TempFile("", ".profile.tusk.bkp")
	if err != nil {
		return err
	}
	defer wf.Close() // nolint: errcheck

	scanner := bufio.NewScanner(rf)

	for scanner.Scan() {
		line := scanner.Text()
		if line == text {
			continue
		}

		_, err := fmt.Fprintln(wf, line)
		if err != nil {
			return err
		}
	}

	return os.Rename(wf.Name(), path)
}

func installZshCompletion(dir string) error {
	// nolint: gosec
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}

	target := filepath.Join(dir, "_tusk")
	if err := ioutil.WriteFile(target, []byte(rawZshCompletion), 0644); err != nil {
		return err
	}

	ui.Info("zsh completions successfully installed", target)
	return nil
}

func uninstallZshCompletion(dir string) error {
	err := os.Remove(filepath.Join(dir, "_tusk"))
	if !os.IsNotExist(err) {
		return err
	}

	return nil
}
<commit_msg>Improve newline handling in completion installation<commit_after>package appcli

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/rliebz/tusk/ui"
)

const zshInstallDir = "/usr/local/share/zsh/site-functions"

// InstallCompletions installs command line completions for a given shell.
func InstallCompletions(shell string) error {
	switch shell {
	case "bash":
		return installBashCompletion()
	case "zsh":
		return installZshCompletion(zshInstallDir)
	default:
		return fmt.Errorf("tab completion for %q is not supported", shell)
	}
}

// UninstallCompletions uninstalls command line completions for a given shell.
func UninstallCompletions(shell string) error {
	switch shell {
	case "bash":
		return uninstallBashCompletion()
	case "zsh":
		return uninstallZshCompletion(zshInstallDir)
	default:
		return fmt.Errorf("tab completion for %q is not supported", shell)
	}
}

// TODO: Write the real command
const bashCommand = `echo "Hello, world"`

var bashRCFiles = []string{".bashrc", ".bash_profile", ".profile"}

func installBashCompletion() error {
	rcfile, err := getBashRCFile()
	if err != nil {
		return err
	}

	return appendIfAbsent(rcfile, bashCommand)
}

func getBashRCFile() (string, error) {
	homedir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}

	for _, rcfile := range bashRCFiles {
		path := filepath.Join(homedir, rcfile)
		if _, err := os.Stat(path); err != nil {
			if os.IsNotExist(err) {
				continue
			}

			return "", err
		}

		return path, nil
	}

	return filepath.Join(homedir, ".bashrc"), nil
}

func appendIfAbsent(path, text string) error {
	// nolint: gosec
	f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		return err
	}
	defer f.Close() // nolint: errcheck

	scanner := bufio.NewScanner(f)

	prependNewline := false
	for scanner.Scan() {
		switch scanner.Text() {
		case text:
			return nil
		case "":
			prependNewline = false
		default:
			prependNewline = true
		}
	}
	if serr := scanner.Err(); serr != nil {
		return serr
	}

	if prependNewline {
		text = "\n" + text
	}

	_, err = fmt.Fprintln(f, text)
	return err
}

func uninstallBashCompletion() error {
	rcfile, err := getBashRCFile()
	if err != nil {
		return err
	}

	return removeLineInFile(rcfile, bashCommand)
}

func removeLineInFile(path, text string) error {
	rf, err := os.OpenFile(path, os.O_RDONLY, 0644) // nolint: gosec
	if err != nil {
		return err
	}
	defer rf.Close() // nolint: errcheck

	wf, err := ioutil.TempFile("", ".profile.tusk.bkp")
	if err != nil {
		return err
	}
	defer wf.Close() // nolint: errcheck

	scanner := bufio.NewScanner(rf)

	buf := ""
	for scanner.Scan() {
		line := scanner.Text()
		switch line {
		case text:
			continue
		case "":
			buf += "\n"
			continue
		}

		_, err := fmt.Fprintln(wf, buf+line)
		if err != nil {
			return err
		}

		buf = ""
	}

	return os.Rename(wf.Name(), path)
}

func installZshCompletion(dir string) error {
	// nolint: gosec
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}

	target := filepath.Join(dir, "_tusk")
	if err := ioutil.WriteFile(target, []byte(rawZshCompletion), 0644); err != nil {
		return err
	}

	ui.Info("zsh completions successfully installed", target)
	return nil
}

func uninstallZshCompletion(dir string) error {
	err := os.Remove(filepath.Join(dir, "_tusk"))
	if !os.IsNotExist(err) {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package request

import (
	"strings"

	"github.com/admpub/nging/v5/application/library/config/subconfig/sdb"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/code"
)

var _ echo.AfterValidate = &Setup{}

type Setup struct {
	Type       string `validate:"oneof='mysql' 'sqlite'"`
	User       string `validate:""`
	Password   string `validate:""`
	Host       string `validate:"omitempty,hostname"`
	Database   string `validate:"excludesrune=',excludesall=0x60"`
	Charset    string `validate:""`
	AdminUser  string `validate:"username"`
	AdminPass  string `validate:"required,min=8,max=64"`
	AdminEmail string `validate:"required,email"`
}

func (s *Setup) AfterValidate(c echo.Context) error {
	if s.Type == `sqlite` {
		s.User = ``
		s.Password = ``
		s.Host = ``
		if !strings.HasSuffix(s.Database, `.db`) {
			s.Database += `.db`
		}
	} else {
		if len(s.Charset) == 0 {
			s.Charset = sdb.MySQLDefaultCharset
		} else {
			if !com.InSlice(s.Charset, sdb.MySQLSupportCharsetList) {
				return c.NewError(code.InvalidParameter, c.T(`字符集参数无效`)).SetZone(`charset`)
			}
		}
	}
	return nil
}
<commit_msg>update<commit_after>package request

import (
	"strings"

	"github.com/admpub/nging/v5/application/library/config/subconfig/sdb"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/code"
)

var _ echo.AfterValidate = &Setup{}

type Setup struct {
	Type       string `validate:"oneof='mysql' 'sqlite'"`
	User       string `validate:""`
	Password   string `validate:""`
	Host       string `validate:"omitempty,hostname"`
	Database   string `validate:"omitempty,alphanum_"`
	Charset    string `validate:""`
	AdminUser  string `validate:"username"`
	AdminPass  string `validate:"required,min=8,max=64"`
	AdminEmail string `validate:"required,email"`
}

func (s *Setup) AfterValidate(c echo.Context) error {
	if s.Type == `sqlite` {
		s.User = ``
		s.Password = ``
		s.Host = ``
		if !strings.HasSuffix(s.Database, `.db`) {
			s.Database += `.db`
		}
	} else {
		if len(s.Charset) == 0 {
			s.Charset = sdb.MySQLDefaultCharset
		} else {
			if !com.InSlice(s.Charset, sdb.MySQLSupportCharsetList) {
				return c.NewError(code.InvalidParameter, c.T(`字符集参数无效`)).SetZone(`charset`)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"path/filepath"
	"strings"
	"time"
)

var buildTopic = &Topic{
	Name:        "build",
	Description: "These commands are used to build the CLI. They are not intended to be used otherwise.",
	Hidden:      true,
}

var buildPluginsCmd = &Command{
	Topic:       "build",
	Command:     "plugins",
	Description: "installs core plugins",
	Hidden:      true,
	Run: func(ctx *Context) {
		pjson, err := readJSON(filepath.Join(corePlugins.Path, "package.json"))
		ExitIfError(err)
		plugins := []string{}
		for name, v := range pjson["dependencies"].(map[string]interface{}) {
			plugins = append(plugins, name+"@"+v.(string))
		}
		ExitIfError(corePlugins.installPackages(plugins...))
		for _, plugin := range plugins {
			plugin, err := corePlugins.ParsePlugin(strings.Split(plugin, "@")[0])
			ExitIfError(err)
			corePlugins.addToCache(plugin)
		}
	},
}

type Manifest struct {
	ReleasedAt string            `json:"released_at"`
	Version    string            `json:"version"`
	Channel    string            `json:"channel"`
	Builds     map[string]*Build `json:"builds"`
}
type Build struct {
	URL    string `json:"url"`
	Sha1   string `json:"sha1"`
	Sha256 string `json:"sha256"`
}

var buildManifestCmd = &Command{
	Topic:       "build",
	Command:     "manifest",
	Description: "builds manifest.json to upload to S3",
	Hidden:      true,
	Flags: []Flag{
		{Name: "dir", Char: "d", Required: true, HasValue: true},
		{Name: "version", Char: "v", Required: true, HasValue: true},
		{Name: "channel", Char: "c", Required: true, HasValue: true},
		{Name: "targets", Char: "t", Required: true, HasValue: true},
	},
	Run: func(ctx *Context) {
		manifest := &Manifest{
			ReleasedAt: time.Now().UTC().Format("2006-01-02T15:04:05Z0700"),
			Version:    ctx.Flags["version"].(string),
			Channel:    ctx.Flags["channel"].(string),
			Builds:     map[string]*Build{},
		}
		files := strings.Split(ctx.Flags["targets"].(string), ",")
		for _, file := range files {
			filename := filepath.Base(file)
			info := strings.Split(filename, "-")
			os := info[3]
			arch := info[4]
			sha1, err := fileSha1(file)
			ExitIfError(err)
			sha256, err := fileSha256(file)
			ExitIfError(err)
			manifest.Builds[os+"-"+arch] = &Build{
				URL:    "https://cli-assets.heroku.com/branches/" + manifest.Channel + "/" + manifest.Version + "/" + filename,
				Sha1:   sha1,
				Sha256: sha256,
			}
		}
		data, err := json.MarshalIndent(manifest, "", "  ")
		ExitIfError(err)
		Println(string(data))
	},
}
<commit_msg>fix manifest names<commit_after>package main

import (
	"encoding/json"
	"path/filepath"
	"regexp"
	"strings"
	"time"
)

var buildTopic = &Topic{
	Name:        "build",
	Description: "These commands are used to build the CLI. They are not intended to be used otherwise.",
	Hidden:      true,
}

var buildPluginsCmd = &Command{
	Topic:       "build",
	Command:     "plugins",
	Description: "installs core plugins",
	Hidden:      true,
	Run: func(ctx *Context) {
		pjson, err := readJSON(filepath.Join(corePlugins.Path, "package.json"))
		ExitIfError(err)
		plugins := []string{}
		for name, v := range pjson["dependencies"].(map[string]interface{}) {
			plugins = append(plugins, name+"@"+v.(string))
		}
		ExitIfError(corePlugins.installPackages(plugins...))
		for _, plugin := range plugins {
			plugin, err := corePlugins.ParsePlugin(strings.Split(plugin, "@")[0])
			ExitIfError(err)
			corePlugins.addToCache(plugin)
		}
	},
}

type Manifest struct {
	ReleasedAt string            `json:"released_at"`
	Version    string            `json:"version"`
	Channel    string            `json:"channel"`
	Builds     map[string]*Build `json:"builds"`
}
type Build struct {
	URL    string `json:"url"`
	Sha1   string `json:"sha1"`
	Sha256 string `json:"sha256"`
}

var buildManifestCmd = &Command{
	Topic:       "build",
	Command:     "manifest",
	Description: "builds manifest.json to upload to S3",
	Hidden:      true,
	Flags: []Flag{
		{Name: "dir", Char: "d", Required: true, HasValue: true},
		{Name: "version", Char: "v", Required: true, HasValue: true},
		{Name: "channel", Char: "c", Required: true, HasValue: true},
		{Name: "targets", Char: "t", Required: true, HasValue: true},
	},
	Run: func(ctx *Context) {
		manifest := &Manifest{
			ReleasedAt: time.Now().UTC().Format("2006-01-02T15:04:05Z0700"),
			Version:    ctx.Flags["version"].(string),
			Channel:    ctx.Flags["channel"].(string),
			Builds:     map[string]*Build{},
		}
		files := strings.Split(ctx.Flags["targets"].(string), ",")
		re := regexp.MustCompile(`heroku-v\d+\.\d+\.\d+-\w+-(\w+)-(\w+)\.tar.xz`)
		for _, file := range files {
			filename := filepath.Base(file)
			info := re.FindStringSubmatch(filename)
			os := info[1]
			arch := info[2]
			sha1, err := fileSha1(file)
			ExitIfError(err)
			sha256, err := fileSha256(file)
			ExitIfError(err)
			manifest.Builds[os+"-"+arch] = &Build{
				URL:    "https://cli-assets.heroku.com/branches/" + manifest.Channel + "/" + manifest.Version + "/" + filename,
				Sha1:   sha1,
				Sha256: sha256,
			}
		}
		data, err := json.MarshalIndent(manifest, "", "  ")
		ExitIfError(err)
		Println(string(data))
	},
}
<|endoftext|>


<commit_before>package main

import (
   "fmt"
   "io"
   "os"
   "time"
   "flag"
   "path"
   "os/exec"
   "math/rand"
   "path/filepath"
   "encoding/json"
   "github.com/GlenKelley/buildtools/git"
)

func main() {
   env := flags()

   groot, err := git.GitRoot()
   panicOnError(err)

   buildDir, err := mkdirRandom()
   panicOnError(err)
   defer os.RemoveAll(buildDir)

   deployDir := path.Join(os.Getenv("HOME"), "Sites")
   c, err := walkDir(groot, buildDir)
   panicOnError(err)
   err = <- c
   panicOnError(err)

   err = os.RemoveAll(deployDir)
   panicOnError(err)
   err = exec.Command("cp", "-r", buildDir, deployDir).Run()
   panicOnError(err)
   err = os.Chmod(deployDir, 0755)
   panicOnError(err)
}

func flags() string {
   envPtr := flag.String("env", "local", "environment")
   flag.Parse()
   fmt.Printf("building for environment [%s]\n", *envPtr)
   return *env
}

func mkdirRandom() (string, error) {
    randomName := fmt.Sprintf("%v", rand.Int())
    dirPath := path.Join(os.TempDir(), randomName)
    err := os.Mkdir(dirPath, os.ModeDir | os.ModeTemporary)
    err = os.Chmod(dirPath, 0755)
    return dirPath, err
}

func walkDir(srcDir string, buildDir string) (chan error, error) {
    onFinish := make(chan error)
    run := func (f ProcessFile, path string, info os.FileInfo) {
        err := f(srcDir, buildDir, path, info)
        if err != nil { fmt.Printf("%s : %s\n", path, err) }
        onFinish <- err
    }

    handlers := map[string]ProcessFile {
        ".less": compileLess,
        ".html": copyAndZip,
        ".css": copyAndZip,
        ".js": copyAndZip,
        ".jpg": copyToBuild,
        ".png": copyToBuild,
        ".gif": copyToBuild,
        ".coffee": compileCoffeeScript,
        ".json": copyAndZip,
        ".svg": copyAndZip,
        ".go": compileGo,
        ".coffeejson": compileCoffeeJson,
        ".fs": copyToBuild,
        ".vs": copyToBuild,
        ".dae": copyToBuild,
        ".DS_Store": ignore,
    }
    ignore := map[string]bool {
       ".git":true,
    }

    visited := 0
    err := filepath.Walk(srcDir, func (path string, info os.FileInfo, err error) error {
        if err != nil {
            fmt.Println(err)
            return nil
        }
        if ignore[info.Name()] { return filepath.SkipDir }
        if info.IsDir() { return nil }
        ext := filepath.Ext(info.Name())
        handler := handlers[ext]
        if handler != nil {
            visited++;
            go run(handler, path, info)
        } else {
            fmt.Printf("unknown ext %s\n", ext)
        }
        return nil
    })
    if err != nil {
        return nil, err
    }
    finished := make(chan error)
    go func(v int) {
        fail := error(nil)
        for ; v > 0; v-- {
            e := <- onFinish
            if e != nil {
               fail = e
            }
        }
        finished <- fail
    }(visited)
    return finished, nil
}

type ProcessFile func(srcDir string, buildDir string, path string, info os.FileInfo) error

func compileGo(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err := replacePathAndExtention(srcDir, buildDir, path, "")
    if err != nil { return err }

    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return err }

    cmd := exec.Command("go", "build", "-o", dest, path)
	stdout, err := cmd.StdoutPipe()
    if err != nil { return err }
	stderr, err := cmd.StderrPipe()
    if err != nil { return err }

    err = cmd.Start()
    if err != nil { return err }

    go io.Copy(os.Stdout, stdout)
    go io.Copy(os.Stdout, stderr)

	err = cmd.Wait()
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func ignore(srcDir string, buildDir string, path string, info os.FileInfo) error {
    return nil
}

func compileLess(srcDir string, buildDir string, path string, info os.FileInfo) error {
    base := filepath.Base(path)
    isChild, err := filepath.Match("_*", base)
    if err != nil { return err }
    if (!isChild) {
        dest, err := replacePathAndExtention(srcDir, buildDir, path, ".css")
        if err != nil { return err }

        dir := filepath.Dir(dest)
        err = MkdirAll(dir)
        if err != nil { return err }

        cmd := exec.Command("lessc", path)
        err = pipeCommandToFile(cmd, dest)
        if err != nil { return err }

        err = gZipFile(dest)
        if err != nil { return err }

        err = setFileTimestamp(dest, info.ModTime())
        if err != nil { return err }

        err = os.Chmod(dest, 0755)
        if err != nil { return err }
    }
    return nil
}

func writeJson(content map[string]interface{}, buildDir string, path string) error {
    dest := filepath.Join(buildDir, path)

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

    encoder := json.NewEncoder(file)
    err = encoder.Encode(content)
    if err != nil { return err }
    file.Close()

    err = gZipFile(dest)
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func compileCoffeeScript(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err := replacePathAndExtention(srcDir, buildDir, path, ".js")
    if err != nil { return err }

    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return err }

    cmd := exec.Command("coffee", "-p", path)
    err = pipeCommandToFile(cmd, dest)
    if err != nil { return err }

    err = gZipFile(dest)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func compileCoffeeJson(srcDir string, buildDir string, path string, info os.FileInfo) error {
    srcDir = filepath.Join(srcDir, "coffee")
    buildDir = filepath.Join(buildDir, "js")

    dest, err := replacePathAndExtention(srcDir, buildDir, path, ".json")
    if err != nil { return err }

    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return err }

    cmd := exec.Command("coffee", "-p", "-b", path)
    err = pipeCommandToFile(cmd, dest)
    if err != nil { return err }

    cmd = exec.Command("perl", "-pi", "-e", "s/;|\\(|\\)//g", dest)
    err = cmd.Run()
    if err != nil { return err }

    cmd = exec.Command("perl", "-pi", "-e", "s/(\\w+):/\"$1\":/g", dest)
    err = cmd.Run()
    if err != nil { return err }

    err = gZipFile(dest)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func copyToBuild(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err := copy(srcDir, buildDir, path, info)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func copyAndZip(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err:= copy(srcDir, buildDir, path, info)
    if err != nil { return err }
    err = gZipFile(dest)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func pipeCommandToFile(cmd *exec.Cmd, path string) error {
    file, err := os.Create(path)
    if err != nil { return err }
    defer file.Close()
    stdout, err := cmd.StdoutPipe()
    if err != nil { return err }
	stderr, err := cmd.StderrPipe()
    if err != nil { return err }

    err = cmd.Start()
    if err != nil { return err }

    go io.Copy(os.Stdout, stderr)

    io.Copy(file, stdout)
    return cmd.Wait()
}

func replaceBasePath(srcDir string, buildDir string, path string) (string, error) {
    relativePath, err := filepath.Rel(srcDir, path)
    if err != nil { return "", err }
    return filepath.Join(buildDir, relativePath), nil
}

func replaceExtention(path string, ext string) string {
    dir := filepath.Dir(path)
    name := nameWithoutExt(path)
    return filepath.Join(dir, name + ext)
}

func replacePathAndExtention(srcDir string, buildDir string, path string, ext string) (string, error) {
    path, err := replaceBasePath(srcDir, buildDir, path)
    if err != nil { return "", err }

    return replaceExtention(path, ext), nil
}

func copy(srcDir string, buildDir string, path string, info os.FileInfo) (string, error) {
    relativePath, err := filepath.Rel(srcDir, path)
    if err != nil { return "", err }

    dest := filepath.Join(buildDir, relativePath)
    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return "", err }

    cmd := exec.Command("cp", path, dest)
    return dest, cmd.Run()
}

func MkdirAll(path string) error {
    return os.MkdirAll(path, 0755)
}

func nameWithoutExt(path string) string {
    filename := filepath.Base(path)
    ext := filepath.Ext(path)
    return filename[0:len(filename)-len(ext)]
}

func minifyJs(jarDir, src, dest string) error {
    jarPath := filepath.Join(jarDir, "compiler.jar")
    cmd := exec.Command("java", "-jar", jarPath, "--js", src, "--js_output_file", dest, "--compilation_level", "SIMPLE_OPTIMIZATIONS")
    return cmd.Run()
}

func gZipFile(path string) error {
    err := exec.Command("gzip", "-n", path).Run()
    if err != nil { return err }
    return os.Rename(path + ".gz", path)
}

func setFileTimestamp(path string, time time.Time) error {
    return os.Chtimes(path, time, time)
}

func panicOnError (err error) {
    if err != nil { panic(err) }
}
<commit_msg>mv not copy build to deploy dir<commit_after>package main

import (
   "fmt"
   "io"
   "os"
   "time"
   "flag"
   "path"
   "os/exec"
   "math/rand"
   "path/filepath"
   "encoding/json"
   "github.com/GlenKelley/buildtools/git"
)

func main() {
   env := flags()

   groot, err := git.GitRoot()
   panicOnError(err)

   buildDir, err := mkdirRandom()
   panicOnError(err)
   defer os.RemoveAll(buildDir)

   deployDir := path.Join(os.Getenv("HOME"), "Sites")
   c, err := walkDir(groot, buildDir)
   panicOnError(err)
   err = <- c
   panicOnError(err)

   err = os.RemoveAll(deployDir)
   panicOnError(err)
   err = exec.Command("mv", buildDir, deployDir).Run()
   panicOnError(err)
}

func flags() string {
   envPtr := flag.String("env", "local", "environment")
   flag.Parse()
   fmt.Printf("building for environment [%s]\n", *envPtr)
   return *env
}

func mkdirRandom() (string, error) {
    randomName := fmt.Sprintf("%v", rand.Int())
    dirPath := path.Join(os.TempDir(), randomName)
    err := os.Mkdir(dirPath, os.ModeDir | os.ModeTemporary)
    err = os.Chmod(dirPath, 0755)
    return dirPath, err
}

func walkDir(srcDir string, buildDir string) (chan error, error) {
    onFinish := make(chan error)
    run := func (f ProcessFile, path string, info os.FileInfo) {
        err := f(srcDir, buildDir, path, info)
        if err != nil { fmt.Printf("%s : %s\n", path, err) }
        onFinish <- err
    }

    handlers := map[string]ProcessFile {
        ".less": compileLess,
        ".html": copyAndZip,
        ".css": copyAndZip,
        ".js": copyAndZip,
        ".jpg": copyToBuild,
        ".png": copyToBuild,
        ".gif": copyToBuild,
        ".coffee": compileCoffeeScript,
        ".json": copyAndZip,
        ".svg": copyAndZip,
        ".go": compileGo,
        ".coffeejson": compileCoffeeJson,
        ".fs": copyToBuild,
        ".vs": copyToBuild,
        ".dae": copyToBuild,
        ".DS_Store": ignore,
    }
    ignore := map[string]bool {
       ".git":true,
    }

    visited := 0
    err := filepath.Walk(srcDir, func (path string, info os.FileInfo, err error) error {
        if err != nil {
            fmt.Println(err)
            return nil
        }
        if ignore[info.Name()] { return filepath.SkipDir }
        if info.IsDir() { return nil }
        ext := filepath.Ext(info.Name())
        handler := handlers[ext]
        if handler != nil {
            visited++;
            go run(handler, path, info)
        } else {
            fmt.Printf("unknown ext %s\n", ext)
        }
        return nil
    })
    if err != nil {
        return nil, err
    }
    finished := make(chan error)
    go func(v int) {
        fail := error(nil)
        for ; v > 0; v-- {
            e := <- onFinish
            if e != nil {
               fail = e
            }
        }
        finished <- fail
    }(visited)
    return finished, nil
}

type ProcessFile func(srcDir string, buildDir string, path string, info os.FileInfo) error

func compileGo(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err := replacePathAndExtention(srcDir, buildDir, path, "")
    if err != nil { return err }

    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return err }

    cmd := exec.Command("go", "build", "-o", dest, path)
	stdout, err := cmd.StdoutPipe()
    if err != nil { return err }
	stderr, err := cmd.StderrPipe()
    if err != nil { return err }

    err = cmd.Start()
    if err != nil { return err }

    go io.Copy(os.Stdout, stdout)
    go io.Copy(os.Stdout, stderr)

	err = cmd.Wait()
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func ignore(srcDir string, buildDir string, path string, info os.FileInfo) error {
    return nil
}

func compileLess(srcDir string, buildDir string, path string, info os.FileInfo) error {
    base := filepath.Base(path)
    isChild, err := filepath.Match("_*", base)
    if err != nil { return err }
    if (!isChild) {
        dest, err := replacePathAndExtention(srcDir, buildDir, path, ".css")
        if err != nil { return err }

        dir := filepath.Dir(dest)
        err = MkdirAll(dir)
        if err != nil { return err }

        cmd := exec.Command("lessc", path)
        err = pipeCommandToFile(cmd, dest)
        if err != nil { return err }

        err = gZipFile(dest)
        if err != nil { return err }

        err = setFileTimestamp(dest, info.ModTime())
        if err != nil { return err }

        err = os.Chmod(dest, 0755)
        if err != nil { return err }
    }
    return nil
}

func writeJson(content map[string]interface{}, buildDir string, path string) error {
    dest := filepath.Join(buildDir, path)

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

    encoder := json.NewEncoder(file)
    err = encoder.Encode(content)
    if err != nil { return err }
    file.Close()

    err = gZipFile(dest)
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func compileCoffeeScript(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err := replacePathAndExtention(srcDir, buildDir, path, ".js")
    if err != nil { return err }

    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return err }

    cmd := exec.Command("coffee", "-p", path)
    err = pipeCommandToFile(cmd, dest)
    if err != nil { return err }

    err = gZipFile(dest)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func compileCoffeeJson(srcDir string, buildDir string, path string, info os.FileInfo) error {
    srcDir = filepath.Join(srcDir, "coffee")
    buildDir = filepath.Join(buildDir, "js")

    dest, err := replacePathAndExtention(srcDir, buildDir, path, ".json")
    if err != nil { return err }

    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return err }

    cmd := exec.Command("coffee", "-p", "-b", path)
    err = pipeCommandToFile(cmd, dest)
    if err != nil { return err }

    cmd = exec.Command("perl", "-pi", "-e", "s/;|\\(|\\)//g", dest)
    err = cmd.Run()
    if err != nil { return err }

    cmd = exec.Command("perl", "-pi", "-e", "s/(\\w+):/\"$1\":/g", dest)
    err = cmd.Run()
    if err != nil { return err }

    err = gZipFile(dest)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func copyToBuild(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err := copy(srcDir, buildDir, path, info)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func copyAndZip(srcDir string, buildDir string, path string, info os.FileInfo) error {
    dest, err:= copy(srcDir, buildDir, path, info)
    if err != nil { return err }
    err = gZipFile(dest)
    if err != nil { return err }

    err = setFileTimestamp(dest, info.ModTime())
    if err != nil { return err }

    err = os.Chmod(dest, 0755)
    if err != nil { return err }

    return nil
}

func pipeCommandToFile(cmd *exec.Cmd, path string) error {
    file, err := os.Create(path)
    if err != nil { return err }
    defer file.Close()
    stdout, err := cmd.StdoutPipe()
    if err != nil { return err }
	stderr, err := cmd.StderrPipe()
    if err != nil { return err }

    err = cmd.Start()
    if err != nil { return err }

    go io.Copy(os.Stdout, stderr)

    io.Copy(file, stdout)
    return cmd.Wait()
}

func replaceBasePath(srcDir string, buildDir string, path string) (string, error) {
    relativePath, err := filepath.Rel(srcDir, path)
    if err != nil { return "", err }
    return filepath.Join(buildDir, relativePath), nil
}

func replaceExtention(path string, ext string) string {
    dir := filepath.Dir(path)
    name := nameWithoutExt(path)
    return filepath.Join(dir, name + ext)
}

func replacePathAndExtention(srcDir string, buildDir string, path string, ext string) (string, error) {
    path, err := replaceBasePath(srcDir, buildDir, path)
    if err != nil { return "", err }

    return replaceExtention(path, ext), nil
}

func copy(srcDir string, buildDir string, path string, info os.FileInfo) (string, error) {
    relativePath, err := filepath.Rel(srcDir, path)
    if err != nil { return "", err }

    dest := filepath.Join(buildDir, relativePath)
    dir := filepath.Dir(dest)
    err = MkdirAll(dir)
    if err != nil { return "", err }

    cmd := exec.Command("cp", path, dest)
    return dest, cmd.Run()
}

func MkdirAll(path string) error {
    return os.MkdirAll(path, 0755)
}

func nameWithoutExt(path string) string {
    filename := filepath.Base(path)
    ext := filepath.Ext(path)
    return filename[0:len(filename)-len(ext)]
}

func minifyJs(jarDir, src, dest string) error {
    jarPath := filepath.Join(jarDir, "compiler.jar")
    cmd := exec.Command("java", "-jar", jarPath, "--js", src, "--js_output_file", dest, "--compilation_level", "SIMPLE_OPTIMIZATIONS")
    return cmd.Run()
}

func gZipFile(path string) error {
    err := exec.Command("gzip", "-n", path).Run()
    if err != nil { return err }
    return os.Rename(path + ".gz", path)
}

func setFileTimestamp(path string, time time.Time) error {
    return os.Chtimes(path, time, time)
}

func panicOnError (err error) {
    if err != nil { panic(err) }
}
<|endoftext|>


<commit_before>package socketio

import (
	"bytes"
	"net"
	"io"
	"fmt"
	"http"
	"os"
	"strings"
	"sync"
)

// SocketIO handles transport abstraction and provide the user
// a handfull of callbacks to observe different events.
type SocketIO struct {
	sessions        map[SessionID]*Conn // Holds the outstanding sessions.
	sessionsLock    *sync.RWMutex       // Protects the sessions.
	config          Config              // Holds the configuration values.
	serveMux        *ServeMux
	transportLookup map[string]Transport

	// The callbacks set by the user
	callbacks struct {
		onConnect    func(*Conn)          // Invoked on new connection.
		onDisconnect func(*Conn)          // Invoked on a lost connection.
		onMessage    func(*Conn, Message) // Invoked on a message.
	}
}

// NewSocketIO creates a new socketio server with chosen transports and configuration
// options. If transports is nil, the DefaultTransports is used. If config is nil, the
// DefaultConfig is used.
func NewSocketIO(config *Config) *SocketIO {
	if config == nil {
		config = &DefaultConfig
	}

	sio := &SocketIO{
		config:          *config,
		sessions:        make(map[SessionID]*Conn),
		sessionsLock:    new(sync.RWMutex),
		transportLookup: make(map[string]Transport),
	}

	for _, t := range sio.config.Transports {
		sio.transportLookup[t.Resource()] = t
	}

	sio.serveMux = NewServeMux(sio)

	return sio
}

// Broadcast schedules data to be sent to each connection.
func (sio *SocketIO) Broadcast(data interface{}) {
	sio.BroadcastExcept(nil, data)
}

// BroadcastExcept schedules data to be sent to each connection except
// c. It does not care about the type of data, but it must marshallable
// by the standard json-package.
func (sio *SocketIO) BroadcastExcept(c *Conn, data interface{}) {
	sio.sessionsLock.RLock()
	defer sio.sessionsLock.RUnlock()

	for _, v := range sio.sessions {
		if v != c {
			v.Send(data)
		}
	}
}

// GetConn digs for a session with sessionid and returns it.
func (sio *SocketIO) GetConn(sessionid SessionID) (c *Conn) {
	sio.sessionsLock.RLock()
	c = sio.sessions[sessionid]
	sio.sessionsLock.RUnlock()
	return
}

// Mux maps resources to the http.ServeMux mux under the resource given.
// The resource must end with a slash and if the mux is nil, the
// http.DefaultServeMux is used. It registers handlers for URLs like:
// <resource><t.resource>[/], e.g. /socket.io/websocket && socket.io/websocket/.
func (sio *SocketIO) ServeMux() *ServeMux {
	return sio.serveMux
}

// OnConnect sets f to be invoked when a new session is established. It passes
// the established connection as an argument to the callback.
func (sio *SocketIO) OnConnect(f func(*Conn)) os.Error {
	sio.callbacks.onConnect = f
	return nil
}

// OnDisconnect sets f to be invoked when a session is considered to be lost. It passes
// the established connection as an argument to the callback. After disconnection
// the connection is considered to be destroyed, and it should not be used anymore.
func (sio *SocketIO) OnDisconnect(f func(*Conn)) os.Error {
	sio.callbacks.onDisconnect = f
	return nil
}

// OnMessage sets f to be invoked when a message arrives. It passes
// the established connection along with the received message as arguments
// to the callback.
func (sio *SocketIO) OnMessage(f func(*Conn, Message)) os.Error {
	sio.callbacks.onMessage = f
	return nil
}

func (sio *SocketIO) Log(v ...interface{}) {
	if sio.config.Logger != nil {
		sio.config.Logger.Println(v...)
	}
}

func (sio *SocketIO) Logf(format string, v ...interface{}) {
	if sio.config.Logger != nil {
		sio.config.Logger.Printf(format, v...)
	}
}

// Handle is invoked on every http-request coming through the muxer.
// It is responsible for parsing the request and passing the http conn/req -pair
// to the corresponding sio connections. It also creates new connections when needed.
// The URL and method must be one of the following:
//
// OPTIONS *
//     GET resource
//     GET resource/sessionid
//    POST resource/sessionid
func (sio *SocketIO) handle(t Transport, w http.ResponseWriter, req *http.Request) {
	var parts []string
	var c *Conn
	var err os.Error

	if origin := req.Header.Get("Origin"); origin != "" {
		if _, ok := sio.verifyOrigin(origin); !ok {
			sio.Log("sio/handle: unauthorized origin:", origin)
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		w.Header().Set("Access-Control-Allow-Origin", origin)
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET")
	}

	switch req.Method {
	case "OPTIONS":
		w.WriteHeader(http.StatusOK)
		return

	case "GET", "POST":
		break

	default:
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	// TODO: fails if the session id matches the transport
	if i := strings.LastIndex(req.URL.Path, t.Resource()); i >= 0 {
		pathLen := len(req.URL.Path)
		if req.URL.Path[pathLen-1] == '/' {
			pathLen--
		}

		parts = strings.Split(req.URL.Path[i:pathLen], "/")
	}

	if len(parts) < 2 || parts[1] == "" {
		c, err = newConn(sio)
		if err != nil {
			sio.Log("sio/handle: unable to create a new connection:", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	} else {
		c = sio.GetConn(SessionID(parts[1]))
	}

	// we should now have a connection
	if c == nil {
		sio.Log("sio/handle: unable to map request to connection:", req.RawURL)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// pass the http conn/req pair to the connection
	if err = c.handle(t, w, req); err != nil {
		sio.Logf("sio/handle: conn/handle: %s: %s", c, err)
		w.WriteHeader(http.StatusUnauthorized)
	}
}

// OnConnect is invoked by a connection when a new connection has been
// established succesfully. The establised connection is passed as an
// argument. It stores the connection and calls the user's OnConnect callback.
func (sio *SocketIO) onConnect(c *Conn) {
	sio.sessionsLock.Lock()
	sio.sessions[c.sessionid] = c
	sio.sessionsLock.Unlock()

	if sio.callbacks.onConnect != nil {
		sio.callbacks.onConnect(c)
	}
}

// OnDisconnect is invoked by a connection when the connection is considered
// to be lost. It removes the connection and calls the user's OnDisconnect callback.
func (sio *SocketIO) onDisconnect(c *Conn) {
	sio.sessionsLock.Lock()
	sio.sessions[c.sessionid] = nil, false
	sio.sessionsLock.Unlock()

	if sio.callbacks.onDisconnect != nil {
		sio.callbacks.onDisconnect(c)
	}
}

// OnMessage is invoked by a connection when a new message arrives. It passes
// this message to the user's OnMessage callback.
func (sio *SocketIO) onMessage(c *Conn, msg Message) {
	if sio.callbacks.onMessage != nil {
		sio.callbacks.onMessage(c, msg)
	}
}

func (sio *SocketIO) verifyOrigin(reqOrigin string) (string, bool) {
	if sio.config.Origins == nil {
		return "", false
	}

	url, err := http.ParseURL(reqOrigin)
	if err != nil || url.Host == "" {
		return "", false
	}

	host := strings.SplitN(url.Host, ":", 2)

	for _, o := range sio.config.Origins {
		origin := strings.SplitN(o, ":", 2)
		if origin[0] == "*" || origin[0] == host[0] {
			if len(origin) < 2 || origin[1] == "*" {
				return o, true
			}
			if len(host) < 2 {
				switch url.Scheme {
				case "http", "ws":
					if origin[1] == "80" {
						return o, true
					}

				case "https", "wss":
					if origin[1] == "443" {
						return o, true
					}
				}
			} else if origin[1] == host[1] {
				return o, true
			}
		}
	}

	return "", false
}

func (sio *SocketIO) generatePolicyFile() []byte {
	buf := new(bytes.Buffer)
	buf.WriteString(`<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="master-only" />
`)

	if sio.config.Origins != nil {
		for _, origin := range sio.config.Origins {
			parts := strings.SplitN(origin, ":", 2)
			if len(parts) < 1 {
				continue
			}
			host, port := "*", "*"
			if parts[0] != "" {
				host = parts[0]
			}
			if len(parts) == 2 && parts[1] != "" {
				port = parts[1]
			}

			fmt.Fprintf(buf, "\t<allow-access-from domain=\"%s\" to-ports=\"%s\" />\n", host, port)
		}
	}

	buf.WriteString("</cross-domain-policy>\n")
	return buf.Bytes()
}

func (sio *SocketIO) ListenAndServeFlashPolicy(laddr string) os.Error {
	var listener net.Listener

	listener, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}

	policy := sio.generatePolicyFile()

	for {
		conn, err := listener.Accept()
		if err != nil {
			sio.Log("ServeFlashsocketPolicy:", err)
			continue
		}

		go func() {
			defer conn.Close()

			buf := make([]byte, 20)
			if _, err := io.ReadFull(conn, buf); err != nil {
				sio.Log("ServeFlashsocketPolicy:", err)
				return
			}
			if !bytes.Equal([]byte("<policy-file-request"), buf) {
				sio.Logf("ServeFlashsocketPolicy: expected \"<policy-file-request\" but got %q", buf)
				return
			}

			var nw int
			for nw < len(policy) {
				n, err := conn.Write(policy[nw:])
				if err != nil && err != os.EAGAIN {
					sio.Log("ServeFlashsocketPolicy:", err)
					return
				}
				if n > 0 {
					nw += n
					continue
				} else {
					sio.Log("ServeFlashsocketPolicy: wrote 0 bytes")
					return
				}
			}
			sio.Log("ServeFlashsocketPolicy: served", conn.RemoteAddr())
		}()
	}

	return nil
}
<commit_msg>extracted isAuthorized() hook into new branch<commit_after>package socketio

import (
	"bytes"
	"net"
	"io"
	"fmt"
	"http"
	"os"
	"strings"
	"sync"
)

// SocketIO handles transport abstraction and provide the user
// a handfull of callbacks to observe different events.
type SocketIO struct {
	sessions        map[SessionID]*Conn // Holds the outstanding sessions.
	sessionsLock    *sync.RWMutex       // Protects the sessions.
	config          Config              // Holds the configuration values.
	serveMux        *ServeMux
	transportLookup map[string]Transport

	// The callbacks set by the user
	callbacks struct {
		onConnect    func(*Conn)              // Invoked on new connection.
		onDisconnect func(*Conn)              // Invoked on a lost connection.
		onMessage    func(*Conn, Message)     // Invoked on a message.
		isAuthorized func(*http.Request) bool // Auth test during new http request
	}
}

// NewSocketIO creates a new socketio server with chosen transports and configuration
// options. If transports is nil, the DefaultTransports is used. If config is nil, the
// DefaultConfig is used.
func NewSocketIO(config *Config) *SocketIO {
	if config == nil {
		config = &DefaultConfig
	}

	sio := &SocketIO{
		config:          *config,
		sessions:        make(map[SessionID]*Conn),
		sessionsLock:    new(sync.RWMutex),
		transportLookup: make(map[string]Transport),
	}

	for _, t := range sio.config.Transports {
		sio.transportLookup[t.Resource()] = t
	}

	sio.serveMux = NewServeMux(sio)

	return sio
}

// Broadcast schedules data to be sent to each connection.
func (sio *SocketIO) Broadcast(data interface{}) {
	sio.BroadcastExcept(nil, data)
}

// BroadcastExcept schedules data to be sent to each connection except
// c. It does not care about the type of data, but it must marshallable
// by the standard json-package.
func (sio *SocketIO) BroadcastExcept(c *Conn, data interface{}) {
	sio.sessionsLock.RLock()
	defer sio.sessionsLock.RUnlock()

	for _, v := range sio.sessions {
		if v != c {
			v.Send(data)
		}
	}
}

// GetConn digs for a session with sessionid and returns it.
func (sio *SocketIO) GetConn(sessionid SessionID) (c *Conn) {
	sio.sessionsLock.RLock()
	c = sio.sessions[sessionid]
	sio.sessionsLock.RUnlock()
	return
}

// Mux maps resources to the http.ServeMux mux under the resource given.
// The resource must end with a slash and if the mux is nil, the
// http.DefaultServeMux is used. It registers handlers for URLs like:
// <resource><t.resource>[/], e.g. /socket.io/websocket && socket.io/websocket/.
func (sio *SocketIO) ServeMux() *ServeMux {
	return sio.serveMux
}

// OnConnect sets f to be invoked when a new session is established. It passes
// the established connection as an argument to the callback.
func (sio *SocketIO) OnConnect(f func(*Conn)) os.Error {
	sio.callbacks.onConnect = f
	return nil
}

// OnDisconnect sets f to be invoked when a session is considered to be lost. It passes
// the established connection as an argument to the callback. After disconnection
// the connection is considered to be destroyed, and it should not be used anymore.
func (sio *SocketIO) OnDisconnect(f func(*Conn)) os.Error {
	sio.callbacks.onDisconnect = f
	return nil
}

// OnMessage sets f to be invoked when a message arrives. It passes
// the established connection along with the received message as arguments
// to the callback.
func (sio *SocketIO) OnMessage(f func(*Conn, Message)) os.Error {
	sio.callbacks.onMessage = f
	return nil
}

// SetAuthorization sets f to be invoked when a new http request is made. It passes
// the http.Request as an argument to the callback.
// The callback should return true if the connection is authorized or false if it
// should be dropped. Not setting this callback results in a default pass-through.
func (sio *SocketIO) SetAuthorization(f func(*http.Request) bool) os.Error {
	sio.callbacks.isAuthorized = f
	return nil
}

func (sio *SocketIO) Log(v ...interface{}) {
	if sio.config.Logger != nil {
		sio.config.Logger.Println(v...)
	}
}

func (sio *SocketIO) Logf(format string, v ...interface{}) {
	if sio.config.Logger != nil {
		sio.config.Logger.Printf(format, v...)
	}
}

// Handle is invoked on every http-request coming through the muxer.
// It is responsible for parsing the request and passing the http conn/req -pair
// to the corresponding sio connections. It also creates new connections when needed.
// The URL and method must be one of the following:
//
// OPTIONS *
//     GET resource
//     GET resource/sessionid
//    POST resource/sessionid
func (sio *SocketIO) handle(t Transport, w http.ResponseWriter, req *http.Request) {
	var parts []string
	var c *Conn
	var err os.Error

	if !sio.isAuthorized(req) {
		sio.Log("sio/handle: unauthorized request:", req)
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	if origin := req.Header.Get("Origin"); origin != "" {
		if _, ok := sio.verifyOrigin(origin); !ok {
			sio.Log("sio/handle: unauthorized origin:", origin)
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		w.Header().Set("Access-Control-Allow-Origin", origin)
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET")
	}

	switch req.Method {
	case "OPTIONS":
		w.WriteHeader(http.StatusOK)
		return

	case "GET", "POST":
		break

	default:
		w.WriteHeader(http.StatusUnauthorized)
		return
	}

	// TODO: fails if the session id matches the transport
	if i := strings.LastIndex(req.URL.Path, t.Resource()); i >= 0 {
		pathLen := len(req.URL.Path)
		if req.URL.Path[pathLen-1] == '/' {
			pathLen--
		}

		parts = strings.Split(req.URL.Path[i:pathLen], "/")
	}

	if len(parts) < 2 || parts[1] == "" {
		c, err = newConn(sio)
		if err != nil {
			sio.Log("sio/handle: unable to create a new connection:", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	} else {
		c = sio.GetConn(SessionID(parts[1]))
	}

	// we should now have a connection
	if c == nil {
		sio.Log("sio/handle: unable to map request to connection:", req.RawURL)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// pass the http conn/req pair to the connection
	if err = c.handle(t, w, req); err != nil {
		sio.Logf("sio/handle: conn/handle: %s: %s", c, err)
		w.WriteHeader(http.StatusUnauthorized)
	}
}

// OnConnect is invoked by a connection when a new connection has been
// established succesfully. The establised connection is passed as an
// argument. It stores the connection and calls the user's OnConnect callback.
func (sio *SocketIO) onConnect(c *Conn) {
	sio.sessionsLock.Lock()
	sio.sessions[c.sessionid] = c
	sio.sessionsLock.Unlock()

	if sio.callbacks.onConnect != nil {
		sio.callbacks.onConnect(c)
	}
}

// OnDisconnect is invoked by a connection when the connection is considered
// to be lost. It removes the connection and calls the user's OnDisconnect callback.
func (sio *SocketIO) onDisconnect(c *Conn) {
	sio.sessionsLock.Lock()
	sio.sessions[c.sessionid] = nil, false
	sio.sessionsLock.Unlock()

	if sio.callbacks.onDisconnect != nil {
		sio.callbacks.onDisconnect(c)
	}
}

// OnMessage is invoked by a connection when a new message arrives. It passes
// this message to the user's OnMessage callback.
func (sio *SocketIO) onMessage(c *Conn, msg Message) {
	if sio.callbacks.onMessage != nil {
		sio.callbacks.onMessage(c, msg)
	}
}

// isAuthorized is called during the handle() of any new http request
// If the user has set a callback, this is a hook for returning whether
// the connection is authorized. If no callback has been set, this method
// always returns true as a pass-through
func (sio *SocketIO) isAuthorized(req *http.Request) bool {
	if sio.callbacks.isAuthorized != nil {
		return sio.callbacks.isAuthorized(req)
	}
	return true
}

func (sio *SocketIO) verifyOrigin(reqOrigin string) (string, bool) {
	if sio.config.Origins == nil {
		return "", false
	}

	url, err := http.ParseURL(reqOrigin)
	if err != nil || url.Host == "" {
		return "", false
	}

	host := strings.SplitN(url.Host, ":", 2)

	for _, o := range sio.config.Origins {
		origin := strings.SplitN(o, ":", 2)
		if origin[0] == "*" || origin[0] == host[0] {
			if len(origin) < 2 || origin[1] == "*" {
				return o, true
			}
			if len(host) < 2 {
				switch url.Scheme {
				case "http", "ws":
					if origin[1] == "80" {
						return o, true
					}

				case "https", "wss":
					if origin[1] == "443" {
						return o, true
					}
				}
			} else if origin[1] == host[1] {
				return o, true
			}
		}
	}

	return "", false
}

func (sio *SocketIO) generatePolicyFile() []byte {
	buf := new(bytes.Buffer)
	buf.WriteString(`<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="master-only" />
`)

	if sio.config.Origins != nil {
		for _, origin := range sio.config.Origins {
			parts := strings.SplitN(origin, ":", 2)
			if len(parts) < 1 {
				continue
			}
			host, port := "*", "*"
			if parts[0] != "" {
				host = parts[0]
			}
			if len(parts) == 2 && parts[1] != "" {
				port = parts[1]
			}

			fmt.Fprintf(buf, "\t<allow-access-from domain=\"%s\" to-ports=\"%s\" />\n", host, port)
		}
	}

	buf.WriteString("</cross-domain-policy>\n")
	return buf.Bytes()
}

func (sio *SocketIO) ListenAndServeFlashPolicy(laddr string) os.Error {
	var listener net.Listener

	listener, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}

	policy := sio.generatePolicyFile()

	for {
		conn, err := listener.Accept()
		if err != nil {
			sio.Log("ServeFlashsocketPolicy:", err)
			continue
		}

		go func() {
			defer conn.Close()

			buf := make([]byte, 20)
			if _, err := io.ReadFull(conn, buf); err != nil {
				sio.Log("ServeFlashsocketPolicy:", err)
				return
			}
			if !bytes.Equal([]byte("<policy-file-request"), buf) {
				sio.Logf("ServeFlashsocketPolicy: expected \"<policy-file-request\" but got %q", buf)
				return
			}

			var nw int
			for nw < len(policy) {
				n, err := conn.Write(policy[nw:])
				if err != nil && err != os.EAGAIN {
					sio.Log("ServeFlashsocketPolicy:", err)
					return
				}
				if n > 0 {
					nw += n
					continue
				} else {
					sio.Log("ServeFlashsocketPolicy: wrote 0 bytes")
					return
				}
			}
			sio.Log("ServeFlashsocketPolicy: served", conn.RemoteAddr())
		}()
	}

	return nil
}<|endoftext|>


<commit_before><commit_msg>remove: meta_key<commit_after><|endoftext|>


<commit_before><commit_msg>Remove internal pad functions (moved up to netlink)<commit_after><|endoftext|>


<commit_before>package modules

import (
	"fmt"
	"text/template"

	"bytes"

	"go/format"

	"github.com/cihangir/gene/generators/common"
	"github.com/cihangir/gene/writers"
	"github.com/cihangir/schema"
	"github.com/cihangir/stringext"
)

// GenerateMainFile handles the main file generation for persistent
// connection rpc server
func (m *Module) GenerateMainFile(rootPath string) error {

	moduleName := stringext.ToLowerFirst(
		m.schema.Title,
	)

	mainFilePath := fmt.Sprintf(
		"%s/%s/main.go",
		rootPath,
		fmt.Sprintf(moduleFolderStucture[0], moduleName),
	)

	f, err := generateMainFile(m.schema)
	if err != nil {
		return err
	}

	return writers.WriteFormattedFile(mainFilePath, f)
}

func generateMainFile(s *schema.Schema) ([]byte, error) {
	const templateName = "mainfile.tmpl"
	temp := template.New(templateName).Funcs(common.TemplateFuncs)

	if _, err := temp.Parse(MainFileTemplate); err != nil {
		return nil, err
	}

	var buf bytes.Buffer

	if err := temp.ExecuteTemplate(&buf, templateName, s); err != nil {
		return nil, err
	}

	return format.Source(buf.Bytes())
}

// MainFileTemplate holds the template for the main file generation
var MainFileTemplate = `
package main

import (
	"fmt"
	"net/http"
	"github.com/youtube/vitess/go/rpcplus"
	"github.com/youtube/vitess/go/rpcplus/jsonrpc"
	"github.com/youtube/vitess/go/rpcwrap"
)

var (
	Name    = "{{.Title}}"
	VERSION string
)

var ContextCreator = func(req *http.Request) context.Context {
	return context.Background()
}

var Mux = http.NewServeMux()

func main() {

	{{$Name := .Title}}
	server := rpcplus.NewServer()
	{{range $key, $value := .Definitions}}
		{{$type := .Type}}
		{{/* export functions if they have any exported function */}}
		{{if len .Functions}}
			{{if Equal $type "object"}}
				server.Register(new({{ToLower $Name}}api.{{$key}}))
			{{end}}
		{{end}}
	{{end}}

	rpcwrap.ServeCustomRPC(
		Mux,
		server,
		false,  // use auth
		"json", // codec name
		jsonrpc.NewServerCodec,
	)

	rpcwrap.ServeHTTPRPC(
		Mux,                    // httpmuxer
		server,                 // rpcserver
		"http_json",            // codec name
		jsonrpc.NewServerCodec, // jsoncodec
		ContextCreator,         // contextCreator
	)

	fmt.Println("Server listening on 3000")
	http.ListenAndServe("localhost:3000", Mux)
}`
<commit_msg>Generator: added doc<commit_after>package modules

import (
	"fmt"
	"text/template"

	"bytes"

	"go/format"

	"github.com/cihangir/gene/generators/common"
	"github.com/cihangir/gene/writers"
	"github.com/cihangir/schema"
	"github.com/cihangir/stringext"
)

// GenerateMainFile handles the main file generation for persistent
// connection rpc server
func (m *Module) GenerateMainFile(rootPath string) error {

	moduleName := stringext.ToLowerFirst(
		m.schema.Title,
	)

	mainFilePath := fmt.Sprintf(
		"%s/%s/main.go",
		rootPath,
		fmt.Sprintf(moduleFolderStucture[0], moduleName),
	)

	f, err := generateMainFile(m.schema)
	if err != nil {
		return err
	}

	return writers.WriteFormattedFile(mainFilePath, f)
}

func generateMainFile(s *schema.Schema) ([]byte, error) {
	const templateName = "mainfile.tmpl"
	temp := template.New(templateName).Funcs(common.TemplateFuncs)

	if _, err := temp.Parse(MainFileTemplate); err != nil {
		return nil, err
	}

	var buf bytes.Buffer

	if err := temp.ExecuteTemplate(&buf, templateName, s); err != nil {
		return nil, err
	}

	return format.Source(buf.Bytes())
}

// MainFileTemplate holds the template for the main file generation
var MainFileTemplate = `
package main

import (
	"fmt"
	"net/http"
	"github.com/youtube/vitess/go/rpcplus"
	"github.com/youtube/vitess/go/rpcplus/jsonrpc"
	"github.com/youtube/vitess/go/rpcwrap"
)

var (
	Name    = "{{.Title}}"
	VERSION string
)

var ContextCreator = func(req *http.Request) context.Context {
	return context.Background()
}

var Mux = http.NewServeMux()

func main() {

	{{$Name := .Title}}
	server := rpcplus.NewServer()
	{{range $key, $value := .Definitions}}
		{{$type := .Type}}
		{{/* export functions if they have any exported function */}}
		{{if len .Functions}}
			{{/* export functions if they are objects */}}
			{{if Equal $type "object"}}
				server.Register(new({{ToLower $Name}}api.{{$key}}))
			{{end}}
		{{end}}
	{{end}}

	rpcwrap.ServeCustomRPC(
		Mux,
		server,
		false,  // use auth
		"json", // codec name
		jsonrpc.NewServerCodec,
	)

	rpcwrap.ServeHTTPRPC(
		Mux,                    // httpmuxer
		server,                 // rpcserver
		"http_json",            // codec name
		jsonrpc.NewServerCodec, // jsoncodec
		ContextCreator,         // contextCreator
	)

	fmt.Println("Server listening on 3000")
	http.ListenAndServe("localhost:3000", Mux)
}`
<|endoftext|>