<commit_before>package server

import (
	jnet "junta/net"
	"junta/paxos"
	"junta/proto"
	"junta/store"
	"junta/util"
	"net"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"
)

const packetSize = 3000

const lease = 3e9 // ns == 3s

var ErrBadPrefix = os.NewError("bad prefix in path")

type conn struct {
	*proto.Conn
	c   net.Conn
	s   *Server
	cal bool
}

type Manager interface {
	paxos.Proposer
	PutFrom(string, paxos.Msg)
	Alpha() int
}

type Server struct {
	Addr         string
	St           *store.Store
	Mg           Manager
	Self, Prefix string
}

func (sv *Server) ListenAndServeUdp(outs chan paxos.Packet) os.Error {
	logger := util.NewLogger("udp server %s", sv.Addr)

	logger.Println("binding")
	u, err := net.ListenPacket("udp", sv.Addr)
	if err != nil {
		logger.Println(err)
		return err
	}
	defer u.Close()
	logger.Println("listening")

	err = sv.ServeUdp(u, outs)
	if err != nil {
		logger.Printf("%s: %s", u, err)
	}
	return err
}

func (sv *Server) ServeUdp(u jnet.Conn, outs chan paxos.Packet) os.Error {
	r := jnet.Ackify(u, outs)

	for p := range r {
		sv.Mg.PutFrom(p.Addr, p.Msg)
	}

	panic("unreachable")
}

var clg = util.NewLogger("cal")

func (s *Server) Serve(l net.Listener, cal chan int) os.Error {
	var ok bool
	for {
		if !ok {
			_, ok = <-cal
		}
		clg.Println(ok)

		rw, e := l.Accept()
		if e != nil {
			return e
		}
		c := &conn{proto.NewConn(rw), rw, s, ok}
		go c.serve()
	}

	panic("unreachable")
}

func (sv *Server) leader() string {
	parts, cas := sv.St.Get("/junta/leader")
	if cas == store.Dir && cas == store.Missing {
		return ""
	}
	return parts[0]
}

func (sv *Server) addrFor(id string) string {
	parts, cas := sv.St.Get("/junta/members/" + id)
	if cas == store.Dir && cas == store.Missing {
		return ""
	}
	return parts[0]
}

// Checks that path begins with the proper prefix and returns the short path
// without the prefix.
func (sv *Server) checkPath(path string) (string, os.Error) {
	logger := util.NewLogger("checkPath")
	if !strings.HasPrefix(path, sv.Prefix+"/") {
		logger.Printf("prefix %q not in %q", sv.Prefix+"/", path)
		return "", ErrBadPrefix
	}
	return path[len(sv.Prefix):], nil
}

// Repeatedly propose nop values until a successful read from `done`.
func (sv *Server) AdvanceUntil(done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		sv.Mg.Propose(store.Nop)
	}
}

func (c *conn) redirect(rid uint) {
	leader := c.s.leader()
	addr := c.s.addrFor(leader)
	if addr == "" {
		c.SendError(rid, "unknown address for leader")
	} else {
		c.SendRedirect(rid, addr)
	}
}

func get(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqGet)
	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return nil, err
	}

	v, cas := s.St.Get(shortPath)
	return []interface{}{v, cas}, nil
}

func sget(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqGet)
	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return "", err
	}

	body, err := store.GetString(s.St.SyncPath(shortPath), shortPath), nil
	if err != nil {
		return nil, err
	}

	return []interface{}{body}, nil
}

func set(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqSet)

	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return nil, err
	}

	seqn, _, err := paxos.Set(s.Mg, shortPath, r.Body, r.Cas)
	if err != nil {
		return nil, err
	}
	return []interface{}{strconv.Uitoa64(seqn)}, nil
}

func del(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqDel)

	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return 0, err
	}

	_, err = paxos.Del(s.Mg, shortPath, r.Cas)
	if err != nil {
		return nil, err
	}

	return []interface{}{"true"}, nil
}

func nop(s *Server, data interface{}) (interface{}, os.Error) {
	s.Mg.Propose(store.Nop)
	return []interface{}{"true"}, nil
}

func join(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqJoin)
	key := "/junta/members/" + r.Who
	seqn, _, err := paxos.Set(s.Mg, key, r.Addr, store.Missing)
	if err != nil {
		return nil, err
	}

	done := make(chan int)
	go s.AdvanceUntil(done)
	s.St.Sync(seqn + uint64(s.Mg.Alpha()))
	close(done)
	seqn, snap := s.St.Snapshot()
	return []interface{}{strconv.Uitoa64(seqn), snap}, nil
}

func checkin(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqCheckin)
	t := time.Nanoseconds() + lease
	_, cas, err := paxos.Set(s.Mg, "/session/"+r.Sid, strconv.Itoa64(t), r.Cas)
	if err != nil {
		return nil, err
	}
	return []interface{}{strconv.Itoa64(t), cas}, nil
}

func indirect(x interface{}) interface{} {
	return reflect.Indirect(reflect.NewValue(x)).Interface()
}

type handler func(*Server, interface{}) (interface{}, os.Error)

type op struct {
	p interface{}
	f handler

	redirect bool
}

var ops = map[string]op{
	"get":{p:new(*proto.ReqGet), f:get},
	"sget":{p:new(*proto.ReqGet), f:sget},
	"set":{p:new(*proto.ReqSet), f:set, redirect:true},
	"del":{p:new(*proto.ReqDel), f:del, redirect:true},
	"nop":{p:new(*[]interface{}), f:nop, redirect:true},
	"join":{p:new(*proto.ReqJoin), f:join, redirect:true},
	"checkin":{p:new(*proto.ReqCheckin), f:checkin, redirect:true},
}

func (c *conn) handle(rid uint, f handler, data interface{}) {
	res, err := f(c.s, data)
	if err != nil {
		c.SendError(rid, err.String())
	} else {
		c.SendResponse(rid, res)
	}
}

func (c *conn) serve() {
	logger := util.NewLogger("%v", c.c.RemoteAddr())
	logger.Println("accepted connection")
	for {
		rid, verb, data, err := c.ReadRequest()
		if err != nil {
			if err == os.EOF {
				logger.Println("connection closed by peer")
			} else {
				logger.Println(err)
			}
			return
		}

		rlogger := util.NewLogger("%v - req [%d]", c.c.RemoteAddr(), rid)

		if o, ok := ops[verb]; ok {
			rlogger.Printf("%s %v", verb, data)

			err := proto.Fit(data, o.p)
			if err != nil {
				c.SendError(rid, err.String())
				continue
			}

			if o.redirect && !c.cal {
				c.redirect(rid)
				continue
			}

			c.handle(rid, o.f, indirect(o.p))
			continue
		}

		rlogger.Printf("unknown command <%s>", verb)
		c.SendError(rid, proto.InvalidCommand+" "+verb)
	}
}
<commit_msg>server: handle requests in parallel<commit_after>package server

import (
	jnet "junta/net"
	"junta/paxos"
	"junta/proto"
	"junta/store"
	"junta/util"
	"net"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"
)

const packetSize = 3000

const lease = 3e9 // ns == 3s

var ErrBadPrefix = os.NewError("bad prefix in path")

type conn struct {
	*proto.Conn
	c   net.Conn
	s   *Server
	cal bool
}

type Manager interface {
	paxos.Proposer
	PutFrom(string, paxos.Msg)
	Alpha() int
}

type Server struct {
	Addr         string
	St           *store.Store
	Mg           Manager
	Self, Prefix string
}

func (sv *Server) ListenAndServeUdp(outs chan paxos.Packet) os.Error {
	logger := util.NewLogger("udp server %s", sv.Addr)

	logger.Println("binding")
	u, err := net.ListenPacket("udp", sv.Addr)
	if err != nil {
		logger.Println(err)
		return err
	}
	defer u.Close()
	logger.Println("listening")

	err = sv.ServeUdp(u, outs)
	if err != nil {
		logger.Printf("%s: %s", u, err)
	}
	return err
}

func (sv *Server) ServeUdp(u jnet.Conn, outs chan paxos.Packet) os.Error {
	r := jnet.Ackify(u, outs)

	for p := range r {
		sv.Mg.PutFrom(p.Addr, p.Msg)
	}

	panic("unreachable")
}

var clg = util.NewLogger("cal")

func (s *Server) Serve(l net.Listener, cal chan int) os.Error {
	var ok bool
	for {
		if !ok {
			_, ok = <-cal
		}
		clg.Println(ok)

		rw, e := l.Accept()
		if e != nil {
			return e
		}
		c := &conn{proto.NewConn(rw), rw, s, ok}
		go c.serve()
	}

	panic("unreachable")
}

func (sv *Server) leader() string {
	parts, cas := sv.St.Get("/junta/leader")
	if cas == store.Dir && cas == store.Missing {
		return ""
	}
	return parts[0]
}

func (sv *Server) addrFor(id string) string {
	parts, cas := sv.St.Get("/junta/members/" + id)
	if cas == store.Dir && cas == store.Missing {
		return ""
	}
	return parts[0]
}

// Checks that path begins with the proper prefix and returns the short path
// without the prefix.
func (sv *Server) checkPath(path string) (string, os.Error) {
	logger := util.NewLogger("checkPath")
	if !strings.HasPrefix(path, sv.Prefix+"/") {
		logger.Printf("prefix %q not in %q", sv.Prefix+"/", path)
		return "", ErrBadPrefix
	}
	return path[len(sv.Prefix):], nil
}

// Repeatedly propose nop values until a successful read from `done`.
func (sv *Server) AdvanceUntil(done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		sv.Mg.Propose(store.Nop)
	}
}

func (c *conn) redirect(rid uint) {
	leader := c.s.leader()
	addr := c.s.addrFor(leader)
	if addr == "" {
		c.SendError(rid, "unknown address for leader")
	} else {
		c.SendRedirect(rid, addr)
	}
}

func get(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqGet)
	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return nil, err
	}

	v, cas := s.St.Get(shortPath)
	return []interface{}{v, cas}, nil
}

func sget(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqGet)
	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return "", err
	}

	body, err := store.GetString(s.St.SyncPath(shortPath), shortPath), nil
	if err != nil {
		return nil, err
	}

	return []interface{}{body}, nil
}

func set(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqSet)

	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return nil, err
	}

	seqn, _, err := paxos.Set(s.Mg, shortPath, r.Body, r.Cas)
	if err != nil {
		return nil, err
	}
	return []interface{}{strconv.Uitoa64(seqn)}, nil
}

func del(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqDel)

	shortPath, err := s.checkPath(r.Path)
	if err != nil {
		return 0, err
	}

	_, err = paxos.Del(s.Mg, shortPath, r.Cas)
	if err != nil {
		return nil, err
	}

	return []interface{}{"true"}, nil
}

func nop(s *Server, data interface{}) (interface{}, os.Error) {
	s.Mg.Propose(store.Nop)
	return []interface{}{"true"}, nil
}

func join(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqJoin)
	key := "/junta/members/" + r.Who
	seqn, _, err := paxos.Set(s.Mg, key, r.Addr, store.Missing)
	if err != nil {
		return nil, err
	}

	done := make(chan int)
	go s.AdvanceUntil(done)
	s.St.Sync(seqn + uint64(s.Mg.Alpha()))
	close(done)
	seqn, snap := s.St.Snapshot()
	return []interface{}{strconv.Uitoa64(seqn), snap}, nil
}

func checkin(s *Server, data interface{}) (interface{}, os.Error) {
	r := data.(*proto.ReqCheckin)
	t := time.Nanoseconds() + lease
	_, cas, err := paxos.Set(s.Mg, "/session/"+r.Sid, strconv.Itoa64(t), r.Cas)
	if err != nil {
		return nil, err
	}
	return []interface{}{strconv.Itoa64(t), cas}, nil
}

func indirect(x interface{}) interface{} {
	return reflect.Indirect(reflect.NewValue(x)).Interface()
}

type handler func(*Server, interface{}) (interface{}, os.Error)

type op struct {
	p interface{}
	f handler

	redirect bool
}

var ops = map[string]op{
	"get":{p:new(*proto.ReqGet), f:get},
	"sget":{p:new(*proto.ReqGet), f:sget},
	"set":{p:new(*proto.ReqSet), f:set, redirect:true},
	"del":{p:new(*proto.ReqDel), f:del, redirect:true},
	"nop":{p:new(*[]interface{}), f:nop, redirect:true},
	"join":{p:new(*proto.ReqJoin), f:join, redirect:true},
	"checkin":{p:new(*proto.ReqCheckin), f:checkin, redirect:true},
}

func (c *conn) handle(rid uint, f handler, data interface{}) {
	res, err := f(c.s, data)
	if err != nil {
		c.SendError(rid, err.String())
	} else {
		c.SendResponse(rid, res)
	}
}

