<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"

	"github.com/appc/cni/pkg/ip"
	"github.com/appc/cni/pkg/ipam"
	"github.com/appc/cni/pkg/ns"
	"github.com/appc/cni/pkg/skel"
	"github.com/appc/cni/pkg/types"
	"github.com/appc/cni/pkg/utils"
)

// Adding additional configuration for EVPN - importRT and exportRT
type NetConf struct {
	types.NetConf
	ImportRT string `json:"importrt"`
	ExportRT string `json:"exportrt"`
	IsGW     bool   `json:"isGateway"`
	IPMasq   bool   `json:"ipMasq"`
	MTU      int    `json:"mtu"`
}

func init() {
	// this ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

func loadNetConf(bytes []byte) (*NetConf, error) {
	n := &NetConf{
		MTU: 1500,
	}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}
	return n, nil
}

func createBGPConf(n *NetConf, LocalPort string, gw string, ipa string, mac string) (b []byte, err error) {

	// JSON payload struct for bagpipeBGP
	type Message struct {
		Import_rt        []string         `json:"import_rt"`
		Vpn_type         string           `json:"vpn_type"`
		Vpn_instance_id  string           `json:"vpn_instance_id"`
		Ip_address       string           `json:"ip_address"`
		Export_rt        []string         `json:"export_rt"`
		Local_port       *json.RawMessage `json:"local_port"`
		Readvertise      string           `json:"readvertise"`
		Gateway_ip       string           `json:"gateway_ip"`
		Mac_address      string           `json:"mac_address"`
		Advertise_subnet bool             `json:"advertise_subnet"`
	}

	// Linuxif Raw JSON object
	type LcPorts struct {
		LinuxIf string `json:"linuxif"`
	}

	tmp := LcPorts{LocalPort}
	l, err := json.Marshal(tmp)
	LcPort := json.RawMessage(l)

	Imports := []string{n.ImportRT}
	Exports := []string{n.ExportRT}

	m := Message{
		Import_rt:        Imports,
		Vpn_type:         "evpn",
		Vpn_instance_id:  LocalPort,
		Ip_address:       ipa,
		Export_rt:        Exports,
		Local_port:       &LcPort,
		Gateway_ip:       gw,
		Mac_address:      mac,
		Advertise_subnet: false,
	}

	b, err = json.Marshal(m)
	return b, err
}

func sendBagpipeReq(n *NetConf, Request string, LocalPort string, gw string, ipa string, mac string) error {
	// send json payload
	url := fmt.Sprintf("http://127.0.0.1:8082/%s_localport", Request)

	var jsonStr []byte
	// create JSON object for BagpipeBGP
	jsonStr, err := createBGPConf(n, LocalPort, gw, ipa, mac)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))

	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()
	return err
}

func setupVeth(netns string, ifName string, mtu int) (contMacAddr string, hostVethName string, err error) {

	err = ns.WithNetNSPath(netns, false, func(hostNS *os.File) error {
		// create the veth pair in the container and move host end into host netns
		hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
		if err != nil {
			return nil
		}

		hostVethName = hostVeth.Attrs().Name
		interfaces, _ := net.Interfaces()

		// Lookup MAC address of eth0 inside namespace
		for _, inter := range interfaces {
			if inter.Name != "lo" {
				contMacAddr = fmt.Sprintf("%v", inter.HardwareAddr)
			}
		}

		return nil
	})
	if err != nil {
		return contMacAddr, hostVethName, err
	}

	if err != nil {
		return contMacAddr, hostVethName, fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
	}

	return contMacAddr, hostVethName, err
}

func calcGatewayIP(ipn *net.IPNet) net.IP {
	nid := ipn.IP.Mask(ipn.Mask)
	return ip.NextIP(nid)
}

func cmdAdd(args *skel.CmdArgs) error {
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}
	var vethName string
	var macAddr string

	if macAddr, vethName, err = setupVeth(args.Netns, args.IfName, n.MTU); err != nil {
		return err
	}

	// run the IPAM plugin and get back the config to apply
	result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	if result.IP4 == nil {
		return errors.New("IPAM plugin returned missing IPv4 config")
	}

	if result.IP4.Gateway == nil && n.IsGW {
		result.IP4.Gateway = calcGatewayIP(&result.IP4.IP)
	}

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		return ipam.ConfigureIface(args.IfName, result)
	})
	if err != nil {
		return err
	}

	if n.IPMasq {
		chain := utils.FormatChainName(n.Name, args.ContainerID)
		comment := utils.FormatComment(n.Name, args.ContainerID)
		if err = ip.SetupIPMasq(ip.Network(&result.IP4.IP), chain, comment); err != nil {
			return err
		}
	}

	var ip_gw, ip_addr string

	ip_gw = fmt.Sprintf("%v", &result.IP4.Gateway)
	ip_addr = fmt.Sprintf("%v", &result.IP4.IP)

	sendBagpipeReq(n, "attach", vethName, ip_gw, ip_addr, macAddr)

	result.DNS = n.DNS
	return result.Print()
}

func cmdDel(args *skel.CmdArgs) error {

	// bagpipe detach should be implemented
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	result, err := ipam.ExecDel(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	return ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		iface, err := netlink.LinkByName(ifName)

		hostVethName := iface.Attrs().Name
		interfaces, _ := net.Interfaces()

		// Lookup MAC address of eth0 inside namespace
		for _, inter := range interfaces {
			if inter.Name != "lo" {
				contMacAddr = fmt.Sprintf("%v", inter.HardwareAddr)
			}
		}

		var ip_gw, ip_addr string

		ip_gw = fmt.Sprintf("%v", &result.IP4.Gateway)
		ip_addr = fmt.Sprintf("%v", &result.IP4.IP)

		sendBagpipeReq(n, "detach", hostVethName, ip_gw, ip_addr, macAddr)
		return ip.DelLinkByName(args.IfName)
	})
}

func main() {
	skel.PluginMain(cmdAdd, cmdDel)
}
<commit_msg>DelCmd alpha version works fine<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"

	"github.com/safchain/ethtool"
	"github.com/vishvananda/netlink"
	"github.com/appc/cni/pkg/ip"
	"github.com/appc/cni/pkg/ipam"
	"github.com/appc/cni/pkg/ns"
	"github.com/appc/cni/pkg/skel"
	"github.com/appc/cni/pkg/types"
	"github.com/appc/cni/pkg/utils"
)

// Adding additional configuration for EVPN - importRT and exportRT
type NetConf struct {
	types.NetConf
	ImportRT string `json:"importrt"`
	ExportRT string `json:"exportrt"`
	IsGW     bool   `json:"isGateway"`
	IPMasq   bool   `json:"ipMasq"`
	MTU      int    `json:"mtu"`
}

func init() {
	// this ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()
}

func loadNetConf(bytes []byte) (*NetConf, error) {
	n := &NetConf{
		MTU: 1500,
	}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}
	return n, nil
}

func createBGPConf(n *NetConf, LocalPort string, gw string, ipa string, mac string) (b []byte, err error) {

	// JSON payload struct for bagpipeBGP
	type Message struct {
		Import_rt        []string         `json:"import_rt"`
		Vpn_type         string           `json:"vpn_type"`
		Vpn_instance_id  string           `json:"vpn_instance_id"`
		Ip_address       string           `json:"ip_address"`
		Export_rt        []string         `json:"export_rt"`
		Local_port       *json.RawMessage `json:"local_port"`
		Readvertise      string           `json:"readvertise"`
		Gateway_ip       string           `json:"gateway_ip"`
		Mac_address      string           `json:"mac_address"`
		Advertise_subnet bool             `json:"advertise_subnet"`
	}

	// Linuxif Raw JSON object
	type LcPorts struct {
		LinuxIf string `json:"linuxif"`
	}

	tmp := LcPorts{LocalPort}
	l, err := json.Marshal(tmp)
	LcPort := json.RawMessage(l)

	Imports := []string{n.ImportRT}
	Exports := []string{n.ExportRT}

	m := Message{
		Import_rt:        Imports,
		Vpn_type:         "evpn",
		Vpn_instance_id:  LocalPort,
		Ip_address:       ipa,
		Export_rt:        Exports,
		Local_port:       &LcPort,
		Gateway_ip:       gw,
		Mac_address:      mac,
		Advertise_subnet: false,
	}

	b, err = json.Marshal(m)
	return b, err
}

func sendBagpipeReq(n *NetConf, Request string, LocalPort string, gw string, ipa string, mac string) error {
	// send json payload
	url := fmt.Sprintf("http://127.0.0.1:8082/%s_localport", Request)

	var jsonStr []byte
	// create JSON object for BagpipeBGP
	jsonStr, err := createBGPConf(n, LocalPort, gw, ipa, mac)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))

	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()
	return err
}

func setupVeth(netns string, ifName string, mtu int) (contMacAddr string, hostVethName string, err error) {

	err = ns.WithNetNSPath(netns, false, func(hostNS *os.File) error {
		// create the veth pair in the container and move host end into host netns
		hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
		if err != nil {
			return nil
		}

		hostVethName = hostVeth.Attrs().Name
		interfaces, _ := net.Interfaces()

		// Lookup MAC address of eth0 inside namespace
		for _, inter := range interfaces {
			if inter.Name != "lo" {
				contMacAddr = fmt.Sprintf("%v", inter.HardwareAddr)
			}

		}
		return nil
	})
	if err != nil {
		return contMacAddr, hostVethName, err
	}

	if err != nil {
		return contMacAddr, hostVethName, fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
	}

	return contMacAddr, hostVethName, err
}

func calcGatewayIP(ipn *net.IPNet) net.IP {
	nid := ipn.IP.Mask(ipn.Mask)
	return ip.NextIP(nid)
}

func cmdAdd(args *skel.CmdArgs) error {
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}
	var vethName string
	var macAddr string

	if macAddr, vethName, err = setupVeth(args.Netns, args.IfName, n.MTU); err != nil {
		return err
	}

	// run the IPAM plugin and get back the config to apply
	result, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	if result.IP4 == nil {
		return errors.New("IPAM plugin returned missing IPv4 config")
	}

	if result.IP4.Gateway == nil && n.IsGW {
		result.IP4.Gateway = calcGatewayIP(&result.IP4.IP)
	}

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		return ipam.ConfigureIface(args.IfName, result)
	})
	if err != nil {
		return err
	}

	if n.IPMasq {
		chain := utils.FormatChainName(n.Name, args.ContainerID)
		comment := utils.FormatComment(n.Name, args.ContainerID)
		if err = ip.SetupIPMasq(ip.Network(&result.IP4.IP), chain, comment); err != nil {
			return err
		}
	}

	var ip_gw, ip_addr string

	ip_gw = fmt.Sprintf("%v", &result.IP4.Gateway)
	ip_addr = fmt.Sprintf("%v", &result.IP4.IP)

	sendBagpipeReq(n, "attach", vethName, ip_gw, ip_addr, macAddr)

	result.DNS = n.DNS
	return result.Print()
}

