<commit_before>package main

import "fmt"
import "os"
import "net/http"
import "io/ioutil"
import "log"

import "github.com/moovweb/gokogiri"
import "github.com/moovweb/gokogiri/xml"
import "github.com/moovweb/gokogiri/xpath"
import "github.com/codegangsta/cli"

func load(url string, fromFile bool) *xml.XmlDocument{
	var data []byte
	if fromFile{
		file, _ := os.Open(url)
		data, _ = ioutil.ReadAll(file)
	} else {
		resp, err := http.Get(url)
		if err != nil {
			log.Fatal(err)
		}
		data, _ = ioutil.ReadAll(resp.Body)
	}
	doc, _ := gokogiri.ParseXml(data)
	return(doc)
}

func multiple(vrouter string, vrf_name string, count bool) {
	url := "http://" + vrouter + ":8085" + "/Snh_PageReq?x=begin:-1,end:-1,table:" + vrf_name + ".uc.route.0,"

	var doc = load(url, false)
	defer doc.Free()
	xps := xpath.Compile("//route_list/list/RouteUcSandeshData/path_list/list/PathSandeshData/nh/NhSandeshData/mc_list/../../../../../../src_ip/text()")
	ss, _ := doc.Root().Search(xps)
	if count {
		fmt.Printf("%d\n", len(ss))
	} else {
		for _, s := range ss {
			fmt.Printf("%s\n", s)
		}
	}
}

type Page struct {
	VrouterUrl string;
	Table string;
}

type File struct {
	Path string;
}

type LoadAble interface {
	Load(descCol DescCol) Collection;
}

// Parse data to XML
func fromDataToCollection(data []byte, descCol DescCol) Collection {
	doc, _ := gokogiri.ParseXml(data)
	ss, _ := doc.Search(descCol.BaseXpath)
	if len(ss) < 1 {
		log.Fatal(fmt.Sprintf("%d Failed to search xpath '%s'", len(ss), descCol.BaseXpath))
	}
	col := Collection{node: ss[0], descCol: descCol}
	col.Init()
	return col
}

func (file File) Load(descCol DescCol) Collection {
	f, _ := os.Open(file.Path)
	data, _ := ioutil.ReadAll(f)
	return fromDataToCollection(data, descCol)
}

func (page Page) Load(descCol DescCol) Collection {
	url := "http://" + page.VrouterUrl + ":8085/Snh_PageReq?x=begin:-1,end:-1,table:" + page.Table + ","
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	data, _ := ioutil.ReadAll(resp.Body)
	return fromDataToCollection(data, descCol)
}

type Collection struct {
	descCol DescCol;
	doc *xml.XmlDocument;
	node xml.Node;
	elements []Element;
}

type DescCol struct {
	PageArgs []string;
	PageBuilder (func([]string) LoadAble);
	BaseXpath string;
	DescElt DescElement;
	SearchXpath (func(string) string);
}

type DescElement struct {
	ShortDetailXpath string;
	LongDetail LongAble;
}

type Element struct {
	node xml.Node;
	desc DescElement;
}

func (col *Collection) Init() {
	ss, _ := col.node.Search("*")
	col.elements = make([]Element, len(ss))
	for i, s := range ss {
		col.elements[i] = Element{node: s, desc: col.descCol.DescElt}
	}
}

func (col *Collection) Search(pattern string) Elements{
	ss, _ := col.node.Search(col.descCol.SearchXpath(pattern))
	var elements []Element = make([]Element, len(ss))
	for i, s := range ss {
		elements[i] = Element{node: s, desc: col.descCol.DescElt}
	}
	return Elements(elements)
}

type Show interface {
	Long()
	Short()
	Xml()
}

type Elements []Element

func (e Element) Xml() {
	fmt.Printf("%s", e.node)
}
func (elts Elements) Xml() {
	for _, e := range elts {
		e.Xml()
	}
}
func (c Collection) Xml() {
	fmt.Printf("%s", c.node)
}

func (e Element) Short() {
	s, _ := e.node.Search(e.desc.ShortDetailXpath)
	if len(s) != 1 {
		log.Fatal("Xpath '" + e.desc.ShortDetailXpath + "' is not valid")
	}
	fmt.Printf("%s\n", s[0])
}
func (col Collection) Short() {
	Elements(col.elements).Short()
}
func (elts Elements) Short() {
	for _, e := range elts {
		e.Short()
	}
}
func (e Element) Long() {
	e.desc.LongDetail.Long(e)
}
func (col Collection) Long() {
	Elements(col.elements).Long()
}
func (elts Elements) Long() {
	for _, e := range elts {
		e.Long()
		fmt.Printf("\n")
	}
}

func DescItf() DescCol {
	return DescCol{
		BaseXpath: "__ItfResp_list/ItfResp/itf_list/list",
		DescElt: DescElement {
			ShortDetailXpath: "name/text()",
			LongDetail: LongXpaths([]string{"uuid/text()", "name/text()"}),
		},
		PageArgs: []string{"vrouter"},
		PageBuilder: func(args []string) LoadAble{
			return Page{Table: "db.interface.0", VrouterUrl: args[0]}
		},
	}
}
func DescRoute() DescCol {
	return DescCol{
		PageArgs: []string{"vrouter", "vrf_name"},
		PageBuilder: func(args []string) LoadAble{
			return Page{VrouterUrl: args[0], Table: args[1] + ".uc.route.0,"}
		},
		BaseXpath: "__Inet4UcRouteResp_list/Inet4UcRouteResp/route_list/list",
		DescElt: DescElement {
			ShortDetailXpath: "src_ip/text()",
			LongDetail: LongFunc(routeDetail)},
		SearchXpath: func(pattern string) string {
			return "RouteUcSandeshData/src_ip[contains(text(),'" + pattern + "')]/.."
		},
	}
}
func DescVrf() DescCol {
	return DescCol{
		PageArgs: []string{"vrouter"},
		PageBuilder: func(args []string) LoadAble{
			return Page{Table: "db.vrf.0", VrouterUrl: args[0]}
		},
		BaseXpath: "__VrfListResp_list/VrfListResp/vrf_list/list",
		DescElt: DescElement {
			ShortDetailXpath: "name/text()",
			LongDetail: LongXpaths([]string{"name/text()"}),
		},
	}
}

type LongFunc (func (Element))
type LongXpaths []string

type LongAble interface {
	Long(e Element);
}
func (lf LongFunc) Long(e Element) {
	lf(e)
}
func (xpaths LongXpaths) Long(e Element) {
	for _, xpath := range xpaths {
		s, _ := e.node.Search(xpath)
		fmt.Printf("%s ", s[0])
	}
}

func routeDetail(e Element) {
	srcIp, _ := e.node.Search("src_ip/text()")
	fmt.Printf("%s\n", srcIp[0])
	paths, _ := e.node.Search("path_list/list/PathSandeshData")
	fmt.Printf("  Dest_ip ; Peers ; Label ; Itfs\n")
	for _, path := range paths {
		nhs, _ := path.Search("nh/NhSandeshData//dip/text()")
		peers, _ := path.Search("peer/text()")
		label, _ := path.Search("label/text()")
		itf, _ := path.Search("nh/NhSandeshData/itf/text()")
		fmt.Printf("  %s %s %s %s\n", nhs, peers, label, itf)
	}
}

func GenCommand(descCol DescCol, name string, usage string) cli.Command {
	return cli.Command{
		Name: name,
		Aliases: []string{"a"},
		Usage: usage,
		ArgsUsage: fmt.Sprintf("%s\n", descCol.PageArgs),
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name: "long, l",
			},
			cli.BoolFlag{
				Name: "xml, x",
			},
			cli.BoolFlag{
				Name: "from-file",
				Usage: "Use a file instead of loading data from URL",
			},
			cli.StringFlag{
				Name: "search, s",
				Usage: "Search string",
				Value: "",
			},
		},
		Action: func(c *cli.Context) {
			var page LoadAble;
			if c.IsSet("from-file") {
				page = File{Path: c.Args()[0]}
			} else {
				if c.NArg() < len(descCol.PageArgs) {
					log.Fatal("Wrong argument number!")
				}
				page = descCol.PageBuilder(c.Args())
			}
			col := page.Load(descCol)
			var list Show;

			if c.String("s") != "" {
				list = col.Search(c.String("s"))
			} else {
				list = col
			}

			if c.IsSet("xml") {
				list.Xml()
				return
			}
			if c.IsSet("long") {
				list.Long()
				return
			}
			list.Short()
		},
	}
}

func main() {
	var showAsXml bool;
	var count bool;

	app := cli.NewApp()
	app.Name = "contrail-introspect-cli"
	app.Usage = "CLI on contrail introspects"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "format-xml",
			Destination: &showAsXml,
		},
	}
	app.Commands = []cli.Command{
		GenCommand(DescRoute(), "route", "Get route information"),
		GenCommand(DescItf(), "itf", "Get interface information"),
		GenCommand(DescVrf(), "vrf", "Get vrf information"),
		{
			Name:      "multiple",
			Usage:     "vrouter vrf_name",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "count",
					Destination: &count,
				}},
			Action: func(c *cli.Context) {
				if c.NArg() != 2 {
					log.Fatal("Wrong argument number!")
				}
				vrouter := c.Args()[0]
				vrf_name := c.Args()[1]
				multiple(vrouter, vrf_name, count)
			},
		},
	}
	app.Run(os.Args)
}
<commit_msg>Improve UI<commit_after>package main

import "fmt"
import "os"
import "net/http"
import "io/ioutil"
import "log"
import "strings"

import "github.com/moovweb/gokogiri"
import "github.com/moovweb/gokogiri/xml"
import "github.com/moovweb/gokogiri/xpath"
import "github.com/codegangsta/cli"

func load(url string, fromFile bool) *xml.XmlDocument{
	var data []byte
	if fromFile{
		file, _ := os.Open(url)
		data, _ = ioutil.ReadAll(file)
	} else {
		resp, err := http.Get(url)
		if err != nil {
			log.Fatal(err)
		}
		data, _ = ioutil.ReadAll(resp.Body)
	}
	doc, _ := gokogiri.ParseXml(data)
	return(doc)
}

func multiple(vrouter string, vrf_name string, count bool) {
	url := "http://" + vrouter + ":8085" + "/Snh_PageReq?x=begin:-1,end:-1,table:" + vrf_name + ".uc.route.0,"

	var doc = load(url, false)
	defer doc.Free()
	xps := xpath.Compile("//route_list/list/RouteUcSandeshData/path_list/list/PathSandeshData/nh/NhSandeshData/mc_list/../../../../../../src_ip/text()")
	ss, _ := doc.Root().Search(xps)
	if count {
		fmt.Printf("%d\n", len(ss))
	} else {
		for _, s := range ss {
			fmt.Printf("%s\n", s)
		}
	}
}

type Page struct {
	VrouterUrl string;
	Table string;
}

type File struct {
	Path string;
}

type LoadAble interface {
	Load(descCol DescCol) Collection;
}

// Parse data to XML
func fromDataToCollection(data []byte, descCol DescCol) Collection {
	doc, _ := gokogiri.ParseXml(data)
	ss, _ := doc.Search(descCol.BaseXpath)
	if len(ss) < 1 {
		log.Fatal(fmt.Sprintf("%d Failed to search xpath '%s'", len(ss), descCol.BaseXpath))
	}
	col := Collection{node: ss[0], descCol: descCol}
	col.Init()
	return col
}

func (file File) Load(descCol DescCol) Collection {
	f, _ := os.Open(file.Path)
	data, _ := ioutil.ReadAll(f)
	return fromDataToCollection(data, descCol)
}

func (page Page) Load(descCol DescCol) Collection {
	url := "http://" + page.VrouterUrl + ":8085/Snh_PageReq?x=begin:-1,end:-1,table:" + page.Table + ","
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	data, _ := ioutil.ReadAll(resp.Body)
	return fromDataToCollection(data, descCol)
}

type Collection struct {
	descCol DescCol;
	doc *xml.XmlDocument;
	node xml.Node;
	elements []Element;
}

type DescCol struct {
	PageArgs []string;
	PageBuilder (func([]string) LoadAble);
	BaseXpath string;
	DescElt DescElement;
	SearchXpath (func(string) string);
}

type DescElement struct {
	ShortDetailXpath string;
	LongDetail LongAble;
}

type Element struct {
	node xml.Node;
	desc DescElement;
}

func (col *Collection) Init() {
	ss, _ := col.node.Search("*")
	col.elements = make([]Element, len(ss))
	for i, s := range ss {
		col.elements[i] = Element{node: s, desc: col.descCol.DescElt}
	}
}

func (col *Collection) Search(pattern string) Elements{
	ss, _ := col.node.Search(col.descCol.SearchXpath(pattern))
	var elements []Element = make([]Element, len(ss))
	for i, s := range ss {
		elements[i] = Element{node: s, desc: col.descCol.DescElt}
	}
	return Elements(elements)
}

type Show interface {
	Long()
	Short()
	Xml()
}

type Elements []Element

func (e Element) Xml() {
	fmt.Printf("%s", e.node)
}
func (elts Elements) Xml() {
	for _, e := range elts {
		e.Xml()
	}
}
func (c Collection) Xml() {
	fmt.Printf("%s", c.node)
}