func (c *conn) serve() {
	logger := util.NewLogger("%v", c.c.RemoteAddr())
	logger.Println("accepted connection")
	for {
		rid, verb, data, err := c.ReadRequest()
		if err != nil {
			if err == os.EOF {
				logger.Println("connection closed by peer")
			} else {
				logger.Println(err)
			}
			return
		}

		rlogger := util.NewLogger("%v - req [%d]", c.c.RemoteAddr(), rid)

		if o, ok := ops[verb]; ok {
			rlogger.Printf("%s %v", verb, data)

			err := proto.Fit(data, o.p)
			if err != nil {
				c.SendError(rid, err.String())
				continue
			}

			if o.redirect && !c.cal {
				c.redirect(rid)
				continue
			}

			go c.handle(rid, o.f, indirect(o.p))
			continue
		}

		rlogger.Printf("unknown command <%s>", verb)
		c.SendError(rid, proto.InvalidCommand+" "+verb)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

import (
	negv1beta1 "k8s.io/ingress-gce/pkg/apis/frontendconfig/v1beta1"
	apisneg "k8s.io/ingress-gce/pkg/apis/svcneg"
	"k8s.io/ingress-gce/pkg/crd"
)

func CRDMeta() *crd.CRDMeta {
	meta := crd.NewCRDMeta(
		apisneg.GroupName,
		"v1beta1",
		"ServiceNetworkEndpointGroup",
		"ServiceNetworkEndpointGroupList",
		"servicenetworkendpointgroup",
		"servicenetworkendpointgroups",
	)
	meta.AddValidationInfo("k8s.io/ingress-gce/pkg/apis/svcneg/v1beta1.ServiceNetworkEndpointGroup", negv1beta1.GetOpenAPIDefinitions)
	return meta
}
<commit_msg>Fix negv1beta1 import<commit_after>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

import (
	apisneg "k8s.io/ingress-gce/pkg/apis/svcneg"
	negv1beta1 "k8s.io/ingress-gce/pkg/apis/svcneg/v1beta1"
	"k8s.io/ingress-gce/pkg/crd"
)

func CRDMeta() *crd.CRDMeta {
	meta := crd.NewCRDMeta(
		apisneg.GroupName,
		"v1beta1",
		"ServiceNetworkEndpointGroup",
		"ServiceNetworkEndpointGroupList",
		"servicenetworkendpointgroup",
		"servicenetworkendpointgroups",
		"svcneg",
	)
	meta.AddValidationInfo("k8s.io/ingress-gce/pkg/apis/svcneg/v1beta1.ServiceNetworkEndpointGroup", negv1beta1.GetOpenAPIDefinitions)
	return meta
}
<|endoftext|>


<commit_before>package util

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

//WalkSkipDir is the Error returned when we want to skip descending into a directory
var WalkSkipDir = errors.New("skip this directory")

//WalkFunc is a callback function called for each path as a directory is walked
//If resolvedPath != "", then we are following symbolic links.
type WalkFunc func(resolvedPath string, info os.FileInfo, err error) error

//Walk walks a path, optionally following symbolic links, and for each path,
//it calls the walkFn passed.
//
//It is similar to filepath.Walk, except that it supports symbolic links and
//can detect infinite loops while following sym links.
//It solves the issue where your WalkFunc needs a path relative to the symbolic link
//(resolving links within walkfunc loses the path to the symbolic link for each traversal).
func Walk(path string, followSymlinks bool, detectSymlinkInfiniteLoop bool, walkFn WalkFunc) error {
	info, err := os.Lstat(path)
	if err != nil {
		return err
	}
	var symlinkPathsFollowed map[string]bool
	var resolvedPath string
	if followSymlinks {
		resolvedPath = path
		if detectSymlinkInfiniteLoop {
			symlinkPathsFollowed = make(map[string]bool, 8)
		}
	}
	return walk(path, info, resolvedPath, symlinkPathsFollowed, walkFn)
}

//walk walks the path. It is a helper/sibling function to Walk.
//It takes a resolvedPath into consideration. This way, paths being walked are
//always relative to the path argument, even if symbolic links were resolved).
//
//If resolvedPath is "", then we are not following symbolic links.
//If symlinkPathsFollowed is not nil, then we need to detect infinite loop.
func walk(path string, info os.FileInfo, resolvedPath string, symlinkPathsFollowed map[string]bool, walkFn WalkFunc) error {
	if info == nil {
		return errors.New("Walk: Nil FileInfo passed")
	}
	err := walkFn(resolvedPath, info, nil)
	if err != nil {
		if info.IsDir() && err == WalkSkipDir {
			err = nil
		}
		return err
	}
	if resolvedPath != "" && info.Mode()&os.ModeSymlink == os.ModeSymlink {
		path2, err := os.Readlink(resolvedPath)
		if err != nil {
			return err
		}
		//vout("SymLink Path: %v, links to: %v", resolvedPath, path2)
		if symlinkPathsFollowed != nil {
			if _, ok := symlinkPathsFollowed[path2]; ok {
				errMsg := "Potential SymLink Infinite Loop. Path: %v, Link To: %v"
				return fmt.Errorf(errMsg, resolvedPath, path2)
			} else {
				symlinkPathsFollowed[path2] = true
			}
		}
		info2, err := os.Lstat(path2)
		if err != nil {
			return err
		}
		return walk(path, info2, path2, symlinkPathsFollowed, walkFn)
	}
	if info.IsDir() {
		list, err := ioutil.ReadDir(path)
		if err != nil {
			return walkFn(resolvedPath, info, err)
		}
		for _, fileInfo := range list {
			path2 := filepath.Join(path, fileInfo.Name())
			var resolvedPath2 string
			if resolvedPath != "" {
				resolvedPath2 = filepath.Join(resolvedPath, fileInfo.Name())
			}
			err = walk(path2, fileInfo, resolvedPath2, symlinkPathsFollowed, walkFn)
			if err != nil {
				return err
			}
		}
		return nil
	}
	return nil
}

func ContainsDistFolder(path string) bool  {
	info, err := os.Lstat(path)
	if err != nil {
		return false
	}

	if !info.IsDir() {
		return false
	}

	list, err := ioutil.ReadDir(path)
	for _, fileInfo := range list {
		if fileInfo.IsDir() && fileInfo.Name() == "dist" {
			return true
		}
	}

	return false
}
<commit_msg>go fmt....<commit_after>package util

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

//WalkSkipDir is the Error returned when we want to skip descending into a directory
var WalkSkipDir = errors.New("skip this directory")

//WalkFunc is a callback function called for each path as a directory is walked
//If resolvedPath != "", then we are following symbolic links.
type WalkFunc func(resolvedPath string, info os.FileInfo, err error) error

//Walk walks a path, optionally following symbolic links, and for each path,
//it calls the walkFn passed.
//
//It is similar to filepath.Walk, except that it supports symbolic links and
//can detect infinite loops while following sym links.
//It solves the issue where your WalkFunc needs a path relative to the symbolic link
//(resolving links within walkfunc loses the path to the symbolic link for each traversal).
func Walk(path string, followSymlinks bool, detectSymlinkInfiniteLoop bool, walkFn WalkFunc) error {
	info, err := os.Lstat(path)
	if err != nil {
		return err
	}
	var symlinkPathsFollowed map[string]bool
	var resolvedPath string
	if followSymlinks {
		resolvedPath = path
		if detectSymlinkInfiniteLoop {
			symlinkPathsFollowed = make(map[string]bool, 8)
		}
	}
	return walk(path, info, resolvedPath, symlinkPathsFollowed, walkFn)
}

//walk walks the path. It is a helper/sibling function to Walk.
//It takes a resolvedPath into consideration. This way, paths being walked are
//always relative to the path argument, even if symbolic links were resolved).
//
//If resolvedPath is "", then we are not following symbolic links.
//If symlinkPathsFollowed is not nil, then we need to detect infinite loop.
func walk(path string, info os.FileInfo, resolvedPath string, symlinkPathsFollowed map[string]bool, walkFn WalkFunc) error {
	if info == nil {
		return errors.New("Walk: Nil FileInfo passed")
	}
	err := walkFn(resolvedPath, info, nil)
	if err != nil {
		if info.IsDir() && err == WalkSkipDir {
			err = nil
		}
		return err
	}
	if resolvedPath != "" && info.Mode()&os.ModeSymlink == os.ModeSymlink {
		path2, err := os.Readlink(resolvedPath)
		if err != nil {
			return err
		}
		//vout("SymLink Path: %v, links to: %v", resolvedPath, path2)
		if symlinkPathsFollowed != nil {
			if _, ok := symlinkPathsFollowed[path2]; ok {
				errMsg := "Potential SymLink Infinite Loop. Path: %v, Link To: %v"
				return fmt.Errorf(errMsg, resolvedPath, path2)
			} else {
				symlinkPathsFollowed[path2] = true
			}
		}
		info2, err := os.Lstat(path2)
		if err != nil {
			return err
		}
		return walk(path, info2, path2, symlinkPathsFollowed, walkFn)
	}
	if info.IsDir() {
		list, err := ioutil.ReadDir(path)
		if err != nil {
			return walkFn(resolvedPath, info, err)
		}
		for _, fileInfo := range list {
			path2 := filepath.Join(path, fileInfo.Name())
			var resolvedPath2 string
			if resolvedPath != "" {
				resolvedPath2 = filepath.Join(resolvedPath, fileInfo.Name())
			}
			err = walk(path2, fileInfo, resolvedPath2, symlinkPathsFollowed, walkFn)
			if err != nil {
				return err
			}
		}
		return nil
	}
	return nil
}

func ContainsDistFolder(path string) bool {
	info, err := os.Lstat(path)
	if err != nil {
		return false
	}

	if !info.IsDir() {
		return false
	}

	list, err := ioutil.ReadDir(path)
	for _, fileInfo := range list {
		if fileInfo.IsDir() && fileInfo.Name() == "dist" {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"

	"github.com/motemen/ghq/utils"
)

// A RemoteRepository represents a remote repository.
type RemoteRepository interface {
	// The repository URL.
	URL() *url.URL
	// Checks if the URL is valid.
	IsValid() bool
	// The VCS backend that hosts the repository.
	VCS() *VCSBackend
}

// A GitHubRepository represents a GitHub repository. Impliments RemoteRepository.
type GitHubRepository struct {
	url *url.URL
}

func (repo *GitHubRepository) URL() *url.URL {
	return repo.url
}

func (repo *GitHubRepository) IsValid() bool {
	if strings.HasPrefix(repo.url.Path, "/blog/") {
		return false
	}

	// must be /{user}/{project}/?
	pathComponents := strings.Split(strings.TrimRight(repo.url.Path, "/"), "/")
	if len(pathComponents) != 3 {
		return false
	}

	return true
}

func (repo *GitHubRepository) VCS() *VCSBackend {
	return GitBackend
}

// A GitHubGistRepository represents a GitHub Gist repository.
type GitHubGistRepository struct {
	url *url.URL
}

func (repo *GitHubGistRepository) URL() *url.URL {
	return repo.url
}

func (repo *GitHubGistRepository) IsValid() bool {
	return true
}

func (repo *GitHubGistRepository) VCS() *VCSBackend {
	return GitBackend
}

type GoogleCodeRepository struct {
	url *url.URL
}

func (repo *GoogleCodeRepository) URL() *url.URL {
	return repo.url
}

var validGoogleCodePathPattern = regexp.MustCompile(`^/p/[^/]+/?$`)

func (repo *GoogleCodeRepository) IsValid() bool {
	return validGoogleCodePathPattern.MatchString(repo.url.Path)
}

func (repo *GoogleCodeRepository) VCS() *VCSBackend {
	if utils.RunSilently("hg", "identify", repo.url.String()) == nil {
		return MercurialBackend
	} else if utils.RunSilently("git", "ls-remote", repo.url.String()) == nil {
		return GitBackend
	} else {
		return nil
	}
}

type DarksHubRepository struct {
	url *url.URL
}

func (repo *DarksHubRepository) URL() *url.URL {
	return repo.url
}

func (repo *DarksHubRepository) IsValid() bool {
	return strings.Count(repo.url.Path, "/") == 2
}

func (repo *DarksHubRepository) VCS() *VCSBackend {
	return DarcsBackend
}

type OtherRepository struct {
	url *url.URL
}

func (repo *OtherRepository) URL() *url.URL {
	return repo.url
}

func (repo *OtherRepository) IsValid() bool {
	return true
}

func (repo *OtherRepository) VCS() *VCSBackend {
	if GitHasFeatureConfigURLMatch() {
		// Respect 'ghq.url.https://ghe.example.com/.vcs' config variable
		// (in gitconfig:)
		//     [ghq "https://ghe.example.com/"]
		//     vcs = github
		vcs, err := GitConfig("--get-urlmatch", "ghq.vcs", repo.URL().String())
		if err != nil {
			utils.Log("error", err.Error())
		}

		if vcs == "git" || vcs == "github" {
			return GitBackend
		}

		if vcs == "svn" || vcs == "subversion" {
			return SubversionBackend
		}

		if vcs == "git-svn" {
			return GitsvnBackend
		}

		if vcs == "hg" || vcs == "mercurial" {
			return MercurialBackend
		}

		if vcs == "darcs" {
			return DarcsBackend
		}
	} else {
		utils.Log("warning", "This version of Git does not support `config --get-urlmatch`; per-URL settings are not available")
	}

	// Detect VCS backend automatically
	if utils.RunSilently("hg", "identify", repo.url.String()) == nil {
		return MercurialBackend
	} else if utils.RunSilently("git", "ls-remote", repo.url.String()) == nil {
		return GitBackend
	} else if utils.RunSilently("svn", "info", repo.url.String()) == nil {
		return SubversionBackend
	} else {
		return nil
	}
}

func NewRemoteRepository(url *url.URL) (RemoteRepository, error) {
	if url.Host == "github.com" {
		return &GitHubRepository{url}, nil
	}

	if url.Host == "gist.github.com" {
		return &GitHubGistRepository{url}, nil
	}

	if url.Host == "code.google.com" {
		return &GoogleCodeRepository{url}, nil
	}

	if url.Host == "hub.darcs.net" {
		return &DarksHubRepository{url}, nil
	}

	gheHosts, err := GitConfigAll("ghq.ghe.host")

	if err != nil {
		return nil, fmt.Errorf("failed to retrieve GH:E hostname from .gitconfig: %s", err)
	}

	for _, host := range gheHosts {
		if url.Host == host {
			return &GitHubRepository{url}, nil
		}
	}

	return &OtherRepository{url}, nil
}
<commit_msg>Support for Bluemix DevOps Git service<commit_after>package main

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"

	"github.com/motemen/ghq/utils"
)

// A RemoteRepository represents a remote repository.
type RemoteRepository interface {
	// The repository URL.
	URL() *url.URL
	// Checks if the URL is valid.
	IsValid() bool
	// The VCS backend that hosts the repository.
	VCS() *VCSBackend
}

// A GitHubRepository represents a GitHub repository. Impliments RemoteRepository.
type GitHubRepository struct {
	url *url.URL
}

func (repo *GitHubRepository) URL() *url.URL {
	return repo.url
}

func (repo *GitHubRepository) IsValid() bool {
	if strings.HasPrefix(repo.url.Path, "/blog/") {
		return false
	}

	// must be /{user}/{project}/?
	pathComponents := strings.Split(strings.TrimRight(repo.url.Path, "/"), "/")
	if len(pathComponents) != 3 {
		return false
	}

	return true
}

func (repo *GitHubRepository) VCS() *VCSBackend {
	return GitBackend
}

// A GitHubGistRepository represents a GitHub Gist repository.
type GitHubGistRepository struct {
	url *url.URL
}

func (repo *GitHubGistRepository) URL() *url.URL {
	return repo.url
}

func (repo *GitHubGistRepository) IsValid() bool {
	return true
}

func (repo *GitHubGistRepository) VCS() *VCSBackend {
	return GitBackend
}

type GoogleCodeRepository struct {
	url *url.URL
}

func (repo *GoogleCodeRepository) URL() *url.URL {
	return repo.url
}

var validGoogleCodePathPattern = regexp.MustCompile(`^/p/[^/]+/?$`)

func (repo *GoogleCodeRepository) IsValid() bool {
	return validGoogleCodePathPattern.MatchString(repo.url.Path)
}

func (repo *GoogleCodeRepository) VCS() *VCSBackend {
	if utils.RunSilently("hg", "identify", repo.url.String()) == nil {
		return MercurialBackend
	} else if utils.RunSilently("git", "ls-remote", repo.url.String()) == nil {
		return GitBackend
	} else {
		return nil
	}
}

type DarksHubRepository struct {
	url *url.URL
}

func (repo *DarksHubRepository) URL() *url.URL {
	return repo.url
}

func (repo *DarksHubRepository) IsValid() bool {
	return strings.Count(repo.url.Path, "/") == 2
}

func (repo *DarksHubRepository) VCS() *VCSBackend {
	return DarcsBackend
}

type BluemixRepository struct {
	url *url.URL
}

func (repo *BluemixRepository) URL() *url.URL {
	return repo.url
}

var validBluemixPathPattern = regexp.MustCompile(`^/git/[^/]+/[^/]+$`)

func (repo *BluemixRepository) IsValid() bool {
	return validBluemixPathPattern.MatchString(repo.url.Path)
}

func (repo *BluemixRepository) VCS() *VCSBackend {
	return GitBackend
}

type OtherRepository struct {
	url *url.URL
}

func (repo *OtherRepository) URL() *url.URL {
	return repo.url
}

func (repo *OtherRepository) IsValid() bool {
	return true
}

func (repo *OtherRepository) VCS() *VCSBackend {
	if GitHasFeatureConfigURLMatch() {
		// Respect 'ghq.url.https://ghe.example.com/.vcs' config variable
		// (in gitconfig:)
		//     [ghq "https://ghe.example.com/"]
		//     vcs = github
		vcs, err := GitConfig("--get-urlmatch", "ghq.vcs", repo.URL().String())
		if err != nil {
			utils.Log("error", err.Error())
		}

		if vcs == "git" || vcs == "github" {
			return GitBackend
		}

		if vcs == "svn" || vcs == "subversion" {
			return SubversionBackend
		}

		if vcs == "git-svn" {
			return GitsvnBackend
		}

		if vcs == "hg" || vcs == "mercurial" {
			return MercurialBackend
		}

		if vcs == "darcs" {
			return DarcsBackend
		}
	} else {
		utils.Log("warning", "This version of Git does not support `config --get-urlmatch`; per-URL settings are not available")
	}

	// Detect VCS backend automatically
	if utils.RunSilently("hg", "identify", repo.url.String()) == nil {
		return MercurialBackend
	} else if utils.RunSilently("git", "ls-remote", repo.url.String()) == nil {
		return GitBackend
	} else if utils.RunSilently("svn", "info", repo.url.String()) == nil {
		return SubversionBackend
	} else {
		return nil
	}
}

func NewRemoteRepository(url *url.URL) (RemoteRepository, error) {
	if url.Host == "github.com" {
		return &GitHubRepository{url}, nil
	}

	if url.Host == "gist.github.com" {
		return &GitHubGistRepository{url}, nil
	}

	if url.Host == "code.google.com" {
		return &GoogleCodeRepository{url}, nil
	}

	if url.Host == "hub.darcs.net" {
		return &DarksHubRepository{url}, nil
	}

	if url.Host == "hub.jazz.net" {
		return &BluemixRepository{url}, nil
	}

	gheHosts, err := GitConfigAll("ghq.ghe.host")

	if err != nil {
		return nil, fmt.Errorf("failed to retrieve GH:E hostname from .gitconfig: %s", err)
	}

	for _, host := range gheHosts {
		if url.Host == host {
			return &GitHubRepository{url}, nil
		}
	}

	return &OtherRepository{url}, nil
}
<|endoftext|>


<commit_before>package render

import (
	"image"
	"image/color"
	"log"
	"math"
	"sort"

	"bitbucket.org/oakmoundstudio/oak/physics"
	"github.com/200sc/go-compgeo/dcel"
)

type Polyhedron struct {
	Sprite
	dcel.DCEL
	Center physics.Vector
}

func NewCuboid(x, y, z, w, h, d float64) *Polyhedron {
	px := x
	py := y
	dc := dcel.DCEL{}
	// Is there a smart way to loop through this?
	// verts
	x = w
	y = h
	z = -d
	dc.Vertices = make([]dcel.Point, 8)
	dc.HalfEdges = make([]dcel.Edge, 24)
	dc.OutEdges = make([]*dcel.Edge, 8)
	for i := 0; i < 8; i++ {
		// Set coordinates of this vertex
		if x == 0 {
			x = w
		} else {
			x = 0
		}
		if i%2 == 0 {
			if y == 0 {
				y = h
			} else {
				y = 0
			}
		}
		if i%4 == 0 {
			z += d
		}

		dc.Vertices[i] = dcel.Point{x, y, z}
	}
	corners := []int{0, 3, 5, 6}
	// These edges, except for the ones
	// at a corner's index, are those a
	// corner's edges' twins start from
	addEdges := []int{7, 4, 2, 1}
	edge := 0
	for k, i := range corners {
		addEdgesK := []int{}
		for k2, v := range addEdges {
			if k2 != k {
				addEdgesK = append(addEdgesK, v)
			}
		}
		m := 0
		for j := edge; j < edge+6; j += 2 {
			dc.HalfEdges[j] = dcel.Edge{
				Origin: &dc.Vertices[i],
			}
			dc.OutEdges[i] = &dc.HalfEdges[j]
			dc.HalfEdges[j+1] = dcel.Edge{
				Origin: &dc.Vertices[addEdgesK[m]],
			}
			dc.OutEdges[addEdgesK[m]] = &dc.HalfEdges[j+1]
			m++
		}
		// 6 edges per corner
		edge += 6
	}
	// Set Twins
	for i := range dc.HalfEdges {
		dc.HalfEdges[i].Twin = &dc.HalfEdges[dcel.EdgeTwin(i)]
	}
	// We're ignoring prev, next, face for now
	// because this is way harder than it should be
	return NewPolyhedronFromDCEL(&dc, px, py)
}

func NewPolyhedronFromDCEL(dc *dcel.DCEL, x, y float64) *Polyhedron {
	p := new(Polyhedron)
	p.SetPos(x, y)
	p.DCEL = *dc
	p.Update()
	p.Center = physics.NewVector(p.X+(1+p.MaxX())/2, p.Y+(1+p.MaxY())/2)
	return p
}

func (p *Polyhedron) Update() {

	// Reset p's rgba
	maxX := p.MaxX() + 1
	maxY := p.MaxY() + 1
	rect := image.Rect(0, 0, int(maxX), int(maxY))
	rgba := image.NewRGBA(rect)
	// We ignore Z -- Z is used for rotations
	// There isn't an alternative to this, aside from
	// recoloring things to account for different z values,
	// without having a camera system, which is a lot of work

	// Try to maintain center
	if p.Center.X != 0 || p.Center.Y != 0 {
		cx := p.X + maxX/2
		cy := p.Y + maxY/2
		p.X -= (cx - p.Center.X)
		p.Y -= (cy - p.Center.Y)
	}

	red := color.RGBA{255, 0, 0, 255}
	gray := color.RGBA{160, 160, 160, 255}
	blue := color.RGBA{0, 0, 255, 255}

	// Eventually:
	// For all Faces, Edges, and Vertices, sort by z value
	// and draw them high-to-low
	zOrder := make([]interface{}, len(p.HalfEdges)/2+len(p.Faces)-1+len(p.Vertices))

	// Step 1: draw all edges
	// Given the edge twin mandate, we can just use
	// every other halfEdge.
	//fmt.Println(p.DCEL)
	for i := 0; i < len(p.HalfEdges); i += 2 {
		points := p.FullEdge(i)
		// draw a line from points[0] to points[1]
		//fmt.Println("Drawing from ", points[0][0], points[0][1], "to",
		//points[1][0], points[1][1])
		zOrder = append(zOrder, points)
		// drawLineOnto(rgba, int(points[0][0]), int(points[0][1]),
		// 	int(points[1][0]), int(points[1][1]), gray)
	}

	// Step 2: draw all vertices
	for _, v := range p.Vertices {
		zOrder = append(zOrder, v)
		//rgba.Set(int(v[0]), int(v[1]), red)
	}

	for i := 1; i < len(p.Faces); i++ {
		f := p.Faces[i]
		verts := f.Vertices()
		max_z := math.MaxFloat64 * -1
		phys_verts := make([]physics.Vector, len(verts))
		for i, v := range verts {
			phys_verts[i] = physics.NewVector(v[0], v[1])
			if v[2] > max_z {
				max_z = v[2]
			}
		}
		poly, err := NewPolygon(phys_verts)
		if err != nil {
			log.Fatal(err)
			return
		}
		fpoly := facePolygon{
			poly,
			max_z,
		}
		zOrder = append(zOrder, fpoly)
	}

	// This is very hacky
	sort.Slice(zOrder, func(i, j int) bool {
		z1 := 0.0
		z2 := 0.0
		switch v := zOrder[i].(type) {
		case facePolygon:
			z1 = v.z
		case dcel.Point:
			z1 = v[2]
		case [2]*dcel.Point:
			z1 = math.Max(v[0][2], v[1][2])
		}
		switch v := zOrder[j].(type) {
		case facePolygon:
			z2 = v.z
		case dcel.Point:
			z2 = v[2]
		case [2]*dcel.Point:
			z2 = math.Max(v[0][2], v[1][2])
		}
		return z1 < z2
	})

	for _, item := range zOrder {
		switch v := item.(type) {
		case facePolygon:
			for x := v.Rect.minX; x < v.Rect.maxX; x++ {
				for y := v.Rect.minY; y < v.Rect.maxY; y++ {
					if v.Contains(x, y) {
						rgba.Set(int(x), int(y), blue)
					}
				}
			}
		case dcel.Point:
			rgba.Set(int(v[0]), int(v[1]), red)
		case [2]*dcel.Point:
			drawLineOnto(rgba, int(v[0][0]), int(v[0][1]),
				int(v[1][0]), int(v[1][1]), gray)
		}
	}

	p.SetRGBA(rgba)
}

type facePolygon struct {
	*Polygon
	z float64
}

func (p *Polyhedron) RotZ(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0]*ct - v[1]*st
		p.Vertices[i][1] = v[1]*ct + v[0]*st
	}
	p.clearNegativePoints()
	p.Update()
}

func (p *Polyhedron) RotX(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for i, v := range p.Vertices {
		p.Vertices[i][1] = v[1]*ct - v[2]*st
		p.Vertices[i][2] = v[2]*ct + v[1]*st
	}
	p.clearNegativePoints()
	p.Update()
}

func (p *Polyhedron) RotY(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0]*ct - v[2]*st
		p.Vertices[i][2] = v[2]*ct + v[0]*st
	}
	p.clearNegativePoints()
	p.Update()
}