func cmdDel(args *skel.CmdArgs) error {

	// bagpipe detach should be implemented
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	var contMacAddr string
	var hostVethName string
	var ip_gw string
	var ip_addr string
	var if_index uint64

	err = ns.WithNetNSPath(args.Netns, false, func(hostNS *os.File) error {
		link, _ := netlink.LinkByName(args.IfName)

		// Getting container MAC address
		contMacAddr =fmt.Sprintf("%s", link.Attrs().HardwareAddr)
		// Getting container IP address, should be rewritten PoC
		cont_IP, _ := netlink.AddrList(link, netlink.FAMILY_V4)
		ip_addr = fmt.Sprintf("%s", cont_IP[0].IPNet.IP)

		// Getting peer interface index in Root namespace
		stats, _ := ethtool.Stats(args.IfName)
		if_index = stats["peer_ifindex"]

		// Getting default gateway address - should be rewritten PoC
		gw_route, _ := netlink.RouteGet(net.ParseIP("1.2.3.4"))
		ip_gw = fmt.Sprintf("%s", gw_route[0].Gw)

		return nil
	})

	// Getting hostlink based on if_index in Root NS
	hostlink, _ := netlink.LinkByIndex(int(if_index))
	hostVethName = hostlink.Attrs().Name

	// Dettaching the route from BaGPipe BGP
	sendBagpipeReq(n, "detach", hostVethName, ip_gw, ip_addr, contMacAddr)
	// Removing the link
	return ip.DelLinkByName(hostVethName)
}

func main() {
	skel.PluginMain(cmdAdd, cmdDel)
}
<|endoftext|>


<commit_before>// +build windows

package uptime

import (
	"syscall"
	"time"
)

var getTickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")

func Get() (time.Duration, error) {
	ret, _, err := getTickCount.Call()
	if err != nil {
		return time.Duration(0), err
	}
	return time.Duration(ret) * time.Millisecond, nil
}
<commit_msg>fix uptime generator on Windows<commit_after>// +build windows

package uptime

import (
	"syscall"
	"time"
)

var getTickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")

func Get() (time.Duration, error) {
	ret, _, err := getTickCount.Call()
	if errno, ok := err.(syscall.Errno); !ok || errno != 0 {
		return time.Duration(0), err
	}
	return time.Duration(ret) * time.Millisecond, nil
}
<|endoftext|>


<commit_before>package db

import (
	"fmt"
	"strings"
	"sync"
)

func init() {
	registerDBCreator(MemDBBackendStr, func(name string, dir string) (DB, error) {
		return NewMemDB(), nil
	}, false)
}

type MemDB struct {
	mtx sync.Mutex
	db  map[string][]byte
}

func NewMemDB() *MemDB {
	database := &MemDB{db: make(map[string][]byte)}
	return database
}

func (db *MemDB) Get(key []byte) []byte {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	return db.db[string(key)]
}

func (db *MemDB) Set(key []byte, value []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	db.db[string(key)] = value
}

func (db *MemDB) SetSync(key []byte, value []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	db.db[string(key)] = value
}

func (db *MemDB) Delete(key []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	delete(db.db, string(key))
}

func (db *MemDB) DeleteSync(key []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	delete(db.db, string(key))
}

func (db *MemDB) Close() {
	// Close is a noop since for an in-memory
	// database, we don't have a destination
	// to flush contents to nor do we want
	// any data loss on invoking Close()
	// See the discussion in https://github.com/tendermint/tmlibs/pull/56
}

func (db *MemDB) Print() {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	for key, value := range db.db {
		fmt.Printf("[%X]:\t[%X]\n", []byte(key), value)
	}
}

func (db *MemDB) Stats() map[string]string {
	stats := make(map[string]string)
	stats["database.type"] = "memDB"
	return stats
}

type memDBIterator struct {
	last int
	keys []string
	db   *MemDB
}

func newMemDBIterator() *memDBIterator {
	return &memDBIterator{}
}

func (it *memDBIterator) Next() bool {
	if it.last >= len(it.keys)-1 {
		return false
	}
	it.last++
	return true
}

func (it *memDBIterator) Key() []byte {
	return []byte(it.keys[it.last])
}

func (it *memDBIterator) Value() []byte {
	return it.db.Get(it.Key())
}

func (it *memDBIterator) Release() {
	it.db = nil
	it.keys = nil
}

func (it *memDBIterator) Error() error {
	return nil
}

func (db *MemDB) Iterator() Iterator {
	return db.IteratorPrefix([]byte{})
}

func (db *MemDB) IteratorPrefix(prefix []byte) Iterator {
	it := newMemDBIterator()
	it.db = db
	it.last = -1

	db.mtx.Lock()
	defer db.mtx.Unlock()

	// unfortunately we need a copy of all of the keys
	for key, _ := range db.db {
		if strings.HasPrefix(key, string(prefix)) {
			it.keys = append(it.keys, key)
		}
	}
	return it
}

func (db *MemDB) NewBatch() Batch {
	return &memDBBatch{db, nil}
}

//--------------------------------------------------------------------------------

type memDBBatch struct {
	db  *MemDB
	ops []operation
}

type opType int

const (
	opTypeSet    = 1
	opTypeDelete = 2
)

type operation struct {
	opType
	key   []byte
	value []byte
}

func (mBatch *memDBBatch) Set(key, value []byte) {
	mBatch.ops = append(mBatch.ops, operation{opTypeSet, key, value})
}

func (mBatch *memDBBatch) Delete(key []byte) {
	mBatch.ops = append(mBatch.ops, operation{opTypeDelete, key, nil})
}

func (mBatch *memDBBatch) Write() {
	mBatch.db.mtx.Lock()
	defer mBatch.db.mtx.Unlock()

	for _, op := range mBatch.ops {
		if op.opType == opTypeSet {
			mBatch.db.db[string(op.key)] = op.value
		} else if op.opType == opTypeDelete {
			delete(mBatch.db.db, string(op.key))
		}
	}

}
<commit_msg>db: sort keys for memdb iterator<commit_after>package db

import (
	"fmt"
	"sort"
	"strings"
	"sync"
)

func init() {
	registerDBCreator(MemDBBackendStr, func(name string, dir string) (DB, error) {
		return NewMemDB(), nil
	}, false)
}

type MemDB struct {
	mtx sync.Mutex
	db  map[string][]byte
}

func NewMemDB() *MemDB {
	database := &MemDB{db: make(map[string][]byte)}
	return database
}

func (db *MemDB) Get(key []byte) []byte {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	return db.db[string(key)]
}

func (db *MemDB) Set(key []byte, value []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	db.db[string(key)] = value
}

func (db *MemDB) SetSync(key []byte, value []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	db.db[string(key)] = value
}

func (db *MemDB) Delete(key []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	delete(db.db, string(key))
}

func (db *MemDB) DeleteSync(key []byte) {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	delete(db.db, string(key))
}

func (db *MemDB) Close() {
	// Close is a noop since for an in-memory
	// database, we don't have a destination
	// to flush contents to nor do we want
	// any data loss on invoking Close()
	// See the discussion in https://github.com/tendermint/tmlibs/pull/56
}

func (db *MemDB) Print() {
	db.mtx.Lock()
	defer db.mtx.Unlock()
	for key, value := range db.db {
		fmt.Printf("[%X]:\t[%X]\n", []byte(key), value)
	}
}

func (db *MemDB) Stats() map[string]string {
	stats := make(map[string]string)
	stats["database.type"] = "memDB"
	return stats
}

type memDBIterator struct {
	last int
	keys []string
	db   *MemDB
}

func newMemDBIterator() *memDBIterator {
	return &memDBIterator{}
}

func (it *memDBIterator) Next() bool {
	if it.last >= len(it.keys)-1 {
		return false
	}
	it.last++
	return true
}

func (it *memDBIterator) Key() []byte {
	return []byte(it.keys[it.last])
}

func (it *memDBIterator) Value() []byte {
	return it.db.Get(it.Key())
}

func (it *memDBIterator) Release() {
	it.db = nil
	it.keys = nil
}

func (it *memDBIterator) Error() error {
	return nil
}

func (db *MemDB) Iterator() Iterator {
	return db.IteratorPrefix([]byte{})
}

func (db *MemDB) IteratorPrefix(prefix []byte) Iterator {
	it := newMemDBIterator()
	it.db = db
	it.last = -1

	db.mtx.Lock()
	defer db.mtx.Unlock()

	// unfortunately we need a copy of all of the keys
	for key, _ := range db.db {
		if strings.HasPrefix(key, string(prefix)) {
			it.keys = append(it.keys, key)
		}
	}
	// and we need to sort them
	sort.Strings(it.keys)
	return it
}

func (db *MemDB) NewBatch() Batch {
	return &memDBBatch{db, nil}
}

//--------------------------------------------------------------------------------

type memDBBatch struct {
	db  *MemDB
	ops []operation
}

type opType int

const (
	opTypeSet    = 1
	opTypeDelete = 2
)

type operation struct {
	opType
	key   []byte
	value []byte
}

func (mBatch *memDBBatch) Set(key, value []byte) {
	mBatch.ops = append(mBatch.ops, operation{opTypeSet, key, value})
}

func (mBatch *memDBBatch) Delete(key []byte) {
	mBatch.ops = append(mBatch.ops, operation{opTypeDelete, key, nil})
}

func (mBatch *memDBBatch) Write() {
	mBatch.db.mtx.Lock()
	defer mBatch.db.mtx.Unlock()

	for _, op := range mBatch.ops {
		if op.opType == opTypeSet {
			mBatch.db.db[string(op.key)] = op.value
		} else if op.opType == opTypeDelete {
			delete(mBatch.db.db, string(op.key))
		}
	}

}
<|endoftext|>


<commit_before>package funcs

import (
	"fmt"
	"text/template"
	_ "unsafe"
)

var Funcs = map[string]interface{}{
	"and":    And,
	"or":     Or,
	"not":    Not,
	"eq":     Eq,
	"ne":     Ne,
	"lt":     Lt,
	"le":     Le,
	"gt":     Gt,
	"ge":     Ge,
	"index":  Index,
	"length": Length,
	"call":   Call,

	"html":     Html,
	"js":       Js,
	"urlquery": Urlquery,
	"print":    Print,
	"printf":   Printf,
	"println":  Println,

	"_html_template_attrescaper":     Attrescaper,
	"_html_template_commentescaper":  Commentescaper,
	"_html_template_cssescaper":      Cssescaper,
	"_html_template_cssvaluefilter":  Cssvaluefilter,
	"_html_template_htmlnamefilter":  Htmlnamefilter,
	"_html_template_htmlescaper":     Htmlescaper,
	"_html_template_jsregexpescaper": Jsregexpescaper,
	"_html_template_jsstrescaper":    Jsstrescaper,
	"_html_template_jsvalescaper":    Jsvalescaper,
	"_html_template_nospaceescaper":  Htmlnospaceescaper,
	"_html_template_rcdataescaper":   Rcdataescaper,
	"_html_template_urlescaper":      Urlescaper,
	"_html_template_urlfilter":       Urlfilter,
	"_html_template_urlnormalizer":   Urlnormalizer,
}

//go:linkname and text/template.and
func and(arg0 interface{}, args ...interface{}) interface{}
func And(arg0 interface{}, args ...interface{}) interface{} {
	return and(arg0, args...)
}

//go:linkname or text/template.or
func or(arg0 interface{}, args ...interface{}) interface{}
func Or(arg0 interface{}, args ...interface{}) interface{} {
	return or(arg0, args...)
}

//go:linkname not text/template.not
func not(arg interface{}) bool
func Not(arg interface{}) bool {
	return not(arg)
}

//go:linkname eq text/template.eq
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error)
func Eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
	return eq(arg1, arg2...)
}

//go:linkname ne text/template.ne
func ne(arg1, arg2 interface{}) (bool, error)
func Ne(arg1, arg2 interface{}) (bool, error) {
	return ne(arg1, arg2)
}

//go:linkname lt text/template.lt
func lt(arg1, arg2 interface{}) (bool, error)
func Lt(arg1, arg2 interface{}) (bool, error) {
	return lt(arg1, arg2)
}

//go:linkname le text/template.le
func le(arg1, arg2 interface{}) (bool, error)
func Le(arg1, arg2 interface{}) (bool, error) {
	return le(arg1, arg2)
}