func (e Element) Short() {
	s, _ := e.node.Search(e.desc.ShortDetailXpath)
	if len(s) != 1 {
		log.Fatal("Xpath '" + e.desc.ShortDetailXpath + "' is not valid")
	}
	fmt.Printf("%s\n", s[0])
}
func (col Collection) Short() {
	Elements(col.elements).Short()
}
func (elts Elements) Short() {
	for _, e := range elts {
		e.Short()
	}
}
func (e Element) Long() {
	e.desc.LongDetail.Long(e)
}
func (col Collection) Long() {
	Elements(col.elements).Long()
}
func (elts Elements) Long() {
	for _, e := range elts {
		e.Long()
		fmt.Printf("\n")
	}
}

func DescItf() DescCol {
	return DescCol{
		BaseXpath: "__ItfResp_list/ItfResp/itf_list/list",
		DescElt: DescElement {
			ShortDetailXpath: "name/text()",
			LongDetail: LongXpaths([]string{"uuid/text()", "name/text()"}),
		},
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) LoadAble{
			return Page{Table: "db.interface.0", VrouterUrl: args[0]}
		},
	}
}
func DescRoute() DescCol {
	return DescCol{
		PageArgs: []string{"vrouter-fqdn", "vrf-name"},
		PageBuilder: func(args []string) LoadAble{
			return Page{VrouterUrl: args[0], Table: args[1] + ".uc.route.0,"}
		},
		BaseXpath: "__Inet4UcRouteResp_list/Inet4UcRouteResp/route_list/list",
		DescElt: DescElement {
			ShortDetailXpath: "src_ip/text()",
			LongDetail: LongFunc(routeDetail)},
		SearchXpath: func(pattern string) string {
			return "RouteUcSandeshData/src_ip[contains(text(),'" + pattern + "')]/.."
		},
	}
}
func DescVrf() DescCol {
	return DescCol{
		PageArgs: []string{"vrouter-fqdn"},
		PageBuilder: func(args []string) LoadAble{
			return Page{Table: "db.vrf.0", VrouterUrl: args[0]}
		},
		BaseXpath: "__VrfListResp_list/VrfListResp/vrf_list/list",
		DescElt: DescElement {
			ShortDetailXpath: "name/text()",
			LongDetail: LongXpaths([]string{"name/text()"}),
		},
	}
}

type LongFunc (func (Element))
type LongXpaths []string

type LongAble interface {
	Long(e Element);
}
func (lf LongFunc) Long(e Element) {
	lf(e)
}
func (xpaths LongXpaths) Long(e Element) {
	for _, xpath := range xpaths {
		s, _ := e.node.Search(xpath)
		fmt.Printf("%s ", s[0])
	}
}

func routeDetail(e Element) {
	srcIp, _ := e.node.Search("src_ip/text()")
	fmt.Printf("%s\n", srcIp[0])
	paths, _ := e.node.Search("path_list/list/PathSandeshData")
	fmt.Printf("  Dest_ip ; Peers ; Label ; Itfs\n")
	for _, path := range paths {
		nhs, _ := path.Search("nh/NhSandeshData//dip/text()")
		peers, _ := path.Search("peer/text()")
		label, _ := path.Search("label/text()")
		itf, _ := path.Search("nh/NhSandeshData/itf/text()")
		fmt.Printf("  %s %s %s %s\n", nhs, peers, label, itf)
	}
}

func GenCommand(descCol DescCol, name string, usage string) cli.Command {
	return cli.Command{
		Name: name,
		Aliases: []string{"a"},
		Usage: usage,
		ArgsUsage: fmt.Sprintf("%s\n", strings.Join(descCol.PageArgs, " ")),
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name: "long, l",
				Usage: "Long version format",
			},
			cli.BoolFlag{
				Name: "xml, x",
				Usage: "XML output format",
			},
			cli.BoolFlag{
				Name: "from-file",
				Usage: "Load file instead URL (for debugging)",
			},
			cli.StringFlag{
				Name: "search, s",
				Usage: "Search pattern",
				Value: "",
			},
		},
		Action: func(c *cli.Context) {
			var page LoadAble;
			if c.IsSet("from-file") {
				page = File{Path: c.Args()[0]}
			} else {
				if c.NArg() < len(descCol.PageArgs) {
					cli.ShowSubcommandHelp(c)
					os.Exit(1)
				}
				page = descCol.PageBuilder(c.Args())
			}
			col := page.Load(descCol)
			var list Show;

			if c.String("s") != "" {
				list = col.Search(c.String("s"))
			} else {
				list = col
			}

			if c.IsSet("xml") {
				list.Xml()
				return
			}
			if c.IsSet("long") {
				list.Long()
				return
			}
			list.Short()
		},
	}
}

func main() {
	var count bool;

	app := cli.NewApp()
	app.Name = "contrail-introspect-cli"
	app.Usage = "CLI on ContraiL Introspects"
	app.Version= "0.0.1"
	app.Commands = []cli.Command{
		GenCommand(DescRoute(), "route", "Show routes"),
		GenCommand(DescItf(), "itf", "Show interfaces"),
		GenCommand(DescVrf(), "vrf", "Show vrfs"),
		{
			Name:      "multiple",
			Usage:     "List routes with multiple nexthops",
			ArgsUsage: "vrouter vrf_name",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "count",
					Destination: &count,
				}},
			Action: func(c *cli.Context) {
				if c.NArg() != 2 {
					log.Fatal("Wrong argument number!")
				}
				vrouter := c.Args()[0]
				vrf_name := c.Args()[1]
				multiple(vrouter, vrf_name, count)
			},
		},
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package cache

import (
	"fmt"
	"sort"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"core"
)