func (p *Polyhedron) Scale(factor float64) {
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] * factor
		p.Vertices[i][1] = v[1] * factor
		p.Vertices[i][2] = v[2] * factor
	}
	p.clearNegativePoints()
	p.Update()
}

func (p *Polyhedron) clearNegativePoints() {
	// Anything with an x,y less than 0 needs to be increased,
	// this is a limitation so we stay in the bounds of a given rgba
	// rectangle on screen, so we increase everything by minX,minY
	x := p.MinX()
	y := p.MinY()
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] - x
	}
	for i, v := range p.Vertices {
		p.Vertices[i][1] = v[1] - y
	}
}

// Utilities
func (p *Polyhedron) String() string {
	return "Polyhedron"
}

func (p *Polyhedron) ShiftX(x float64) {
	p.Center.X += x
	p.Sprite.ShiftX(x)
}

func (p *Polyhedron) ShiftY(y float64) {
	p.Center.Y += y
	p.Sprite.ShiftY(y)
}
<commit_msg>Polyhedrons have an implicit preference to draw face->edge->vertex. Update calls clearNegative.<commit_after>package render

import (
	"image"
	"image/color"
	"log"
	"math"
	"sort"

	"bitbucket.org/oakmoundstudio/oak/physics"
	"github.com/200sc/go-compgeo/dcel"
)