//go:linkname gt text/template.gt
func gt(arg1, arg2 interface{}) (bool, error)
func Gt(arg1, arg2 interface{}) (bool, error) {
	return gt(arg1, arg2)
}

//go:linkname ge text/template.ge
func ge(arg1, arg2 interface{}) (bool, error)
func Ge(arg1, arg2 interface{}) (bool, error) {
	return ge(arg1, arg2)
}

//go:linkname index text/template.index
func index(item interface{}, indices ...interface{}) (interface{}, error)
func Index(item interface{}, indices ...interface{}) (interface{}, error) {
	return index(item, indices...)
}

//go:linkname length text/template.length
func length(item interface{}) (int, error)
func Length(item interface{}) (int, error) {
	return length(item)
}

//go:linkname call text/template.call
func call(fn interface{}, args ...interface{}) (interface{}, error)
func Call(fn interface{}, args ...interface{}) (interface{}, error) {
	return call(fn, args...)
}

func Html(args ...interface{}) string {
	return template.HTMLEscaper(args...)
}

func Js(args ...interface{}) string {
	return template.JSEscaper(args...)
}

func Urlquery(args ...interface{}) string {
	return template.URLQueryEscaper(args...)
}

func Print(a ...interface{}) string {
	return fmt.Sprint(a...)
}

func Printf(format string, a ...interface{}) string {
	return fmt.Sprintf(format, a...)
}

func Println(a ...interface{}) string {
	return fmt.Sprintln(a...)
}
<commit_msg>length -> len<commit_after>package funcs

import (
	"fmt"
	"text/template"
	_ "unsafe"
)

var Funcs = map[string]interface{}{
	"and":   And,
	"or":    Or,
	"not":   Not,
	"eq":    Eq,
	"ne":    Ne,
	"lt":    Lt,
	"le":    Le,
	"gt":    Gt,
	"ge":    Ge,
	"index": Index,
	"len":   Length,
	"call":  Call,

	"html":     Html,
	"js":       Js,
	"urlquery": Urlquery,
	"print":    Print,
	"printf":   Printf,
	"println":  Println,

	"_html_template_attrescaper":     Attrescaper,
	"_html_template_commentescaper":  Commentescaper,
	"_html_template_cssescaper":      Cssescaper,
	"_html_template_cssvaluefilter":  Cssvaluefilter,
	"_html_template_htmlnamefilter":  Htmlnamefilter,
	"_html_template_htmlescaper":     Htmlescaper,
	"_html_template_jsregexpescaper": Jsregexpescaper,
	"_html_template_jsstrescaper":    Jsstrescaper,
	"_html_template_jsvalescaper":    Jsvalescaper,
	"_html_template_nospaceescaper":  Htmlnospaceescaper,
	"_html_template_rcdataescaper":   Rcdataescaper,
	"_html_template_urlescaper":      Urlescaper,
	"_html_template_urlfilter":       Urlfilter,
	"_html_template_urlnormalizer":   Urlnormalizer,
}

//go:linkname and text/template.and
func and(arg0 interface{}, args ...interface{}) interface{}
func And(arg0 interface{}, args ...interface{}) interface{} {
	return and(arg0, args...)
}

//go:linkname or text/template.or
func or(arg0 interface{}, args ...interface{}) interface{}
func Or(arg0 interface{}, args ...interface{}) interface{} {
	return or(arg0, args...)
}

//go:linkname not text/template.not
func not(arg interface{}) bool
func Not(arg interface{}) bool {
	return not(arg)
}

//go:linkname eq text/template.eq
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error)
func Eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
	return eq(arg1, arg2...)
}

//go:linkname ne text/template.ne
func ne(arg1, arg2 interface{}) (bool, error)
func Ne(arg1, arg2 interface{}) (bool, error) {
	return ne(arg1, arg2)
}

//go:linkname lt text/template.lt
func lt(arg1, arg2 interface{}) (bool, error)
func Lt(arg1, arg2 interface{}) (bool, error) {
	return lt(arg1, arg2)
}

//go:linkname le text/template.le
func le(arg1, arg2 interface{}) (bool, error)
func Le(arg1, arg2 interface{}) (bool, error) {
	return le(arg1, arg2)
}

//go:linkname gt text/template.gt
func gt(arg1, arg2 interface{}) (bool, error)
func Gt(arg1, arg2 interface{}) (bool, error) {
	return gt(arg1, arg2)
}

//go:linkname ge text/template.ge
func ge(arg1, arg2 interface{}) (bool, error)
func Ge(arg1, arg2 interface{}) (bool, error) {
	return ge(arg1, arg2)
}

//go:linkname index text/template.index
func index(item interface{}, indices ...interface{}) (interface{}, error)
func Index(item interface{}, indices ...interface{}) (interface{}, error) {
	return index(item, indices...)
}

//go:linkname length text/template.length
func length(item interface{}) (int, error)
func Length(item interface{}) (int, error) {
	return length(item)
}

//go:linkname call text/template.call
func call(fn interface{}, args ...interface{}) (interface{}, error)
func Call(fn interface{}, args ...interface{}) (interface{}, error) {
	return call(fn, args...)
}

func Html(args ...interface{}) string {
	return template.HTMLEscaper(args...)
}

func Js(args ...interface{}) string {
	return template.JSEscaper(args...)
}

func Urlquery(args ...interface{}) string {
	return template.URLQueryEscaper(args...)
}

func Print(a ...interface{}) string {
	return fmt.Sprint(a...)
}

func Printf(format string, a ...interface{}) string {
	return fmt.Sprintf(format, a...)
}

func Println(a ...interface{}) string {
	return fmt.Sprintln(a...)
}
<|endoftext|>


<commit_before>// TODO currently the cached trees are not persisted and we build them at
// startup. For petabytes of data this might take a long time.

package proto

import (
	"bufio"
	"fmt"
	"io"
	"os"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/errors"
)

// merkleRootsCacheHeight is the height of the subTrees in cachedSubTrees. A
// height of 7 means that 128 sector roots are covered by a single cached
// subTree.
const merkleRootsCacheHeight = 7

// merkleRootsPerCache is the number of merkle roots in a cached subTree of
// merkleRootsCacheHeight height.
const merkleRootsPerCache = 1 << merkleRootsCacheHeight

type (
	// merkleRoots is a helper struct that makes it easier to add/insert/remove
	// merkleRoots within a SafeContract.
	merkleRoots struct {
		// cachedSubTrees are cached trees that can be used to more efficiently
		// compute the merkle root of a contract.
		cachedSubTrees []*cachedSubTree
		// uncachedRoots contains the sector roots that are not part of a
		// cached subTree. The uncachedRoots slice should never get longer than
		// 2^merkleRootsCacheHeight since that would simply result in a new
		// cached subTree in cachedSubTrees.
		uncachedRoots []crypto.Hash

		// file is the file of the safe contract that contains the root.
		file *os.File
		// numMerkleRoots is the number of merkle roots in file.
		numMerkleRoots int
	}

	// cachedSubTree is a cached subTree of a merkle tree. A height of 0 means
	// that the sum is the hash of a leaf. A subTree of height 1 means sum is
	// the root of 2 leaves. A subTree of height 2 contains the root of 4
	// leaves and so on.
	cachedSubTree struct {
		height int         // height of the subTree
		sum    crypto.Hash // root of the subTree
	}
)

// loadExistingMerkleRoots reads creates a merkleRoots object from existing
// merkle roots.
func loadExistingMerkleRoots(file *os.File) (*merkleRoots, error) {
	mr := &merkleRoots{
		file: file,
	}
	// Get the number of roots stored in the file.
	var err error
	mr.numMerkleRoots, err = mr.lenFromFile()
	if err != nil {
		return nil, err
	}
	// Seek to the first root's offset.
	if _, err = file.Seek(fileOffsetFromRootIndex(0), io.SeekStart); err != nil {
		return nil, err
	}
	// Read the roots from the file without reading all of them at once.
	r := bufio.NewReader(file)
	for i := 0; i < mr.numMerkleRoots; i++ {
		var root crypto.Hash
		if _, err = io.ReadFull(r, root[:]); err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}

		// Append the root to the uncachedRoots
		mr.appendRoot(root)
	}
	return mr, nil
}

// newCachedSubTree creates a cachedSubTree from exactly
// 2^merkleRootsCacheHeight roots.
func newCachedSubTree(roots []crypto.Hash) *cachedSubTree {
	// Sanity check the input length.
	if len(roots) != merkleRootsPerCache {
		build.Critical("can't create a cached subTree from the provided number of roots")
	}
	return &cachedSubTree{
		height: int(merkleRootsCacheHeight + sectorHeight),
		sum:    cachedMerkleRoot(roots),
	}
}

// newMerkleRoots creates a new merkleRoots object. This doesn't load existing
// roots from file and will assume that the file doesn't contain any roots.
// Don't use this on a file that contains roots.
func newMerkleRoots(file *os.File) *merkleRoots {
	return &merkleRoots{
		file: file,
	}
}

// fileOffsetFromRootIndex calculates the offset of the merkle root at index i from
// the beginning of the contract file.
func fileOffsetFromRootIndex(i int) int64 {
	return contractHeaderSize + crypto.HashSize*int64(i)
}

// delete deletes the sector root at a certain index.
func (mr *merkleRoots) delete(i int) error {
	// Check if the index is correct
	if i >= mr.numMerkleRoots {
		build.Critical("can't delete non-existing root")
		return nil
	}
	// If i is the index of the last element we call deleteLastRoot.
	if i == mr.numMerkleRoots-1 {
		return mr.deleteLastRoot()
	}
	// If we don't have any uncached roots we need to delete the last cached
	// tree and add its elements to the uncached roots.
	if len(mr.uncachedRoots) == 0 {
		mr.cachedSubTrees = mr.cachedSubTrees[:len(mr.cachedSubTrees)-1]
		rootIndex := len(mr.cachedSubTrees) * merkleRootsPerCache
		roots, err := mr.merkleRootsFromIndex(rootIndex, mr.numMerkleRoots)
		if err != nil {
			return errors.AddContext(err, "failed to read cached tree's roots")
		}
		mr.uncachedRoots = append(mr.uncachedRoots, roots...)
	}
	// Swap the root at index i with the last root in mr.uncachedRoots.
	_, err := mr.file.WriteAt(mr.uncachedRoots[len(mr.uncachedRoots)-1][:], fileOffsetFromRootIndex(i))
	if err != nil {
		return errors.AddContext(err, "failed to swap root to delete with last one")
	}
	// If the deleted root was cached we need to rebuild that cache.
	if cacheIndex, cached := mr.isIndexCached(i); cached {
		err = mr.rebuildCachedTree(cacheIndex)
	}
	if err != nil {
		return errors.AddContext(err, "failed to rebuild cached tree")
	}
	// Now that the element we want to delete is the last root we can simply
	// delete it by calling mr.deleteLastRoot.
	return mr.deleteLastRoot()
}

// deleteLastRoot deletes the last sector root of the contract.
func (mr *merkleRoots) deleteLastRoot() error {
	// Decrease the numMerkleRoots counter.
	mr.numMerkleRoots--
	// Truncate file to avoid interpreting trailing data as valid.
	if err := mr.file.Truncate(fileOffsetFromRootIndex(mr.numMerkleRoots)); err != nil {
		return errors.AddContext(err, "failed to delete last root from file")
	}
	// If the last element is uncached we can simply remove it from the slice.
	if len(mr.uncachedRoots) > 0 {
		mr.uncachedRoots = mr.uncachedRoots[:len(mr.uncachedRoots)-1]
		return nil
	}
	// If it is not uncached we need to delete the last cached tree and load
	// its elements into mr.uncachedRoots.
	mr.cachedSubTrees = mr.cachedSubTrees[:len(mr.cachedSubTrees)-1]
	rootIndex := len(mr.cachedSubTrees) * merkleRootsPerCache
	roots, err := mr.merkleRootsFromIndex(rootIndex, mr.numMerkleRoots)
	if err != nil {
		return errors.AddContext(err, "failed to read cached tree's roots")
	}
	mr.uncachedRoots = append(mr.uncachedRoots, roots...)
	return nil
}