func TestStore(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_store")
	aCache.Store(target, nil)
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestStoreExtra(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_store_extra")
	aCache.StoreExtra(target, nil, "some_other_file")
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestRetrieve(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_retrieve")
	aCache.Retrieve(target, nil)
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestRetrieveExtra(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_retrieve_extra")
	aCache.RetrieveExtra(target, nil, "some_other_file")
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestClean(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_clean")
	aCache.Clean(target)
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestConcurrentStores(t *testing.T) {
	// The cache shouldn't run multiple concurrent stores for the same target.
	// Our mock cache will panic if it detects that, so here we just throw enough
	// concurrent requests at it to try to make sure that we're likely to exercise that.
	// It's pretty hard to really guarantee that it does happen though.
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_concurrent")
	expected := []string{}
	for i := 0; i < 20; i++ {
		s := fmt.Sprintf("file%02d", i)
		aCache.StoreExtra(target, nil, s)
		expected = append(expected, s)
	}
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
	stored := mCache.stored[target]
	sort.Strings(stored)
	assert.Equal(t, expected, stored)
}

// Fake cache implementation to ensure our async cache behaves itself.
type mockCache struct {
	sync.Mutex
	inFlight  map[*core.BuildTarget]bool
	completed map[*core.BuildTarget]bool
	stored    map[*core.BuildTarget][]string
}

func (c *mockCache) Store(target *core.BuildTarget, key []byte) {
	c.StoreExtra(target, key, "")
}

func (c *mockCache) StoreExtra(target *core.BuildTarget, key []byte, file string) {
	c.Lock()
	if c.inFlight[target] {
		panic("Concurrent store on " + target.Label.String())
	}
	c.inFlight[target] = true
	c.Unlock()
	time.Sleep(10 * time.Millisecond) // Fake a small delay to mimic the real thing
	c.Lock()
	c.inFlight[target] = false
	c.completed[target] = true
	c.stored[target] = append(c.stored[target], file)
	c.Unlock()
}

func (c *mockCache) Retrieve(target *core.BuildTarget, key []byte) bool {
	c.Lock()
	c.completed[target] = true
	c.Unlock()
	return false
}

func (c *mockCache) RetrieveExtra(target *core.BuildTarget, key []byte, file string) bool {
	return c.Retrieve(target, key)
}

func (c *mockCache) Clean(target *core.BuildTarget) {
	c.Retrieve(target, nil)
}

func (*mockCache) Shutdown() {}

func makeTarget(label string) *core.BuildTarget {
	return core.NewBuildTarget(core.ParseBuildLabel(label, ""))
}

func makeCaches() (mockCache, core.Cache) {
	mCache := mockCache{
		inFlight:  make(map[*core.BuildTarget]bool),
		completed: make(map[*core.BuildTarget]bool),
		stored:    make(map[*core.BuildTarget][]string),
	}
	config := core.DefaultConfiguration()
	config.Cache.Workers = 10
	return mCache, newAsyncCache(&mCache, config)
}
<commit_msg>Add a test on async cache<commit_after>package cache

import (
	"fmt"
	"sort"
	"sync"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"

	"core"
)

func TestStore(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_store")
	aCache.Store(target, nil)
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestStoreExtra(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_store_extra")
	aCache.StoreExtra(target, nil, "some_other_file")
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestRetrieve(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_retrieve")
	aCache.Retrieve(target, nil)
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestRetrieveExtra(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_retrieve_extra")
	aCache.RetrieveExtra(target, nil, "some_other_file")
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestClean(t *testing.T) {
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_clean")
	aCache.Clean(target)
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
}

func TestConcurrentStores(t *testing.T) {
	// The cache shouldn't run multiple concurrent stores for the same target.
	// Our mock cache will panic if it detects that, so here we just throw enough
	// concurrent requests at it to try to make sure that we're likely to exercise that.
	// It's pretty hard to really guarantee that it does happen though.
	mCache, aCache := makeCaches()
	target := makeTarget("//pkg1:test_concurrent")
	expected := []string{}
	for i := 0; i < 20; i++ {
		s := fmt.Sprintf("file%02d", i)
		aCache.StoreExtra(target, nil, s)
		expected = append(expected, s)
	}
	aCache.Shutdown()
	assert.False(t, mCache.inFlight[target])
	assert.True(t, mCache.completed[target])
	stored := mCache.stored[target]
	sort.Strings(stored)
	assert.Equal(t, expected, stored)
}

func TestLotsOfConcurrentStores(t *testing.T) {
	// Throw a lot of concurrent store / store extra actions at the cache and make sure
	// it does it in order.
	const n = 10
	var wg sync.WaitGroup
	wg.Add(n)
	mCache, aCache := makeCaches()
	for i := 0; i < n; i++ {
		go func(i int) {
			target := makeTarget(fmt.Sprintf("//test_pkg:target%03d", i))
			aCache.Store(target, nil)
			aCache.StoreExtra(target, nil, fmt.Sprintf("file%03d", i))
			aCache.StoreExtra(target, nil, fmt.Sprintf("file%03d_2", i))
			wg.Done()
		}(i)
	}
	wg.Wait()
	assert.Equal(t, n, len(mCache.stored))
	for target, stored := range mCache.stored {
		assert.Equal(t, []string{
			"",
			"file" + target.Label.Name[len(target.Label.Name)-3:],
			"file" + target.Label.Name[len(target.Label.Name)-3:] + "_2",
		}, stored)
	}
}

// Fake cache implementation to ensure our async cache behaves itself.
type mockCache struct {
	sync.Mutex
	inFlight  map[*core.BuildTarget]bool
	completed map[*core.BuildTarget]bool
	stored    map[*core.BuildTarget][]string
}

func (c *mockCache) Store(target *core.BuildTarget, key []byte) {
	c.StoreExtra(target, key, "")
}

func (c *mockCache) StoreExtra(target *core.BuildTarget, key []byte, file string) {
	c.Lock()
	if c.inFlight[target] {
		panic("Concurrent store on " + target.Label.String())
	}
	c.inFlight[target] = true
	c.Unlock()
	time.Sleep(10 * time.Millisecond) // Fake a small delay to mimic the real thing
	c.Lock()
	c.inFlight[target] = false
	c.completed[target] = true
	c.stored[target] = append(c.stored[target], file)
	c.Unlock()
}

func (c *mockCache) Retrieve(target *core.BuildTarget, key []byte) bool {
	c.Lock()
	c.completed[target] = true
	c.Unlock()
	return false
}

func (c *mockCache) RetrieveExtra(target *core.BuildTarget, key []byte, file string) bool {
	return c.Retrieve(target, key)
}

func (c *mockCache) Clean(target *core.BuildTarget) {
	c.Retrieve(target, nil)
}

func (*mockCache) Shutdown() {}

func makeTarget(label string) *core.BuildTarget {
	return core.NewBuildTarget(core.ParseBuildLabel(label, ""))
}

func makeCaches() (mockCache, core.Cache) {
	mCache := mockCache{
		inFlight:  make(map[*core.BuildTarget]bool),
		completed: make(map[*core.BuildTarget]bool),
		stored:    make(map[*core.BuildTarget][]string),
	}
	config := core.DefaultConfiguration()
	config.Cache.Workers = 10
	return mCache, newAsyncCache(&mCache, config)
}
<|endoftext|>


<commit_before>// run

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

package main

import (
	"fmt"
	"io"
	"runtime"
)

type T struct {
	io.Closer
}

func f1() {
	// The 4 here and below depends on the number of internal runtime frames
	// that sit between a deferred function called during panic and
	// the original frame. If that changes, this test will start failing and
	// the number here will need to be updated.
	defer checkLine(4)
	var t *T
	var c io.Closer = t
	c.Close()
}

func f2() {
	defer checkLine(4)
	var t T
	var c io.Closer = t
	c.Close()
}

func main() {
	f1()
	f2()
}

func checkLine(n int) {
	if err := recover(); err == nil {
		panic("did not panic")
	}
	_, file, line, _ := runtime.Caller(n)
	if file != "<autogenerated>" || line != 1 {
		panic(fmt.Sprintf("expected <autogenerated>:1 have %s:%d", file, line))
	}
}
<commit_msg>test: fix flakey test case for issue 4388<commit_after>// run

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

package main

import (
	"fmt"
	"io"
	"runtime"
)

type T struct {
	io.Closer
}

func f1() {
	// The 4 here and below depends on the number of internal runtime frames
	// that sit between a deferred function called during panic and
	// the original frame. If that changes, this test will start failing and
	// the number here will need to be updated.
	defer checkLine(4)
	var t *T
	var c io.Closer = t
	c.Close()
}

func f2() {
	defer checkLine(4)
	var t T
	var c io.Closer = t
	c.Close()
}

func main() {
	f1()
	f2()
}

func checkLine(n int) {
	if err := recover(); err == nil {
		panic("did not panic")
	}
	var file string
	var line int
	for i := 1; i <= n; i++ {
		_, file, line, _ = runtime.Caller(i)
		if file != "<autogenerated>" || line != 1 {
			continue
		}
		return
	}
	panic(fmt.Sprintf("expected <autogenerated>:1 have %s:%d", file, line))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/zrepl/zrepl/model"
	"github.com/zrepl/zrepl/sshbytestream"
	"github.com/zrepl/zrepl/util"
	// "bytes"
	_ "bufio"
	// "strings"
	"fmt"
	"io"
	"os"
	_ "time"
)

func main() {

	mode := flag.String("mode", "", "incoming|outgoing")
	incomingFile := flag.String("incoming.file", "", "file to deliver to callers")
	outgoingHost := flag.String("outgoing.sshHost", "", "ssh host")
	outgoingUser := flag.String("outgoing.sshUser", "", "ssh user")
	outgoingPort := flag.Uint("outgoing.sshPort", 22, "ssh port")
	flag.Parse()

	switch {
	case (*mode == "incoming"):

		conn, err := sshbytestream.Incoming()
		if err != nil {
			panic(err)
		}

		file, err := os.Open(*incomingFile)
		if err != nil {
			panic(err)
		}

		chunker := chunking.NewChunker(file)

		_, err = io.Copy(conn, &chunker)
		if err != nil && err != io.EOF {
			panic(err)
		}

		fmt.Fprintf(os.Stderr, "Chunk Count: %d\n", chunker.ChunkCount)

	case *mode == "outgoing":

		conn, err := sshbytestream.Outgoing("client", model.SSHTransport{
			Host:                 *outgoingHost,
			User:                 *outgoingUser,
			Port:                 uint16(*outgoingPort),
			Options:              []string{"Compression=no"},
			TransportOpenCommand: []string{"/tmp/sshwrap", "-mode", "incoming", "-incoming.file", "/random.img"},
		})

		if err != nil {
			panic(err)
		}

		unchunker := chunking.NewUnchunker(conn)

		_, err = io.Copy(os.Stdout, &unchunker)
		if err != nil {
			panic(err)
		}

		conn.Close()

		fmt.Fprintf(os.Stderr, "Chunk Count: %d\n", unchunker.ChunkCount)

		os.Exit(0)

	default:
		panic("unsupported mode!")

	}

}
<commit_msg>Lift chunker up to recent sshbytestream changes.<commit_after>package main

import (
	"flag"
	"github.com/zrepl/zrepl/sshbytestream"
	"github.com/zrepl/zrepl/util"
	// "bytes"
	_ "bufio"
	// "strings"
	"fmt"
	"io"
	"os"
	_ "time"
)

func main() {

	mode := flag.String("mode", "", "incoming|outgoing")
	incomingFile := flag.String("incoming.file", "", "file to deliver to callers")
	outgoingHost := flag.String("outgoing.sshHost", "", "ssh host")
	outgoingUser := flag.String("outgoing.sshUser", "", "ssh user")
	outgoingIdentity := flag.String("outgoing.sshIdentity", "", "ssh private key")
	outgoingPort := flag.Uint("outgoing.sshPort", 22, "ssh port")
	outgoingFile := flag.String("outgoing.File", "", "")
	flag.Parse()

	switch {
	case (*mode == "incoming"):

		conn, err := sshbytestream.Incoming()
		if err != nil {
			panic(err)
		}

		file, err := os.Open(*incomingFile)
		if err != nil {
			panic(err)
		}

		chunker := chunking.NewChunker(file)

		_, err = io.Copy(conn, &chunker)
		if err != nil && err != io.EOF {
			panic(err)
		}

		fmt.Fprintf(os.Stderr, "Chunk Count: %d\n", chunker.ChunkCount)

	case *mode == "outgoing":

		conn, err := sshbytestream.Outgoing(sshbytestream.SSHTransport{
			Host:         *outgoingHost,
			User:         *outgoingUser,
			IdentityFile: *outgoingIdentity,
			Port:         uint16(*outgoingPort),
		})
		if err != nil {
			panic(err)
		}

		f, err := os.OpenFile(*outgoingFile, os.O_WRONLY, 0600)
		if err != nil {
			panic(err)
		}

		unchunker := chunking.NewUnchunker(conn)

		_, err = io.Copy(f, unchunker)
		if err != nil {
			panic(err)
		}

		conn.Close()

		fmt.Fprintf(os.Stderr, "Chunk Count: %d\n", unchunker.ChunkCount)

		os.Exit(0)

	default:
		panic("unsupported mode!")

	}

}
<|endoftext|>


<commit_before>package main

import (
  pbkdf2 "github.com/ctz/go-fastpbkdf2"
	"golang.org/x/crypto/scrypt"
  "unsafe"
	"crypto/sha256"
	"fmt"
	"time"
	"os"
	"math/rand"
	"github.com/vsergeev/btckeygenie/btckey"
)

const wordSize = int(unsafe.Sizeof(uintptr(0)))
var c chan []byte // goroutine channel
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func random(r *rand.Rand, n int) string {
    b := make([]byte, n)
	for i := range b {
        b[i] = letterBytes[r.Intn(62)]
    }

    return string(b)
}

func main () {
	r := rand.New(rand.NewSource(time.Now().Unix()))
  c = make(chan []byte)

	var address string
	saltValue := ""

	if len(os.Args) >= 2 {
		address = os.Args[1]
		if len(os.Args) == 3 {
			saltValue = os.Args[2]
		} else {
			saltValue = "";
		}
	} else {
		fmt.Printf("Usage: %s [Address] [Salt - optional]\n\n", os.Args[0])
		os.Exit(0)
	}

	fmt.Printf("Using address \"%s\" and salt \"%s\"\n", address, saltValue)

	tries := 0
	start := time.Now()
	for {
		passphraseValue := random(r, 8)
		result := bruteforce(passphraseValue, saltValue, address);
		if result != "" {
			fmt.Printf("Found! Passphrase %s\n", passphraseValue)
			os.Exit(0)
		} else {
			tries += 1
			fmt.Printf("\rTried %d passphrases in %s [last passphrase: %s]", tries, time.Since(start), passphraseValue)
		}
	}
}

func bruteforce(passphraseValue string, saltValue string, address string) string {
  var priv btckey.PrivateKey
  var err error
  go doScrypt(fmt.Sprint(passphraseValue, "\x01"), fmt.Sprint(saltValue, "\x01"), c)
  go doPbkdf2(fmt.Sprint(passphraseValue, "\x02"), fmt.Sprint(saltValue, "\x02"), c)

  key1, key2 := <-c, <-c

  result := make([]byte, 32)
  fastXORWords(result, key1, key2)

	err = priv.FromBytes(result)
	if err != nil {
		fmt.Printf("Error importing private key: %s [%s]\n", err, passphraseValue)
		return ""
	}

	if (priv.ToAddressUncompressed() == address) {
		return passphraseValue
	}

	return ""
}

func doScrypt(pass string, salt string, c chan []byte) {
   scryptKey, _ := scrypt.Key([]byte(pass), []byte(salt), 262144, 8, 1, 32)
   c <- scryptKey
}

func doPbkdf2(pass string, salt string, c chan []byte) {
  pbkdf2Key := pbkdf2.Key([]byte(pass), []byte(salt), 65536, 32, sha256.New)
  c <- pbkdf2Key
}

// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
// The arguments are assumed to be of equal length.
func fastXORWords(dst, a, b []byte) {
	dw := *(*[]uintptr)(unsafe.Pointer(&dst))
	aw := *(*[]uintptr)(unsafe.Pointer(&a))
	bw := *(*[]uintptr)(unsafe.Pointer(&b))
	n := len(b) / wordSize
	for i := 0; i < n; i++ {
		dw[i] = aw[i] ^ bw[i]
	}
}
<commit_msg>print better diagnostic info<commit_after>package main

import (
  pbkdf2 "github.com/ctz/go-fastpbkdf2"
	"golang.org/x/crypto/scrypt"
  "unsafe"
	"crypto/sha256"
	"fmt"
	"time"
	"os"
	"math/rand"
	"github.com/vsergeev/btckeygenie/btckey"
)

const wordSize = int(unsafe.Sizeof(uintptr(0)))
var c chan []byte // goroutine channel
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func random(r *rand.Rand, n int) string {
    b := make([]byte, n)
	for i := range b {
        b[i] = letterBytes[r.Intn(62)]
    }

    return string(b)
}

func main () {
	r := rand.New(rand.NewSource(time.Now().Unix()))
  c = make(chan []byte)

	var address string
	saltValue := ""

	if len(os.Args) >= 2 {
		address = os.Args[1]
		if len(os.Args) == 3 {
			saltValue = os.Args[2]
		} else {
			saltValue = "";
		}
	} else {
		fmt.Printf("Usage: %s [Address] [Salt - optional]\n\n", os.Args[0])
		os.Exit(0)
	}

	fmt.Printf("Using address \"%s\" and salt \"%s\"\n", address, saltValue)

	tries := 0
	start := time.Now()
	for {
		passphraseValue := random(r, 8)
		result := bruteforce(passphraseValue, saltValue, address);
		if result != "" {
			fmt.Printf("Found! Passphrase %s\n", passphraseValue)
			os.Exit(0)
		} else {
			tries += 1
      timeElapsed := time.Since(start)
      hashRate := float64(tries) / (timeElapsed.Seconds())
			fmt.Printf("\rspeed=%.2fh/s, last=%s, tries=%d, elapsed=%s", hashRate, passphraseValue, tries, timeElapsed)
		}
	}
}

func bruteforce(passphraseValue string, saltValue string, address string) string {
  var priv btckey.PrivateKey
  var err error
  go doScrypt(fmt.Sprint(passphraseValue, "\x01"), fmt.Sprint(saltValue, "\x01"), c)
  go doPbkdf2(fmt.Sprint(passphraseValue, "\x02"), fmt.Sprint(saltValue, "\x02"), c)

  key1, key2 := <-c, <-c

  result := make([]byte, 32)
  fastXORWords(result, key1, key2)

	err = priv.FromBytes(result)
	if err != nil {
		fmt.Printf("Error importing private key: %s [%s]\n", err, passphraseValue)
		return ""
	}

	if (priv.ToAddressUncompressed() == address) {
		return passphraseValue
	}

	return ""
}

func doScrypt(pass string, salt string, c chan []byte) {
   scryptKey, _ := scrypt.Key([]byte(pass), []byte(salt), 262144, 8, 1, 32)
   c <- scryptKey
}

func doPbkdf2(pass string, salt string, c chan []byte) {
  pbkdf2Key := pbkdf2.Key([]byte(pass), []byte(salt), 65536, 32, sha256.New)
  c <- pbkdf2Key
}

// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
// The arguments are assumed to be of equal length.
func fastXORWords(dst, a, b []byte) {
	dw := *(*[]uintptr)(unsafe.Pointer(&dst))
	aw := *(*[]uintptr)(unsafe.Pointer(&a))
	bw := *(*[]uintptr)(unsafe.Pointer(&b))
	n := len(b) / wordSize
	for i := 0; i < n; i++ {
		dw[i] = aw[i] ^ bw[i]
	}
}
<|endoftext|>


<commit_before>package timing

import (
	"fmt"
	"sort"
	"sync/atomic"
	"time"
)

var percentiles = []int{90, 95, 99}

func New() *Timing {
	t := &Timing{
		begin:     time.Now(),
		results:   make(chan record, 10),
		collected: make(map[string][]record),
	}
	go t.collector()
	return t
}

type Timing struct {
	begin     time.Time
	results   chan record
	done      int32
	collected map[string][]record
}

func (t *Timing) collector() {
	for result := range t.results {
		t.collected[result.key] = append(t.collected[result.key], result)
	}
	atomic.AddInt32(&t.done, 1)
}

func (t *Timing) Log(elapsed time.Duration, key string) {
	t.results <- record{
		key:     key,
		elapsed: elapsed,
	}
}

func (t *Timing) LogSince(begin time.Time, key string) {
	t.Log(time.Since(begin), key)
}

func (t *Timing) Report() Report {
	dest := make(Report)
	t.ReportInto(dest)
	return dest
}

func (t *Timing) ReportInto(dest Report) {
	dest["elapsed"] = time.Since(t.begin).String()
	if atomic.LoadInt32(&t.done) == 0 {
		close(t.results)
	}
	for k, records := range t.collected {
		sort.Sort(recordsByTime(records))

		// calculate mean
		var total time.Duration
		for _, record := range records {
			total += record.elapsed
		}
		dest[fmt.Sprintf("%s_avg", k)] = (total / time.Duration(len(records))).String()

		// calculate all the percentiles
		for _, p := range percentiles {
			// TODO do we need a ceiling operator?
			target := len(records) * p / 100
			dest[fmt.Sprintf("%s_%dth", k, p)] = records[target].elapsed.String()
		}
	}
}

type Report map[string]interface{}

type record struct {
	key     string
	elapsed time.Duration
}

type recordsByTime []record

func (r recordsByTime) Len() int           { return len(r) }
func (r recordsByTime) Less(i, j int) bool { return r[i].elapsed < r[j].elapsed }
func (r recordsByTime) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
<commit_msg>Fix a possible off-by-one error<commit_after>package timing

import (
	"fmt"
	"sort"
	"sync/atomic"
	"time"
)

var percentiles = []int{90, 95, 99}

func New() *Timing {
	t := &Timing{
		begin:     time.Now(),
		results:   make(chan record, 10),
		collected: make(map[string][]record),
	}
	go t.collector()
	return t
}

type Timing struct {
	begin     time.Time
	results   chan record
	done      int32
	collected map[string][]record
}

func (t *Timing) collector() {
	for result := range t.results {
		t.collected[result.key] = append(t.collected[result.key], result)
	}
	atomic.AddInt32(&t.done, 1)
}

func (t *Timing) Log(elapsed time.Duration, key string) {
	t.results <- record{
		key:     key,
		elapsed: elapsed,
	}
}

func (t *Timing) LogSince(begin time.Time, key string) {
	t.Log(time.Since(begin), key)
}

func (t *Timing) Report() Report {
	dest := make(Report)
	t.ReportInto(dest)
	return dest
}

func (t *Timing) ReportInto(dest Report) {
	dest["elapsed"] = time.Since(t.begin).String()
	if atomic.LoadInt32(&t.done) == 0 {
		close(t.results)
	}
	for k, records := range t.collected {
		sort.Sort(recordsByTime(records))

		// calculate mean
		var total time.Duration
		for _, record := range records {
			total += record.elapsed
		}
		dest[fmt.Sprintf("%s_samples", k)] = len(records)
		dest[fmt.Sprintf("%s_avg", k)] = (total / time.Duration(len(records))).String()

		// calculate all the percentiles
		for _, p := range percentiles {
			// TODO do we need a ceiling operator?
			target := len(records) * p / 100
			if target >= len(records) {
				target = len(records) - 1
			}
			dest[fmt.Sprintf("%s_%dth", k, p)] = records[target].elapsed.String()
		}
	}
}

type Report map[string]interface{}

type record struct {
	key     string
	elapsed time.Duration
}

type recordsByTime []record

func (r recordsByTime) Len() int           { return len(r) }
func (r recordsByTime) Less(i, j int) bool { return r[i].elapsed < r[j].elapsed }
func (r recordsByTime) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/dynport/dgtk/tagparse"
)

type action struct {
	path        string             // Path used for the routing.
	params      map[string]*option // Mapping of flags and options (short and long) to according value.
	opts        []*option          // The options available for the action.
	args        []*argument        // List of arguments accepted.
	runner      Runner             // Who's connected to the action.
	description string             // Description of the action.
	value       reflect.Value
}

// Register an action for the given path with the given runner.
func newAction(path string, r Runner, desc string) (act *action, e error) {

	act = &action{
		path:        path,
		runner:      r,
		params:      map[string]*option{},
		description: desc}

	// Inject the "help" option (handled specially).
	helpOption := &option{field: "Help", short: "h", long: "help", isFlag: true, desc: "show help for action"}
	act.opts = append(act.opts, helpOption)
	act.params["h"] = helpOption
	act.params["help"] = helpOption

	if e := act.reflect(); e != nil {
		return nil, e
	}
	return act, nil
}

// Method to reflect on the action's runner type and determine the according options and arguments.
func (a *action) reflect() (e error) {
	v := reflect.ValueOf(a.runner)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	a.value = v
	e = a.reflectRecurse(v)
	if e != nil {
		e = fmt.Errorf("%s: %s", v.Type().Name(), e)
	}
	return e
}

func (a *action) reflectRecurse(value reflect.Value) (e error) {
	if !value.IsValid() {
		// ignore invalid stuff
		return nil
	}

	v := reflect.ValueOf(value.Interface())
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			v = reflect.New(v.Type().Elem())
		}
		v = v.Elem()
	}

	if v.Kind() != reflect.Struct {
		return nil
	}

	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		value := v.Field(i)

		if field.PkgPath != "" { // Unexported field have a pkg path set.
			continue // Ignore unexported fields.
		}

		if field.Anonymous {
			e = a.reflectRecurse(reflect.ValueOf(value.Interface()))
			if e != nil {
				return e
			}
			continue
		}

		e = a.handleField(field, value)
		if e != nil {
			return e
		}
	}
	return nil
}

func splitter(tagval string) (key, value string, e error) {
	switch {
	case tagval == "required":
		return "required", "true", nil
	case tagval == "opt":
		return "type", "opt", nil
	case tagval == "arg":
		return "type", "arg", nil
	case strings.HasPrefix(tagval, "--"):
		return "long", tagval[2:], nil
	case strings.HasPrefix(tagval, "-"):
		return "short", tagval[1:], nil
	}
	return "", "", fmt.Errorf("failed")
}

func (a *action) handleField(field reflect.StructField, value reflect.Value) (e error) {
	tagMap, e := tagparse.ParseCustom(field, "cli", splitter)
	if e != nil {
		return fmt.Errorf("failed to parse tag for field %q: %s", field.Name, e)
	}

	if len(tagMap) == 0 {
		return nil
	}

	switch tagMap["type"] {
	case "arg":
		if e = a.createArgument(field, value, tagMap); e != nil {
			return e
		}
	case "opt":
		if e = a.createOption(field, value, tagMap); e != nil {
			return e
		}
	default:
		if tagMap["type"] == "" {
			return fmt.Errorf("tag for field %q has no type set", field.Name)
		}
		return fmt.Errorf("tag for field %q has unknown type %q", field.Name, tagMap["type"])
	}
	return nil
}

func (a *action) parseArgs(params []string) (e error) {
	argIdx := 0
	ignoreOptions := false
	for idx := 0; idx < len(params); idx++ {
		value := params[idx]
		switch {
		case !ignoreOptions && strings.Contains(value, " "): // Must be an arg!
			if argIdx, e = a.handleArgs(value, argIdx); e != nil {
				return e
			}
		case !ignoreOptions && value == "--":
			ignoreOptions = true
		case !ignoreOptions && strings.HasPrefix(value, "--"):
			idx, e = a.handleParams(value[2:], false, params, idx)
			if e != nil {
				return e
			}
		case !ignoreOptions && strings.HasPrefix(value, "-"):
			idx, e = a.handleParams(value[1:], true, params, idx)
			if e != nil {
				return e
			}
		default:
			if argIdx, e = a.handleArgs(value, argIdx); e != nil {
				return e
			}
		}
	}
	return a.reflectIntoRunner()
}

func (a *action) handleArgs(value string, index int) (int, error) {
	if arg := a.argumentForPosition(index); arg != nil {
		arg.setValue(value)
		return index + 1, nil
	}
	return -1, fmt.Errorf("too many arguments given")
}

func (a *action) handleParams(paramName string, short bool, args []string, idx int) (int, error) {
	var value string
	if !short {
		parts := strings.SplitN(paramName, "=", 2)
		if len(parts) == 2 {
			fmt.Printf("--> %s = %s\n", parts[0], parts[1])
			paramName = parts[0]
			value = parts[1]
		}
	}

	// Keep that on top, as this is some special sort of handling. Required to make help appear in usage description,
	// but not be injected to deep.
	if paramName == "h" || paramName == "help" {
		return -1, ErrorHelpRequested
	}

	option, found := a.params[paramName]
	if !found {
		return -1, fmt.Errorf("unknown parameter found: %q", paramName)
	}

	if option.isFlag {
		if option.value == "" || option.value == "false" {
			option.value = "true"
		}
	} else {
		if value == "" {
			if idx+1 > len(args) {
				return -1, fmt.Errorf("missing value for option %q!", option.field)
			}
			value = args[idx+1]
			idx += 1
		}
		option.value = value
	}
	return idx, nil
}

// Use reflection to set values of the runner, if the action was called with a matching route.
func (a *action) reflectIntoRunner() (e error) {
	if e = a.reflectOptions(); e != nil {
		return e
	}
	if e = a.reflectArguments(); e != nil {
		return e
	}
	return nil
}

func (a *action) reflectOptions() (e error) {
	for _, option := range a.opts {
		if e = option.reflectTo(a.value); e != nil {
			return e
		}
	}
	return nil
}

func (a *action) reflectArguments() (e error) {
	for _, arg := range a.args {
		if e = arg.reflectTo(a.value); e != nil {
			return e
		}
	}
	return nil
}

func (a *action) showHelp() {
	a.showShortHelp()
	if a.description != "" {
		logger.Print("  ", a.description)
	}

	optsAvailable := false
	if len(a.opts) > 0 {
		optsAvailable = true
		logger.Print("  OPTIONS")
		for _, opt := range a.opts {
			logger.Print(opt.description())
		}
	}
	if len(a.args) > 0 {
		if optsAvailable {
			logger.Println()
		}
		logger.Print("  ARGUMENTS")
		for _, arg := range a.args {
			logger.Print(arg.description())
		}
	}
	logger.Println()
}

func (a *action) showShortHelp() {
	line := strings.Replace(a.path, "/", " ", -1) + " "
	for i := range a.opts {
		line += "[" + a.opts[i].shortDescription("|") + "] "
	}
	for _, arg := range a.args {
		line += arg.shortDescription()
		line += " "
	}
	logger.Print(line)
}

func (a *action) showTabularHelp(t *table) {
	oDesc := make([]string, len(a.opts))
	aDesc := make([]string, len(a.args))
	for i := range a.opts {
		if a.opts[i].required {
			oDesc[i] = "[" + a.opts[i].shortDescription("|") + "]"
		}
	}
	for i := range a.args {
		aDesc[i] = a.args[i].shortDescription()
	}
	t.addRow(
		row{
			strings.Replace(a.path, "/", " ", -1),
			strings.Join(oDesc, " "),
			strings.Join(aDesc, " "),
			a.description,
		})
}
<commit_msg>fixed issue with indexing<commit_after>package cli

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/dynport/dgtk/tagparse"
)

type action struct {
	path        string             // Path used for the routing.
	params      map[string]*option // Mapping of flags and options (short and long) to according value.
	opts        []*option          // The options available for the action.
	args        []*argument        // List of arguments accepted.
	runner      Runner             // Who's connected to the action.
	description string             // Description of the action.
	value       reflect.Value
}

// Register an action for the given path with the given runner.
func newAction(path string, r Runner, desc string) (act *action, e error) {

	act = &action{
		path:        path,
		runner:      r,
		params:      map[string]*option{},
		description: desc}

	// Inject the "help" option (handled specially).
	helpOption := &option{field: "Help", short: "h", long: "help", isFlag: true, desc: "show help for action"}
	act.opts = append(act.opts, helpOption)
	act.params["h"] = helpOption
	act.params["help"] = helpOption

	if e := act.reflect(); e != nil {
		return nil, e
	}
	return act, nil
}

// Method to reflect on the action's runner type and determine the according options and arguments.
func (a *action) reflect() (e error) {
	v := reflect.ValueOf(a.runner)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	a.value = v
	e = a.reflectRecurse(v)
	if e != nil {
		e = fmt.Errorf("%s: %s", v.Type().Name(), e)
	}
	return e
}

func (a *action) reflectRecurse(value reflect.Value) (e error) {
	if !value.IsValid() {
		// ignore invalid stuff
		return nil
	}

	v := reflect.ValueOf(value.Interface())
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			v = reflect.New(v.Type().Elem())
		}
		v = v.Elem()
	}

	if v.Kind() != reflect.Struct {
		return nil
	}

	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		value := v.Field(i)

		if field.PkgPath != "" { // Unexported field have a pkg path set.
			continue // Ignore unexported fields.
		}

		if field.Anonymous {
			e = a.reflectRecurse(reflect.ValueOf(value.Interface()))
			if e != nil {
				return e
			}
			continue
		}

		e = a.handleField(field, value)
		if e != nil {
			return e
		}
	}
	return nil
}

func splitter(tagval string) (key, value string, e error) {
	switch {
	case tagval == "required":
		return "required", "true", nil
	case tagval == "opt":
		return "type", "opt", nil
	case tagval == "arg":
		return "type", "arg", nil
	case strings.HasPrefix(tagval, "--"):
		return "long", tagval[2:], nil
	case strings.HasPrefix(tagval, "-"):
		return "short", tagval[1:], nil
	}
	return "", "", fmt.Errorf("failed")
}

func (a *action) handleField(field reflect.StructField, value reflect.Value) (e error) {
	tagMap, e := tagparse.ParseCustom(field, "cli", splitter)
	if e != nil {
		return fmt.Errorf("failed to parse tag for field %q: %s", field.Name, e)
	}

	if len(tagMap) == 0 {
		return nil
	}

	switch tagMap["type"] {
	case "arg":
		if e = a.createArgument(field, value, tagMap); e != nil {
			return e
		}
	case "opt":
		if e = a.createOption(field, value, tagMap); e != nil {
			return e
		}
	default:
		if tagMap["type"] == "" {
			return fmt.Errorf("tag for field %q has no type set", field.Name)
		}
		return fmt.Errorf("tag for field %q has unknown type %q", field.Name, tagMap["type"])
	}
	return nil
}

func (a *action) parseArgs(params []string) (e error) {
	argIdx := 0
	ignoreOptions := false
	for idx := 0; idx < len(params); idx++ {
		value := params[idx]
		switch {
		case !ignoreOptions && strings.Contains(value, " "): // Must be an arg!
			if argIdx, e = a.handleArgs(value, argIdx); e != nil {
				return e
			}
		case !ignoreOptions && value == "--":
			ignoreOptions = true
		case !ignoreOptions && strings.HasPrefix(value, "--"):
			idx, e = a.handleParams(value[2:], false, params, idx)
			if e != nil {
				return e
			}
		case !ignoreOptions && strings.HasPrefix(value, "-"):
			idx, e = a.handleParams(value[1:], true, params, idx)
			if e != nil {
				return e
			}
		default:
			if argIdx, e = a.handleArgs(value, argIdx); e != nil {
				return e
			}
		}
	}
	return a.reflectIntoRunner()
}

func (a *action) handleArgs(value string, index int) (int, error) {
	if arg := a.argumentForPosition(index); arg != nil {
		arg.setValue(value)
		return index + 1, nil
	}
	return -1, fmt.Errorf("too many arguments given")
}

func (a *action) handleParams(paramName string, short bool, args []string, idx int) (int, error) {
	var value string
	if !short {
		parts := strings.SplitN(paramName, "=", 2)
		if len(parts) == 2 {
			fmt.Printf("--> %s = %s\n", parts[0], parts[1])
			paramName = parts[0]
			value = parts[1]
		}
	}

	// Keep that on top, as this is some special sort of handling. Required to make help appear in usage description,
	// but not be injected to deep.
	if paramName == "h" || paramName == "help" {
		return -1, ErrorHelpRequested
	}

	option, found := a.params[paramName]
	if !found {
		return -1, fmt.Errorf("unknown parameter found: %q", paramName)
	}

	if option.isFlag {
		if option.value == "" || option.value == "false" {
			option.value = "true"
		}
	} else {
		if value == "" {
			if idx+1 >= len(args) {
				return -1, fmt.Errorf("missing value for option %q!", option.field)
			}
			value = args[idx+1]
			idx += 1
		}
		option.value = value
	}
	return idx, nil
}

// Use reflection to set values of the runner, if the action was called with a matching route.
func (a *action) reflectIntoRunner() (e error) {
	if e = a.reflectOptions(); e != nil {
		return e
	}
	if e = a.reflectArguments(); e != nil {
		return e
	}
	return nil
}

func (a *action) reflectOptions() (e error) {
	for _, option := range a.opts {
		if e = option.reflectTo(a.value); e != nil {
			return e
		}
	}
	return nil
}

func (a *action) reflectArguments() (e error) {
	for _, arg := range a.args {
		if e = arg.reflectTo(a.value); e != nil {
			return e
		}
	}
	return nil
}

func (a *action) showHelp() {
	a.showShortHelp()
	if a.description != "" {
		logger.Print("  ", a.description)
	}

	optsAvailable := false
	if len(a.opts) > 0 {
		optsAvailable = true
		logger.Print("  OPTIONS")
		for _, opt := range a.opts {
			logger.Print(opt.description())
		}
	}
	if len(a.args) > 0 {
		if optsAvailable {
			logger.Println()
		}
		logger.Print("  ARGUMENTS")
		for _, arg := range a.args {
			logger.Print(arg.description())
		}
	}
	logger.Println()
}

func (a *action) showShortHelp() {
	line := strings.Replace(a.path, "/", " ", -1) + " "
	for i := range a.opts {
		line += "[" + a.opts[i].shortDescription("|") + "] "
	}
	for _, arg := range a.args {
		line += arg.shortDescription()
		line += " "
	}
	logger.Print(line)
}

func (a *action) showTabularHelp(t *table) {
	oDesc := make([]string, len(a.opts))
	aDesc := make([]string, len(a.args))
	for i := range a.opts {
		if a.opts[i].required {
			oDesc[i] = "[" + a.opts[i].shortDescription("|") + "]"
		}
	}
	for i := range a.args {
		aDesc[i] = a.args[i].shortDescription()
	}
	t.addRow(
		row{
			strings.Replace(a.path, "/", " ", -1),
			strings.Join(oDesc, " "),
			strings.Join(aDesc, " "),
			a.description,
		})
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/99designs/aws-vault/prompt"
	"github.com/99designs/aws-vault/vault"
	"github.com/99designs/keyring"
	"golang.org/x/crypto/ssh/terminal"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

const (
	KeyringName = "aws-vault"
)

var (
	keyringImpl      keyring.Keyring
	awsConfig        *vault.Config
	promptsAvailable = prompt.Available()
)

var GlobalFlags struct {
	Debug        bool
	Backend      string
	PromptDriver string
}

func ConfigureGlobals(app *kingpin.Application) {
	backendsAvailable := []string{}
	for _, backendType := range keyring.AvailableBackends() {
		backendsAvailable = append(backendsAvailable, string(backendType))
	}

	app.Flag("debug", "Show debugging output").
		BoolVar(&GlobalFlags.Debug)

	app.Flag("backend", fmt.Sprintf("Secret backend to use %v", backendsAvailable)).
		OverrideDefaultFromEnvar("AWS_VAULT_BACKEND").
		EnumVar(&GlobalFlags.Backend, backendsAvailable...)

	app.Flag("prompt", fmt.Sprintf("Prompt driver to use %v", promptsAvailable)).
		Default("terminal").
		OverrideDefaultFromEnvar("AWS_VAULT_PROMPT").
		EnumVar(&GlobalFlags.PromptDriver, promptsAvailable...)

	app.PreAction(func(c *kingpin.ParseContext) (err error) {
		if !GlobalFlags.Debug {
			log.SetOutput(ioutil.Discard)
		} else {
			keyring.Debug = true
		}
		if keyringImpl == nil {
			allowedBackends := []keyring.BackendType{}
			if GlobalFlags.Backend != "" {
				allowedBackends = append(allowedBackends, keyring.BackendType(GlobalFlags.Backend))
			}

			keyringImpl, err = keyring.Open(keyring.Config{
				ServiceName:      "aws-vault",
				AllowedBackends:  allowedBackends,
				KeychainName:     "aws-vault",
				FileDir:          "~/.awsvault/keys/",
				FilePasswordFunc: fileKeyringPassphrasePrompt,
				KWalletAppID:     "aws-vault",
				KWalletFolder:    "aws-vault",
			})
		}
		if awsConfig == nil {
			awsConfig, err = vault.LoadConfigFromEnv()
		}
		return err
	})
}

func fileKeyringPassphrasePrompt(prompt string) (string, error) {
	if password := os.Getenv("AWS_VAULT_FILE_PASSPHRASE"); password != "" {
		return password, nil
	}

	fmt.Printf("%s: ", prompt)
	b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
	if err != nil {
		return "", err
	}
	fmt.Println()
	return string(b), nil
}
<commit_msg>Use nil slice vs empty slice<commit_after>package cli

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/99designs/aws-vault/prompt"
	"github.com/99designs/aws-vault/vault"
	"github.com/99designs/keyring"
	"golang.org/x/crypto/ssh/terminal"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

const (
	KeyringName = "aws-vault"
)

var (
	keyringImpl      keyring.Keyring
	awsConfig        *vault.Config
	promptsAvailable = prompt.Available()
)

var GlobalFlags struct {
	Debug        bool
	Backend      string
	PromptDriver string
}

func ConfigureGlobals(app *kingpin.Application) {
	backendsAvailable := []string{}
	for _, backendType := range keyring.AvailableBackends() {
		backendsAvailable = append(backendsAvailable, string(backendType))
	}

	app.Flag("debug", "Show debugging output").
		BoolVar(&GlobalFlags.Debug)

	app.Flag("backend", fmt.Sprintf("Secret backend to use %v", backendsAvailable)).
		OverrideDefaultFromEnvar("AWS_VAULT_BACKEND").
		EnumVar(&GlobalFlags.Backend, backendsAvailable...)

	app.Flag("prompt", fmt.Sprintf("Prompt driver to use %v", promptsAvailable)).
		Default("terminal").
		OverrideDefaultFromEnvar("AWS_VAULT_PROMPT").
		EnumVar(&GlobalFlags.PromptDriver, promptsAvailable...)

	app.PreAction(func(c *kingpin.ParseContext) (err error) {
		if !GlobalFlags.Debug {
			log.SetOutput(ioutil.Discard)
		} else {
			keyring.Debug = true
		}
		if keyringImpl == nil {
			var allowedBackends []keyring.BackendType
			if GlobalFlags.Backend != "" {
				allowedBackends = append(allowedBackends, keyring.BackendType(GlobalFlags.Backend))
			}

			keyringImpl, err = keyring.Open(keyring.Config{
				ServiceName:      "aws-vault",
				AllowedBackends:  allowedBackends,
				KeychainName:     "aws-vault",
				FileDir:          "~/.awsvault/keys/",
				FilePasswordFunc: fileKeyringPassphrasePrompt,
				KWalletAppID:     "aws-vault",
				KWalletFolder:    "aws-vault",
			})
		}
		if awsConfig == nil {
			awsConfig, err = vault.LoadConfigFromEnv()
		}
		return err
	})
}

func fileKeyringPassphrasePrompt(prompt string) (string, error) {
	if password := os.Getenv("AWS_VAULT_FILE_PASSPHRASE"); password != "" {
		return password, nil
	}

	fmt.Printf("%s: ", prompt)
	b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
	if err != nil {
		return "", err
	}
	fmt.Println()
	return string(b), nil
}
<|endoftext|>


<commit_before>// Package client provides a Stripe client for invoking APIs across all resources
package client

import (
	. "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/account"
	"github.com/stripe/stripe-go/balance"
	"github.com/stripe/stripe-go/bankaccount"
	"github.com/stripe/stripe-go/bitcoinreceiver"
	"github.com/stripe/stripe-go/bitcointransaction"
	"github.com/stripe/stripe-go/card"
	"github.com/stripe/stripe-go/charge"
	"github.com/stripe/stripe-go/countryspec"
	"github.com/stripe/stripe-go/coupon"
	"github.com/stripe/stripe-go/customer"
	"github.com/stripe/stripe-go/discount"
	"github.com/stripe/stripe-go/dispute"
	"github.com/stripe/stripe-go/ephemeralkey"
	"github.com/stripe/stripe-go/event"
	"github.com/stripe/stripe-go/exchangerate"
	"github.com/stripe/stripe-go/fee"
	"github.com/stripe/stripe-go/feerefund"
	"github.com/stripe/stripe-go/fileupload"
	"github.com/stripe/stripe-go/invoice"
	"github.com/stripe/stripe-go/invoiceitem"
	"github.com/stripe/stripe-go/loginlink"
	"github.com/stripe/stripe-go/order"
	"github.com/stripe/stripe-go/orderreturn"
	"github.com/stripe/stripe-go/paymentsource"
	"github.com/stripe/stripe-go/payout"
	"github.com/stripe/stripe-go/plan"
	"github.com/stripe/stripe-go/product"
	"github.com/stripe/stripe-go/recipient"
	"github.com/stripe/stripe-go/refund"
	"github.com/stripe/stripe-go/reversal"
	"github.com/stripe/stripe-go/sku"
	"github.com/stripe/stripe-go/source"
	"github.com/stripe/stripe-go/sub"
	"github.com/stripe/stripe-go/subitem"
	"github.com/stripe/stripe-go/token"
	"github.com/stripe/stripe-go/transfer"
)

// API is the Stripe client. It contains all the different resources available.
type API struct {
	// Charges is the client used to invoke /charges APIs.
	// For more details see https://stripe.com/docs/api#charges.
	Charges *charge.Client
	// Customers is the client used to invoke /customers APIs.
	// For more details see https://stripe.com/docs/api#customers.
	Customers *customer.Client
	// Cards is the client used to invoke /cards APIs.
	// For more details see https://stripe.com/docs/api#cards.
	Cards *card.Client
	// Subscriptions is the client used to invoke /subscriptions APIs.
	// For more details see https://stripe.com/docs/api#subscriptions.
	Subscriptions *sub.Client
	// SubscriptionItems is the client used to invoke subscription's items-related APIs.
	// For more details see https://stripe.com/docs/api#subscription_items.
	SubscriptionItems *subitem.Client
	// Plans is the client used to invoke /plans APIs.
	// For more details see https://stripe.com/docs/api#plans.
	Plans *plan.Client
	// Coupons is the client used to invoke /coupons APIs.
	// For more details see https://stripe.com/docs/api#coupons.
	Coupons *coupon.Client
	// Discounts is the client used to invoke discount-related APIs.
	// For mode details see https://stripe.com/docs/api#discounts.
	Discounts *discount.Client
	// Invoices is the client used to invoke /invoices APIs.
	// For more details see https://stripe.com/docs/api#invoices.
	Invoices *invoice.Client
	// InvoiceItems is the client used to invoke /invoiceitems APIs.
	// For more details see https://stripe.com/docs/api#invoiceitems.
	InvoiceItems *invoiceitem.Client
	// LoginLinks is the client used to invoke /v1/accounts/<account_id>/login_links APIs.
	// For more details see https://stripe.com/docs/api#login_link_object.
	LoginLinks *loginlink.Client
	// Disputes is the client used to invoke dispute-related APIs.
	// For more details see https://stripe.com/docs/api#disputes.
	Disputes *dispute.Client
	// Transfers is the client used to invoke /transfers APIs.
	// For more details see https://stripe.com/docs/api#transfers.
	Transfers *transfer.Client
	// Payouts is the client used to invoke /payouts APIs.
	// For more details see https://stripe.com/docs/api#payouts.
	Payouts *payout.Client
	// Recipients is the client used to invoke /recipients APIs.
	// For more details see https://stripe.com/docs/api#recipients.
	Recipients *recipient.Client
	// Refunds is the client used to invoke /refunds APIs.
	// For more details see https://stripe.com/docs/api#refunds.
	Refunds *refund.Client
	// Fees is the client used to invoke /application_fees APIs.
	// For more details see https://stripe.com/docs/api#application_fees.
	Fees *fee.Client
	// FeeRefunds is the client used to invoke /application_fees/refunds APIs.
	// For more details see https://stripe.com/docs/api#fee_refundss.
	FeeRefunds *feerefund.Client
	// Account is the client used to invoke /account APIs.
	// For more details see https://stripe.com/docs/api#account.
	Account *account.Client
	// CountrySpec is the client used to invoke /country_specs APIs.
	// For more details see https://stripe.com/docs/api#country_specs.
	CountrySpec *countryspec.Client
	// Balance is the client used to invoke /balance and transaction-related APIs.
	// For more details see https://stripe.com/docs/api#balance.
	Balance *balance.Client
	// EphemeralKeys is the client used to invoke /ephemeral_keys APIs.
	// For more details see https://stripe.com/docs/api#ephemeral_keys.
	EphemeralKeys *ephemeralkey.Client
	// Events is the client used to invoke /events APIs.
	// For more details see https://stripe.com/docs/api#events.
	Events *event.Client
	// Tokens is the client used to invoke /tokens APIs.
	// For more details see https://stripe.com/docs/api#tokens.
	Tokens *token.Client
	// FileUploads is the client used to invoke the uploads /files APIs.
	// For more details see https://stripe.com/docs/api#file_uploads.
	FileUploads *fileupload.Client
	// BitcoinReceivers is the client used to invoke /bitcoin/receivers APIs.
	// For more details see https://stripe.com/docs/api#bitcoin_receivers.
	BitcoinReceivers *bitcoinreceiver.Client
	// BitcoinTransactions is the client used to invoke /bitcoin/transactions APIs.
	// For more details see https://stripe.com/docs/api#bitcoin_receivers.
	BitcoinTransactions *bitcointransaction.Client
	// Reversals is the client used to invoke /transfers/reversals APIs.
	Reversals *reversal.Client
	// BankAccounts is the client used to invoke /accounts/bank_accounts APIs.
	BankAccounts *bankaccount.Client
	// Products is the client used to invoke /products APIs.
	// For more details see https://stripe.com/docs/api#products.
	Products *product.Client
	// Orders is the client used to invoke /orders APIs.
	// For more details see https://stripe.com/docs/api#orders.
	Orders *order.Client
	// OrderReturns is the client used to invoke /order_returns APIs.
	// For more details, see https://stripe.com/docs/api#order_returns.
	OrderReturns *orderreturn.Client
	// Skus is the client used to invoke /skus APIs.
	// For more details see https://stripe.com/docs/api#skus.
	Skus *sku.Client
	// Sources is the client used to invoke /sources APIs.
	// For more details see https://stripe.com/docs/api#sources.
	Sources *source.Client
	// PaymentSource is used to invoke /sources APIs.
	// For more details see https://stripe.com/docs/api.
	PaymentSource *paymentsource.Client
	// ExchangeRates is the client used to invoke /exchange_rates APIs.
	ExchangeRates *exchangerate.Client
}

// Init initializes the Stripe client with the appropriate secret key
// as well as providing the ability to override the backend as needed.
func (a *API) Init(key string, backends *Backends) {
	if backends == nil {
		backends = &Backends{API: GetBackend(APIBackend), Uploads: GetBackend(UploadsBackend)}
	}

	a.Charges = &charge.Client{B: backends.API, Key: key}
	a.Customers = &customer.Client{B: backends.API, Key: key}
	a.Cards = &card.Client{B: backends.API, Key: key}
	a.Subscriptions = &sub.Client{B: backends.API, Key: key}
	a.SubscriptionItems = &subitem.Client{B: backends.API, Key: key}
	a.Plans = &plan.Client{B: backends.API, Key: key}
	a.Coupons = &coupon.Client{B: backends.API, Key: key}
	a.Discounts = &discount.Client{B: backends.API, Key: key}
	a.Invoices = &invoice.Client{B: backends.API, Key: key}
	a.InvoiceItems = &invoiceitem.Client{B: backends.API, Key: key}
	a.LoginLinks = &loginlink.Client{B: backends.API, Key: key}
	a.Disputes = &dispute.Client{B: backends.API, Key: key}
	a.Transfers = &transfer.Client{B: backends.API, Key: key}
	a.Payouts = &payout.Client{B: backends.API, Key: key}
	a.Recipients = &recipient.Client{B: backends.API, Key: key}
	a.Refunds = &refund.Client{B: backends.API, Key: key}
	a.Fees = &fee.Client{B: backends.API, Key: key}
	a.FeeRefunds = &feerefund.Client{B: backends.API, Key: key}
	a.Account = &account.Client{B: backends.API, Key: key}
	a.CountrySpec = &countryspec.Client{B: backends.API, Key: key}
	a.Balance = &balance.Client{B: backends.API, Key: key}
	a.EphemeralKeys = &ephemeralkey.Client{B: backends.API, Key: key}
	a.Events = &event.Client{B: backends.API, Key: key}
	a.Tokens = &token.Client{B: backends.API, Key: key}
	a.FileUploads = &fileupload.Client{B: backends.Uploads, Key: key}
	a.BitcoinReceivers = &bitcoinreceiver.Client{B: backends.API, Key: key}
	a.BitcoinTransactions = &bitcointransaction.Client{B: backends.API, Key: key}
	a.Reversals = &reversal.Client{B: backends.API, Key: key}
	a.BankAccounts = &bankaccount.Client{B: backends.API, Key: key}
	a.Products = &product.Client{B: backends.API, Key: key}
	a.Orders = &order.Client{B: backends.API, Key: key}
	a.OrderReturns = &orderreturn.Client{B: backends.API, Key: key}
	a.Skus = &sku.Client{B: backends.API, Key: key}
	a.Sources = &source.Client{B: backends.API, Key: key}
	a.PaymentSource = &paymentsource.Client{B: backends.API, Key: key}
	a.ExchangeRates = &exchangerate.Client{B: backends.API, Key: key}
}

// New creates a new Stripe client with the appropriate secret key
// as well as providing the ability to override the backends as needed.
func New(key string, backends *Backends) *API {
	api := API{}
	api.Init(key, backends)
	return &api
}
<commit_msg>Properly order packages in api.go<commit_after>// Package client provides a Stripe client for invoking APIs across all resources
package client

import (
	. "github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/account"
	"github.com/stripe/stripe-go/balance"
	"github.com/stripe/stripe-go/bankaccount"
	"github.com/stripe/stripe-go/bitcoinreceiver"
	"github.com/stripe/stripe-go/bitcointransaction"
	"github.com/stripe/stripe-go/card"
	"github.com/stripe/stripe-go/charge"
	"github.com/stripe/stripe-go/countryspec"
	"github.com/stripe/stripe-go/coupon"
	"github.com/stripe/stripe-go/customer"
	"github.com/stripe/stripe-go/discount"
	"github.com/stripe/stripe-go/dispute"
	"github.com/stripe/stripe-go/ephemeralkey"
	"github.com/stripe/stripe-go/event"
	"github.com/stripe/stripe-go/exchangerate"
	"github.com/stripe/stripe-go/fee"
	"github.com/stripe/stripe-go/feerefund"
	"github.com/stripe/stripe-go/fileupload"
	"github.com/stripe/stripe-go/invoice"
	"github.com/stripe/stripe-go/invoiceitem"
	"github.com/stripe/stripe-go/loginlink"
	"github.com/stripe/stripe-go/order"
	"github.com/stripe/stripe-go/orderreturn"
	"github.com/stripe/stripe-go/paymentsource"
	"github.com/stripe/stripe-go/payout"
	"github.com/stripe/stripe-go/plan"
	"github.com/stripe/stripe-go/product"
	"github.com/stripe/stripe-go/recipient"
	"github.com/stripe/stripe-go/refund"
	"github.com/stripe/stripe-go/reversal"
	"github.com/stripe/stripe-go/sku"
	"github.com/stripe/stripe-go/source"
	"github.com/stripe/stripe-go/sub"
	"github.com/stripe/stripe-go/subitem"
	"github.com/stripe/stripe-go/token"
	"github.com/stripe/stripe-go/transfer"
)

// API is the Stripe client. It contains all the different resources available.
type API struct {
	// Account is the client used to invoke /accounts APIs.
	Account *account.Client
	// Balance is the client used to invoke /balance and transaction-related APIs.
	Balance *balance.Client
	// BankAccounts is the client used to invoke bank account related APIs.
	BankAccounts *bankaccount.Client
	// BitcoinReceivers is the client used to invoke /bitcoin/receivers APIs.
	BitcoinReceivers *bitcoinreceiver.Client
	// BitcoinTransactions is the client used to invoke /bitcoin/transactions APIs.
	BitcoinTransactions *bitcointransaction.Client
	// Cards is the client used to invoke card related APIs.
	Cards *card.Client
	// Charges is the client used to invoke /charges APIs.
	Charges *charge.Client
	// CountrySpec is the client used to invoke /country_specs APIs.
	CountrySpec *countryspec.Client
	// Coupons is the client used to invoke /coupons APIs.
	Coupons *coupon.Client
	// Customers is the client used to invoke /customers APIs.
	Customers *customer.Client
	// Discounts is the client used to invoke discount related APIs.
	Discounts *discount.Client
	// Disputes is the client used to invoke /disputes APIs.
	Disputes *dispute.Client
	// EphemeralKeys is the client used to invoke /ephemeral_keys APIs.
	EphemeralKeys *ephemeralkey.Client
	// Events is the client used to invoke /events APIs.
	Events *event.Client
	// ExchangeRates is the client used to invoke /exchange_rates APIs.
	ExchangeRates *exchangerate.Client
	// Fees is the client used to invoke /application_fees APIs.
	Fees *fee.Client
	// FeeRefunds is the client used to invoke /application_fees/refunds APIs.
	FeeRefunds *feerefund.Client
	// FileUploads is the client used to invoke the /files APIs.
	FileUploads *fileupload.Client
	// Invoices is the client used to invoke /invoices APIs.
	Invoices *invoice.Client
	// InvoiceItems is the client used to invoke /invoiceitems APIs.
	InvoiceItems *invoiceitem.Client
	// LoginLinks is the client used to invoke login link related APIs.
	LoginLinks *loginlink.Client
	// Orders is the client used to invoke /orders APIs.
	Orders *order.Client
	// OrderReturns is the client used to invoke /order_returns APIs.
	OrderReturns *orderreturn.Client
	// PaymentSource is used to invoke customer sources related APIs.
	PaymentSource *paymentsource.Client
	// Payouts is the client used to invoke /payouts APIs.
	Payouts *payout.Client
	// Plans is the client used to invoke /plans APIs.
	Plans *plan.Client
	// Products is the client used to invoke /products APIs.
	Products *product.Client
	// Recipients is the client used to invoke /recipients APIs.
	Recipients *recipient.Client
	// Refunds is the client used to invoke /refunds APIs.
	Refunds *refund.Client
	// Reversals is the client used to invoke /transfers/reversals APIs.
	Reversals *reversal.Client
	// Skus is the client used to invoke /skus APIs.
	Skus *sku.Client
	// Sources is the client used to invoke /sources APIs.
	Sources *source.Client
	// Subscriptions is the client used to invoke /subscriptions APIs.
	Subscriptions *sub.Client
	// SubscriptionItems is the client used to invoke subscription's items related APIs.
	SubscriptionItems *subitem.Client
	// Tokens is the client used to invoke /tokens APIs.
	Tokens *token.Client
	// Transfers is the client used to invoke /transfers APIs.
	Transfers *transfer.Client
}

// Init initializes the Stripe client with the appropriate secret key
// as well as providing the ability to override the backend as needed.
func (a *API) Init(key string, backends *Backends) {
	if backends == nil {
		backends = &Backends{API: GetBackend(APIBackend), Uploads: GetBackend(UploadsBackend)}
	}

	a.Account = &account.Client{B: backends.API, Key: key}
	a.Balance = &balance.Client{B: backends.API, Key: key}
	a.BankAccounts = &bankaccount.Client{B: backends.API, Key: key}
	a.BitcoinReceivers = &bitcoinreceiver.Client{B: backends.API, Key: key}
	a.BitcoinTransactions = &bitcointransaction.Client{B: backends.API, Key: key}
	a.Cards = &card.Client{B: backends.API, Key: key}
	a.Charges = &charge.Client{B: backends.API, Key: key}
	a.CountrySpec = &countryspec.Client{B: backends.API, Key: key}
	a.Coupons = &coupon.Client{B: backends.API, Key: key}
	a.Customers = &customer.Client{B: backends.API, Key: key}
	a.Discounts = &discount.Client{B: backends.API, Key: key}
	a.Disputes = &dispute.Client{B: backends.API, Key: key}
	a.EphemeralKeys = &ephemeralkey.Client{B: backends.API, Key: key}
	a.ExchangeRates = &exchangerate.Client{B: backends.API, Key: key}
	a.Events = &event.Client{B: backends.API, Key: key}
	a.Fees = &fee.Client{B: backends.API, Key: key}
	a.FeeRefunds = &feerefund.Client{B: backends.API, Key: key}
	a.FileUploads = &fileupload.Client{B: backends.Uploads, Key: key}
	a.Invoices = &invoice.Client{B: backends.API, Key: key}
	a.InvoiceItems = &invoiceitem.Client{B: backends.API, Key: key}
	a.LoginLinks = &loginlink.Client{B: backends.API, Key: key}
	a.Orders = &order.Client{B: backends.API, Key: key}
	a.OrderReturns = &orderreturn.Client{B: backends.API, Key: key}
	a.PaymentSource = &paymentsource.Client{B: backends.API, Key: key}
	a.Payouts = &payout.Client{B: backends.API, Key: key}
	a.Plans = &plan.Client{B: backends.API, Key: key}
	a.Products = &product.Client{B: backends.API, Key: key}
	a.Recipients = &recipient.Client{B: backends.API, Key: key}
	a.Refunds = &refund.Client{B: backends.API, Key: key}
	a.Reversals = &reversal.Client{B: backends.API, Key: key}
	a.Skus = &sku.Client{B: backends.API, Key: key}
	a.Sources = &source.Client{B: backends.API, Key: key}
	a.Subscriptions = &sub.Client{B: backends.API, Key: key}
	a.SubscriptionItems = &subitem.Client{B: backends.API, Key: key}
	a.Tokens = &token.Client{B: backends.API, Key: key}
	a.Transfers = &transfer.Client{B: backends.API, Key: key}
}

// New creates a new Stripe client with the appropriate secret key
// as well as providing the ability to override the backends as needed.
func New(key string, backends *Backends) *API {
	api := API{}
	api.Init(key, backends)
	return &api
}
<|endoftext|>


<commit_before>package fate

import "sort"

// tokset maintains a set of tokens as a sorted slice of integers.
//
// 1-byte tokens (<= 0xFF) are in buf[0:c1]
// 2-byte tokens (<= 0xFFFF) are in buf[c1:c1+2*c2]
// 3-byte tokens (<= 0xFFFFFF) are in buf[c1+2*c2:]
//
// They're stored little-endian. Adds are O(log N). Choosing a random
// token in the set is O(1).
//
// tokens greater than 0xFFFFFF are not currently supported. This is
// enough token space to handle the Web 1T corpus.
type tokset struct {
	buf []byte

	// count of 2-byte tokens, count of 1-byte tokens
	c2 uint16
	c1 uint8
}

func (t *tokset) Add(tok token) bool {
	switch {
	case tok <= 0xFF:
		if len(t.buf) == 0 {
			t.buf = append(t.buf, byte(tok))
			t.c1++
			return false
		}

		return t.add1(tok)
	case tok <= 0xFFFF:
		if len(t.buf) == 0 {
			t.buf = append(t.buf, byte(tok), byte(tok>>8))
			t.c2++
			return false
		}

		return t.add2(tok)
	case tok <= 0xFFFFFF:
		if len(t.buf) == 0 {
			t.buf = append(t.buf, byte(tok), byte(tok>>8), byte(tok>>16))
			return false
		}

		return t.add3(tok)
	}

	panic("oops")
}

func (t *tokset) span1() []byte {
	return t.buf[0:t.c1]
}

func (t *tokset) span2() []byte {
	return t.buf[int(t.c1) : int(t.c1)+2*int(t.c2)]
}

func (t *tokset) span3() []byte {
	return t.buf[int(t.c1)+2*int(t.c2):]
}

func (t *tokset) add1(tok token) bool {
	span := t.span1()
	loc := sort.Search(len(span), func(i int) bool {
		return token(span[i]) >= tok
	})

	if loc < len(span) && token(span[loc]) == tok {
		return true
	}

	t.buf = append(t.buf, 0)
	copy(t.buf[loc+1:], t.buf[loc:])
	t.buf[loc] = byte(tok)

	t.c1++

	return false
}

func (t *tokset) add2(tok token) bool {
	span := t.span2()
	idx := sort.Search(len(span)/2, func(i int) bool {
		return unpack2(span[2*i:]) >= tok
	})

	if idx < len(span)/2 && unpack2(span[2*idx:]) == tok {
		return true
	}

	t.buf = append(t.buf, 0, 0)

	loc := int(t.c1) + 2*idx
	copy(t.buf[loc+2:], t.buf[loc:])
	put2(t.buf[loc:], tok)

	t.c2++

	return false
}
func (t *tokset) add3(tok token) bool {
	span := t.span3()
	idx := sort.Search(len(span)/3, func(i int) bool {
		return unpack3(span[3*i:]) >= tok
	})

	if idx < len(span)/3 && unpack3(span[3*idx:]) == tok {
		return true
	}

	t.buf = append(t.buf, 0, 0, 0)

	loc := int(t.c1) + 2*int(t.c2) + 3*idx
	copy(t.buf[loc+3:], t.buf[loc:])
	put3(t.buf[loc:], tok)

	return false
}

func (t *tokset) Len() int {
	if t == nil {
		return 0
	}

	return int(t.c1) + int(t.c2) + len(t.span3())/3
}

func (t *tokset) Tokens() []token {
	if t == nil {
		return nil
	}

	var tokens = make([]token, 0, t.Len())
	for _, val := range t.span1() {
		tokens = append(tokens, token(val))
	}

	span2 := t.span2()
	for i := 0; i < len(span2); i += 2 {
		tokens = append(tokens, unpack2(span2[i:]))
	}

	span3 := t.span3()
	for i := 0; i < len(span3); i += 3 {
		tokens = append(tokens, unpack3(span3[i:]))
	}

	return tokens
}

func put2(buf []byte, tok token) {
	buf[0] = byte(tok)
	buf[1] = byte(tok >> 8)
}

func put3(buf []byte, tok token) {
	buf[0] = byte(tok)
	buf[1] = byte(tok >> 8)
	buf[2] = byte(tok >> 16)
}

func unpack2(buf []byte) token {
	return token(buf[0]) | token(buf[1])<<8
}

func unpack3(buf []byte) token {
	return token(buf[0]) | token(buf[1])<<8 | token(buf[2])<<16
}

func (t tokset) Choice(r Intn) token {
	index := r.Intn(t.Len())

	switch {
	case index < int(t.c1):
		return token(t.buf[index])
	case index < int(t.c1)+int(t.c2):
		span := t.span2()
		return unpack2(span[2*(index-int(t.c1)):])
	case index < t.Len():
		span := t.span3()
		return unpack3(span[3*(index-(int(t.c2)+int(t.c1))):])
	}

	panic("oops")
}

// tokset2 stores constant width tokens in a sorted slice.
type tokset2 struct {
	t []token
}

// Add inserts tok into this set, if not already present. It may
// return a new slice, so use its return value as the new set.
//
// Returns a bool signaling whether the token was already in the set
// (similar logic to map lookups).
func (t *tokset2) Add(tok token) bool {
	size := len(t.t)

	// Fast path for empty sets or brand new tokens.
	if size == 0 || tok > t.t[size-1] {
		t.t = append(t.t, tok)
		return false
	}

	loc := sort.Search(size, func(i int) bool { return t.t[i] >= tok })
	if t.t[loc] == tok {
		return true
	}

	t.t = append(t.t, 0)
	copy(t.t[loc+1:], t.t[loc:])
	t.t[loc] = tok

	return false
}

func (t *tokset2) Tokens() []token {
	if t == nil {
		return nil
	}

	return t.t
}
<commit_msg>Move the tokset empty array special cases into add1/add2/add3<commit_after>package fate

import "sort"

// tokset maintains a set of tokens as a sorted slice of integers.
//
// 1-byte tokens (<= 0xFF) are in buf[0:c1]
// 2-byte tokens (<= 0xFFFF) are in buf[c1:c1+2*c2]
// 3-byte tokens (<= 0xFFFFFF) are in buf[c1+2*c2:]
//
// They're stored little-endian. Adds are O(log N). Choosing a random
// token in the set is O(1).
//
// tokens greater than 0xFFFFFF are not currently supported. This is
// enough token space to handle the Web 1T corpus.
type tokset struct {
	buf []byte

	// count of 2-byte tokens, count of 1-byte tokens
	c2 uint16
	c1 uint8
}

func (t *tokset) Add(tok token) bool {
	switch {
	case tok <= 0xFF:
		return t.add1(tok)
	case tok <= 0xFFFF:
		return t.add2(tok)
	case tok <= 0xFFFFFF:
		return t.add3(tok)
	}

	panic("oops")
}

func (t *tokset) span1() []byte {
	return t.buf[0:t.c1]
}

func (t *tokset) span2() []byte {
	return t.buf[int(t.c1) : int(t.c1)+2*int(t.c2)]
}

func (t *tokset) span3() []byte {
	return t.buf[int(t.c1)+2*int(t.c2):]
}

func (t *tokset) add1(tok token) bool {
	if len(t.buf) == 0 {
		t.buf = append(t.buf, byte(tok))
		t.c1++
		return false
	}

	span := t.span1()
	loc := sort.Search(len(span), func(i int) bool {
		return token(span[i]) >= tok
	})

	if loc < len(span) && token(span[loc]) == tok {
		return true
	}

	t.buf = append(t.buf, 0)
	copy(t.buf[loc+1:], t.buf[loc:])
	t.buf[loc] = byte(tok)

	t.c1++

	return false
}

func (t *tokset) add2(tok token) bool {
	if len(t.buf) == 0 {
		t.buf = append(t.buf, byte(tok), byte(tok>>8))
		t.c2++
		return false
	}

	span := t.span2()
	idx := sort.Search(len(span)/2, func(i int) bool {
		return unpack2(span[2*i:]) >= tok
	})

	if idx < len(span)/2 && unpack2(span[2*idx:]) == tok {
		return true
	}

	t.buf = append(t.buf, 0, 0)

	loc := int(t.c1) + 2*idx
	copy(t.buf[loc+2:], t.buf[loc:])
	put2(t.buf[loc:], tok)

	t.c2++

	return false
}
func (t *tokset) add3(tok token) bool {
	if len(t.buf) == 0 {
		t.buf = append(t.buf, byte(tok), byte(tok>>8), byte(tok>>16))
		return false
	}

	span := t.span3()
	idx := sort.Search(len(span)/3, func(i int) bool {
		return unpack3(span[3*i:]) >= tok
	})

	if idx < len(span)/3 && unpack3(span[3*idx:]) == tok {
		return true
	}

	t.buf = append(t.buf, 0, 0, 0)

	loc := int(t.c1) + 2*int(t.c2) + 3*idx
	copy(t.buf[loc+3:], t.buf[loc:])
	put3(t.buf[loc:], tok)

	return false
}

func (t *tokset) Len() int {
	if t == nil {
		return 0
	}

	return int(t.c1) + int(t.c2) + len(t.span3())/3
}

func (t *tokset) Tokens() []token {
	if t == nil {
		return nil
	}

	var tokens = make([]token, 0, t.Len())
	for _, val := range t.span1() {
		tokens = append(tokens, token(val))
	}

	span2 := t.span2()
	for i := 0; i < len(span2); i += 2 {
		tokens = append(tokens, unpack2(span2[i:]))
	}

	span3 := t.span3()
	for i := 0; i < len(span3); i += 3 {
		tokens = append(tokens, unpack3(span3[i:]))
	}

	return tokens
}

func put2(buf []byte, tok token) {
	buf[0] = byte(tok)
	buf[1] = byte(tok >> 8)
}

func put3(buf []byte, tok token) {
	buf[0] = byte(tok)
	buf[1] = byte(tok >> 8)
	buf[2] = byte(tok >> 16)
}

func unpack2(buf []byte) token {
	return token(buf[0]) | token(buf[1])<<8
}

func unpack3(buf []byte) token {
	return token(buf[0]) | token(buf[1])<<8 | token(buf[2])<<16
}

func (t tokset) Choice(r Intn) token {
	index := r.Intn(t.Len())

	switch {
	case index < int(t.c1):
		return token(t.buf[index])
	case index < int(t.c1)+int(t.c2):
		span := t.span2()
		return unpack2(span[2*(index-int(t.c1)):])
	case index < t.Len():
		span := t.span3()
		return unpack3(span[3*(index-(int(t.c2)+int(t.c1))):])
	}

	panic("oops")
}

// tokset2 stores constant width tokens in a sorted slice.
type tokset2 struct {
	t []token
}

// Add inserts tok into this set, if not already present. It may
// return a new slice, so use its return value as the new set.
//
// Returns a bool signaling whether the token was already in the set
// (similar logic to map lookups).
func (t *tokset2) Add(tok token) bool {
	size := len(t.t)

	// Fast path for empty sets or brand new tokens.
	if size == 0 || tok > t.t[size-1] {
		t.t = append(t.t, tok)
		return false
	}

	loc := sort.Search(size, func(i int) bool { return t.t[i] >= tok })
	if t.t[loc] == tok {
		return true
	}

	t.t = append(t.t, 0)
	copy(t.t[loc+1:], t.t[loc:])
	t.t[loc] = tok

	return false
}

func (t *tokset2) Tokens() []token {
	if t == nil {
		return nil
	}

	return t.t
}
<|endoftext|>


<commit_before>package tparse

import (
	"bytes"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
	"unicode"
)

// Parse will return the time value corresponding to the specified layout and value.  It also parses
// floating point and integer epoch values.
func Parse(layout, value string) (time.Time, error) {
	return ParseWithMap(layout, value, make(map[string]time.Time))
}

// ParseNow will return the time value corresponding to the specified layout and value.  It also
// parses floating point and integer epoch values.  It recognizes the special string `now` and
// replaces that with the time ParseNow is called.  This allows a suffix adding or subtracting
// various values from the base time.  For instance, ParseNow(time.ANSIC, "now+1d") will return a
// time corresponding to 24 hours from the moment the function is invoked.
//
// In addition to the duration abbreviations recognized by time.ParseDuration, it recognizes various
// tokens for days, weeks, months, and years.
//
//	package main
//
//	import (
//		"fmt"
//		"os"
//		"time"
//
//		tparse "gopkg.in/karrick/tparse.v2"
//	)
//
//	func main() {
//		actual, err := tparse.ParseNow(time.RFC3339, "now+1d3w4mo7y6h4m")
//		if err != nil {
//			fmt.Fprintf(os.Stderr, "error: %s\n", err)
//			os.Exit(1)
//		}
//
//		fmt.Printf("time is: %s\n", actual)
//	}
func ParseNow(layout, value string) (time.Time, error) {
	m := map[string]time.Time{"now": time.Now()}
	return ParseWithMap(layout, value, m)
}

// ParseWithMap will return the time value corresponding to the specified layout and value.  It also
// parses floating point and integer epoch values.  It accepts a map of strings to time.Time values,
// and if the value string starts with one of the keys in the map, it replaces the string with the
// corresponding time.Time value.
//
//	package main
//
//	import (
//		"fmt"
//		"os"
//		"time"
//
//		tparse "gopkg.in/karrick/tparse.v2"
//	)
//
//	func main() {
//		m := make(map[string]time.Time)
//		m["start"] = start
//
//		end, err := tparse.ParseWithMap(time.RFC3339, "start+8h", m)
//		if err != nil {
//			fmt.Fprintf(os.Stderr, "error: %s\n", err)
//			os.Exit(1)
//		}
//
//		fmt.Printf("start: %s; end: %s\n", start, end)
//	}
func ParseWithMap(layout, value string, dict map[string]time.Time) (time.Time, error) {
	if epoch, err := strconv.ParseFloat(value, 64); err == nil && epoch >= 0 {
		trunc := math.Trunc(epoch)
		nanos := fractionToNanos(epoch - trunc)
		return time.Unix(int64(trunc), int64(nanos)), nil
	}

	var matchKey []byte
	var matchTime time.Time
	// find longest matching key in dict
	for k, v := range dict {
		if strings.HasPrefix(value, k) && len(k) > len(matchKey) {
			matchKey = []byte(k)
			matchTime = v
		}
	}
	if len(matchKey) > 0 {
		return addDuration(matchTime, value[len(matchKey):])
	}
	return time.Parse(layout, value)
}

func fractionToNanos(fraction float64) int64 {
	return int64(fraction * float64(time.Second/time.Nanosecond))
}

// on err, returns epoch and error
func addDuration(base time.Time, value string) (time.Time, error) {
	if len(value) == 0 {
		return base, nil
	}
	var epoch time.Time
	var ty, tm, td int
	var tdur time.Duration
	var identifier, setComplete bool
	positive := true
	var iUnit, iNumber int
	var startNumberNextRune bool

	for i, rune := range value {
		if startNumberNextRune {
			iNumber = i
			startNumberNextRune = false
		}
		// [+-][0-9]+[^-+0-9]+
		if identifier {
			switch {
			case rune == '+', rune == '-':
				identifier = false
				setComplete = true
				startNumberNextRune = true
			case unicode.IsDigit(rune):
				identifier = false
				setComplete = true
			}
			if setComplete {
				if i > 0 {
					// we should have all we need for previous set
					y, m, d, dur, err := bar(value, positive, iNumber, iUnit, i)
					if err != nil {
						return epoch, err
					}
					ty += y
					tm += m
					td += d
					tdur += dur
					iNumber = i
				}
				setComplete = false
			}
			switch {
			case rune == '+':
				positive = true
			case rune == '-':
				positive = false
			}
		} else { // number
			switch {
			case rune == '+':
				positive = true
				startNumberNextRune = true
			case rune == '-':
				positive = false
				startNumberNextRune = true
			case unicode.IsDigit(rune):
				// nop
			default:
				identifier = true
				iUnit = i
			}
		}
	}

	if iNumber < iUnit && iUnit < len(value) {
		y, m, d, dur, err := bar(value, positive, iNumber, iUnit, len(value))
		if err != nil {
			return epoch, err
		}
		ty += y
		tm += m
		td += d
		tdur += dur
	} else {
		return epoch, fmt.Errorf("extra characters: %s", value[iNumber:])
	}
	return base.Add(tdur).AddDate(ty, tm, td), nil
}

func bar(value string, positive bool, iNumber, iUnit, i int) (int, int, int, time.Duration, error) {
	number := value[iNumber:iUnit]
	unit := value[iUnit:i]
	return calcDuration(positive, number, unit)
}

func calcDuration(positive bool, number, unit string) (int, int, int, time.Duration, error) {
	value, err := strconv.Atoi(number)
	if err != nil {
		return 0, 0, 0, 0, err
	}

	var y, m, d int
	var duration time.Duration

	// NOTE: compare byte slices because some units, i.e. ms, are multi-rune
	switch {
	case bytes.Equal([]byte(unit), []byte("d")) || bytes.Equal([]byte(unit), []byte("day")) || bytes.Equal([]byte(unit), []byte("days")):
		d = value
	case bytes.Equal([]byte(unit), []byte("w")) || bytes.Equal([]byte(unit), []byte("week")) || bytes.Equal([]byte(unit), []byte("weeks")):
		d = 7 * value
	case bytes.Equal([]byte(unit), []byte("mo")) || bytes.Equal([]byte(unit), []byte("mon")) || bytes.Equal([]byte(unit), []byte("month")) || bytes.Equal([]byte(unit), []byte("months")) || bytes.Equal([]byte(unit), []byte("mth")) || bytes.Equal([]byte(unit), []byte("mn")):
		m = value
	case bytes.Equal([]byte(unit), []byte("y")) || bytes.Equal([]byte(unit), []byte("year")) || bytes.Equal([]byte(unit), []byte("years")):
		y = value
	case bytes.Equal([]byte(unit), []byte("sec")) || bytes.Equal([]byte(unit), []byte("second")) || bytes.Equal([]byte(unit), []byte("seconds")):
		duration = time.Duration(value) * time.Second
	case bytes.Equal([]byte(unit), []byte("min")) || bytes.Equal([]byte(unit), []byte("minute")) || bytes.Equal([]byte(unit), []byte("minutes")):
		duration = time.Duration(value) * time.Minute
	case bytes.Equal([]byte(unit), []byte("hr")) || bytes.Equal([]byte(unit), []byte("hour")) || bytes.Equal([]byte(unit), []byte("hours")):
		duration = time.Duration(value) * time.Hour

	default:
		duration, err = time.ParseDuration(number + unit)
	}
	if !positive {
		y = -y
		m = -m
		d = -d
		duration = -duration
	}
	return y, m, d, duration, nil
}
<commit_msg>faster performance<commit_after>package tparse

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
	"unicode"
)

// Parse will return the time value corresponding to the specified layout and value.  It also parses
// floating point and integer epoch values.
func Parse(layout, value string) (time.Time, error) {
	return ParseWithMap(layout, value, make(map[string]time.Time))
}

// ParseNow will return the time value corresponding to the specified layout and value.  It also
// parses floating point and integer epoch values.  It recognizes the special string `now` and
// replaces that with the time ParseNow is called.  This allows a suffix adding or subtracting
// various values from the base time.  For instance, ParseNow(time.ANSIC, "now+1d") will return a
// time corresponding to 24 hours from the moment the function is invoked.
//
// In addition to the duration abbreviations recognized by time.ParseDuration, it recognizes various
// tokens for days, weeks, months, and years.
//
//	package main
//
//	import (
//		"fmt"
//		"os"
//		"time"
//
//		tparse "gopkg.in/karrick/tparse.v2"
//	)
//
//	func main() {
//		actual, err := tparse.ParseNow(time.RFC3339, "now+1d3w4mo7y6h4m")
//		if err != nil {
//			fmt.Fprintf(os.Stderr, "error: %s\n", err)
//			os.Exit(1)
//		}
//
//		fmt.Printf("time is: %s\n", actual)
//	}
func ParseNow(layout, value string) (time.Time, error) {
	m := map[string]time.Time{"now": time.Now()}
	return ParseWithMap(layout, value, m)
}

// ParseWithMap will return the time value corresponding to the specified layout and value.  It also
// parses floating point and integer epoch values.  It accepts a map of strings to time.Time values,
// and if the value string starts with one of the keys in the map, it replaces the string with the
// corresponding time.Time value.
//
//	package main
//
//	import (
//		"fmt"
//		"os"
//		"time"
//
//		tparse "gopkg.in/karrick/tparse.v2"
//	)
//
//	func main() {
//		m := make(map[string]time.Time)
//		m["start"] = start
//
//		end, err := tparse.ParseWithMap(time.RFC3339, "start+8h", m)
//		if err != nil {
//			fmt.Fprintf(os.Stderr, "error: %s\n", err)
//			os.Exit(1)
//		}
//
//		fmt.Printf("start: %s; end: %s\n", start, end)
//	}
func ParseWithMap(layout, value string, dict map[string]time.Time) (time.Time, error) {
	if epoch, err := strconv.ParseFloat(value, 64); err == nil && epoch >= 0 {
		trunc := math.Trunc(epoch)
		nanos := fractionToNanos(epoch - trunc)
		return time.Unix(int64(trunc), int64(nanos)), nil
	}

	var matchKey []byte
	var matchTime time.Time
	// find longest matching key in dict
	for k, v := range dict {
		if strings.HasPrefix(value, k) && len(k) > len(matchKey) {
			matchKey = []byte(k)
			matchTime = v
		}
	}
	if len(matchKey) > 0 {
		return addDuration(matchTime, value[len(matchKey):])
	}
	return time.Parse(layout, value)
}

func fractionToNanos(fraction float64) int64 {
	return int64(fraction * float64(time.Second/time.Nanosecond))
}

// on err, returns epoch and error
func addDuration(base time.Time, value string) (time.Time, error) {
	if len(value) == 0 {
		return base, nil
	}
	var epoch time.Time
	var ty, tm, td int
	var tdur time.Duration
	var identifier, setComplete bool
	positive := true
	var iUnit, iNumber int
	var startNumberNextRune bool

	for i, rune := range value {
		if startNumberNextRune {
			iNumber = i
			startNumberNextRune = false
		}
		// [+-][0-9]+[^-+0-9]+
		if identifier {
			switch {
			case rune == '+', rune == '-':
				identifier = false
				setComplete = true
				startNumberNextRune = true
			case unicode.IsDigit(rune):
				identifier = false
				setComplete = true
			}
			if setComplete {
				if i > 0 {
					// we should have all we need for previous set
					y, m, d, dur, err := bar(value, positive, iNumber, iUnit, i)
					if err != nil {
						return epoch, err
					}
					ty += y
					tm += m
					td += d
					tdur += dur
					iNumber = i
				}
				setComplete = false
			}
			switch {
			case rune == '+':
				positive = true
			case rune == '-':
				positive = false
			}
		} else { // number
			switch {
			case rune == '+':
				positive = true
				startNumberNextRune = true
			case rune == '-':
				positive = false
				startNumberNextRune = true
			case unicode.IsDigit(rune):
				// nop
			default:
				identifier = true
				iUnit = i
			}
		}
	}

	if iNumber < iUnit && iUnit < len(value) {
		y, m, d, dur, err := bar(value, positive, iNumber, iUnit, len(value))
		if err != nil {
			return epoch, err
		}
		ty += y
		tm += m
		td += d
		tdur += dur
	} else {
		return epoch, fmt.Errorf("extra characters: %s", value[iNumber:])
	}
	return base.Add(tdur).AddDate(ty, tm, td), nil
}

func bar(value string, positive bool, iNumber, iUnit, i int) (int, int, int, time.Duration, error) {
	number := value[iNumber:iUnit]
	unit := value[iUnit:i]
	return calcDuration(positive, number, unit)
}

func calcDuration(positive bool, number, unit string) (int, int, int, time.Duration, error) {
	value, err := strconv.Atoi(number)
	if err != nil {
		return 0, 0, 0, 0, err
	}

	var y, m, d int
	var duration time.Duration

	// NOTE: compare byte slices because some units, i.e. ms, are multi-rune
	switch unit {
	case "d", "day", "days":
		d = value
	case "w", "week", "weeks":
		d = 7 * value
	case "mo", "mon", "month", "months", "mth", "mn":
		m = value
	case "y", "year", "years":
		y = value
	case "sec", "second", "seconds":
		duration = time.Duration(value) * time.Second
	case "min", "minute", "minutes":
		duration = time.Duration(value) * time.Minute
	case "hr", "hour", "hours":
		duration = time.Duration(value) * time.Hour
	default:
		duration, err = time.ParseDuration(number + unit)
	}

	if !positive {
		y = -y
		m = -m
		d = -d
		duration = -duration
	}

	return y, m, d, duration, nil
}
<|endoftext|>