type Polyhedron struct {
	Sprite
	dcel.DCEL
	Center physics.Vector
}

func NewCuboid(x, y, z, w, h, d float64) *Polyhedron {
	px := x
	py := y
	dc := dcel.DCEL{}
	// Is there a smart way to loop through this?
	// verts
	x = w
	y = h
	z = -d
	dc.Vertices = make([]dcel.Point, 8)
	dc.HalfEdges = make([]dcel.Edge, 24)
	dc.OutEdges = make([]*dcel.Edge, 8)
	for i := 0; i < 8; i++ {
		// Set coordinates of this vertex
		if x == 0 {
			x = w
		} else {
			x = 0
		}
		if i%2 == 0 {
			if y == 0 {
				y = h
			} else {
				y = 0
			}
		}
		if i%4 == 0 {
			z += d
		}

		dc.Vertices[i] = dcel.Point{x, y, z}
	}
	corners := []int{0, 3, 5, 6}
	// These edges, except for the ones
	// at a corner's index, are those a
	// corner's edges' twins start from
	addEdges := []int{7, 4, 2, 1}
	edge := 0
	for k, i := range corners {
		addEdgesK := []int{}
		for k2, v := range addEdges {
			if k2 != k {
				addEdgesK = append(addEdgesK, v)
			}
		}
		m := 0
		for j := edge; j < edge+6; j += 2 {
			dc.HalfEdges[j] = dcel.Edge{
				Origin: &dc.Vertices[i],
			}
			dc.OutEdges[i] = &dc.HalfEdges[j]
			dc.HalfEdges[j+1] = dcel.Edge{
				Origin: &dc.Vertices[addEdgesK[m]],
			}
			dc.OutEdges[addEdgesK[m]] = &dc.HalfEdges[j+1]
			m++
		}
		// 6 edges per corner
		edge += 6
	}
	// Set Twins
	for i := range dc.HalfEdges {
		dc.HalfEdges[i].Twin = &dc.HalfEdges[dcel.EdgeTwin(i)]
	}
	// We're ignoring prev, next, face for now
	// because this is way harder than it should be
	return NewPolyhedronFromDCEL(&dc, px, py)
}

func NewPolyhedronFromDCEL(dc *dcel.DCEL, x, y float64) *Polyhedron {
	p := new(Polyhedron)
	p.SetPos(x, y)
	p.DCEL = *dc
	p.Update()
	p.Center = physics.NewVector(p.X+(1+p.MaxX())/2, p.Y+(1+p.MaxY())/2)
	return p
}

func (p *Polyhedron) Update() {

	p.clearNegativePoints()

	// Reset p's rgba
	maxX := p.MaxX() + 1
	maxY := p.MaxY() + 1
	rect := image.Rect(0, 0, int(maxX), int(maxY))
	rgba := image.NewRGBA(rect)
	// We ignore Z -- Z is used for rotations
	// There isn't an alternative to this, aside from
	// recoloring things to account for different z values,
	// without having a camera system, which is a lot of work

	// Try to maintain center
	if p.Center.X != 0 || p.Center.Y != 0 {
		cx := p.X + maxX/2
		cy := p.Y + maxY/2
		p.X -= (cx - p.Center.X)
		p.Y -= (cy - p.Center.Y)
	}

	red := color.RGBA{255, 0, 0, 255}
	gray := color.RGBA{160, 160, 160, 255}
	blue := color.RGBA{0, 0, 255, 255}

	// Eventually:
	// For all Faces, Edges, and Vertices, sort by z value
	// and draw them high-to-low
	zOrder := make([]interface{}, len(p.HalfEdges)/2+len(p.Faces)-1+len(p.Vertices))

	// Step 1: draw all edges
	// Given the edge twin mandate, we can just use
	// every other halfEdge.
	//fmt.Println(p.DCEL)
	for i := 0; i < len(p.HalfEdges); i += 2 {
		points := p.FullEdge(i)
		// draw a line from points[0] to points[1]
		//fmt.Println("Drawing from ", points[0][0], points[0][1], "to",
		//points[1][0], points[1][1])
		zOrder = append(zOrder, points)
		// drawLineOnto(rgba, int(points[0][0]), int(points[0][1]),
		// 	int(points[1][0]), int(points[1][1]), gray)
	}

	// Step 2: draw all vertices
	for _, v := range p.Vertices {
		zOrder = append(zOrder, v)
		//rgba.Set(int(v[0]), int(v[1]), red)
	}

	for i := 1; i < len(p.Faces); i++ {
		f := p.Faces[i]
		verts := f.Vertices()
		max_z := math.MaxFloat64 * -1
		phys_verts := make([]physics.Vector, len(verts))
		for i, v := range verts {
			phys_verts[i] = physics.NewVector(v[0], v[1])
			if v[2] > max_z {
				max_z = v[2]
			}
		}
		poly, err := NewPolygon(phys_verts)
		if err != nil {
			log.Fatal(err)
			return
		}
		fpoly := facePolygon{
			poly,
			max_z,
		}
		zOrder = append(zOrder, fpoly)
	}

	// This is very hacky
	sort.Slice(zOrder, func(i, j int) bool {
		z1 := 0.0
		z2 := 0.0
		switch v := zOrder[i].(type) {
		case facePolygon:
			z1 = v.z
		case dcel.Point:
			z1 = v[2] + .002
		case [2]*dcel.Point:
			z1 = math.Max(v[0][2], v[1][2]) + .001
		}
		switch v := zOrder[j].(type) {
		case facePolygon:
			z2 = v.z
		case dcel.Point:
			z2 = v[2] + .002
		case [2]*dcel.Point:
			z2 = math.Max(v[0][2], v[1][2]) + .001
		}
		return z1 < z2
	})

	for _, item := range zOrder {
		switch v := item.(type) {
		case facePolygon:
			for x := v.Rect.minX; x < v.Rect.maxX; x++ {
				for y := v.Rect.minY; y < v.Rect.maxY; y++ {
					if v.Contains(x, y) {
						rgba.Set(int(x), int(y), blue)
					}
				}
			}
		case dcel.Point:
			rgba.Set(int(v[0]), int(v[1]), red)
		case [2]*dcel.Point:
			drawLineOnto(rgba, int(v[0][0]), int(v[0][1]),
				int(v[1][0]), int(v[1][1]), gray)
		}
	}

	p.SetRGBA(rgba)
}

type facePolygon struct {
	*Polygon
	z float64
}

func (p *Polyhedron) RotZ(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0]*ct - v[1]*st
		p.Vertices[i][1] = v[1]*ct + v[0]*st
	}
	p.Update()
}

func (p *Polyhedron) RotX(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for i, v := range p.Vertices {
		p.Vertices[i][1] = v[1]*ct - v[2]*st
		p.Vertices[i][2] = v[2]*ct + v[1]*st
	}
	p.Update()
}

func (p *Polyhedron) RotY(theta float64) {
	st := math.Sin(theta)
	ct := math.Cos(theta)

	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0]*ct - v[2]*st
		p.Vertices[i][2] = v[2]*ct + v[0]*st
	}
	p.Update()
}

func (p *Polyhedron) Scale(factor float64) {
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] * factor
		p.Vertices[i][1] = v[1] * factor
		p.Vertices[i][2] = v[2] * factor
	}
	p.Update()
}

func (p *Polyhedron) clearNegativePoints() {
	// Anything with an x,y less than 0 needs to be increased,
	// this is a limitation so we stay in the bounds of a given rgba
	// rectangle on screen, so we increase everything by minX,minY
	x := p.MinX()
	y := p.MinY()
	for i, v := range p.Vertices {
		p.Vertices[i][0] = v[0] - x
	}
	for i, v := range p.Vertices {
		p.Vertices[i][1] = v[1] - y
	}
}

// Utilities
func (p *Polyhedron) String() string {
	return "Polyhedron"
}

func (p *Polyhedron) ShiftX(x float64) {
	p.Center.X += x
	p.Sprite.ShiftX(x)
}

func (p *Polyhedron) ShiftY(y float64) {
	p.Center.Y += y
	p.Sprite.ShiftY(y)
}
<|endoftext|>


<commit_before>package metric

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"edgeg.io/gtm/env"
)

var testdata string = `
1458681900:map[vim.log:1]
1458682260:map[cmd/commit.go:1]
1458683340:map[event/event.go:1]
1458682740:map[vim.log:1]
1458676380:map[scm/git.go:1]
1458682440:map[event/event.go:2 metric/metric.go:1]
1458683460:map[vim.log:2]
1458682200:map[event/event.go:2 cmd/commit.go:2]
1458911580:map[metric/metric.go:1]
1458683400:map[event/event.go:4 event/event_test.go:2]
1458911460:map[metric/metric.go:2]
1458682320:map[cmd/commit.go:1]
1458682500:map[event/event.go:1]
1458682560:map[event/event.go:2]
1458681780:map[vim.log:1]
1458682080:map[event/event.go:1]
1458682620:map[vim.log:1]
1458683580:map[vim.log:1]
1458676500:map[scm/git.go:1]
1458676560:map[scm/git.go:1]
1458682020:map[cmd/record.go:1 env/env.go:1]
1458682140:map[cmd/record.go:2 event/event.go:2]
1458911520:map[metric/metric.go:1]
1458676440:map[scm/git.go:1]
1458681840:map[vim.log:1]
1458682680:map[vim.log:1]
1458911400:map[event/event_test.go:2]
1458683520:map[vim.log:1]]

6f53bc90ba625b5afaac80b422b44f1f609d6367:{Updated:true GitFile:event/event.go Time:380}
fd3de0b7135021cc4c5ef23b8bea9ff98b704c47:{Updated:true GitFile:scm/git.go Time:240}
26c5bdda12d74ceb9cf191911a79454bccd80640:{Updated:true GitFile:metric/metric.go Time:200}
e65b42b6bf1eda6349451b063d46134dd7ab9921:{Updated:true GitFile:event/event_test.go Time:80}
f93cea510c5049ff60ef12c62825a53f7d6e7d48:{Updated:true GitFile:cmd/record.go Time:60}
1301df137d0acac0abf8cdc29bb74ef39ad2b042:{Updated:true GitFile:env/env.go Time:30}
2dbf769f7faf2f921b89f3ff9d81d7b5e02a17a5:{Updated:true GitFile:vim.log Time:540}
c2369545266e4a15c3db04a9f52b021364330bb7:{Updated:true GitFile:cmd/commit.go Time:150}]
`

func TestAllocateTime(t *testing.T) {
	cases := []struct {
		metric   map[string]metricFile
		event    map[string]int
		expected map[string]metricFile
	}{
		{
			map[string]metricFile{},
			map[string]int{"event/event.go": 1},
			map[string]metricFile{
				"6f53bc90ba625b5afaac80b422b44f1f609d6367": metricFile{Updated: true, GitFile: "event/event.go", Time: 60}},
		},
		{
			map[string]metricFile{},
			map[string]int{"event/event.go": 4, "event/event_test.go": 2},
			map[string]metricFile{
				"6f53bc90ba625b5afaac80b422b44f1f609d6367": metricFile{Updated: true, GitFile: "event/event.go", Time: 40},
				"e65b42b6bf1eda6349451b063d46134dd7ab9921": metricFile{Updated: true, GitFile: "event/event_test.go", Time: 20}},
		},
		{
			map[string]metricFile{"e65b42b6bf1eda6349451b063d46134dd7ab9921": metricFile{Updated: true, GitFile: "event/event_test.go", Time: 60}},
			map[string]int{"event/event.go": 4, "event/event_test.go": 2},
			map[string]metricFile{
				"6f53bc90ba625b5afaac80b422b44f1f609d6367": metricFile{Updated: true, GitFile: "event/event.go", Time: 40},
				"e65b42b6bf1eda6349451b063d46134dd7ab9921": metricFile{Updated: true, GitFile: "event/event_test.go", Time: 80}},
		},
	}

	for _, tc := range cases {
		// copy metric map because it's updated in place during testing
		metricOrig := map[string]metricFile{}
		for k, v := range tc.metric {
			metricOrig[k] = v

		}
		allocateTime(tc.metric, tc.event)
		if !reflect.DeepEqual(tc.metric, tc.expected) {
			t.Errorf("allocateTime(%+v, %+v)\n want %+v\n got  %+v\n", metricOrig, tc.event, tc.expected, tc.metric)
		}
	}
}