// insert inserts a root by replacing a root at an existing index.
func (mr *merkleRoots) insert(index int, root crypto.Hash) error {
	if index > mr.numMerkleRoots {
		return errors.New("can't insert at a index greater than the number of roots")
	}
	if index == mr.numMerkleRoots {
		return mr.push(root)
	}
	// Replaced the root on disk.
	_, err := mr.file.WriteAt(root[:], fileOffsetFromRootIndex(index))
	if err != nil {
		return errors.AddContext(err, "failed to insert root on disk")
	}

	// Find out if the root is in mr.cachedSubTree or mr.uncachedRoots.
	i, cached := mr.isIndexCached(index)
	// If the root was not cached we can simply replace it in mr.uncachedRoots.
	if !cached {
		mr.uncachedRoots[i] = root
		return nil
	}
	// If the root was cached we need to rebuild the cache.
	if err := mr.rebuildCachedTree(i); err != nil {
		return errors.AddContext(err, "failed to rebuild cache for inserted root")
	}
	return nil
}

// isIndexCached determines if the root at index i is already cached in
// mr.cachedSubTree or if it is still in mr.uncachedRoots. It will return true
// or false and the index of the root in the corresponding data structure.
func (mr *merkleRoots) isIndexCached(i int) (int, bool) {
	if i/(1<<merkleRootsCacheHeight) == len(mr.cachedSubTrees) {
		// Root is not cached. Return the false and the position in
		// mr.uncachedRoots
		return i - len(mr.cachedSubTrees)*merkleRootsPerCache, false
	}
	return i / merkleRootsPerCache, true
}

// lenFromFile returns the number of merkle roots by computing it from the
// filesize.
func (mr *merkleRoots) lenFromFile() (int, error) {
	stat, err := mr.file.Stat()
	if err != nil {
		return 0, err
	}
	size := stat.Size()
	// If we haven't written a single root yet we just return 0.
	if size < contractHeaderSize {
		return 0, nil
	}

	// Sanity check contract file length.
	if (size-contractHeaderSize)%crypto.HashSize != 0 {
		return 0, errors.New("contract file has unexpected length and might be corrupted")
	}
	return int((size - contractHeaderSize) / crypto.HashSize), nil
}

// len returns the number of merkle roots. It should always return the same
// number as lenFromFile.
func (mr *merkleRoots) len() int {
	return mr.numMerkleRoots
}

// appendRoot appends a root to the in-memory structure of the merkleRoots. If
// the length of the uncachedRoots grows too large they will be compressed into
// a cachedSubTree.
func (mr *merkleRoots) appendRoot(root crypto.Hash) {
	mr.uncachedRoots = append(mr.uncachedRoots, root)
	if len(mr.uncachedRoots) == merkleRootsPerCache {
		mr.cachedSubTrees = append(mr.cachedSubTrees, newCachedSubTree(mr.uncachedRoots))
		mr.uncachedRoots = mr.uncachedRoots[:0]
	}
}

// push appends a merkle root to the end of the contract. If the number of
// uncached merkle roots grows too big we cache them in a new subTree.
func (mr *merkleRoots) push(root crypto.Hash) error {
	// Sanity check the number of uncached roots before adding a new one.
	if len(mr.uncachedRoots) == merkleRootsPerCache {
		build.Critical("the number of uncachedRoots is too big. They should've been cached by now")
	}
	// Calculate the root offset within the file and write it to disk.
	rootOffset := fileOffsetFromRootIndex(mr.len())
	if _, err := mr.file.WriteAt(root[:], rootOffset); err != nil {
		return err
	}
	// Add the root to the unached roots.
	mr.appendRoot(root)

	// Increment the number of roots.
	mr.numMerkleRoots++
	return nil
}

// root returns the root of the merkle roots.
func (mr *merkleRoots) root() crypto.Hash {
	tree := crypto.NewCachedTree(sectorHeight)
	for _, st := range mr.cachedSubTrees {
		if err := tree.PushSubTree(st.height, st.sum); err != nil {
			// This should never fail.
			build.Critical(err)
		}
	}
	for _, root := range mr.uncachedRoots {
		tree.Push(root)
	}
	return tree.Root()
}

// newRoot returns the root of the merkleTree after appending the newRoot
// without actually appending it.
func (mr *merkleRoots) newRoot(newRoot crypto.Hash) crypto.Hash {
	tree := crypto.NewCachedTree(sectorHeight)
	for _, st := range mr.cachedSubTrees {
		if err := tree.PushSubTree(st.height, st.sum); err != nil {
			// This should never fail.
			build.Critical(err)
		}
	}
	for _, root := range mr.uncachedRoots {
		tree.Push(root)
	}
	// Push the new root.
	tree.Push(newRoot)
	return tree.Root()
}

// merkleRoots reads all the merkle roots from disk and returns them. This is
// not very fast and should only be used for testing purposes.
func (mr *merkleRoots) merkleRoots() (roots []crypto.Hash, err error) {
	// Get roots.
	roots, err = mr.merkleRootsFromIndex(0, mr.numMerkleRoots)
	if err != nil {
		return nil, err
	}
	// Sanity check: should have read exactly numMerkleRoots roots.
	if len(roots) != mr.numMerkleRoots {
		build.Critical(fmt.Sprintf("Number of merkle roots on disk (%v) doesn't match numMerkleRoots (%v)",
			len(roots), mr.numMerkleRoots))
	}
	return
}

// merkleRootsFrom index readds all the merkle roots in range [from;to)
func (mr *merkleRoots) merkleRootsFromIndex(from, to int) ([]crypto.Hash, error) {
	merkleRoots := make([]crypto.Hash, 0, to-from)
	if _, err := mr.file.Seek(fileOffsetFromRootIndex(from), io.SeekStart); err != nil {
		return merkleRoots, err
	}
	r := bufio.NewReader(mr.file)
	for i := from; to-i > 0; i++ {
		var root crypto.Hash
		if _, err := io.ReadFull(r, root[:]); err == io.EOF {
			return nil, io.ErrUnexpectedEOF
		} else if err != nil {
			return merkleRoots, errors.AddContext(err, "failed to read root from disk")
		}
		merkleRoots = append(merkleRoots, root)
	}
	return merkleRoots, nil
}

// rebuildCachedTree rebuilds the tree in mr.cachedSubTree at index i.
func (mr *merkleRoots) rebuildCachedTree(index int) error {
	// Find the index of the first root of the cached tree on disk.
	rootIndex := index * merkleRootsPerCache
	// Read all the roots necessary for creating the cached tree.
	roots, err := mr.merkleRootsFromIndex(rootIndex, rootIndex+(1<<merkleRootsCacheHeight))
	if err != nil {
		return errors.AddContext(err, "failed to read sectors for rebuilding cached tree")
	}
	// Replace the old cached tree.
	mr.cachedSubTrees[index] = newCachedSubTree(roots)
	return nil
}
<commit_msg>fix TestDelete<commit_after>// TODO currently the cached trees are not persisted and we build them at
// startup. For petabytes of data this might take a long time.

package proto

import (
	"bufio"
	"fmt"
	"io"
	"os"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/errors"
)

// merkleRootsCacheHeight is the height of the subTrees in cachedSubTrees. A
// height of 7 means that 128 sector roots are covered by a single cached
// subTree.
const merkleRootsCacheHeight = 7

// merkleRootsPerCache is the number of merkle roots in a cached subTree of
// merkleRootsCacheHeight height.
const merkleRootsPerCache = 1 << merkleRootsCacheHeight

type (
	// merkleRoots is a helper struct that makes it easier to add/insert/remove
	// merkleRoots within a SafeContract.
	merkleRoots struct {
		// cachedSubTrees are cached trees that can be used to more efficiently
		// compute the merkle root of a contract.
		cachedSubTrees []*cachedSubTree
		// uncachedRoots contains the sector roots that are not part of a
		// cached subTree. The uncachedRoots slice should never get longer than
		// 2^merkleRootsCacheHeight since that would simply result in a new
		// cached subTree in cachedSubTrees.
		uncachedRoots []crypto.Hash

		// file is the file of the safe contract that contains the root.
		file *os.File
		// numMerkleRoots is the number of merkle roots in file.
		numMerkleRoots int
	}

	// cachedSubTree is a cached subTree of a merkle tree. A height of 0 means
	// that the sum is the hash of a leaf. A subTree of height 1 means sum is
	// the root of 2 leaves. A subTree of height 2 contains the root of 4
	// leaves and so on.
	cachedSubTree struct {
		height int         // height of the subTree
		sum    crypto.Hash // root of the subTree
	}
)

// loadExistingMerkleRoots reads creates a merkleRoots object from existing
// merkle roots.
func loadExistingMerkleRoots(file *os.File) (*merkleRoots, error) {
	mr := &merkleRoots{
		file: file,
	}
	// Get the number of roots stored in the file.
	var err error
	mr.numMerkleRoots, err = mr.lenFromFile()
	if err != nil {
		return nil, err
	}
	// Seek to the first root's offset.
	if _, err = file.Seek(fileOffsetFromRootIndex(0), io.SeekStart); err != nil {
		return nil, err
	}
	// Read the roots from the file without reading all of them at once.
	r := bufio.NewReader(file)
	for i := 0; i < mr.numMerkleRoots; i++ {
		var root crypto.Hash
		if _, err = io.ReadFull(r, root[:]); err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}

		// Append the root to the uncachedRoots
		mr.appendRoot(root)
	}
	return mr, nil
}

// newCachedSubTree creates a cachedSubTree from exactly
// 2^merkleRootsCacheHeight roots.
func newCachedSubTree(roots []crypto.Hash) *cachedSubTree {
	// Sanity check the input length.
	if len(roots) != merkleRootsPerCache {
		build.Critical("can't create a cached subTree from the provided number of roots")
	}
	return &cachedSubTree{
		height: int(merkleRootsCacheHeight + sectorHeight),
		sum:    cachedMerkleRoot(roots),
	}
}

// newMerkleRoots creates a new merkleRoots object. This doesn't load existing
// roots from file and will assume that the file doesn't contain any roots.
// Don't use this on a file that contains roots.
func newMerkleRoots(file *os.File) *merkleRoots {
	return &merkleRoots{
		file: file,
	}
}

// fileOffsetFromRootIndex calculates the offset of the merkle root at index i from
// the beginning of the contract file.
func fileOffsetFromRootIndex(i int) int64 {
	return contractHeaderSize + crypto.HashSize*int64(i)
}