func TestFileID(t *testing.T) {
	want := "6f53bc90ba625b5afaac80b422b44f1f609d6367"
	got := getFileID("event/event.go")
	if want != got {
		t.Errorf("getFileID(%s), want %s, got %s", "event/event.go", want, got)

	}
}

func TestProcess(t *testing.T) {
	if runtime.GOOS == "windows" {
		// TODO: fix this, exec.Command("cp", path.Join(fixturePath, f.Name()), gtmPath) is not compatible with Windows
		fmt.Println("Skipping TestSweep, not compatible with Windows")
		return
	}

	var (
		rootPath   string
		gtmPath    string
		sourcePath string
		sourceFile string
		err        error
	)

	// Setup directories and source files
	rootPath, err = ioutil.TempDir("", "gtm")
	if err != nil {
		t.Fatalf("Unable to create tempory directory %s, %s", rootPath, err)
	}
	gtmPath = path.Join(rootPath, ".gtm")
	if err = os.MkdirAll(gtmPath, 0700); err != nil {
		t.Fatalf("Unable to create tempory directory %s, %s", gtmPath, err)
	}
	sourcePath = path.Join(rootPath, "event")
	if err = os.MkdirAll(sourcePath, 0700); err != nil {
		t.Fatalf("Unable to create tempory directory %s, %s", sourcePath, err)
	}
	sourceFile = path.Join(sourcePath, "event.go")
	if err = ioutil.WriteFile(sourceFile, []byte{}, 0600); err != nil {
		t.Fatalf("Unable to create tempory file %s, %s", sourceFile, err)
	}
	sourceFile = path.Join(sourcePath, "event_test.go")
	if err = ioutil.WriteFile(sourceFile, []byte{}, 0600); err != nil {
		t.Fatalf("Unable to create tempory file %s, %s", sourceFile, err)
	}
	defer func() {
		if err = os.RemoveAll(rootPath); err != nil {
			fmt.Printf("Error removing %s dir, %s", rootPath, err)
		}
	}()

	// Replace env.Paths with a mock
	savePaths := env.Paths
	env.Paths = func(path ...string) (string, string, error) {
		return rootPath, gtmPath, nil
	}
	defer func() { env.Paths = savePaths }()

	var (
		wd          string
		fixturePath string
		cmd         *exec.Cmd
		files       []os.FileInfo
	)

	// Copy fixtures
	wd, err = os.Getwd()
	if err != nil {
		t.Fatalf("Sweep(), error getting current working directory, %s", err)
	}
	fixturePath = path.Join(wd, "../event/test-fixtures")
	files, err = ioutil.ReadDir(fixturePath)
	for _, f := range files {
		cmd = exec.Command("cp", path.Join(fixturePath, f.Name()), gtmPath)
		_, err = cmd.Output()
		if err != nil {
			t.Fatalf("Unable to copy %s directory to %s", fixturePath, gtmPath)
		}
	}

	// Chandge working directory and initialize git repo
	os.Chdir(rootPath)
	cmd = exec.Command("git", "init")
	b, err := cmd.Output()
	if err != nil {
		t.Fatalf("Unable to initialize git repo, %s", string(b))
	}

	// Commit source files to git repo
	cmd = exec.Command("git", "add", "event/")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git add, %s", string(b))
	}
	cmd = exec.Command("git", "commit", "-m", "Initial commit")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git commit, %s", string(b))
	}

	err = Process(false)
	if err != nil {
		t.Fatalf("Process(false), want error nil, got %s", err)
	}

	cmd = exec.Command("git", "notes", "--ref", "gtm", "show")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git notes, %s", string(b))
	}

	want := []string{"total: 300", "event.go: 280", "event_test.go: 20"}
	for _, s := range want {
		if !strings.Contains(string(b), s) {
			t.Errorf("Process(false), \nwant \n%s, \ngot \n%s", s, string(b))
		}

	}
}
<commit_msg>Test processing partial commit<commit_after>package metric

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"edgeg.io/gtm/env"
)

var testdata string = `
1458681900:map[vim.log:1]
1458682260:map[cmd/commit.go:1]
1458683340:map[event/event.go:1]
1458682740:map[vim.log:1]
1458676380:map[scm/git.go:1]
1458682440:map[event/event.go:2 metric/metric.go:1]
1458683460:map[vim.log:2]
1458682200:map[event/event.go:2 cmd/commit.go:2]
1458911580:map[metric/metric.go:1]
1458683400:map[event/event.go:4 event/event_test.go:2]
1458911460:map[metric/metric.go:2]
1458682320:map[cmd/commit.go:1]
1458682500:map[event/event.go:1]
1458682560:map[event/event.go:2]
1458681780:map[vim.log:1]
1458682080:map[event/event.go:1]
1458682620:map[vim.log:1]
1458683580:map[vim.log:1]
1458676500:map[scm/git.go:1]
1458676560:map[scm/git.go:1]
1458682020:map[cmd/record.go:1 env/env.go:1]
1458682140:map[cmd/record.go:2 event/event.go:2]
1458911520:map[metric/metric.go:1]
1458676440:map[scm/git.go:1]
1458681840:map[vim.log:1]
1458682680:map[vim.log:1]
1458911400:map[event/event_test.go:2]
1458683520:map[vim.log:1]]

6f53bc90ba625b5afaac80b422b44f1f609d6367:{Updated:true GitFile:event/event.go Time:380}
fd3de0b7135021cc4c5ef23b8bea9ff98b704c47:{Updated:true GitFile:scm/git.go Time:240}
26c5bdda12d74ceb9cf191911a79454bccd80640:{Updated:true GitFile:metric/metric.go Time:200}
e65b42b6bf1eda6349451b063d46134dd7ab9921:{Updated:true GitFile:event/event_test.go Time:80}
f93cea510c5049ff60ef12c62825a53f7d6e7d48:{Updated:true GitFile:cmd/record.go Time:60}
1301df137d0acac0abf8cdc29bb74ef39ad2b042:{Updated:true GitFile:env/env.go Time:30}
2dbf769f7faf2f921b89f3ff9d81d7b5e02a17a5:{Updated:true GitFile:vim.log Time:540}
c2369545266e4a15c3db04a9f52b021364330bb7:{Updated:true GitFile:cmd/commit.go Time:150}]
`

func TestAllocateTime(t *testing.T) {
	cases := []struct {
		metric   map[string]metricFile
		event    map[string]int
		expected map[string]metricFile
	}{
		{
			map[string]metricFile{},
			map[string]int{"event/event.go": 1},
			map[string]metricFile{
				"6f53bc90ba625b5afaac80b422b44f1f609d6367": metricFile{Updated: true, GitFile: "event/event.go", Time: 60}},
		},
		{
			map[string]metricFile{},
			map[string]int{"event/event.go": 4, "event/event_test.go": 2},
			map[string]metricFile{
				"6f53bc90ba625b5afaac80b422b44f1f609d6367": metricFile{Updated: true, GitFile: "event/event.go", Time: 40},
				"e65b42b6bf1eda6349451b063d46134dd7ab9921": metricFile{Updated: true, GitFile: "event/event_test.go", Time: 20}},
		},
		{
			map[string]metricFile{"e65b42b6bf1eda6349451b063d46134dd7ab9921": metricFile{Updated: true, GitFile: "event/event_test.go", Time: 60}},
			map[string]int{"event/event.go": 4, "event/event_test.go": 2},
			map[string]metricFile{
				"6f53bc90ba625b5afaac80b422b44f1f609d6367": metricFile{Updated: true, GitFile: "event/event.go", Time: 40},
				"e65b42b6bf1eda6349451b063d46134dd7ab9921": metricFile{Updated: true, GitFile: "event/event_test.go", Time: 80}},
		},
	}

	for _, tc := range cases {
		// copy metric map because it's updated in place during testing
		metricOrig := map[string]metricFile{}
		for k, v := range tc.metric {
			metricOrig[k] = v

		}
		allocateTime(tc.metric, tc.event)
		if !reflect.DeepEqual(tc.metric, tc.expected) {
			t.Errorf("allocateTime(%+v, %+v)\n want %+v\n got  %+v\n", metricOrig, tc.event, tc.expected, tc.metric)
		}
	}
}

func TestFileID(t *testing.T) {
	want := "6f53bc90ba625b5afaac80b422b44f1f609d6367"
	got := getFileID("event/event.go")
	if want != got {
		t.Errorf("getFileID(%s), want %s, got %s", "event/event.go", want, got)

	}
}

func TestProcess(t *testing.T) {
	if runtime.GOOS == "windows" {
		// TODO: fix this, exec.Command("cp", path.Join(fixturePath, f.Name()), gtmPath) is not compatible with Windows
		fmt.Println("Skipping TestSweep, not compatible with Windows")
		return
	}

	rootPath, _, f1 := processSetup(t)
	defer f1()

	var (
		cmd *exec.Cmd
	)

	// Test process with committing both git tracked files that have been modified

	// chandge working directory and initialize git repo
	savedCurDir, _ := os.Getwd()
	defer func() { os.Chdir(savedCurDir) }()
	os.Chdir(rootPath)
	cmd = exec.Command("git", "init")
	b, err := cmd.Output()
	if err != nil {
		t.Fatalf("Unable to initialize git repo, %s", string(b))
	}

	// commit source files to git repo
	cmd = exec.Command("git", "add", "event/")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git add, %s", string(b))
	}
	cmd = exec.Command("git", "commit", "-m", "Initial commit")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git commit, %s", string(b))
	}

	err = Process(false)
	if err != nil {
		t.Fatalf("Process(false), want error nil, got %s", err)
	}

	cmd = exec.Command("git", "notes", "--ref", "gtm", "show")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git notes, %s", string(b))
	}

	want := []string{"total: 300", "event.go: 280", "event_test.go: 20"}
	for _, s := range want {
		if !strings.Contains(string(b), s) {
			t.Errorf("Process(false) - test full commit, \nwant \n%s, \ngot \n%s", s, string(b))
		}

	}

	// Test Process with committing only one of the two git tracked files that have been modified

	// change back to saved current working directory and setup
	os.Chdir(savedCurDir)
	rootPath, gtmPath, f2 := processSetup(t)
	defer f2()

	// chandge working directory and initialize git repo
	os.Chdir(rootPath)
	cmd = exec.Command("git", "init")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to initialize git repo, %s", string(b))
	}

	// commit source files to git repo
	cmd = exec.Command("git", "add", "event/event_test.go")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git add, %s", string(b))
	}
	cmd = exec.Command("git", "commit", "-m", "Initial commit")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git commit, %s", string(b))
	}

	err = Process(false)
	if err != nil {
		t.Fatalf("Process(false), want error nil, got %s", err)
	}

	cmd = exec.Command("git", "notes", "--ref", "gtm", "show")
	b, err = cmd.Output()
	if err != nil {
		t.Fatalf("Unable to run git notes, %s", string(b))
	}

	want = []string{"total: 20", "event_test.go: 20"}
	for _, s := range want {
		if !strings.Contains(string(b), s) {
			t.Errorf("Process(false), \nwant \n%s, \ngot \n%s", s, string(b))
		}

	}
	p := path.Join(gtmPath, "6f53bc90ba625b5afaac80b422b44f1f609d6367.metric")
	if !env.FileExists(path.Join(gtmPath, p)) {
		t.Errorf("Process(false) - test partial commit, want file %s exist, got file exists false", p)
	}
}

func processSetup(t *testing.T) (string, string, func()) {
	var (
		rootPath   string
		gtmPath    string
		sourcePath string
		sourceFile string
		err        error
	)

	// setup directories and source files
	rootPath, err = ioutil.TempDir("", "gtm")
	if err != nil {
		t.Fatalf("Unable to create tempory directory %s, %s", rootPath, err)
	}
	gtmPath = path.Join(rootPath, ".gtm")
	if err = os.MkdirAll(gtmPath, 0700); err != nil {
		t.Fatalf("Unable to create tempory directory %s, %s", gtmPath, err)
	}
	sourcePath = path.Join(rootPath, "event")
	if err = os.MkdirAll(sourcePath, 0700); err != nil {
		t.Fatalf("Unable to create tempory directory %s, %s", sourcePath, err)
	}
	sourceFile = path.Join(sourcePath, "event.go")
	if err = ioutil.WriteFile(sourceFile, []byte{}, 0600); err != nil {
		t.Fatalf("Unable to create tempory file %s, %s", sourceFile, err)
	}
	sourceFile = path.Join(sourcePath, "event_test.go")
	if err = ioutil.WriteFile(sourceFile, []byte{}, 0600); err != nil {
		t.Fatalf("Unable to create tempory file %s, %s", sourceFile, err)
	}

	// replace env.Paths with a mock
	savePaths := env.Paths
	env.Paths = func(path ...string) (string, string, error) {
		return rootPath, gtmPath, nil
	}

	var (
		wd          string
		fixturePath string
		cmd         *exec.Cmd
		files       []os.FileInfo
	)

	// copy fixtures
	wd, err = os.Getwd()
	if err != nil {
		t.Fatalf("Sweep(), error getting current working directory, %s", err)
	}
	fixturePath = path.Join(wd, "../event/test-fixtures")
	files, err = ioutil.ReadDir(fixturePath)
	for _, f := range files {
		cmd = exec.Command("cp", path.Join(fixturePath, f.Name()), gtmPath)
		_, err = cmd.Output()
		if err != nil {
			t.Fatalf("Unable to copy %s directory to %s", fixturePath, gtmPath)
		}
	}

	return rootPath, gtmPath, func() {
		env.Paths = savePaths
		if err = os.RemoveAll(rootPath); err != nil {
			fmt.Printf("Error removing %s dir, %s", rootPath, err)
		}
	}
}
<|endoftext|>


<commit_before>package nethttp

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"path/filepath"
	"sort"
	"strings"

	"github.com/lestrrat/go-hsup/internal/genutil"
	"github.com/lestrrat/go-jshschema"
	"github.com/lestrrat/go-jsschema"
	"github.com/lestrrat/go-jsval"
	"github.com/lestrrat/go-jsval/builder"
	"github.com/lestrrat/go-pdebug"
)

type Builder struct {
	AppPkg       string
	ValidatorPkg string
}

type genctx struct {
	apppkg             string
	schema             *hschema.HyperSchema
	clientpkg          string
	validatorpkg       string
	methods            map[string]string
	methodPayloadType  map[string]string
	methodNames        []string
	pathToMethods      map[string]string
	requestValidators  map[string]*jsval.JSVal
	responseValidators map[string]*jsval.JSVal
}

func New() *Builder {
	return &Builder{
		AppPkg:       "app",
		ValidatorPkg: "validator",
	}
}

func (b *Builder) ProcessFile(f string) error {
	log.Printf(" ===> Using schema file '%s'", f)
	s, err := hschema.ReadFile(f)
	if err != nil {
		return err
	}
	return b.Process(s)
}

func (b *Builder) Process(s *hschema.HyperSchema) error {
	ctx := genctx{
		schema:             s,
		methodNames:        make([]string, len(s.Links)),
		apppkg:             b.AppPkg,
		clientpkg:          "client",
		validatorpkg:       b.ValidatorPkg,
		methods:            make(map[string]string),
		methodPayloadType:  make(map[string]string),
		pathToMethods:      make(map[string]string),
		requestValidators:  make(map[string]*jsval.JSVal),
		responseValidators: make(map[string]*jsval.JSVal),
	}

	if err := parse(&ctx, s); err != nil {
		return err
	}

	if err := generateFiles(&ctx); err != nil {
		return err
	}

	log.Printf(" <=== All files generated")
	return nil
}

func parse(ctx *genctx, s *hschema.HyperSchema) error {
	for i, link := range s.Links {
		methodName := genutil.TitleToName(link.Title)

		// Got to do this first, because validators are used in makeMethod()
		if s := link.Schema; s != nil {
			v, err := makeValidator(ctx, s)
			if err != nil {
				return err
			}
			v.Name = fmt.Sprintf("HTTP%sRequest", methodName)
			ctx.requestValidators[methodName] = v
		}
		ctx.methodPayloadType[methodName] = "interface{}"
		if s := link.TargetSchema; s != nil {
			v, err := makeValidator(ctx, s)
			if err != nil {
				return err
			}
			v.Name = fmt.Sprintf("HTTP%sResponse", methodName)
			ctx.responseValidators[methodName] = v
		}
		if ls := link.Schema; ls != nil {
			if !ls.IsResolved() {
				rs, err := ls.Resolve(ctx.schema)
				if err != nil {
					return err
				}
				ls = rs
			}
			if pdebug.Enabled {
				pdebug.Printf("checking extras for %s: %#v", link.Path(), ls.Extras)
			}
			if gt, ok := ls.Extras["gotype"]; ok {
				ctx.methodPayloadType[methodName] = gt.(string)
			}
		}
		ctx.methodNames[i] = methodName
		ctx.pathToMethods[link.Path()] = methodName
		ctx.methods[methodName] = makeMethod(ctx, methodName, link)
	}

	sort.Strings(ctx.methodNames)
	return nil
}

func makeMethod(ctx *genctx, name string, l *hschema.Link) string {
	buf := bytes.Buffer{}

	fmt.Fprintf(&buf, `func http%s(w http.ResponseWriter, r *http.Response) {`+"\n", name)
	if m := l.Method; m != "" {
		buf.WriteString("\tif strings.ToLower(r.Method) != `")
		fmt.Fprintf(&buf, "%s", strings.ToLower(m))
		buf.WriteString("` {\n\t\thttp.Error(w, `Not Found`, http.StatusNotFound)\n\t}\n")
	}

	if v := ctx.requestValidators[name]; v != nil {
		payloadType := ctx.methodPayloadType[name]
		fmt.Fprintf(&buf, "\n\tvar payload %s", payloadType)
		buf.WriteString("\n\tif err := json.NewDecoder(r.Body).Decode(&payload); err != nil {")
		buf.WriteString("\n\t\thttp.Error(w, `Invalid input`, http.StatusInternalServerError)")
		buf.WriteString("\n\t\treturn")
		buf.WriteString("\n\t}")
		fmt.Fprintf(&buf, "\n\n\tif err := %s.%s.Validate(payload); err != nil {", ctx.validatorpkg, v.Name)
		buf.WriteString("\n\t\thttp.Error(w, `Invalid input`, http.StatusInternalServerError)")
		buf.WriteString("\n\t\treturn")
		buf.WriteString("\n\t}")
	}

	fmt.Fprintf(&buf, "\n\tdo%s(context.Background(), w, r, payload)", name)
	buf.WriteString("\n}\n")
	return buf.String()
}

func makeValidator(ctx *genctx, s *schema.Schema) (*jsval.JSVal, error) {
	b := builder.New()
	v, err := b.BuildWithCtx(s, ctx.schema)
	if err != nil {
		return nil, err
	}

	return v, nil
}

func generateFile(ctx *genctx, fn string, cb func(io.Writer, *genctx) error) error {
	log.Printf(" + Generating file '%s'", fn)
	f, err := genutil.CreateFile(fn)
	if err != nil {
		return err
	}
	defer f.Close()
	return cb(f, ctx)
}

func generateFiles(ctxif interface{}) error {
	ctx, ok := ctxif.(*genctx)
	if !ok {
		return errors.New("expected genctx type")
	}

	{
		fn := filepath.Join(ctx.apppkg, fmt.Sprintf("%s.go", ctx.apppkg))
		if err := generateFile(ctx, fn, generateServerCode); err != nil {
			return err
		}
	}

	{
		fn := filepath.Join(ctx.apppkg, ctx.validatorpkg, fmt.Sprintf("%s.go", ctx.validatorpkg))
		if err := generateFile(ctx, fn, generateValidatorCode); err != nil {
			return err
		}
	}

	return nil
}

func generateServerCode(out io.Writer, ctx *genctx) error {
	buf := bytes.Buffer{}

	fmt.Fprintf(&buf, "package %s\n\n", ctx.apppkg)

	genutil.WriteImports(
		&buf,
		[]string{
			"net/http",
			"strings",
		},
		[]string{
			"github.com/gorilla/mux",
			"golang.org/x/context",
		},
	)

	buf.WriteString(`
type Server struct {
	*mux.Router
}

func New() *Server {
	s := &Server{
		Router: mux.NewRouter(),
	}
	s.SetupRoutes()
	return s
}

`)

	for _, methodName := range ctx.methodNames {
		buf.WriteString(ctx.methods[methodName])
		buf.WriteString("\n")
	}

	buf.WriteString("func (s *Server) SetupRoutes() {")
	buf.WriteString("\n\tr := s.Router")
	paths := make([]string, 0, len(ctx.pathToMethods))
	for path := range ctx.pathToMethods {
		paths = append(paths, path)
	}
	sort.Strings(paths)
	for _, path := range paths {
		method := ctx.pathToMethods[path]
		fmt.Fprintf(&buf, "\n\tr.HandleFunc(`%s`, %s)", path, method)
	}
	buf.WriteString("\n}\n")

	if _, err := buf.WriteTo(out); err != nil {
		return err
	}
	return nil
}

func generateValidatorCode(out io.Writer, ctx *genctx) error {
	g := jsval.NewGenerator()
	validators := make([]*jsval.JSVal, 0, len(ctx.requestValidators)+len(ctx.responseValidators))
	for _, v := range ctx.requestValidators {
		validators = append(validators, v)
	}
	for _, v := range ctx.responseValidators {
		validators = append(validators, v)
	}

	buf := bytes.Buffer{}
	buf.WriteString("package " + ctx.validatorpkg + "\n\n")

	genutil.WriteImports(
		&buf,
		nil,
		[]string{
			"github.com/lestrrat/go-jsval",
		},
	)
	if err := g.Process(&buf, validators...); err != nil {
		return err
	}
	buf.WriteString("\n\n")

	if _, err := buf.WriteTo(out); err != nil {
		return err
	}

	return nil
}
<commit_msg>format!<commit_after>package nethttp

import (
	"bytes"
	"errors"
	"fmt"
	"go/format"
	"io"
	"log"
	"path/filepath"
	"sort"
	"strings"

	"github.com/lestrrat/go-hsup/internal/genutil"
	"github.com/lestrrat/go-jshschema"
	"github.com/lestrrat/go-jsschema"
	"github.com/lestrrat/go-jsval"
	"github.com/lestrrat/go-jsval/builder"
	"github.com/lestrrat/go-pdebug"
)

type Builder struct {
	AppPkg       string
	ValidatorPkg string
}

type genctx struct {
	apppkg             string
	schema             *hschema.HyperSchema
	clientpkg          string
	validatorpkg       string
	methods            map[string]string
	methodPayloadType  map[string]string
	methodNames        []string
	pathToMethods      map[string]string
	requestValidators  map[string]*jsval.JSVal
	responseValidators map[string]*jsval.JSVal
}

func New() *Builder {
	return &Builder{
		AppPkg:       "app",
		ValidatorPkg: "validator",
	}
}

func (b *Builder) ProcessFile(f string) error {
	log.Printf(" ===> Using schema file '%s'", f)
	s, err := hschema.ReadFile(f)
	if err != nil {
		return err
	}
	return b.Process(s)
}

func (b *Builder) Process(s *hschema.HyperSchema) error {
	ctx := genctx{
		schema:             s,
		methodNames:        make([]string, len(s.Links)),
		apppkg:             b.AppPkg,
		clientpkg:          "client",
		validatorpkg:       b.ValidatorPkg,
		methods:            make(map[string]string),
		methodPayloadType:  make(map[string]string),
		pathToMethods:      make(map[string]string),
		requestValidators:  make(map[string]*jsval.JSVal),
		responseValidators: make(map[string]*jsval.JSVal),
	}

	if err := parse(&ctx, s); err != nil {
		return err
	}

	if err := generateFiles(&ctx); err != nil {
		return err
	}

	log.Printf(" <=== All files generated")
	return nil
}

func parse(ctx *genctx, s *hschema.HyperSchema) error {
	for i, link := range s.Links {
		methodName := genutil.TitleToName(link.Title)

		// Got to do this first, because validators are used in makeMethod()
		if s := link.Schema; s != nil {
			v, err := makeValidator(ctx, s)
			if err != nil {
				return err
			}
			v.Name = fmt.Sprintf("HTTP%sRequest", methodName)
			ctx.requestValidators[methodName] = v
		}
		ctx.methodPayloadType[methodName] = "interface{}"
		if s := link.TargetSchema; s != nil {
			v, err := makeValidator(ctx, s)
			if err != nil {
				return err
			}
			v.Name = fmt.Sprintf("HTTP%sResponse", methodName)
			ctx.responseValidators[methodName] = v
		}
		if ls := link.Schema; ls != nil {
			if !ls.IsResolved() {
				rs, err := ls.Resolve(ctx.schema)
				if err != nil {
					return err
				}
				ls = rs
			}
			if pdebug.Enabled {
				pdebug.Printf("checking extras for %s: %#v", link.Path(), ls.Extras)
			}
			if gt, ok := ls.Extras["gotype"]; ok {
				ctx.methodPayloadType[methodName] = gt.(string)
			}
		}
		ctx.methodNames[i] = methodName
		ctx.pathToMethods[link.Path()] = methodName
		ctx.methods[methodName] = makeMethod(ctx, methodName, link)
	}

	sort.Strings(ctx.methodNames)
	return nil
}