// delete deletes the sector root at a certain index.
func (mr *merkleRoots) delete(i int) error {
	// Check if the index is correct
	if i >= mr.numMerkleRoots {
		build.Critical("can't delete non-existing root")
		return nil
	}
	// If i is the index of the last element we call deleteLastRoot.
	if i == mr.numMerkleRoots-1 {
		return mr.deleteLastRoot()
	}
	// If we don't have any uncached roots we need to delete the last cached
	// tree and add its elements to the uncached roots.
	if len(mr.uncachedRoots) == 0 {
		mr.cachedSubTrees = mr.cachedSubTrees[:len(mr.cachedSubTrees)-1]
		rootIndex := len(mr.cachedSubTrees) * merkleRootsPerCache
		roots, err := mr.merkleRootsFromIndex(rootIndex, mr.numMerkleRoots)
		if err != nil {
			return errors.AddContext(err, "failed to read cached tree's roots")
		}
		mr.uncachedRoots = append(mr.uncachedRoots, roots...)
	}
	// Swap the root at index i with the last root in mr.uncachedRoots.
	_, err := mr.file.WriteAt(mr.uncachedRoots[len(mr.uncachedRoots)-1][:], fileOffsetFromRootIndex(i))
	if err != nil {
		return errors.AddContext(err, "failed to swap root to delete with last one")
	}
	// If the deleted root was not cached we swap the roots in memory too.
	// Otherwise we rebuild the cachedSubTree.
	if index, cached := mr.isIndexCached(i); !cached {
		mr.uncachedRoots[index] = mr.uncachedRoots[len(mr.uncachedRoots)-1]
	} else {
		err = mr.rebuildCachedTree(index)
	}
	if err != nil {
		return errors.AddContext(err, "failed to rebuild cached tree")
	}
	// Now that the element we want to delete is the last root we can simply
	// delete it by calling mr.deleteLastRoot.
	return mr.deleteLastRoot()
}

// deleteLastRoot deletes the last sector root of the contract.
func (mr *merkleRoots) deleteLastRoot() error {
	// Decrease the numMerkleRoots counter.
	mr.numMerkleRoots--
	// Truncate file to avoid interpreting trailing data as valid.
	if err := mr.file.Truncate(fileOffsetFromRootIndex(mr.numMerkleRoots)); err != nil {
		return errors.AddContext(err, "failed to delete last root from file")
	}
	// If the last element is uncached we can simply remove it from the slice.
	if len(mr.uncachedRoots) > 0 {
		mr.uncachedRoots = mr.uncachedRoots[:len(mr.uncachedRoots)-1]
		return nil
	}
	// If it is not uncached we need to delete the last cached tree and load
	// its elements into mr.uncachedRoots.
	mr.cachedSubTrees = mr.cachedSubTrees[:len(mr.cachedSubTrees)-1]
	rootIndex := len(mr.cachedSubTrees) * merkleRootsPerCache
	roots, err := mr.merkleRootsFromIndex(rootIndex, mr.numMerkleRoots)
	if err != nil {
		return errors.AddContext(err, "failed to read cached tree's roots")
	}
	mr.uncachedRoots = append(mr.uncachedRoots, roots...)
	return nil
}

// insert inserts a root by replacing a root at an existing index.
func (mr *merkleRoots) insert(index int, root crypto.Hash) error {
	if index > mr.numMerkleRoots {
		return errors.New("can't insert at a index greater than the number of roots")
	}
	if index == mr.numMerkleRoots {
		return mr.push(root)
	}
	// Replaced the root on disk.
	_, err := mr.file.WriteAt(root[:], fileOffsetFromRootIndex(index))
	if err != nil {
		return errors.AddContext(err, "failed to insert root on disk")
	}

	// Find out if the root is in mr.cachedSubTree or mr.uncachedRoots.
	i, cached := mr.isIndexCached(index)
	// If the root was not cached we can simply replace it in mr.uncachedRoots.
	if !cached {
		mr.uncachedRoots[i] = root
		return nil
	}
	// If the root was cached we need to rebuild the cache.
	if err := mr.rebuildCachedTree(i); err != nil {
		return errors.AddContext(err, "failed to rebuild cache for inserted root")
	}
	return nil
}

// isIndexCached determines if the root at index i is already cached in
// mr.cachedSubTree or if it is still in mr.uncachedRoots. It will return true
// or false and the index of the root in the corresponding data structure.
func (mr *merkleRoots) isIndexCached(i int) (int, bool) {
	if i/merkleRootsPerCache == len(mr.cachedSubTrees) {
		// Root is not cached. Return the false and the position in
		// mr.uncachedRoots
		return i - len(mr.cachedSubTrees)*merkleRootsPerCache, false
	}
	return i / merkleRootsPerCache, true
}

// lenFromFile returns the number of merkle roots by computing it from the
// filesize.
func (mr *merkleRoots) lenFromFile() (int, error) {
	stat, err := mr.file.Stat()
	if err != nil {
		return 0, err
	}
	size := stat.Size()
	// If we haven't written a single root yet we just return 0.
	if size < contractHeaderSize {
		return 0, nil
	}

	// Sanity check contract file length.
	if (size-contractHeaderSize)%crypto.HashSize != 0 {
		return 0, errors.New("contract file has unexpected length and might be corrupted")
	}
	return int((size - contractHeaderSize) / crypto.HashSize), nil
}

// len returns the number of merkle roots. It should always return the same
// number as lenFromFile.
func (mr *merkleRoots) len() int {
	return mr.numMerkleRoots
}

// appendRoot appends a root to the in-memory structure of the merkleRoots. If
// the length of the uncachedRoots grows too large they will be compressed into
// a cachedSubTree.
func (mr *merkleRoots) appendRoot(root crypto.Hash) {
	mr.uncachedRoots = append(mr.uncachedRoots, root)
	if len(mr.uncachedRoots) == merkleRootsPerCache {
		mr.cachedSubTrees = append(mr.cachedSubTrees, newCachedSubTree(mr.uncachedRoots))
		mr.uncachedRoots = mr.uncachedRoots[:0]
	}
}

// push appends a merkle root to the end of the contract. If the number of
// uncached merkle roots grows too big we cache them in a new subTree.
func (mr *merkleRoots) push(root crypto.Hash) error {
	// Sanity check the number of uncached roots before adding a new one.
	if len(mr.uncachedRoots) == merkleRootsPerCache {
		build.Critical("the number of uncachedRoots is too big. They should've been cached by now")
	}
	// Calculate the root offset within the file and write it to disk.
	rootOffset := fileOffsetFromRootIndex(mr.len())
	if _, err := mr.file.WriteAt(root[:], rootOffset); err != nil {
		return err
	}
	// Add the root to the unached roots.
	mr.appendRoot(root)

	// Increment the number of roots.
	mr.numMerkleRoots++
	return nil
}

// root returns the root of the merkle roots.
func (mr *merkleRoots) root() crypto.Hash {
	tree := crypto.NewCachedTree(sectorHeight)
	for _, st := range mr.cachedSubTrees {
		if err := tree.PushSubTree(st.height, st.sum); err != nil {
			// This should never fail.
			build.Critical(err)
		}
	}
	for _, root := range mr.uncachedRoots {
		tree.Push(root)
	}
	return tree.Root()
}

// newRoot returns the root of the merkleTree after appending the newRoot
// without actually appending it.
func (mr *merkleRoots) newRoot(newRoot crypto.Hash) crypto.Hash {
	tree := crypto.NewCachedTree(sectorHeight)
	for _, st := range mr.cachedSubTrees {
		if err := tree.PushSubTree(st.height, st.sum); err != nil {
			// This should never fail.
			build.Critical(err)
		}
	}
	for _, root := range mr.uncachedRoots {
		tree.Push(root)
	}
	// Push the new root.
	tree.Push(newRoot)
	return tree.Root()
}

// merkleRoots reads all the merkle roots from disk and returns them. This is
// not very fast and should only be used for testing purposes.
func (mr *merkleRoots) merkleRoots() (roots []crypto.Hash, err error) {
	// Get roots.
	roots, err = mr.merkleRootsFromIndex(0, mr.numMerkleRoots)
	if err != nil {
		return nil, err
	}
	// Sanity check: should have read exactly numMerkleRoots roots.
	if len(roots) != mr.numMerkleRoots {
		build.Critical(fmt.Sprintf("Number of merkle roots on disk (%v) doesn't match numMerkleRoots (%v)",
			len(roots), mr.numMerkleRoots))
	}
	return
}

// merkleRootsFrom index readds all the merkle roots in range [from;to)
func (mr *merkleRoots) merkleRootsFromIndex(from, to int) ([]crypto.Hash, error) {
	merkleRoots := make([]crypto.Hash, 0, to-from)
	if _, err := mr.file.Seek(fileOffsetFromRootIndex(from), io.SeekStart); err != nil {
		return merkleRoots, err
	}
	r := bufio.NewReader(mr.file)
	for i := from; to-i > 0; i++ {
		var root crypto.Hash
		if _, err := io.ReadFull(r, root[:]); err == io.EOF {
			return nil, io.ErrUnexpectedEOF
		} else if err != nil {
			return merkleRoots, errors.AddContext(err, "failed to read root from disk")
		}
		merkleRoots = append(merkleRoots, root)
	}
	return merkleRoots, nil
}

// rebuildCachedTree rebuilds the tree in mr.cachedSubTree at index i.
func (mr *merkleRoots) rebuildCachedTree(index int) error {
	// Find the index of the first root of the cached tree on disk.
	rootIndex := index * merkleRootsPerCache
	// Read all the roots necessary for creating the cached tree.
	roots, err := mr.merkleRootsFromIndex(rootIndex, rootIndex+(1<<merkleRootsCacheHeight))
	if err != nil {
		return errors.AddContext(err, "failed to read sectors for rebuilding cached tree")
	}
	// Replace the old cached tree.
	mr.cachedSubTrees[index] = newCachedSubTree(roots)
	return nil
}
<|endoftext|>


<commit_before>package db

import (
	"fmt"
	"sort"
	"strings"
)

var CurrentSchema int = currentSchema()

var Schemas = map[int]Schema{
	1: v1Schema{},
	2: v2Schema{},
	3: v3Schema{},
	4: v4Schema{},
	5: v5Schema{},
	6: v6Schema{},
	7: v7Schema{},
}

type Schema interface {
	Deploy(*DB) error
}

func (db *DB) Setup(want int) (int, error) {
	current, err := db.SchemaVersion()
	if err != nil {
		return 0, err
	}

	if want == 0 {
		want = CurrentSchema
	}
	if current > want {
		err = fmt.Errorf("Schema version %d is newer than this version of SHIELD (%d)", current, want)
		if err != nil {
			return 0, err
		}
	}

	versions := schemaVersions()

	for _, version := range versions {
		if current < version {
			err = Schemas[version].Deploy(db)
			if err != nil {
				return version - 1, err
			}
		}
		if want == version {
			break
		}
	}

	return want, nil
}

func schemaVersions() []int {
	var versions []int
	for k := range Schemas {
		versions = append(versions, k)
	}
	sort.Ints(versions)
	return versions
}

func currentSchema() int {
	versions := schemaVersions()
	return int(versions[len(versions)-1:][0])
}

func (db *DB) SchemaVersion() (int, error) {
	r, err := db.Query(`SELECT version FROM schema_info LIMIT 1`)
	if err != nil {
		if err.Error() == "no such table: schema_info" {
			return 0, nil
		}
		if err.Error() == `pq: relation "schema_info" does not exist` {
			return 0, nil
		}
		if strings.HasPrefix(err.Error(), `Error 1146: Table`) {
			return 0, nil
		}
		return 0, err
	}
	defer r.Close()

	// no records = no schema
	if !r.Next() {
		return 0, nil
	}

	var v int
	err = r.Scan(&v)
	// failed unmarshall is an actual error
	if err != nil {
		return 0, err
	}

	// invalid (negative) schema version is an actual error
	if v < 0 {
		return 0, fmt.Errorf("Invalid schema version %d found", v)
	}

	return int(v), nil
}

func (db *DB) CheckCurrentSchema() error {
	v, err := db.SchemaVersion()
	if err != nil {
		return err
	}
	if v != CurrentSchema {
		return fmt.Errorf("wrong schema version (%d, but want to be at %d)", v, CurrentSchema)
	}
	return nil
}
<commit_msg>Activate schema v8<commit_after>package db

import (
	"fmt"
	"sort"
	"strings"
)

var CurrentSchema int = currentSchema()