func makeMethod(ctx *genctx, name string, l *hschema.Link) string {
	buf := bytes.Buffer{}

	fmt.Fprintf(&buf, `func http%s(w http.ResponseWriter, r *http.Response) {`+"\n", name)
	if m := l.Method; m != "" {
		buf.WriteString("\tif strings.ToLower(r.Method) != `")
		fmt.Fprintf(&buf, "%s", strings.ToLower(m))
		buf.WriteString("` {\n\t\thttp.Error(w, `Not Found`, http.StatusNotFound)\n\t}\n")
	}

	if v := ctx.requestValidators[name]; v != nil {
		payloadType := ctx.methodPayloadType[name]
		fmt.Fprintf(&buf, "\n\tvar payload %s", payloadType)
		buf.WriteString("\n\tif err := json.NewDecoder(r.Body).Decode(&payload); err != nil {")
		buf.WriteString("\n\t\thttp.Error(w, `Invalid input`, http.StatusInternalServerError)")
		buf.WriteString("\n\t\treturn")
		buf.WriteString("\n\t}")
		fmt.Fprintf(&buf, "\n\n\tif err := %s.%s.Validate(payload); err != nil {", ctx.validatorpkg, v.Name)
		buf.WriteString("\n\t\thttp.Error(w, `Invalid input`, http.StatusInternalServerError)")
		buf.WriteString("\n\t\treturn")
		buf.WriteString("\n\t}")
	}

	fmt.Fprintf(&buf, "\n\tdo%s(context.Background(), w, r, payload)", name)
	buf.WriteString("\n}\n")
	return buf.String()
}

func makeValidator(ctx *genctx, s *schema.Schema) (*jsval.JSVal, error) {
	b := builder.New()
	v, err := b.BuildWithCtx(s, ctx.schema)
	if err != nil {
		return nil, err
	}

	return v, nil
}

func generateFile(ctx *genctx, fn string, cb func(io.Writer, *genctx) error) error {
	log.Printf(" + Generating file '%s'", fn)
	f, err := genutil.CreateFile(fn)
	if err != nil {
		return err
	}
	defer f.Close()
	return cb(f, ctx)
}

func generateFiles(ctxif interface{}) error {
	ctx, ok := ctxif.(*genctx)
	if !ok {
		return errors.New("expected genctx type")
	}

	{
		fn := filepath.Join(ctx.apppkg, fmt.Sprintf("%s.go", ctx.apppkg))
		if err := generateFile(ctx, fn, generateServerCode); err != nil {
			return err
		}
	}

	{
		fn := filepath.Join(ctx.apppkg, ctx.validatorpkg, fmt.Sprintf("%s.go", ctx.validatorpkg))
		if err := generateFile(ctx, fn, generateValidatorCode); err != nil {
			return err
		}
	}

	return nil
}

func generateServerCode(out io.Writer, ctx *genctx) error {
	buf := bytes.Buffer{}

	fmt.Fprintf(&buf, "package %s\n\n", ctx.apppkg)

	genutil.WriteImports(
		&buf,
		[]string{
			"net/http",
			"strings",
		},
		[]string{
			"github.com/gorilla/mux",
			"golang.org/x/context",
		},
	)

	buf.WriteString(`
type Server struct {
	*mux.Router
}

func New() *Server {
	s := &Server{
		Router: mux.NewRouter(),
	}
	s.SetupRoutes()
	return s
}

`)

	for _, methodName := range ctx.methodNames {
		buf.WriteString(ctx.methods[methodName])
		buf.WriteString("\n")
	}

	buf.WriteString("func (s *Server) SetupRoutes() {")
	buf.WriteString("\n\tr := s.Router")
	paths := make([]string, 0, len(ctx.pathToMethods))
	for path := range ctx.pathToMethods {
		paths = append(paths, path)
	}
	sort.Strings(paths)
	for _, path := range paths {
		method := ctx.pathToMethods[path]
		fmt.Fprintf(&buf, "\n\tr.HandleFunc(`%s`, %s)", path, method)
	}
	buf.WriteString("\n}\n")

	fsrc, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}

	if _, err := out.Write(fsrc); err != nil {
		return err
	}
	return nil
}

func generateValidatorCode(out io.Writer, ctx *genctx) error {
	g := jsval.NewGenerator()
	validators := make([]*jsval.JSVal, 0, len(ctx.requestValidators)+len(ctx.responseValidators))
	for _, v := range ctx.requestValidators {
		validators = append(validators, v)
	}
	for _, v := range ctx.responseValidators {
		validators = append(validators, v)
	}

	buf := bytes.Buffer{}
	buf.WriteString("package " + ctx.validatorpkg + "\n\n")

	genutil.WriteImports(
		&buf,
		nil,
		[]string{
			"github.com/lestrrat/go-jsval",
		},
	)
	if err := g.Process(&buf, validators...); err != nil {
		return err
	}
	buf.WriteString("\n\n")

	fsrc, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}

	if _, err := out.Write(fsrc); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Hari haran. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

// +build linux

// Package network provides different network related data.
package network

import (
	"net"
	"os/exec"
	"strconv"
	"strings"
)

// Data represents the network data.
type Data map[string]interface{}

// CollectData collects the data and returns an error if any.
func CollectData() (Data, error) {
	d := make(Data)
	d["interfaces"] = make(map[string]interface{})
	ifaces := d["interfaces"].(map[string]interface{})
	out, err := exec.Command("ip", "addr").Output()
	if err != nil {
		return d, err
	}
	lines := strings.Split(string(out), "\n")
	var (
		name  string
		iface map[string]interface{}
		addrs map[string]interface{}
	)
	for i := 0; i < len(lines); i++ {
		line := lines[i]
		if strings.ContainsAny(line, "<>") {
			// 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
			a := strings.Fields(line)
			name = strings.Trim(a[1], " :")
			ifaces[name] = make(map[string]interface{})
			iface = ifaces[name].(map[string]interface{})
			flags := strings.Split(strings.Trim(a[2], "<> "), ",")
			iface["flags"] = flags
			for i := range a {
				if a[i] == "mtu" {
					iface["mtu"] = a[i+1]
				}

				if a[i] == "state" {
					iface["state"] = strings.ToLower(a[i+1])
				}
			}
			iface["addresses"] = make(map[string]interface{})
			addrs = iface["addresses"].(map[string]interface{})

		} else {
			line = strings.TrimSpace(line)
			// link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
			// link/ether 4c:eb:42:0f:8e:99 brd ff:ff:ff:ff:ff:ff
			if strings.HasPrefix(line, "link/") {
				a := strings.Fields(line)
				iface["encapsulation"] = strings.TrimPrefix(a[0], "link/")
				if len(a) >= 4 {
					if a[1] != "00:00:00:00:00:00" {
						addrs[a[1]] = map[string]string{
							"family": "lladdr",
						}
					}
				}
			}

			if strings.HasPrefix(line, "inet") {
				a := strings.Fields(line)
				// inet 192.168.1.119/24 brd 192.168.1.255 scope global wlan0
				// inet 127.0.0.1/8 scope host lo
				if len(a) >= 5 {
					ip, ipnet, err := net.ParseCIDR(a[1])
					if err != nil {
						return d, err
					}
					ones, _ := ipnet.Mask.Size() // ignore the number of bits
					var tempScope string
					for i := range a {
						if a[i] == "scope" {
							tempScope = scope(a[i+1])
						}
					}
					addrs[ip.String()] = make(map[string]string)
					t := addrs[ip.String()].(map[string]string)
					t["family"] = "inet"
					t["prefixlen"] = strconv.Itoa(ones)
					t["scope"] = tempScope

					// by converting into IP type, we get the string in the form a.b.c.d
					t["netmask"] = net.IP(ipnet.Mask).String()

					for i := range a {
						if a[i] == "brd" {
							t["broadcast"] = a[i+1]
						}

						if a[i] == "peer" {
							t["peer"] = a[i+1]
						}
					}
				}
			}

			if strings.HasPrefix(line, "inet6") {
				a := strings.Fields(line)
				// inet6 ::1/128 scope host
				if len(a) >= 4 {
					ip, ipnet, err := net.ParseCIDR(a[1])
					if err != nil {
						return d, err
					}
					ones, _ := ipnet.Mask.Size() // ignore the number of bits
					addrs[ip.String()] = map[string]string{
						"family":    "inet6",
						"prefixlen": strconv.Itoa(ones),
						"scope":     scope(a[3]),
					}
				}
			}
		}
	}

	if err := defaultGateway(d); err != nil {
		return d, err
	}

	if err := arp(d); err != nil {
		return d, err
	}

	return d, nil
}

func scope(s string) string {
	if s == "host" {
		return "Node"
	}
	return strings.Title(s)
}

// defaultGateway adds the default gateway and default interface
// data to the given map.
func defaultGateway(d Data) error {
	out, err := exec.Command("route", "-n").Output()
	if err != nil {
		return err
	}
	s := strings.Split(string(out), "\n")
	// s[0] is the title, s[1] is the column headings. Also, we only
	// consider s[2] for the default interface and gateway.
	a := strings.Fields(s[2])
	d["default_gateway"] = a[1]
	d["default_interface"] = a[7]
	return nil
}

// arp adds the arp data to the given map.
func arp(d Data) error {
	out, err := exec.Command("arp", "-an").Output()
	if err != nil {
		return err
	}
	s := strings.Split(string(out), "\n")
	for i := range s {
		line := s[i]
		// ? (192.164.1.1) at 48:f8:c3:46:03:44 [ether] on wlan
		a := strings.Fields(line)
		if len(a) >= 4 {
			d["arp"] = map[string]string{
				strings.Trim(a[1], "()"): a[3],
			}
		}
	}
	return nil
}
<commit_msg>network: add routes and neighbours data<commit_after>// Copyright 2015 Hari haran. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

// +build linux

// Package network provides different network related data.
package network

import (
	"net"
	"os/exec"
	"strconv"
	"strings"

	"github.com/hariharan-uno/recon/internal/fileutil"
)

// Data represents the network data.
type Data map[string]interface{}

// CollectData collects the data and returns an error if any.
func CollectData() (Data, error) {
	d := make(Data)
	d["interfaces"] = make(map[string]interface{})
	ifaces := d["interfaces"].(map[string]interface{})
	out, err := exec.Command("ip", "addr").Output()
	if err != nil {
		return d, err
	}
	lines := strings.Split(string(out), "\n")
	var (
		name  string
		iface map[string]interface{}
		addrs map[string]interface{}
	)
	for i := 0; i < len(lines); i++ {
		line := lines[i]
		if strings.ContainsAny(line, "<>") {
			// 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
			a := strings.Fields(line)
			name = strings.Trim(a[1], " :")
			ifaces[name] = make(map[string]interface{})
			iface = ifaces[name].(map[string]interface{})
			flags := strings.Split(strings.Trim(a[2], "<> "), ",")
			iface["flags"] = flags
			for i := range a {
				if a[i] == "mtu" {
					iface["mtu"] = a[i+1]
				}

				if a[i] == "state" {
					iface["state"] = strings.ToLower(a[i+1])
				}
			}
			iface["addresses"] = make(map[string]interface{})
			addrs = iface["addresses"].(map[string]interface{})

		} else {
			line = strings.TrimSpace(line)
			// link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
			// link/ether 4c:eb:42:0f:8e:99 brd ff:ff:ff:ff:ff:ff
			if strings.HasPrefix(line, "link/") {
				a := strings.Fields(line)
				iface["encapsulation"] = strings.TrimPrefix(a[0], "link/")
				if len(a) >= 4 {
					if a[1] != "00:00:00:00:00:00" {
						addrs[a[1]] = map[string]string{
							"family": "lladdr",
						}
					}
				}
			}

			if strings.HasPrefix(line, "inet") {
				a := strings.Fields(line)
				// inet 192.168.1.119/24 brd 192.168.1.255 scope global wlan0
				// inet 127.0.0.1/8 scope host lo
				if len(a) >= 5 {
					ip, ipnet, err := net.ParseCIDR(a[1])
					if err != nil {
						return d, err
					}
					ones, _ := ipnet.Mask.Size() // ignore the number of bits
					var tempScope string
					for i := range a {
						if a[i] == "scope" {
							tempScope = scope(a[i+1])
						}
					}
					addrs[ip.String()] = make(map[string]string)
					t := addrs[ip.String()].(map[string]string)
					t["family"] = "inet"
					t["prefixlen"] = strconv.Itoa(ones)
					t["scope"] = tempScope

					// by converting into IP type, we get the string in the form a.b.c.d
					t["netmask"] = net.IP(ipnet.Mask).String()

					for i := range a {
						if a[i] == "brd" {
							t["broadcast"] = a[i+1]
						}

						if a[i] == "peer" {
							t["peer"] = a[i+1]
						}
					}
				}
			}

			if strings.HasPrefix(line, "inet6") {
				a := strings.Fields(line)
				// inet6 ::1/128 scope host
				if len(a) >= 4 {
					ip, ipnet, err := net.ParseCIDR(a[1])
					if err != nil {
						return d, err
					}
					ones, _ := ipnet.Mask.Size() // ignore the number of bits
					addrs[ip.String()] = map[string]string{
						"family":    "inet6",
						"prefixlen": strconv.Itoa(ones),
						"scope":     scope(a[3]),
					}
				}
			}
		}
	}

	if err := defaultGateway(d); err != nil {
		return d, err
	}

	if err := routes(d); err != nil {
		return d, err
	}

	if err := neighbours(d); err != nil {
		return d, err
	}

	// arp data is added in the neighbours function itself.
	// If that fails, this one adds the arp data.
	if err := arp(d); err != nil {
		return d, err
	}

	return d, nil
}

func scope(s string) string {
	if s == "host" {
		return "Node"
	}
	return strings.Title(s)
}