var Schemas = map[int]Schema{
	1: v1Schema{},
	2: v2Schema{},
	3: v3Schema{},
	4: v4Schema{},
	5: v5Schema{},
	6: v6Schema{},
	7: v7Schema{},
	8: v8Schema{},
}

type Schema interface {
	Deploy(*DB) error
}

func (db *DB) Setup(want int) (int, error) {
	current, err := db.SchemaVersion()
	if err != nil {
		return 0, err
	}

	if want == 0 {
		want = CurrentSchema
	}
	if current > want {
		err = fmt.Errorf("Schema version %d is newer than this version of SHIELD (%d)", current, want)
		if err != nil {
			return 0, err
		}
	}

	versions := schemaVersions()

	for _, version := range versions {
		if current < version {
			err = Schemas[version].Deploy(db)
			if err != nil {
				return version - 1, err
			}
		}
		if want == version {
			break
		}
	}

	return want, nil
}

func schemaVersions() []int {
	var versions []int
	for k := range Schemas {
		versions = append(versions, k)
	}
	sort.Ints(versions)
	return versions
}

func currentSchema() int {
	versions := schemaVersions()
	return int(versions[len(versions)-1:][0])
}

func (db *DB) SchemaVersion() (int, error) {
	r, err := db.Query(`SELECT version FROM schema_info LIMIT 1`)
	if err != nil {
		if err.Error() == "no such table: schema_info" {
			return 0, nil
		}
		if err.Error() == `pq: relation "schema_info" does not exist` {
			return 0, nil
		}
		if strings.HasPrefix(err.Error(), `Error 1146: Table`) {
			return 0, nil
		}
		return 0, err
	}
	defer r.Close()

	// no records = no schema
	if !r.Next() {
		return 0, nil
	}

	var v int
	err = r.Scan(&v)
	// failed unmarshall is an actual error
	if err != nil {
		return 0, err
	}

	// invalid (negative) schema version is an actual error
	if v < 0 {
		return 0, fmt.Errorf("Invalid schema version %d found", v)
	}

	return int(v), nil
}

func (db *DB) CheckCurrentSchema() error {
	v, err := db.SchemaVersion()
	if err != nil {
		return err
	}
	if v != CurrentSchema {
		return fmt.Errorf("wrong schema version (%d, but want to be at %d)", v, CurrentSchema)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"
	"unicode/utf8"

	. "github.com/matzoe/xunlei/api"
	"github.com/zyxar/taipei"
)

type Term interface {
	ReadLine() (string, error)
	Restore()
}

func _find(req string) (map[string]*Task, error) {
	if t, ok := M.Tasks[req]; ok {
		return map[string]*Task{req: t}, nil
	}
	if ok, _ := regexp.MatchString(`(.+=.+)+`, req); ok {
		return FindTasks(req)
	}
	return FindTasks("name=" + req)
}

func find(req []string) (map[string]*Task, error) {
	if len(req) == 0 {
		return nil, errors.New("Empty find query.")
	} else if len(req) == 1 {
		return _find(req[0])
	}
	return _find("name=" + strings.Join(req, "|"))
}

func fixedLengthName(name string, size int) string {
	l := utf8.RuneCountInString(name)
	var b bytes.Buffer
	var i int = 0
	for i < l && i < size {
		r, s := utf8.DecodeRuneInString(name)
		b.WriteRune(r)
		name = name[s:]
		if s > 1 {
			i += 2
		} else {
			i++
		}
	}
	for i < size {
		b.WriteByte(' ')
		i++
	}
	return b.String()
}

func main() {
	initConf()
	flag.StringVar(&conf.Id, "login", conf.Id, "login account")
	flag.StringVar(&conf.Pass, "pass", conf.Pass, "password/passhash")
	flag.BoolVar(&printVer, "version", false, "print version")
	flag.BoolVar(&daemon, "d", false, "run as daemon/server")
	flag.Parse()
	if printVer {
		printVersion()
		return
	}
	if err := ResumeSession(cookie_file); err != nil {
		log.Println(err)
		if err = Login(conf.Id, conf.Pass); err != nil {
			log.Println(err)
			os.Exit(1)
		}
		if err = SaveSession(cookie_file); err != nil {
			log.Println(err)
		}
	}
	GetGdriveId()
	if daemon {
		daemonLoop()
		return
	}
	term := newTerm()
	defer term.Restore()
	{
		var err error
		insufficientArgErr := errors.New("Insufficient arguments.")
		noTasksMatchesErr := errors.New("No task matches.")
		var line string
		var cmds []string
		clearscr()
	LOOP:
		for {
			line, err = term.ReadLine()
			if err != nil {
				break
			}
			cmds = strings.Fields(line)
			if len(cmds) == 0 {
				continue
			}
			switch cmds[0] {
			case "ison":
				log.Println(IsOn())
			case "relogin":
				if !IsOn() {
					if err = Login(conf.Id, conf.Pass); err != nil {
						log.Println(err)
					} else if err = SaveSession(cookie_file); err != nil {
						log.Println(err)
					}
				} else {
					fmt.Println("Already log on.")
				}
			case "saveconf":
				{
					b, err := conf.save(conf_file)
					if err == nil {
						fmt.Printf("%s\n", b)
					}
				}
			case "loadconf":
				{
					if _, err = conf.load(conf_file); err == nil {
						fmt.Printf("%+v\n", conf)
					}
				}
			case "cls", "clear":
				clearscr()
			case "ls":
				ts, err := GetTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "ld":
				ts, err := GetDeletedTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "le":
				ts, err := GetExpiredTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "lc":
				ts, err := GetCompletedTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "ll":
				ts, err := GetTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Repr())
						k++
					}
				}
			case "info":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						j := 0
						for i, _ := range ts {
							if ts[i].IsBt() {
								m, err := ts[i].FillBtList()
								fmt.Printf("#%d %v\n", j, ts[i].Repr())
								if err == nil {
									fmt.Printf("%v\n", m)
								}
							} else {
								fmt.Printf("#%d %v\n", j, ts[i].Repr())
							}
							j++
						}
					}
				}
			case "dl", "download":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					pay := make(map[string]*struct {
						t *Task
						s string
					})
					del := false
					check := conf.CheckHash
					for i, _ := range cmds[1:] {
						if strings.HasPrefix(cmds[1:][i], "--") {
							switch cmds[1:][i][2:] {
							case "delete":
								del = true
							case "check":
								check = true
							case "no-check", "nocheck":
								check = false
							}
						} else {
							p := strings.Split(cmds[1:][i], "/")
							m, err := _find(p[0])
							if err == nil {
								for i, _ := range m {
									var filter string
									if len(p) == 1 {
										filter = `.*`
									} else {
										filter = p[1]
									}
									pay[m[i].Id] = &struct {
										t *Task
										s string
									}{m[i], filter}
								}
							}
						}
					}
					for i, _ := range pay {
						if err = download(pay[i].t, pay[i].s, true, check); err != nil {
							fmt.Println(err)
						} else if del {
							if err = pay[i].t.Remove(); err != nil {
								fmt.Println(err)
							}
						}
					}
					err = nil
				}
			case "dt":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil { // TODO: improve find query
						for i, _ := range ts {
							if ts[i].IsBt() {
								if err = GetTorrentFileByHash(ts[i].Cid, ts[i].TaskName+".torrent"); err != nil {
									fmt.Println(err)
								}
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "ti":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil { // TODO: improve find query
						for i, _ := range ts {
							if ts[i].IsBt() {
								if b, err := GetTorrentByHash(ts[i].Cid); err != nil {
									fmt.Println(err)
								} else {
									if m, err := taipei.DecodeMetaInfo(b); err != nil {
										fmt.Println(err)
									} else {
										taipei.Iconv(m)
										fmt.Println(m)
									}
								}
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "add":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					req := cmds[1:]
					for j, _ := range req {
						if err = AddTask(req[j]); err != nil {
							fmt.Println(err)
						}
					}
					err = nil
				}
			case "rm", "delete":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Remove(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				}
			case "purge":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Purge(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				}
			case "readd":
				// re-add tasks from deleted or expired
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						ReAddTasks(ts)
					}
				} else {
					err = insufficientArgErr
				}
			case "delayall":
				{
					DelayAllTasks()
				}
			case "pause":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Pause(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "resume":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Resume(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "rename", "mv":
				if len(cmds) == 3 {
					// must be task id here
					if t, ok := M.Tasks[cmds[1]]; ok {
						t.Rename(cmds[2])
					} else {
						err = noTasksMatchesErr
					}
				} else {
					err = insufficientArgErr
				}
			case "delay":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Delay(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				}
			case "link":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						k := 0
						for i, _ := range ts {
							if !ts[i].IsBt() {
								fmt.Printf("#%d %s: %v\n", k, ts[i].Id, ts[i].LixianURL)
							} else {
								m, err := ts[i].FillBtList()
								if err == nil {
									fmt.Printf("#%d %s:\n", k, ts[i].Id)
									for j, _ := range m.Record {
										fmt.Printf("  #%d %s\n", m.Record[j].Id, m.Record[j].DownURL)
									}
								}
							}
							k++
						}
					}
				} else {
					err = insufficientArgErr
				}
			case "find":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						k := 0
						for i, _ := range ts {
							fmt.Printf("#%d %v\n", k, ts[i].Coloring())
							k++
						}
					}
				} else {
					err = insufficientArgErr
				}
			case "st":
				{
				}
			case "rpc":
				{
				}
			case "play", "vod":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							low, high, err := ts[i].GetVodURL()
							if err == nil {
								fmt.Printf("%s\n%s\n", low, high)
							}
						}
					}
				} else {
					err = insufficientArgErr
				}
			case "version":
				printVersion()
			case "update":
				err = ProcessTask(func(t *Task) {
					log.Printf("%s %s %sB/s %.2f%%\n", t.Id, fixedLengthName(t.TaskName, 32), t.Speed, t.Progress)
				})
			case "quit", "exit":
				break LOOP
			case "help":
				// TODO
			default:
				err = fmt.Errorf("Unrecognised command: %s", cmds[0])
			}
			if err != nil {
				fmt.Println(err)
			}
		}
	}
}
<commit_msg>add err printing in `link`<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"
	"unicode/utf8"

	. "github.com/matzoe/xunlei/api"
	"github.com/zyxar/taipei"
)

type Term interface {
	ReadLine() (string, error)
	Restore()
}

func _find(req string) (map[string]*Task, error) {
	if t, ok := M.Tasks[req]; ok {
		return map[string]*Task{req: t}, nil
	}
	if ok, _ := regexp.MatchString(`(.+=.+)+`, req); ok {
		return FindTasks(req)
	}
	return FindTasks("name=" + req)
}

func find(req []string) (map[string]*Task, error) {
	if len(req) == 0 {
		return nil, errors.New("Empty find query.")
	} else if len(req) == 1 {
		return _find(req[0])
	}
	return _find("name=" + strings.Join(req, "|"))
}

func fixedLengthName(name string, size int) string {
	l := utf8.RuneCountInString(name)
	var b bytes.Buffer
	var i int = 0
	for i < l && i < size {
		r, s := utf8.DecodeRuneInString(name)
		b.WriteRune(r)
		name = name[s:]
		if s > 1 {
			i += 2
		} else {
			i++
		}
	}
	for i < size {
		b.WriteByte(' ')
		i++
	}
	return b.String()
}