// defaultGateway adds the default gateway and default interface
// data to the given map.
func defaultGateway(d Data) error {
	out, err := exec.Command("route", "-n").Output()
	if err != nil {
		return err
	}
	s := strings.Split(string(out), "\n")
	// s[0] is the title, s[1] is the column headings. Also, we only
	// consider s[2] for the default interface and gateway.
	a := strings.Fields(s[2])
	d["default_gateway"] = a[1]
	d["default_interface"] = a[7]
	return nil
}

// arp adds the arp data to the given map.
func arp(d Data) error {
	out, err := exec.Command("arp", "-an").Output()
	if err != nil {
		return err
	}
	s := strings.Split(string(out), "\n")
	for i := range s {
		line := s[i]
		// ? (192.164.1.1) at 48:f8:c3:46:03:44 [ether] on wlan
		a := strings.Fields(line)
		if len(a) >= 4 {
			d["arp"] = map[string]string{
				strings.Trim(a[1], "()"): a[3],
			}
		}
	}
	return nil
}

// ipv6Enabled returns true if IPv6 is enabled
// on the machine.
func ipv6Enabled() bool {
	return fileutil.Exists("/proc/net/if_inet6")
}

// families to get default routes from.
var families = []map[string]string{
	{
		"name":               "inet",
		"defaultRoute":       "0.0.0.0/0",
		"defaultPrefix":      "default",
		"neighbourAttribute": "arp",
	},
}

func init() {
	if ipv6Enabled() {
		families = append(families, map[string]string{
			"name":               "inet6",
			"defaultRoute":       "::/0",
			"defaultPrefix":      "default_inet6",
			"neighbourAttribute": "neighbour_inet6",
		})
	}
}

// neighbours adds the neighbours data of families to the given map.
func neighbours(d Data) error {
	for _, family := range families {
		out, err := exec.Command("ip", "-f", family["name"], "neigh", "show").Output()
		if err != nil {
			return err
		}
		lines := strings.Split(string(out), "\n")
		for _, line := range lines {
			a := strings.Fields(line)
			// 192.167.1.1 dev wlan0 lladdr 48:f8:b3:36:03:44 REACHABLE
			// fe80::4af7:b3ff:fe36:344 dev wlan0 lladdr 48:f8:b3:36:06:44 router STALE
			if len(a) >= 5 {
				d[family["neighbourAttribute"]] = map[string]string{
					a[0]: a[4],
				}
			}
		}
	}
	return nil
}

func routes(d Data) error {
	var routes []map[string]string
	for _, family := range families {
		out, err := exec.Command("ip", "-o", "-f", family["name"], "route", "show").Output()
		if err != nil {
			return err
		}
		lines := strings.Split(string(out), "\n")
		for _, line := range lines {
			// default via 192.168.1.1 dev wlan0  proto static
			// fd01:37b7:3570::/64 dev wlan0  proto kernel  metric 256  expires 6837sec mtu 1280
			a := strings.Fields(line)
			if len(a) >= 1 {
				m := map[string]string{
					"destination": a[0],
					"family":      family["name"],
				}
				for i := range a {
					switch a[i] {
					case "via":
						m["via"] = a[i+1]
					case "src":
						m["src"] = a[i+1]
					case "proto":
						m["proto"] = a[i+1]
					case "metric":
						m["metric"] = a[i+1]
					case "scope":
						m["scope"] = a[i+1]

					}

				}
				routes = append(routes, m)
			}

		}
	}
	d["routes"] = routes
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"code.google.com/p/goprotobuf/proto"
	"compress/gzip"
	"flag"
	"fmt"
	"github.com/rootsdev/fsbff/fs_data"
	"io"
	"io/ioutil"
	"log"
	"math"
	"os"
	"runtime"
	"sort"
	"strings"
)

type Location struct {
	place string
	decade int32
}

type Locations []Location
func NewLocations() Locations {
	return make(Locations, 0)
}
// Methods required by sort.Interface.
func (l Locations) Len() int {
    return len(l)
}
func (l Locations) Less(i, j int) bool {
    if l[i].decade == l[j].decade {
    	return l[i].place < l[j].place
    }
	return l[i].decade < l[j].decade
}
func (l Locations) Swap(i, j int) {
    l[i], l[j] = l[j], l[i]
}

// Maps "from" Location to multiple "to" Locations with count each one occurred
type Migrations map[Location]map[Location]int
func (m Migrations) add(from, to Location) {
	f := m[from]
	if f == nil {
		f = make(map[Location]int)
		m[from] = f
	}
	f[to] = f[to] + 1
}

var migrations Migrations

func NewLocation(fact *fs_data.FSFact) Location {
	decade := *fact.Year - *fact.Year % 10
	return Location{*fact.Place, decade}
}

func processFile(filename string) int {
	fsPersons := readPersons(filename)

	for _, person := range fsPersons.Persons {
		locations := NewLocations()
		for _, fact := range person.Facts {
			if fact.Place != nil && fact.Year != nil {
				locations = append(locations, NewLocation(fact))
			}
		}
		if len(locations) <= 1 {
			continue
		}
		sort.Sort(locations)
		// If place changes from one location to the next, we have
		// a migration. Record the most recent location as "from"
		// and new location as "to".
		fmt.Println("Person", person)
		prev := Location{}
		for _, location := range locations {
			if prev.place != "" {
				if location.place != prev.place {
					migrations.add(prev, location)
					fmt.Printf("Migrated from: %v to %v (%d migrations)\n", prev, location, migrations[prev][location])
				}
			}
			prev = location
		}
	}
	return len(fsPersons.Persons)
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func readPersons(filename string) *fs_data.FamilySearchPersons {
	var file io.ReadCloser
	var err error

	file, err = os.Open(filename)
	check(err)
	defer file.Close()

	if strings.HasSuffix(filename, ".gz") {
		file, err = gzip.NewReader(file)
		check(err)
		defer file.Close()
	}

	bytes, err := ioutil.ReadAll(file)
	check(err)

	fsPersons := &fs_data.FamilySearchPersons{}
	err = proto.Unmarshal(bytes, fsPersons)
	check(err)

	return fsPersons
}

func processFiles(fileNames chan string, results chan int) {
	for fileName := range fileNames {
		fmt.Printf("Processing file: %s", fileName)
		n := processFile(fileName)
		fmt.Printf("; processed %d people", n)
		results <- n
	}
}

func getFilenames(filename string) (int, chan string) {
	numFiles := 0
	fileNames := make(chan string, 100000)
	fileInfo, err := os.Stat(filename)
	check(err)
	if fileInfo.IsDir() {
		fileInfos, err := ioutil.ReadDir(filename)
		check(err)
		for _, fileInfo := range fileInfos {
			fileNames <- filename + "/" + fileInfo.Name()
			numFiles++
		}
	} else {
		fileNames <- filename
		numFiles++
	}
	close(fileNames)

	return numFiles, fileNames
}

var inFilename = flag.String("i", "", "input filename or directory")
var outFilename = flag.String("o", "", "output filename")
var numWorkers = flag.Int("w", 1, "number of workers)")

func main() {
	flag.Parse()

	numCPU := runtime.NumCPU()
	fmt.Printf("Number of CPUs=%d\n", numCPU)
	runtime.GOMAXPROCS(int(math.Min(float64(numCPU), float64(*numWorkers))))

	numFiles, fileNames := getFilenames(*inFilename)

	fmt.Println("Processing files")
	results := make(chan int)

	migrations = make(Migrations)
	for i := 0; i < *numWorkers; i++ {
		go processFiles(fileNames, results)
	}

	// Make sure all files have been processed by draining the channel
	total := 0
	for i := 0; i < numFiles; i++ {
		total = total + <-results
	}
	fmt.Println("\n\nTotal:", total)

	out, err := os.Create(*outFilename)
	check(err)
	defer out.Close()
	buf := bufio.NewWriter(out)
	// Get all the "from" locations and sort them, the write migrations
	locs := NewLocations()
	for l, _ := range migrations {
		locs = append(locs, l)
	}
	sort.Sort(locs)
	for _, loc := range locs {
		buf.WriteString(fmt.Sprintf("From: %v To:", loc))
		for l, c := range migrations[loc] {
			buf.WriteString(fmt.Sprintf(" %v (%d)", l, c))
		}
		buf.WriteString("\n")
	}
	buf.Flush()
	out.Sync()
}
<commit_msg>Support processing files concurrently.<commit_after>package main

import (
	"bufio"
	"code.google.com/p/goprotobuf/proto"
	"compress/gzip"
	"flag"
	"fmt"
	"github.com/rootsdev/fsbff/fs_data"
	"io"
	"io/ioutil"
	"log"
	"math"
	"os"
	"runtime"
	"sort"
	"strings"
)

type Location struct {
	place string
	decade int32
}

type Locations []Location
func NewLocations() Locations {
	return make(Locations, 0)
}
// Methods required by sort.Interface.
func (l Locations) Len() int {
    return len(l)
}
func (l Locations) Less(i, j int) bool {
    if l[i].decade == l[j].decade {
    	return l[i].place < l[j].place
    }
	return l[i].decade < l[j].decade
}
func (l Locations) Swap(i, j int) {
    l[i], l[j] = l[j], l[i]
}

// Maps "from" Location to multiple "to" Locations with count each one occurred
type Migrations map[Location]map[Location]int
func (m Migrations) add(from, to Location, count int) {
	f := m[from]
	if f == nil {
		f = make(map[Location]int)
		m[from] = f
	}
	f[to] = f[to] + count
}

func NewLocation(fact *fs_data.FSFact) Location {
	decade := *fact.Year - *fact.Year % 10
	return Location{*fact.Place, decade}
}

func processFile(filename string) Migrations {
	fsPersons := readPersons(filename)

	migrations := make(Migrations)
	for _, person := range fsPersons.Persons {
		locations := NewLocations()
		for _, fact := range person.Facts {
			if fact.Place != nil && fact.Year != nil {
				locations = append(locations, NewLocation(fact))
			}
		}
		if len(locations) <= 1 {
			continue
		}
		sort.Sort(locations)
		// If place changes from one location to the next, we have
		// a migration. Record the most recent location as "from"
		// and new location as "to".
		fmt.Println("Person", person)
		prev := Location{}
		for _, location := range locations {
			if prev.place != "" {
				if location.place != prev.place {
					migrations.add(prev, location, 1)
					fmt.Printf("Migrated from: %v to %v (%d migrations)\n", prev, location, migrations[prev][location])
				}
			}
			prev = location
		}
	}
	return migrations
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func readPersons(filename string) *fs_data.FamilySearchPersons {
	var file io.ReadCloser
	var err error

	file, err = os.Open(filename)
	check(err)
	defer file.Close()

	if strings.HasSuffix(filename, ".gz") {
		file, err = gzip.NewReader(file)
		check(err)
		defer file.Close()
	}

	bytes, err := ioutil.ReadAll(file)
	check(err)

	fsPersons := &fs_data.FamilySearchPersons{}
	err = proto.Unmarshal(bytes, fsPersons)
	check(err)

	return fsPersons
}

func processFiles(fileNames chan string, results chan Migrations) {
	for fileName := range fileNames {
		fmt.Printf("Processing file: %s", fileName)
		m := processFile(fileName)
		fmt.Printf("; found %d migration starts", len(m))
		results <- m
	}
}

func getFilenames(filename string) (int, chan string) {
	numFiles := 0
	fileNames := make(chan string, 100000)
	fileInfo, err := os.Stat(filename)
	check(err)
	if fileInfo.IsDir() {
		fileInfos, err := ioutil.ReadDir(filename)
		check(err)
		for _, fileInfo := range fileInfos {
			fileNames <- filename + "/" + fileInfo.Name()
			numFiles++
		}
	} else {
		fileNames <- filename
		numFiles++
	}
	close(fileNames)

	return numFiles, fileNames
}

var inFilename = flag.String("i", "", "input filename or directory")
var outFilename = flag.String("o", "", "output filename")
var numWorkers = flag.Int("w", 1, "number of workers)")

func main() {
	flag.Parse()

	numCPU := runtime.NumCPU()
	fmt.Printf("Number of CPUs=%d\n", numCPU)
	runtime.GOMAXPROCS(int(math.Min(float64(numCPU), float64(*numWorkers))))

	numFiles, fileNames := getFilenames(*inFilename)

	fmt.Println("Processing files")
	results := make(chan Migrations)

	for i := 0; i < *numWorkers; i++ {
		go processFiles(fileNames, results)
	}

	// Merge all the resulting migration maps
	migrations := make(Migrations)
	for i := 0; i < numFiles; i++ {
		m := <-results
		for from, toMap := range m {
			for to, count := range toMap {
				migrations.add(from, to, count)
			}
		}
	}
	fmt.Println("\n\nTotal:", len(migrations))

	out, err := os.Create(*outFilename)
	check(err)
	defer out.Close()
	buf := bufio.NewWriter(out)
	// Get all the "from" locations and sort them, the write migrations
	locs := NewLocations()
	for l, _ := range migrations {
		locs = append(locs, l)
	}
	sort.Sort(locs)
	for _, loc := range locs {
		buf.WriteString(fmt.Sprintf("From: %v To:", loc))
		for l, c := range migrations[loc] {
			buf.WriteString(fmt.Sprintf(" %v (%d)", l, c))
		}
		buf.WriteString("\n")
	}
	buf.Flush()
	out.Sync()
}
<|endoftext|>