func main() {
	initConf()
	flag.StringVar(&conf.Id, "login", conf.Id, "login account")
	flag.StringVar(&conf.Pass, "pass", conf.Pass, "password/passhash")
	flag.BoolVar(&printVer, "version", false, "print version")
	flag.BoolVar(&daemon, "d", false, "run as daemon/server")
	flag.Parse()
	if printVer {
		printVersion()
		return
	}
	if err := ResumeSession(cookie_file); err != nil {
		log.Println(err)
		if err = Login(conf.Id, conf.Pass); err != nil {
			log.Println(err)
			os.Exit(1)
		}
		if err = SaveSession(cookie_file); err != nil {
			log.Println(err)
		}
	}
	GetGdriveId()
	if daemon {
		daemonLoop()
		return
	}
	term := newTerm()
	defer term.Restore()
	{
		var err error
		insufficientArgErr := errors.New("Insufficient arguments.")
		noTasksMatchesErr := errors.New("No task matches.")
		var line string
		var cmds []string
		clearscr()
	LOOP:
		for {
			line, err = term.ReadLine()
			if err != nil {
				break
			}
			cmds = strings.Fields(line)
			if len(cmds) == 0 {
				continue
			}
			switch cmds[0] {
			case "ison":
				log.Println(IsOn())
			case "relogin":
				if !IsOn() {
					if err = Login(conf.Id, conf.Pass); err != nil {
						log.Println(err)
					} else if err = SaveSession(cookie_file); err != nil {
						log.Println(err)
					}
				} else {
					fmt.Println("Already log on.")
				}
			case "saveconf":
				{
					b, err := conf.save(conf_file)
					if err == nil {
						fmt.Printf("%s\n", b)
					}
				}
			case "loadconf":
				{
					if _, err = conf.load(conf_file); err == nil {
						fmt.Printf("%+v\n", conf)
					}
				}
			case "cls", "clear":
				clearscr()
			case "ls":
				ts, err := GetTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "ld":
				ts, err := GetDeletedTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "le":
				ts, err := GetExpiredTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "lc":
				ts, err := GetCompletedTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Coloring())
						k++
					}
				}
			case "ll":
				ts, err := GetTasks()
				if err == nil {
					k := 0
					for i, _ := range ts {
						fmt.Printf("#%d %v\n", k, ts[i].Repr())
						k++
					}
				}
			case "info":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						j := 0
						for i, _ := range ts {
							if ts[i].IsBt() {
								m, err := ts[i].FillBtList()
								fmt.Printf("#%d %v\n", j, ts[i].Repr())
								if err == nil {
									fmt.Printf("%v\n", m)
								}
							} else {
								fmt.Printf("#%d %v\n", j, ts[i].Repr())
							}
							j++
						}
					}
				}
			case "dl", "download":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					pay := make(map[string]*struct {
						t *Task
						s string
					})
					del := false
					check := conf.CheckHash
					for i, _ := range cmds[1:] {
						if strings.HasPrefix(cmds[1:][i], "--") {
							switch cmds[1:][i][2:] {
							case "delete":
								del = true
							case "check":
								check = true
							case "no-check", "nocheck":
								check = false
							}
						} else {
							p := strings.Split(cmds[1:][i], "/")
							m, err := _find(p[0])
							if err == nil {
								for i, _ := range m {
									var filter string
									if len(p) == 1 {
										filter = `.*`
									} else {
										filter = p[1]
									}
									pay[m[i].Id] = &struct {
										t *Task
										s string
									}{m[i], filter}
								}
							}
						}
					}
					for i, _ := range pay {
						if err = download(pay[i].t, pay[i].s, true, check); err != nil {
							fmt.Println(err)
						} else if del {
							if err = pay[i].t.Remove(); err != nil {
								fmt.Println(err)
							}
						}
					}
					err = nil
				}
			case "dt":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil { // TODO: improve find query
						for i, _ := range ts {
							if ts[i].IsBt() {
								if err = GetTorrentFileByHash(ts[i].Cid, ts[i].TaskName+".torrent"); err != nil {
									fmt.Println(err)
								}
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "ti":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil { // TODO: improve find query
						for i, _ := range ts {
							if ts[i].IsBt() {
								if b, err := GetTorrentByHash(ts[i].Cid); err != nil {
									fmt.Println(err)
								} else {
									if m, err := taipei.DecodeMetaInfo(b); err != nil {
										fmt.Println(err)
									} else {
										taipei.Iconv(m)
										fmt.Println(m)
									}
								}
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "add":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					req := cmds[1:]
					for j, _ := range req {
						if err = AddTask(req[j]); err != nil {
							fmt.Println(err)
						}
					}
					err = nil
				}
			case "rm", "delete":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Remove(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				}
			case "purge":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Purge(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				}
			case "readd":
				// re-add tasks from deleted or expired
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						ReAddTasks(ts)
					}
				} else {
					err = insufficientArgErr
				}
			case "delayall":
				{
					DelayAllTasks()
				}
			case "pause":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Pause(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "resume":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Resume(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				} else {
					err = insufficientArgErr
				}
			case "rename", "mv":
				if len(cmds) == 3 {
					// must be task id here
					if t, ok := M.Tasks[cmds[1]]; ok {
						t.Rename(cmds[2])
					} else {
						err = noTasksMatchesErr
					}
				} else {
					err = insufficientArgErr
				}
			case "delay":
				if len(cmds) < 2 {
					err = insufficientArgErr
				} else {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							if err = ts[i].Delay(); err != nil {
								fmt.Println(err)
							}
						}
						err = nil
					}
				}
			case "link":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						k := 0
						for i, _ := range ts {
							if !ts[i].IsBt() {
								fmt.Printf("#%d %s: %v\n", k, ts[i].Id, ts[i].LixianURL)
							} else {
								m, err := ts[i].FillBtList()
								if err == nil {
									fmt.Printf("#%d %s:\n", k, ts[i].Id)
									for j, _ := range m.Record {
										fmt.Printf("  #%d %s\n", m.Record[j].Id, m.Record[j].DownURL)
									}
								} else {
									fmt.Println(err)
								}
							}
							k++
						}
					}
				} else {
					err = insufficientArgErr
				}
			case "find":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						k := 0
						for i, _ := range ts {
							fmt.Printf("#%d %v\n", k, ts[i].Coloring())
							k++
						}
					}
				} else {
					err = insufficientArgErr
				}
			case "st":
				{
				}
			case "rpc":
				{
				}
			case "play", "vod":
				if len(cmds) > 1 {
					var ts map[string]*Task
					if ts, err = find(cmds[1:]); err == nil {
						for i, _ := range ts {
							low, high, err := ts[i].GetVodURL()
							if err == nil {
								fmt.Printf("%s\n%s\n", low, high)
							}
						}
					}
				} else {
					err = insufficientArgErr
				}
			case "version":
				printVersion()
			case "update":
				err = ProcessTask(func(t *Task) {
					log.Printf("%s %s %sB/s %.2f%%\n", t.Id, fixedLengthName(t.TaskName, 32), t.Speed, t.Progress)
				})
			case "quit", "exit":
				break LOOP
			case "help":
				// TODO
			default:
				err = fmt.Errorf("Unrecognised command: %s", cmds[0])
			}
			if err != nil {
				fmt.Println(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package lzb

import "errors"

type dict struct {
	buf  *buffer
	head int64
	size int64
}

func newDict(b *buffer, head int64, size int64) (d *dict, err error) {
	switch {
	case size <= 0:
		return nil, errors.New("size must be positive")
	case size > int64(b.capacity()):
		return nil, errors.New("size exceeds buffer capacity")
	case !(b.bottom <= head && head <= b.top):
		return nil, errOffset
	}
	return &dict{buf: b, head: head, size: size}, nil
}

func (d *dict) byteAt(dist int64) byte {
	if !(0 < dist && dist <= d.size) {
		panic("dist out of range")
	}
	off := d.head - dist
	if off < d.buf.bottom {
		return 0
	}
	return d.buf.data[d.buf.index(off)]
}

var errWhence = errors.New("unsupported whence value")

func (d *dict) Seek(offset int64, whence int) (off int64, err error) {
	switch whence {
	case 0:
		off = offset
	case 1:
		off = d.head + offset
	case 2:
		off = d.buf.top + offset
	default:
		return d.head, errWhence
	}
	if !(d.buf.bottom <= off && off <= d.buf.top) {
		return d.head, errOffset
	}
	d.head = off
	return
}
<commit_msg>lzb: optimized dict.Seek<commit_after>package lzb

import "errors"

type dict struct {
	buf  *buffer
	head int64
	size int64
}

func newDict(b *buffer, head int64, size int64) (d *dict, err error) {
	switch {
	case size <= 0:
		return nil, errors.New("size must be positive")
	case size > int64(b.capacity()):
		return nil, errors.New("size exceeds buffer capacity")
	case !(b.bottom <= head && head <= b.top):
		return nil, errOffset
	}
	return &dict{buf: b, head: head, size: size}, nil
}

func (d *dict) byteAt(dist int64) byte {
	if !(0 < dist && dist <= d.size) {
		panic("dist out of range")
	}
	off := d.head - dist
	if off < d.buf.bottom {
		return 0
	}
	return d.buf.data[d.buf.index(off)]
}

var errWhence = errors.New("unsupported whence value")

func (d *dict) Seek(offset int64, whence int) (off int64, err error) {
	switch whence {
	case 0:
		off = offset
	case 1:
		if offset == 0 {
			return d.head, nil
		}
		off = d.head + offset
	case 2:
		off = d.buf.top + offset
	default:
		return d.head, errWhence
	}
	if !(d.buf.bottom <= off && off <= d.buf.top) {
		return d.head, errOffset
	}
	d.head = off
	return
}
<|endoftext|>


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

// guru: a tool for answering questions about Go source code.
//
//    http://golang.org/s/oracle-design
//    http://golang.org/s/oracle-user-manual

package commands

import (
	"encoding/json"
	"fmt"
	"go/build"
	"go/token"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"golang.org/x/tools/cmd/guru/serial"

	"nvim-go/gb"
	"nvim-go/guru"
	"nvim-go/nvim"
)

func init() {
	plugin.HandleFunction("GoGuru", &plugin.FunctionOptions{Eval: "*"}, funcGuru)
}

type funcGuruEval struct {
	FileInfo funcGuruFileInfo
	Env      funcGuruEnv
}

type funcGuruFileInfo struct {
	Cwd  string `eval:"expand('%:p:h')"`
	File string `eval:"expand('%:p')"`
}

type funcGuruEnv struct {
	Reflection int64 `eval:"g:go#guru#reflection"`
	KeepCursor int64 `eval:"g:go#guru#keep_cursor"`
	JumpFirst  int64 `eval:"g:go#guru#jump_first"`
}

func funcGuru(v *vim.Vim, args []string, eval *funcGuruEval) {
	go Guru(v, args, eval)
}

func Guru(v *vim.Vim, args []string, eval *funcGuruEval) error {
	defer nvim.Profile(time.Now(), "Guru")

	defer gb.WithGoBuildForPath(eval.FileInfo.Cwd)()

	reflection := false
	keepCursor := false
	jumpfirst := false

	if eval.Env.Reflection == int64(1) {
		reflection = true
	}

	if eval.Env.KeepCursor == int64(1) {
		keepCursor = true
	}

	if eval.Env.JumpFirst == int64(1) {
		jumpfirst = true
	}

	var b vim.Buffer

	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	if err := p.Wait(); err != nil {
		return err
	}

	dir := strings.Split(eval.FileInfo.Cwd, "src/")
	scopeFlag := dir[len(dir)-1]

	mode := args[0]

	pos, err := nvim.ByteOffset(p)
	if err != nil {
		return nvim.Echomsg(v, "%v", err)
	}

	var outputMu sync.Mutex
	var d []*nvim.ErrorlistData
	output := func(fset *token.FileSet, qr guru.QueryResult) {
		outputMu.Lock()
		defer outputMu.Unlock()
		if d, err = parseResult(mode, fset, qr.JSON(fset)); err != nil {
			nvim.Echoerr(v, err)
		}
	}

	query := guru.Query{
		Output:     output,
		Pos:        eval.FileInfo.File + ":#" + strconv.FormatInt(int64(pos), 10),
		Build:      &build.Default,
		Scope:      []string{scopeFlag},
		Reflection: reflection,
	}

	if err := guru.Run(mode, &query); err != nil {
		return nvim.Echomsg(v, "GoGuru:", err)
	}

	if err := nvim.SetLoclist(p, d); err != nil {
		return nvim.Echomsg(v, "GoGuru:", err)
	}

	if jumpfirst || mode == "definition" {
		p.Command("silent! ll 1")
		p.FeedKeys("zz", "n", false)
		return nil
	} else {
		var w vim.Window
		p.CurrentWindow(&w)
		return nvim.OpenLoclist(p, w, d, keepCursor)
	}
}

func parseResult(mode string, fset *token.FileSet, data []byte) ([]*nvim.ErrorlistData, error) {
	var (
		loclist []*nvim.ErrorlistData
		fname   string
		line    int
		col     int
		text    string
	)

	switch mode {

	case "callees":
		var value = serial.Callees{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value.Callees {
			fname, line, col = nvim.SplitPos(v.Pos)
			text = value.Desc + ": " + v.Name
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "callers":
		var value = []serial.Caller{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value {
			fname, line, col = nvim.SplitPos(v.Pos)
			text = v.Desc + ": " + v.Caller
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "callstack":
		var value = serial.CallStack{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value.Callers {
			fname, line, col = nvim.SplitPos(v.Pos)
			text = v.Desc + " " + value.Target
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "definition":
		var value = serial.Definition{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col = nvim.SplitPos(value.ObjPos)
		text = value.Desc
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     text,
		})

	case "describe":
		var value = serial.Describe{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col = nvim.SplitPos(value.Value.ObjPos)
		text = value.Desc + " " + value.Value.Type
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     text,
		})

	case "freevars":
		var value = serial.FreeVar{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col = nvim.SplitPos(value.Pos)
		text = value.Kind + " " + value.Type + " " + value.Ref
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     text,
		})

	case "implements":
		var value = serial.Implements{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value.AssignableFrom {
			fname, line, col := nvim.SplitPos(v.Pos)
			text = v.Kind + " " + v.Name
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "peers":
		var value = serial.Peers{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col := nvim.SplitPos(value.Pos)
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     "Base: selected channel op (<-)",
		})
		for _, v := range value.Allocs {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Allocs: make(chan) ops",
			})
		}
		for _, v := range value.Sends {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Sends: ch<-x ops",
			})
		}
		for _, v := range value.Receives {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Receives: <-ch ops",
			})
		}
		for _, v := range value.Closes {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Closes: close(ch) ops",
			})
		}

	case "pointsto":
		var value = []serial.PointsTo{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value {
			fname, line, col := nvim.SplitPos(v.NamePos)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "type: " + v.Type,
			})
			if len(v.Labels) > -1 {
				for _, vl := range v.Labels {
					fname, line, col := nvim.SplitPos(vl.Pos)
					loclist = append(loclist, &nvim.ErrorlistData{
						FileName: fname,
						LNum:     line,
						Col:      col,
						Text:     vl.Desc,
					})
				}
			}
		}

	case "referrers":
		var packages = serial.ReferrersPackage{}
		if err := json.Unmarshal(data, &packages); err != nil {
			return loclist, err
		}
		for _, v := range packages.Refs {
			fname, line, col := nvim.SplitPos(v.Pos)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     v.Text,
			})
		}

	case "whicherrs":
		var value = serial.WhichErrs{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col := nvim.SplitPos(value.ErrPos)
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     "Errror Position",
		})
		for _, vg := range value.Globals {
			fname, line, col := nvim.SplitPos(vg)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Globals",
			})
		}
		for _, vc := range value.Constants {
			fname, line, col := nvim.SplitPos(vc)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Constants",
			})
		}
		for _, vt := range value.Types {
			fname, line, col := nvim.SplitPos(vt.Position)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Types: " + vt.Type,
			})
		}

	}

	if len(loclist) == 0 {
		return loclist, fmt.Errorf("%s not fount", mode)
	}
	return loclist, nil
}

func onComplete(v *vim.Vim) ([]string, error) {
	return []string{
		"callees",
		"callers",
		"callstack",
		"definition",
		"describe",
		"freevars",
		"implements",
		"peers",
		"pointsto",
		"referrers",
		"what",
		"whicherrs",
	}, nil
}
<commit_msg>Remove unused code(GoGuru: onComplete)<commit_after>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// guru: a tool for answering questions about Go source code.
//
//    http://golang.org/s/oracle-design
//    http://golang.org/s/oracle-user-manual

package commands

import (
	"encoding/json"
	"fmt"
	"go/build"
	"go/token"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"golang.org/x/tools/cmd/guru/serial"

	"nvim-go/gb"
	"nvim-go/guru"
	"nvim-go/nvim"
)

func init() {
	plugin.HandleFunction("GoGuru", &plugin.FunctionOptions{Eval: "*"}, funcGuru)
}

type funcGuruEval struct {
	FileInfo funcGuruFileInfo
	Env      funcGuruEnv
}

type funcGuruFileInfo struct {
	Cwd  string `eval:"expand('%:p:h')"`
	File string `eval:"expand('%:p')"`
}

type funcGuruEnv struct {
	Reflection int64 `eval:"g:go#guru#reflection"`
	KeepCursor int64 `eval:"g:go#guru#keep_cursor"`
	JumpFirst  int64 `eval:"g:go#guru#jump_first"`
}

func funcGuru(v *vim.Vim, args []string, eval *funcGuruEval) {
	go Guru(v, args, eval)
}

func Guru(v *vim.Vim, args []string, eval *funcGuruEval) error {
	defer nvim.Profile(time.Now(), "Guru")

	defer gb.WithGoBuildForPath(eval.FileInfo.Cwd)()

	reflection := false
	keepCursor := false
	jumpfirst := false

	if eval.Env.Reflection == int64(1) {
		reflection = true
	}

	if eval.Env.KeepCursor == int64(1) {
		keepCursor = true
	}

	if eval.Env.JumpFirst == int64(1) {
		jumpfirst = true
	}

	var b vim.Buffer

	p := v.NewPipeline()
	p.CurrentBuffer(&b)
	if err := p.Wait(); err != nil {
		return err
	}

	dir := strings.Split(eval.FileInfo.Cwd, "src/")
	scopeFlag := dir[len(dir)-1]

	mode := args[0]

	pos, err := nvim.ByteOffset(p)
	if err != nil {
		return nvim.Echomsg(v, "%v", err)
	}

	var outputMu sync.Mutex
	var d []*nvim.ErrorlistData
	output := func(fset *token.FileSet, qr guru.QueryResult) {
		outputMu.Lock()
		defer outputMu.Unlock()
		if d, err = parseResult(mode, fset, qr.JSON(fset)); err != nil {
			nvim.Echoerr(v, err)
		}
	}

	query := guru.Query{
		Output:     output,
		Pos:        eval.FileInfo.File + ":#" + strconv.FormatInt(int64(pos), 10),
		Build:      &build.Default,
		Scope:      []string{scopeFlag},
		Reflection: reflection,
	}

	if err := guru.Run(mode, &query); err != nil {
		return nvim.Echomsg(v, "GoGuru:", err)
	}

	if err := nvim.SetLoclist(p, d); err != nil {
		return nvim.Echomsg(v, "GoGuru:", err)
	}

	if jumpfirst || mode == "definition" {
		p.Command("silent! ll 1")
		p.FeedKeys("zz", "n", false)
		return nil
	} else {
		var w vim.Window
		p.CurrentWindow(&w)
		return nvim.OpenLoclist(p, w, d, keepCursor)
	}
}

func parseResult(mode string, fset *token.FileSet, data []byte) ([]*nvim.ErrorlistData, error) {
	var (
		loclist []*nvim.ErrorlistData
		fname   string
		line    int
		col     int
		text    string
	)

	switch mode {

	case "callees":
		var value = serial.Callees{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value.Callees {
			fname, line, col = nvim.SplitPos(v.Pos)
			text = value.Desc + ": " + v.Name
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "callers":
		var value = []serial.Caller{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value {
			fname, line, col = nvim.SplitPos(v.Pos)
			text = v.Desc + ": " + v.Caller
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "callstack":
		var value = serial.CallStack{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value.Callers {
			fname, line, col = nvim.SplitPos(v.Pos)
			text = v.Desc + " " + value.Target
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "definition":
		var value = serial.Definition{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col = nvim.SplitPos(value.ObjPos)
		text = value.Desc
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     text,
		})

	case "describe":
		var value = serial.Describe{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col = nvim.SplitPos(value.Value.ObjPos)
		text = value.Desc + " " + value.Value.Type
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     text,
		})

	case "freevars":
		var value = serial.FreeVar{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col = nvim.SplitPos(value.Pos)
		text = value.Kind + " " + value.Type + " " + value.Ref
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     text,
		})

	case "implements":
		var value = serial.Implements{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value.AssignableFrom {
			fname, line, col := nvim.SplitPos(v.Pos)
			text = v.Kind + " " + v.Name
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     text,
			})
		}

	case "peers":
		var value = serial.Peers{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col := nvim.SplitPos(value.Pos)
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     "Base: selected channel op (<-)",
		})
		for _, v := range value.Allocs {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Allocs: make(chan) ops",
			})
		}
		for _, v := range value.Sends {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Sends: ch<-x ops",
			})
		}
		for _, v := range value.Receives {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Receives: <-ch ops",
			})
		}
		for _, v := range value.Closes {
			fname, line, col := nvim.SplitPos(v)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Closes: close(ch) ops",
			})
		}

	case "pointsto":
		var value = []serial.PointsTo{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		for _, v := range value {
			fname, line, col := nvim.SplitPos(v.NamePos)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "type: " + v.Type,
			})
			if len(v.Labels) > -1 {
				for _, vl := range v.Labels {
					fname, line, col := nvim.SplitPos(vl.Pos)
					loclist = append(loclist, &nvim.ErrorlistData{
						FileName: fname,
						LNum:     line,
						Col:      col,
						Text:     vl.Desc,
					})
				}
			}
		}

	case "referrers":
		var packages = serial.ReferrersPackage{}
		if err := json.Unmarshal(data, &packages); err != nil {
			return loclist, err
		}
		for _, v := range packages.Refs {
			fname, line, col := nvim.SplitPos(v.Pos)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     v.Text,
			})
		}

	case "whicherrs":
		var value = serial.WhichErrs{}
		err := json.Unmarshal(data, &value)
		if err != nil {
			return loclist, err
		}
		fname, line, col := nvim.SplitPos(value.ErrPos)
		loclist = append(loclist, &nvim.ErrorlistData{
			FileName: fname,
			LNum:     line,
			Col:      col,
			Text:     "Errror Position",
		})
		for _, vg := range value.Globals {
			fname, line, col := nvim.SplitPos(vg)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Globals",
			})
		}
		for _, vc := range value.Constants {
			fname, line, col := nvim.SplitPos(vc)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Constants",
			})
		}
		for _, vt := range value.Types {
			fname, line, col := nvim.SplitPos(vt.Position)
			loclist = append(loclist, &nvim.ErrorlistData{
				FileName: fname,
				LNum:     line,
				Col:      col,
				Text:     "Types: " + vt.Type,
			})
		}

	}

	if len(loclist) == 0 {
		return loclist, fmt.Errorf("%s not fount", mode)
	}
	return loclist, nil
}
<|endoftext|>