<commit_before>package cmd

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

type Manager struct {
	name     string
	commands map[string]interface{}
	Stdout   io.Writer
	Stderr   io.Writer
}

func (m *Manager) Register(command interface{}) {
	if m.commands == nil {
		m.commands = make(map[string]interface{})
	}
	name := command.(Infoer).Info().Name
	_, found := m.commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.commands[name] = command
}

func (m *Manager) Run(args []string) {
	if len(args) == 0 {
		args = []string{"help"}
	}
	cmds := m.extractCommandFromArgs(args)
	if len(cmds) <= 0 {
		io.WriteString(m.Stderr, fmt.Sprintf("command %s does not exist\n", args[0]))
		return
	}
	args = args[len(cmds):]
	command := m.commands[cmds[0]]
	command = getSubcommand(command, cmds)
	if len(args) < command.(Infoer).Info().MinArgs && cmds[0] != "help" {
		io.WriteString(m.Stdout, fmt.Sprintf("Not enough arguments to call %s.\n\n", command.(Infoer).Info().Name))
		command = m.commands["help"]
		args = cmds
		cmds = []string{"help"}
	}
	err := command.(Command).Run(&Context{cmds, args, m.Stdout, m.Stderr}, NewClient(&http.Client{}))
	if err != nil {
		io.WriteString(m.Stderr, err.Error())
	}
}

func (m *Manager) extractCommandFromArgs(args []string) []string {
	cmds := []string{}
	if len(args) <= 0 {
		return cmds
	}
	if cmd, exists := m.commands[args[0]]; exists {
		cmds = append(cmds, args[0])
		if container, ok := cmd.(CommandContainer); ok && len(args) >= 2 {
			if _, exists = container.Subcommands()[args[1]]; exists {
				cmds = append(cmds, args[1])
			}
		}
	}
	return cmds
}

func getSubcommand(cmd interface{}, cmds []string) interface{} {
	if c, ok := cmd.(CommandContainer); ok && len(cmds) == 2 {
		if subcommand, exist := c.Subcommands()[cmds[1]]; exist {
			cmd = subcommand
		}
	}
	return cmd
}

func NewManager(name string, stdout, stderr io.Writer) Manager {
	m := Manager{name: name, Stdout: stdout, Stderr: stderr}
	m.Register(&Help{manager: &m})
	return m
}

type CommandContainer interface {
	Subcommands() map[string]interface{}
}

type Infoer interface {
	Info() *Info
}

type Command interface {
	Run(context *Context, client Doer) error
}

type Context struct {
	Cmds   []string
	Args   []string
	Stdout io.Writer
	Stderr io.Writer
}

type Info struct {
	Name    string
	MinArgs int
	Usage   string
	Desc    string
}

type Help struct {
	manager *Manager
}

func (c *Help) Info() *Info {
	return &Info{
		Name:  "help",
		Usage: "command [args]",
	}
}

func (c *Help) Run(context *Context, client Doer) error {
	output := ""
	if len(context.Args) > 0 {
		cmd := c.manager.commands[context.Args[0]]
		cmd = getSubcommand(cmd, context.Args)
		info := cmd.(Infoer).Info()
		output = output + fmt.Sprintf("Usage: %s %s\n", c.manager.name, info.Usage)
		output = output + fmt.Sprintf("\n%s\n", info.Desc)
		if info.MinArgs > 0 {
			output = output + fmt.Sprintf("\nMinimum arguments: %d\n", info.MinArgs)
		}
	} else {
		output = output + fmt.Sprintf("Usage: %s %s\n", c.manager.name, c.Info().Usage)
	}
	io.WriteString(context.Stdout, output)
	return nil
}

func ExtractProgramName(path string) string {
	parts := strings.Split(path, "/")
	return parts[len(parts)-1]
}
<commit_msg>cmd: changes in code style<commit_after>package cmd

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

type Manager struct {
	name     string
	commands map[string]interface{}
	Stdout   io.Writer
	Stderr   io.Writer
}

func NewManager(name string, stdout, stderr io.Writer) Manager {
	m := Manager{name: name, Stdout: stdout, Stderr: stderr}
	m.Register(&Help{manager: &m})
	return m
}

func (m *Manager) Register(command interface{}) {
	if m.commands == nil {
		m.commands = make(map[string]interface{})
	}
	name := command.(Infoer).Info().Name
	_, found := m.commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.commands[name] = command
}

func (m *Manager) Run(args []string) {
	if len(args) == 0 {
		args = []string{"help"}
	}
	cmds := m.extractCommandFromArgs(args)
	if len(cmds) <= 0 {
		io.WriteString(m.Stderr, fmt.Sprintf("command %s does not exist\n", args[0]))
		return
	}
	args = args[len(cmds):]
	command := m.commands[cmds[0]]
	command = getSubcommand(command, cmds)
	if len(args) < command.(Infoer).Info().MinArgs && cmds[0] != "help" {
		io.WriteString(m.Stdout, fmt.Sprintf("Not enough arguments to call %s.\n\n", command.(Infoer).Info().Name))
		command = m.commands["help"]
		args = cmds
		cmds = []string{"help"}
	}
	err := command.(Command).Run(&Context{cmds, args, m.Stdout, m.Stderr}, NewClient(&http.Client{}))
	if err != nil {
		io.WriteString(m.Stderr, err.Error())
	}
}

func (m *Manager) extractCommandFromArgs(args []string) []string {
	cmds := []string{}
	if len(args) <= 0 {
		return cmds
	}
	if cmd, exists := m.commands[args[0]]; exists {
		cmds = append(cmds, args[0])
		if container, ok := cmd.(CommandContainer); ok && len(args) >= 2 {
			if _, exists = container.Subcommands()[args[1]]; exists {
				cmds = append(cmds, args[1])
			}
		}
	}
	return cmds
}

func getSubcommand(cmd interface{}, cmds []string) interface{} {
	if c, ok := cmd.(CommandContainer); ok && len(cmds) == 2 {
		if subcommand, exist := c.Subcommands()[cmds[1]]; exist {
			cmd = subcommand
		}
	}
	return cmd
}

type CommandContainer interface {
	Subcommands() map[string]interface{}
}

type Infoer interface {
	Info() *Info
}

type Command interface {
	Run(context *Context, client Doer) error
}

type Context struct {
	Cmds   []string
	Args   []string
	Stdout io.Writer
	Stderr io.Writer
}

type Info struct {
	Name    string
	MinArgs int
	Usage   string
	Desc    string
}

type Help struct {
	manager *Manager
}

func (c *Help) Info() *Info {
	return &Info{
		Name:  "help",
		Usage: "command [args]",
	}
}

func (c *Help) Run(context *Context, client Doer) error {
	output := ""
	if len(context.Args) > 0 {
		cmd := c.manager.commands[context.Args[0]]
		cmd = getSubcommand(cmd, context.Args)
		info := cmd.(Infoer).Info()
		output = output + fmt.Sprintf("Usage: %s %s\n", c.manager.name, info.Usage)
		output = output + fmt.Sprintf("\n%s\n", info.Desc)
		if info.MinArgs > 0 {
			output = output + fmt.Sprintf("\nMinimum arguments: %d\n", info.MinArgs)
		}
	} else {
		output = output + fmt.Sprintf("Usage: %s %s\n", c.manager.name, c.Info().Usage)
	}
	io.WriteString(context.Stdout, output)
	return nil
}

func ExtractProgramName(path string) string {
	parts := strings.Split(path, "/")
	return parts[len(parts)-1]
}
<|endoftext|>


<commit_before>package fastping

import (
	"net"
	"sync"
	"testing"
	"time"
)

type addHostTest struct {
	host   string
	addr   *net.IPAddr
	expect bool
}

var addHostTests = []addHostTest{
	{host: "127.0.0.1", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: true},
	{host: "localhost", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: false},
}

func TestAddIP(t *testing.T) {
	p := NewPinger()

	for _, tt := range addHostTests {
		if ok := p.AddIP(tt.host); ok != nil {
			if tt.expect != false {
				t.Errorf("AddIP failed: got %v, expected %v", ok, tt.expect)
			}
		}
	}
	for _, tt := range addHostTests {
		if tt.expect {
			if !p.addrs[tt.host].IP.Equal(tt.addr.IP) {
				t.Errorf("AddIP didn't save IPAddr: %v", tt.host)
			}
		}
	}
}

func TestRun(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	if err := p.AddIP("127.0.0.100"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	found1, found100 := false, false
	called, idle := false, false
	p.AddHandler("receive", func(ip *net.IPAddr, d time.Duration) {
		called = true
		if ip.String() == "127.0.0.1" {
			found1 = true
		} else if ip.String() == "127.0.0.100" {
			found100 = true
		}
	})
	p.AddHandler("idle", func() {
		idle = true
	})
	err := p.Run()
	if err != nil {
		t.Fatalf("Pinger returns error: %v", err)
	}
	if !called {
		t.Fatalf("Pinger didn't get any responses")
	}
	if !idle {
		t.Fatalf("Pinger didn't call OnIdle function")
	}
	if !found1 {
		t.Fatalf("Pinger `127.0.0.1` didn't respond")
	}
	if found100 {
		t.Fatalf("Pinger `127.0.0.100` responded")
	}
}

func TestMultiRun(t *testing.T) {
	p1 := NewPinger()
	p2 := NewPinger()

	if err := p1.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	if err := p2.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	var mu sync.Mutex
	res1 := 0
	p1.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res1++
		mu.Unlock()
	})

	res2 := 0
	p2.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res2++
		mu.Unlock()
	})
	p1.MaxRTT, p2.MaxRTT = time.Millisecond*100, time.Millisecond*100

	if err := p1.Run(); err != nil {
		t.Fatalf("Pinger 1 returns error: %v", err)
	}
	if res1 == 0 {
		t.Fatalf("Pinger 1 didn't get any responses")
	}
	if res2 > 0 {
		t.Fatalf("Pinger 2 got response")
	}

	res1, res2 = 0, 0
	if err := p2.Run(); err != nil {
		t.Fatalf("Pinger 2 returns error: %v", err)
	}
	if res1 > 0 {
		t.Fatalf("Pinger 1 got response")
	}
	if res2 == 0 {
		t.Fatalf("Pinger 2 didn't get any responses")
	}

	res1, res2 = 0, 0
	errch1, errch2 := make(chan error), make(chan error)
	go func(ch chan error) {
		err := p1.Run()
		if err != nil {
			ch <- err
		}
	}(errch1)
	go func(ch chan error) {
		err := p2.Run()
		if err != nil {
			ch <- err
		}
	}(errch2)
	ticker := time.NewTicker(time.Millisecond * 200)
	select {
	case err := <-errch1:
		t.Fatalf("Pinger 1 returns error: %v", err)
	case err := <-errch2:
		t.Fatalf("Pinger 2 returns error: %v", err)
	case <-ticker.C:
		break
	}
	mu.Lock()
	if res1 != 1 {
		t.Fatalf("Pinger 1 didn't get correct response")
	}
	if res2 != 1 {
		t.Fatalf("Pinger 2 didn't get correct response")
	}
	mu.Unlock()
}

func TestRunLoop(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}
	p.MaxRTT = time.Millisecond * 100

	recvCount, idleCount := 0, 0
	p.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		recvCount++
	})
	p.AddHandler("idle", func() {
		idleCount++
	})

	wait := make(chan bool)
	quit, errch := p.RunLoop()
	ticker := time.NewTicker(time.Millisecond * 250)
	select {
	case err := <-errch:
		t.Fatalf("Pinger returns error %v", err)
	case <-ticker.C:
		quit <- wait
	case <-wait:
		break
	}

	if recvCount < 2 {
		t.Fatalf("Pinger recieve count less than 2")
	}
	if idleCount < 2 {
		t.Fatalf("Pinger idle count less than 2")
	}
}

func TestTimeToBytes(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	expect := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	for i := 0; i < 8; i++ {
		if b[i] != expect[i] {
			t.Errorf("timeToBytes failed: got %v, expected: %v", b, expect)
			break
		}
	}
}

func TestBytesToTime(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	b := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	expect, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	tm := bytesToTime(b)
	if !tm.Equal(expect) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm.UTC(), expect.UTC())
	}
}

func TestTimeToBytesToTime(t *testing.T) {
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	tm2 := bytesToTime(b)
	if !tm.Equal(tm2) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm2.UTC(), tm.UTC())
	}
}
<commit_msg>Fixed typo<commit_after>package fastping

import (
	"net"
	"sync"
	"testing"
	"time"
)

type addHostTest struct {
	host   string
	addr   *net.IPAddr
	expect bool
}

var addHostTests = []addHostTest{
	{host: "127.0.0.1", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: true},
	{host: "localhost", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: false},
}

func TestAddIP(t *testing.T) {
	p := NewPinger()

	for _, tt := range addHostTests {
		if ok := p.AddIP(tt.host); ok != nil {
			if tt.expect != false {
				t.Errorf("AddIP failed: got %v, expected %v", ok, tt.expect)
			}
		}
	}
	for _, tt := range addHostTests {
		if tt.expect {
			if !p.addrs[tt.host].IP.Equal(tt.addr.IP) {
				t.Errorf("AddIP didn't save IPAddr: %v", tt.host)
			}
		}
	}
}

func TestRun(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	if err := p.AddIP("127.0.0.100"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	found1, found100 := false, false
	called, idle := false, false
	p.AddHandler("receive", func(ip *net.IPAddr, d time.Duration) {
		called = true
		if ip.String() == "127.0.0.1" {
			found1 = true
		} else if ip.String() == "127.0.0.100" {
			found100 = true
		}
	})
	p.AddHandler("idle", func() {
		idle = true
	})
	err := p.Run()
	if err != nil {
		t.Fatalf("Pinger returns error: %v", err)
	}
	if !called {
		t.Fatalf("Pinger didn't get any responses")
	}
	if !idle {
		t.Fatalf("Pinger didn't call OnIdle function")
	}
	if !found1 {
		t.Fatalf("Pinger `127.0.0.1` didn't respond")
	}
	if found100 {
		t.Fatalf("Pinger `127.0.0.100` responded")
	}
}

func TestMultiRun(t *testing.T) {
	p1 := NewPinger()
	p2 := NewPinger()

	if err := p1.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	if err := p2.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	var mu sync.Mutex
	res1 := 0
	p1.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res1++
		mu.Unlock()
	})

	res2 := 0
	p2.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res2++
		mu.Unlock()
	})
	p1.MaxRTT, p2.MaxRTT = time.Millisecond*100, time.Millisecond*100

	if err := p1.Run(); err != nil {
		t.Fatalf("Pinger 1 returns error: %v", err)
	}
	if res1 == 0 {
		t.Fatalf("Pinger 1 didn't get any responses")
	}
	if res2 > 0 {
		t.Fatalf("Pinger 2 got response")
	}

	res1, res2 = 0, 0
	if err := p2.Run(); err != nil {
		t.Fatalf("Pinger 2 returns error: %v", err)
	}
	if res1 > 0 {
		t.Fatalf("Pinger 1 got response")
	}
	if res2 == 0 {
		t.Fatalf("Pinger 2 didn't get any responses")
	}

	res1, res2 = 0, 0
	errch1, errch2 := make(chan error), make(chan error)
	go func(ch chan error) {
		err := p1.Run()
		if err != nil {
			ch <- err
		}
	}(errch1)
	go func(ch chan error) {
		err := p2.Run()
		if err != nil {
			ch <- err
		}
	}(errch2)
	ticker := time.NewTicker(time.Millisecond * 200)
	select {
	case err := <-errch1:
		t.Fatalf("Pinger 1 returns error: %v", err)
	case err := <-errch2:
		t.Fatalf("Pinger 2 returns error: %v", err)
	case <-ticker.C:
		break
	}
	mu.Lock()
	if res1 != 1 {
		t.Fatalf("Pinger 1 didn't get correct response")
	}
	if res2 != 1 {
		t.Fatalf("Pinger 2 didn't get correct response")
	}
	mu.Unlock()
}

func TestRunLoop(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}
	p.MaxRTT = time.Millisecond * 100

	recvCount, idleCount := 0, 0
	p.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		recvCount++
	})
	p.AddHandler("idle", func() {
		idleCount++
	})

	wait := make(chan bool)
	quit, errch := p.RunLoop()
	ticker := time.NewTicker(time.Millisecond * 250)
	select {
	case err := <-errch:
		t.Fatalf("Pinger returns error %v", err)
	case <-ticker.C:
		quit <- wait
	case <-wait:
		break
	}

	if recvCount < 2 {
		t.Fatalf("Pinger receive count less than 2")
	}
	if idleCount < 2 {
		t.Fatalf("Pinger idle count less than 2")
	}
}

func TestTimeToBytes(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	expect := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	for i := 0; i < 8; i++ {
		if b[i] != expect[i] {
			t.Errorf("timeToBytes failed: got %v, expected: %v", b, expect)
			break
		}
	}
}

func TestBytesToTime(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	b := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	expect, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	tm := bytesToTime(b)
	if !tm.Equal(expect) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm.UTC(), expect.UTC())
	}
}

func TestTimeToBytesToTime(t *testing.T) {
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	tm2 := bytesToTime(b)
	if !tm.Equal(tm2) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm2.UTC(), tm.UTC())
	}
}
<|endoftext|>


<commit_before>package ipfs

import (
	"context"
	"errors"
	ipfs "github.com/ipfs/go-ipfs-api"
	"log"
	"strings"
)

var invalidErrorPrefixes = [...]string{
	"proto: required field",                // Example: QmYAqhbqNDpU7X9VW6FV5imtngQ3oBRY35zuDXduuZnyA8
	"proto: unixfs_pb.Data: illegal tag 0", // Example: QmQkaTUmqcdGAXKaFXpe8t8yaEDGHe7xGQJHcfihrzAFTj
	"unexpected EOF",                       // Example: QmdtMPULYK2xBVt2stYdAdxmuQukbJNFEgsdB5KV3jvsBq
	"unrecognized object type",             // Example: z43AaGEvwdfzjrCZ3Sq7DKxdDHrwoaPQDtqF4jfdkNEVTiqGVFW
	"not unixfs node",                      // Example: z8mWaJHXieAVxxLagBpdaNWFEBKVWmMiE
	"proto: can't skip unknown wire type",
	"failed to decode Protocol Buffers",
	"protobuf: (PBNode) invalid wireType",
	"protobuf: (PBNode) invalid fieldNumber",
	"proto: invalid field number",
	"proto: variable length integer overflow",
}

// isInvalidResourceErr determines whether an error returned by protocol methods represents invalid content.
func isInvalidResourceErr(err error) bool {
	if errors.Is(err, context.DeadlineExceeded) {
		// Timeouts are explicitly not protocol errors
		return false
	}

	ipfsErr, ok := err.(*ipfs.Error)

	if !ok {
		log.Printf("Unexpected protocol error: %T:%v", err, err)
		return false
	}

	for _, p := range invalidErrorPrefixes {
		if strings.HasPrefix(ipfsErr.Message, p) {
			// Known invalid.
			return true
		}
	}

	log.Printf("Unexpected *ipfs.Error: %v", ipfsErr.Message)

	return false
}
<commit_msg>Defuck weird character in error!?<commit_after>package ipfs

import (
	"context"
	"errors"
	"log"
	"strings"

	ipfs "github.com/ipfs/go-ipfs-api"
)

var invalidErrorPrefixes = [...]string{
	"proto: required field",                // Example: QmYAqhbqNDpU7X9VW6FV5imtngQ3oBRY35zuDXduuZnyA8
	"proto: unixfs_pb.Data: illegal tag 0", // Example: QmQkaTUmqcdGAXKaFXpe8t8yaEDGHe7xGQJHcfihrzAFTj
	"unexpected EOF",                       // Example: QmdtMPULYK2xBVt2stYdAdxmuQukbJNFEgsdB5KV3jvsBq
	"unrecognized object type",             // Example: z43AaGEvwdfzjrCZ3Sq7DKxdDHrwoaPQDtqF4jfdkNEVTiqGVFW
	"not unixfs node",                      // Example: z8mWaJHXieAVxxLagBpdaNWFEBKVWmMiE
	"proto: can't skip unknown wire type",
	"failed to decode Protocol Buffers",
	"protobuf: (PBNode) invalid wireType",
	"protobuf: (PBNode) invalid fieldNumber",
	"proto: invalid field number",
	"proto: invalid field number", // Thefuck
	"proto: variable length integer overflow",
}

// isInvalidResourceErr determines whether an error returned by protocol methods represents invalid content.
func isInvalidResourceErr(err error) bool {
	if errors.Is(err, context.DeadlineExceeded) {
		// Timeouts are explicitly not protocol errors
		return false
	}

	ipfsErr, ok := err.(*ipfs.Error)

	if !ok {
		log.Printf("Unexpected protocol error: %T:%v", err, err)
		return false
	}

	for _, p := range invalidErrorPrefixes {
		if strings.HasPrefix(ipfsErr.Message, p) {
			// Known invalid.
			return true
		}
	}

	log.Printf("Unexpected *ipfs.Error: %v", ipfsErr.Message)

	return false
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"go/build"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/spf13/cobra"
)

// newCmd represents the new command
var newCmd = &cobra.Command{
	Use:   "new",
	Short: "Create a new mercurius project",
	Long:  `Create a new mercurius project`,
	Run: func(cmd *cobra.Command, args []string) {
		// checking number of arguments
		if len(args) > 0 {
			fmt.Println("Too many arguments")
			os.Exit(-1)
		}
		initGoPaths()
		setApplicationPath()
		copyNewAppFiles(confValues())
		vendorize()
		packageStateCheck()
	},
}

const (
	mercuriusPath = "github.com/novatrixtech/mercurius"
	godepPath     = "github.com/tools/godep"
)

var (
	// go related paths
	gopath  string
	srcRoot string

	// mercurius related paths
	mercuriusPkg *build.Package
	appPath      string
	appName      string
	basePath     string
	importPath   string
	skeletonPath string
)

// lookup and set Go related variables
func initGoPaths() {
	// lookup go path
	gopath = build.Default.GOPATH
	if gopath == "" {
		fmt.Println("Abort: GOPATH environment variable is not set. " +
			"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
		os.Exit(-1)
	}

	// check for go executable
	var err error
	_, err = exec.LookPath("go")
	if err != nil {
		fmt.Println("Go executable not found in PATH.")
		os.Exit(-1)
	}

	//support relative path
	workingDir, _ := os.Getwd()
	goPathList := filepath.SplitList(gopath)
	for _, path := range goPathList {
		if strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
			srcRoot = path
			break
		}

		path, _ = filepath.EvalSymlinks(path)
		if len(path) > 0 && strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
			srcRoot = path
			break
		}
	}

	if len(srcRoot) == 0 {
		fmt.Println("Abort: could not create a Mercurius application outside of GOPATH.")
		os.Exit(-1)
	}

	// set go src path
	srcRoot = filepath.Join(srcRoot, "src")
}

func setApplicationPath() {
	var err error
	appName = terminal("What is your application name?", "")
	gitPath := terminal("What is your git or mercurial host?", "github.com")
	gitUser := terminal("What is your git or mercurial username?", "")

	//check if gitUser is not empty to put gitUser between slashes
	if gitUser != "" {
		gitUser = fmt.Sprintf("/%s", gitUser)
	}

	//build import path
	importPath = fmt.Sprintf("%s%s/%s", gitPath, gitUser, appName)

	//check if import path is valid
	if importPath == "" {
		fmt.Println("Abort: could not create a Mercurius application with empty application path.")
		os.Exit(-1)
	}

	// validate relative path, we cannot use built-in functions
	// since Go import path is valid relative path too.
	// so check basic part of the path, which is "."
	if filepath.IsAbs(importPath) || strings.HasPrefix(importPath, ".") {
		fmt.Printf("Abort: '%s' looks like a directory.  Please provide a Go import path instead.\n", importPath)
		os.Exit(-1)
	}

	_, err = build.Import(importPath, "", build.FindOnly)
	if err == nil {
		fmt.Printf("Alert: Import path %s already exists.\n", importPath)
	}

	mercuriusPkg, err = build.Import(mercuriusPath, "", build.FindOnly)
	if err != nil {
		fmt.Printf("Abort: Could not find Mercurius source code: %s\n", err)
		os.Exit(-1)
	}

	appPath = filepath.Join(srcRoot, filepath.FromSlash(importPath))
	basePath = filepath.ToSlash(filepath.Dir(importPath))

	if basePath == "." {
		// we need to remove the a single '.' when
		// the app is in the $GOROOT/src directory
		basePath = ""
	} else {
		// we need to append a '/' when the app is
		// is a subdirectory such as $GOROOT/src/path/to/mercurius
		basePath += "/"
	}
	// set base project path
	skeletonPath = filepath.Join(mercuriusPkg.Dir, "skeleton")
}

func copyNewAppFiles(cfgs map[string]interface{}) {
	var err error
	err = os.MkdirAll(appPath, 0777)
	if err != nil {
		fmt.Printf("Abort: Could not generate app %s\n", err)
		os.Exit(-1)
	}

	mustCopyDir(appPath, skeletonPath, cfgs)

	// Dotfiles are skipped by mustCopyDir, so we have to explicitly copy the .gitignore.
	gitignore := ".gitignore"
	mustCopyFile(filepath.Join(appPath, gitignore), filepath.Join(skeletonPath, gitignore))

}

func confValues() map[string]interface{} {
	// Define default value for cache types
	// See https://go-macaron.com/docs/middlewares/cache for details
	cacheMap := map[string]string{
		"memory":   "",
		"file":     "data/caches",
		"redis":    "addr=127.0.0.1:6379",
		"memcache": "127.0.0.1:11211",
	}

	// define configs
	cfgs := make(map[string]interface{})
	cfgs["AppPath"] = importPath
	cfgs["AppName"] = appName
	cfgs["DBType"] = terminal("What database do you want to use?", "mysql")
	cfgs["DBUser"] = terminal("What is your database user?", "root")
	cfgs["DBPw"] = terminal("What is your database password?", "")
	cfgs["DBName"] = terminal("What is your database name?", "")
	cfgs["DBHost"] = terminal("What is your database host?", "localhost")
	cfgs["DBPort"] = terminal("What is your database port?", "3306")
	cfgs["MaxConn"] = terminal("What is your database max connection pool?", "10")
	cfgs["IdleConn"] = terminal("What is your database idle connection pool?", "10")
	cache := terminal("What cache do you want to use?", "memory")
	cfgs["CacheType"] = cache
	cfgs["CacheCfgs"] = terminal("What is your cache server address?", cacheMap[cache])
	cfgs["Key"] = terminal("What is your oauth key (key size must be 24 or 32)?", "")
	cfgs["HttpPort"] = terminal("What is your HTTP port?", "8080")
	return cfgs
}

func packageStateCheck() {
	pkg := getGeneratedCode()

	cd(pkg.Dir)

	cmd := exec.Command("go", "build")
	out, _ := cmd.CombinedOutput()
	msg := string(out)
	fmt.Println(msg)
	if msg != "" {
		if runtime.GOOS == "windows" {
			cmd = exec.Command("rd", "/s", "/q", pkg.Dir)
		} else {
			cmd = exec.Command("rm", "-rf", pkg.Dir)
		}
		err := cmd.Run()
		if err != nil {
			fmt.Printf("Abort: %s\n", err)
			os.Exit(-1)
		}
	}

}

func getGeneratedCode() *build.Package {
	pkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		fmt.Printf("Abort: Could not find generated app: %s\n", err)
		os.Exit(-1)
	}
	return pkg
}

func getGodep() {
	_, err := build.Import(godepPath, "", build.FindOnly)
	if err != nil {
		cmd := exec.Command("go", "get", godepPath)
		err = cmd.Run()
		if err != nil {
			fmt.Printf("Abort: %s\n", err)
			os.Exit(-1)
		}
	}
}

func getDependencides() {
	cmd := exec.Command("go", "get", "./...")
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Abort: %s\n", err)
		os.Exit(-1)
	}
}

func vendorize() {
	getDependencides()
	getGodep()
	pkg := getGeneratedCode()

	cd(pkg.Dir)

	cmd := exec.Command("godep", "save")
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Abort: %s\n", err)
		os.Exit(-1)
	}
}

func cd(dir string) {
	err := os.Chdir(dir)
	if err != nil {
		fmt.Printf("Abort: %s\n", err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.AddCommand(newCmd)
}
<commit_msg>make vendorization optional<commit_after>package cmd

import (
	"fmt"

	"go/build"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/spf13/cobra"
)

// newCmd represents the new command
var newCmd = &cobra.Command{
	Use:   "new",
	Short: "Create a new mercurius project",
	Long:  `Create a new mercurius project`,
	Run: func(cmd *cobra.Command, args []string) {
		// checking number of arguments
		if len(args) > 0 {
			fmt.Println("Too many arguments")
			os.Exit(-1)
		}
		initGoPaths()
		setApplicationPath()
		copyNewAppFiles(confValues())
		vendorize()
		packageStateCheck()
	},
}

const (
	mercuriusPath = "github.com/novatrixtech/mercurius"
	godepPath     = "github.com/tools/godep"
)

var (
	// go related paths
	gopath  string
	srcRoot string

	// mercurius related paths
	mercuriusPkg *build.Package
	appPath      string
	appName      string
	basePath     string
	importPath   string
	skeletonPath string
)

// lookup and set Go related variables
func initGoPaths() {
	// lookup go path
	gopath = build.Default.GOPATH
	if gopath == "" {
		fmt.Println("Abort: GOPATH environment variable is not set. " +
			"Please refer to http://golang.org/doc/code.html to configure your Go environment.")
		os.Exit(-1)
	}

	// check for go executable
	var err error
	_, err = exec.LookPath("go")
	if err != nil {
		fmt.Println("Go executable not found in PATH.")
		os.Exit(-1)
	}

	//support relative path
	workingDir, _ := os.Getwd()
	goPathList := filepath.SplitList(gopath)
	for _, path := range goPathList {
		if strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
			srcRoot = path
			break
		}

		path, _ = filepath.EvalSymlinks(path)
		if len(path) > 0 && strings.HasPrefix(strings.ToLower(workingDir), strings.ToLower(path)) {
			srcRoot = path
			break
		}
	}

	if len(srcRoot) == 0 {
		fmt.Println("Abort: could not create a Mercurius application outside of GOPATH.")
		os.Exit(-1)
	}

	// set go src path
	srcRoot = filepath.Join(srcRoot, "src")
}

func setApplicationPath() {
	var err error
	appName = terminal("What is your application name?", "")
	gitPath := terminal("What is your git or mercurial host?", "github.com")
	gitUser := terminal("What is your git or mercurial username?", "")

	//check if gitUser is not empty to put gitUser between slashes
	if gitUser != "" {
		gitUser = fmt.Sprintf("/%s", gitUser)
	}

	//build import path
	importPath = fmt.Sprintf("%s%s/%s", gitPath, gitUser, appName)

	//check if import path is valid
	if importPath == "" {
		fmt.Println("Abort: could not create a Mercurius application with empty application path.")
		os.Exit(-1)
	}

	// validate relative path, we cannot use built-in functions
	// since Go import path is valid relative path too.
	// so check basic part of the path, which is "."
	if filepath.IsAbs(importPath) || strings.HasPrefix(importPath, ".") {
		fmt.Printf("Abort: '%s' looks like a directory.  Please provide a Go import path instead.\n", importPath)
		os.Exit(-1)
	}

	_, err = build.Import(importPath, "", build.FindOnly)
	if err == nil {
		fmt.Printf("Alert: Import path %s already exists.\n", importPath)
	}

	mercuriusPkg, err = build.Import(mercuriusPath, "", build.FindOnly)
	if err != nil {
		fmt.Printf("Abort: Could not find Mercurius source code: %s\n", err)
		os.Exit(-1)
	}

	appPath = filepath.Join(srcRoot, filepath.FromSlash(importPath))
	basePath = filepath.ToSlash(filepath.Dir(importPath))

	if basePath == "." {
		// we need to remove the a single '.' when
		// the app is in the $GOROOT/src directory
		basePath = ""
	} else {
		// we need to append a '/' when the app is
		// is a subdirectory such as $GOROOT/src/path/to/mercurius
		basePath += "/"
	}
	// set base project path
	skeletonPath = filepath.Join(mercuriusPkg.Dir, "skeleton")
}

func copyNewAppFiles(cfgs map[string]interface{}) {
	var err error
	err = os.MkdirAll(appPath, 0777)
	if err != nil {
		fmt.Printf("Abort: Could not generate app %s\n", err)
		os.Exit(-1)
	}

	mustCopyDir(appPath, skeletonPath, cfgs)

	// Dotfiles are skipped by mustCopyDir, so we have to explicitly copy the .gitignore.
	gitignore := ".gitignore"
	mustCopyFile(filepath.Join(appPath, gitignore), filepath.Join(skeletonPath, gitignore))

}

func confValues() map[string]interface{} {
	// Define default value for cache types
	// See https://go-macaron.com/docs/middlewares/cache for details
	cacheMap := map[string]string{
		"memory":   "",
		"file":     "data/caches",
		"redis":    "addr=127.0.0.1:6379",
		"memcache": "127.0.0.1:11211",
	}

	// define configs
	cfgs := make(map[string]interface{})
	cfgs["AppPath"] = importPath
	cfgs["AppName"] = appName
	cfgs["DBType"] = terminal("What database do you want to use?", "mysql")
	cfgs["DBUser"] = terminal("What is your database user?", "root")
	cfgs["DBPw"] = terminal("What is your database password?", "")
	cfgs["DBName"] = terminal("What is your database name?", "")
	cfgs["DBHost"] = terminal("What is your database host?", "localhost")
	cfgs["DBPort"] = terminal("What is your database port?", "3306")
	cfgs["MaxConn"] = terminal("What is your database max connection pool?", "10")
	cfgs["IdleConn"] = terminal("What is your database idle connection pool?", "10")
	cache := terminal("What cache do you want to use?", "memory")
	cfgs["CacheType"] = cache
	cfgs["CacheCfgs"] = terminal("What is your cache server address?", cacheMap[cache])
	cfgs["Key"] = terminal("What is your oauth key (key size must be 24 or 32)?", "")
	cfgs["HttpPort"] = terminal("What is your HTTP port?", "8080")
	return cfgs
}

func packageStateCheck() {
	pkg := getGeneratedCode()

	cd(pkg.Dir)

	cmd := exec.Command("go", "build")
	out, _ := cmd.CombinedOutput()
	msg := string(out)
	fmt.Println(msg)
	if msg != "" {
		if runtime.GOOS == "windows" {
			cmd = exec.Command("rd", "/s", "/q", pkg.Dir)
		} else {
			cmd = exec.Command("rm", "-rf", pkg.Dir)
		}
		err := cmd.Run()
		if err != nil {
			fmt.Printf("Abort: %s\n", err)
			os.Exit(-1)
		}
	}

}

func getGeneratedCode() *build.Package {
	pkg, err := build.Import(importPath, "", build.FindOnly)
	if err != nil {
		fmt.Printf("Abort: Could not find generated app: %s\n", err)
		os.Exit(-1)
	}
	return pkg
}

func getGodep() {
	_, err := build.Import(godepPath, "", build.FindOnly)
	if err != nil {
		cmd := exec.Command("go", "get", godepPath)
		err = cmd.Run()
		if err != nil {
			fmt.Printf("Abort: %s\n", err)
			os.Exit(-1)
		}
	}
}

func getDependencides() {
	cmd := exec.Command("go", "get", "./...")
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Abort: %s\n", err)
		os.Exit(-1)
	}
}

func vendorize() {
	v := terminal("Do you want vendorize your app using Godep?", "y")
	if v == "y" {
		getDependencides()
		getGodep()
		pkg := getGeneratedCode()

		cd(pkg.Dir)

		cmd := exec.Command("godep", "save")
		err := cmd.Run()
		if err != nil {
			fmt.Printf("Abort: %s\n", err)
			os.Exit(-1)
		}
		return
	}
	fmt.Println("vendorization skipped")
}

func cd(dir string) {
	err := os.Chdir(dir)
	if err != nil {
		fmt.Printf("Abort: %s\n", err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.AddCommand(newCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"html/template"
	"log"
	"os"

	"github.com/fatih/color"
)

var (
	configTmpl = `[app]
runMode = "dev"
name = "{{.AppName}}"
port = 18080

logProvider = "stdout"
logPath = "/tmp"
logRotate = true
logRotateType = "day"
logLimit = "100MB"

[mysql_manager]
init = true
ping = false

[redis_manager]
init = true
ping = false

[[mysql]]
name="master"
host="localhost"
port=3306
user="root"
db="test"
password=""
read_only=false

[[mysql]]
name="slave-01"
host="localhost"
port=3306
user="root"
db="test"
password=""
read_only=true

[redis]
host="localhost"
port= 6379
db = 0
ping = false
	`

	makefileTmpl = `# Ensure GOPATH is set before running build process.
ifeq "$(GOPATH)" ""
  $(error Please set the environment variable GOPATH before running 'make')
endif

CURDIR := $(shell pwd)
GO        := go
GOBUILD   := $(GO) build
GOTEST    := $(GO) test

OS        := "` + "`uname -s`" + `"
LINUX     := "Linux"
MAC       := "Darwin"
PACKAGES  := $$(go list ./...| grep -vE 'vendor|tests')
FILES     := $$(find . -name '*.go' | grep -vE 'vendor')
TARGET	  := "{{.AppName}}"
LDFLAGS   += -X "main.BuildTS=$(shell date -u '+%Y-%m-%d %I:%M:%S')"
LDFLAGS   += -X "main.GitHash=$(shell git rev-parse HEAD)"

test:
	$(GOTEST) $(PACKAGES) -cover

build:
	$(GOBUILD) -ldflags '$(LDFLAGS)' -o $(TARGET)

dev: test build

clean:
	rm $(TARGET)
	`

	mainTmpl = `
package main

import (
	"flag"

	"github.com/labstack/echo"
	"github.com/silentred/toolkit/service"
	svc "{{.SrcPath}}/{{.AppName}}/service"
)

var (
	GitHash = "None"
	BuildTS = "None"
)

func main() {
	flag.Parse()

	app := service.NewWebApp()
	app.RegisterHook(service.ConfigHook, initConfig)
	app.RegisterHook(service.RouterHook, initRoute)
	app.RegisterHook(service.ServiceHook, initService)
	app.Initialize()
	app.ListenAndServe()
}

func initConfig(app service.Application) error {
	return nil
}

func initService(app service.Application) error {
	// init hello service
	hello := &svc.HelloService{}
	app.Inject(hello)
	app.Set("hello", hello, nil)
	return nil
}

func initRoute(app service.Application) error {
	if web, ok := app.(service.WebApplication); ok {
		web.GetRouter().GET("/", func(ctx echo.Context) error {
			var ret = ctx.QueryParam("say")
			if ret == "" {
				ret = "Hello world"
			}
			if h, ok := web.Get("hello").(*svc.HelloService); ok {
				ret = h.SayHello(ret)
			}
			return ctx.String(200, ret)
		})
	}
	return nil
}
	`

	echoTmpl = `
package service

import (
	"fmt"

	"github.com/silentred/toolkit/service"
)

var (
	tmpl =` + "`" + `
( %s )
( )
 ,__, |    |
(oo)\\|    |___
(__)\\|    |   )\\_
      |    |_w |  \\
      |    |  ||   *

		Cower....` +
		"`" + `
)

type HelloService struct {
	WebApp service.WebApplication` + "`inject:\"app.web\"`" + `
}

func (h *HelloService) SayHello(thought string) string {
	return fmt.Sprintf(tmpl, thought)
}
	`
)

type file struct {
	path string
	data string
}

// RunNew runs new command
func RunNew(path, appName string) {
	gopath, has := os.LookupEnv("GOPATH")
	if !has {
		log.Fatal("Please set GOPATH first")
	}

	makeFiles(gopath, path, appName)

	color.Yellow("# Step2: run following commands to start the app")
	color.Blue("cd $GOPATH/%s/%s", path, appName)
	color.Blue("git init && git add * && git commit -m \"init commit\" ")
	color.Blue("go get github.com/labstack/echo")
	color.Blue("make build && ./%s", appName)
	color.Green("Have fun!")
}

func makeFiles(gopath, path, appName string) {
	var data = map[string]string{
		"SrcPath": path,
		"AppName": appName,
	}

	// file path -> template
	sources := map[string]*template.Template{}
	sources["Makefile"], _ = template.New("make").Parse(makefileTmpl)
	sources["config.toml"], _ = template.New("make").Parse(configTmpl)
	sources["main.go"], _ = template.New("make").Parse(mainTmpl)
	sources["service/echo.go"], _ = template.New("make").Parse(echoTmpl)

	appDir := fmt.Sprintf("%s/src/%s/%s", gopath, path, appName)
	dirs := []string{
		appDir,
		appDir + "/service",
	}
	for _, val := range dirs {
		err := os.MkdirAll(val, 0755|os.ModeSticky)
		if err != nil {
			log.Fatalf("create dir %s: %v", val, err)
		}
	}

	color.Yellow("# Step1: creating dirs and files")
	for key, val := range sources {
		path := fmt.Sprintf("%s/src/%s/%s/%s", gopath, path, appName, key)
		f, err := os.Create(path)
		if err != nil {
			log.Fatalf("create file %s: %v", path, err)
		}
		// log create file
		color.Blue("create file: %s", path)
		val.Execute(f, data)
	}

	color.Green("create file successful")
}
<commit_msg>fix cd path<commit_after>package cmd

import (
	"fmt"
	"html/template"
	"log"
	"os"

	"github.com/fatih/color"
)

var (
	configTmpl = `[app]
runMode = "dev"
name = "{{.AppName}}"
port = 18080

logProvider = "stdout"
logPath = "/tmp"
logRotate = true
logRotateType = "day"
logLimit = "100MB"

[mysql_manager]
init = true
ping = false

[redis_manager]
init = true
ping = false

[[mysql]]
name="master"
host="localhost"
port=3306
user="root"
db="test"
password=""
read_only=false

[[mysql]]
name="slave-01"
host="localhost"
port=3306
user="root"
db="test"
password=""
read_only=true

[redis]
host="localhost"
port= 6379
db = 0
ping = false
	`

	makefileTmpl = `# Ensure GOPATH is set before running build process.
ifeq "$(GOPATH)" ""
  $(error Please set the environment variable GOPATH before running 'make')
endif

CURDIR := $(shell pwd)
GO        := go
GOBUILD   := $(GO) build
GOTEST    := $(GO) test

OS        := "` + "`uname -s`" + `"
LINUX     := "Linux"
MAC       := "Darwin"
PACKAGES  := $$(go list ./...| grep -vE 'vendor|tests')
FILES     := $$(find . -name '*.go' | grep -vE 'vendor')
TARGET	  := "{{.AppName}}"
LDFLAGS   += -X "main.BuildTS=$(shell date -u '+%Y-%m-%d %I:%M:%S')"
LDFLAGS   += -X "main.GitHash=$(shell git rev-parse HEAD)"

test:
	$(GOTEST) $(PACKAGES) -cover

build:
	$(GOBUILD) -ldflags '$(LDFLAGS)' -o $(TARGET)

dev: test build

clean:
	rm $(TARGET)
	`

	mainTmpl = `
package main

import (
	"flag"

	"github.com/labstack/echo"
	"github.com/silentred/toolkit/service"
	svc "{{.SrcPath}}/{{.AppName}}/service"
)

var (
	GitHash = "None"
	BuildTS = "None"
)

func main() {
	flag.Parse()

	app := service.NewWebApp()
	app.RegisterHook(service.ConfigHook, initConfig)
	app.RegisterHook(service.RouterHook, initRoute)
	app.RegisterHook(service.ServiceHook, initService)
	app.Initialize()
	app.ListenAndServe()
}

func initConfig(app service.Application) error {
	return nil
}

func initService(app service.Application) error {
	// init hello service
	hello := &svc.HelloService{}
	app.Inject(hello)
	app.Set("hello", hello, nil)
	return nil
}

func initRoute(app service.Application) error {
	if web, ok := app.(service.WebApplication); ok {
		web.GetRouter().GET("/", func(ctx echo.Context) error {
			var ret = ctx.QueryParam("say")
			if ret == "" {
				ret = "Hello world"
			}
			if h, ok := web.Get("hello").(*svc.HelloService); ok {
				ret = h.SayHello(ret)
			}
			return ctx.String(200, ret)
		})
	}
	return nil
}
	`

	echoTmpl = `
package service

import (
	"fmt"

	"github.com/silentred/toolkit/service"
)

var (
	tmpl =` + "`" + `
( %s )
( )
 ,__, |    |
(oo)\\|    |___
(__)\\|    |   )\\_
      |    |_w |  \\
      |    |  ||   *

		Cower....` +
		"`" + `
)

type HelloService struct {
	WebApp service.WebApplication` + "`inject:\"app.web\"`" + `
}

func (h *HelloService) SayHello(thought string) string {
	return fmt.Sprintf(tmpl, thought)
}
	`
)

type file struct {
	path string
	data string
}

// RunNew runs new command
func RunNew(path, appName string) {
	gopath, has := os.LookupEnv("GOPATH")
	if !has {
		log.Fatal("Please set GOPATH first")
	}

	makeFiles(gopath, path, appName)

	color.Yellow("# Step2: run following commands to start the app")
	color.Blue("cd $GOPATH/src/%s/%s", path, appName)
	color.Blue("git init && git add * && git commit -m \"init commit\" ")
	color.Blue("go get github.com/labstack/echo")
	color.Blue("make build && ./%s", appName)
	color.Green("Have fun!")
}

func makeFiles(gopath, path, appName string) {
	var data = map[string]string{
		"SrcPath": path,
		"AppName": appName,
	}

	// file path -> template
	sources := map[string]*template.Template{}
	sources["Makefile"], _ = template.New("make").Parse(makefileTmpl)
	sources["config.toml"], _ = template.New("make").Parse(configTmpl)
	sources["main.go"], _ = template.New("make").Parse(mainTmpl)
	sources["service/echo.go"], _ = template.New("make").Parse(echoTmpl)

	appDir := fmt.Sprintf("%s/src/%s/%s", gopath, path, appName)
	dirs := []string{
		appDir,
		appDir + "/service",
	}
	for _, val := range dirs {
		err := os.MkdirAll(val, 0755|os.ModeSticky)
		if err != nil {
			log.Fatalf("create dir %s: %v", val, err)
		}
	}

	color.Yellow("# Step1: creating dirs and files")
	for key, val := range sources {
		path := fmt.Sprintf("%s/src/%s/%s/%s", gopath, path, appName, key)
		f, err := os.Create(path)
		if err != nil {
			log.Fatalf("create file %s: %v", path, err)
		}
		// log create file
		color.Blue("create file: %s", path)
		val.Execute(f, data)
	}

	color.Green("create file successful")
}
<|endoftext|>


<commit_before>/*----------------------------------------------------------------
 *  Copyright (c) ThoughtWorks, Inc.
 *  Licensed under the Apache License, Version 2.0
 *  See LICENSE in the project root for license information.
 *----------------------------------------------------------------*/

package cmd

import (
	"fmt"
	"os"
	"strconv"

	"github.com/getgauge/gauge/gauge"

	"strings"

	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/env"
	"github.com/getgauge/gauge/execution"
	"github.com/getgauge/gauge/execution/rerun"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

const (
	verboseDefault         = false
	simpleConsoleDefault   = false
	failedDefault          = false
	repeatDefault          = false
	parallelDefault        = false
	sortDefault            = false
	installPluginsDefault  = true
	environmentDefault     = "default"
	tagsDefault            = ""
	rowsDefault            = ""
	strategyDefault        = "lazy"
	onlyDefault            = ""
	groupDefault           = -1
	maxRetriesCountDefault = 1
	retryOnlyTagsDefault   = ""
	failSafeDefault        = false
	skipCommandSaveDefault = false

	verboseName         = "verbose"
	simpleConsoleName   = "simple-console"
	failedName          = "failed"
	repeatName          = "repeat"
	parallelName        = "parallel"
	sortName            = "sort"
	installPluginsName  = "install-plugins"
	environmentName     = "env"
	tagsName            = "tags"
	rowsName            = "table-rows"
	strategyName        = "strategy"
	groupName           = "group"
	maxRetriesCountName = "max-retries-count"
	retryOnlyTagsName   = "retry-only"
	streamsName         = "n"
	onlyName            = "only"
	failSafeName        = "fail-safe"
	skipCommandSaveName = "skip-save"
	scenarioName        = "scenario"
)

var overrideRerunFlags = []string{verboseName, simpleConsoleName, machineReadableName, dirName, logLevelName}
var streamsDefault = util.NumberOfCores()

var (
	runCmd = &cobra.Command{
		Use:   "run [flags] [args]",
		Short: "Run specs",
		Long:  `Run specs.`,
		Example: `  gauge run specs/
  gauge run --tags "login" -s -p specs/`,
		Run: func(cmd *cobra.Command, args []string) {
			logger.Debugf(true, "gauge %s %v", cmd.Name(), strings.Join(args, " "))
			if err := config.SetProjectRoot(args); err != nil {
				exit(err, cmd.UsageString())
			}
			if er := handleConflictingParams(cmd.Flags(), args); er != nil {
				exit(er, "")
			}
			if repeat {
				repeatLastExecution(cmd)
			} else if failed {
				executeFailed(cmd)
			} else {
				addFlagsToExecutionArgs(cmd.Flags())
				execute(cmd, args)
			}
		},
		DisableAutoGenTag: true,
	}
	verbose                    bool
	simpleConsole              bool
	failed                     bool
	repeat                     bool
	parallel                   bool
	sort                       bool
	installPlugins             bool
	environment                string
	tags                       string
	tagsToFilterForParallelRun string
	rows                       string
	strategy                   string
	streams                    int
	maxRetriesCount            int
	retryOnlyTags              string
	group                      int
	failSafe                   bool
	skipCommandSave            bool
	scenarios                  []string
	scenarioNameDefault        []string
)

func init() {
	GaugeCmd.AddCommand(runCmd)
	f := runCmd.Flags()
	f.BoolVarP(&verbose, verboseName, "v", verboseDefault, "Enable step level reporting on console, default being scenario level")
	f.BoolVarP(&simpleConsole, simpleConsoleName, "", simpleConsoleDefault, "Removes colouring and simplifies the console output")
	f.StringVarP(&environment, environmentName, "e", environmentDefault, "Specifies the environment to use")
	f.StringVarP(&tags, tagsName, "t", tagsDefault, "Executes the specs and scenarios tagged with given tags")
	f.StringVarP(&rows, rowsName, "r", rowsDefault, "Executes the specs and scenarios only for the selected rows. It can be specified by range as 2-4 or as list 2,4")
	f.BoolVarP(&parallel, parallelName, "p", parallelDefault, "Execute specs in parallel")
	f.IntVarP(&streams, streamsName, "n", streamsDefault, "Specify number of parallel execution streams")
	f.IntVarP(&maxRetriesCount, maxRetriesCountName, "c", maxRetriesCountDefault, "Max count of iterations for failed scenario")
	f.StringVarP(&retryOnlyTags, retryOnlyTagsName, "", retryOnlyTagsDefault, "Retries the specs and scenarios tagged with given tags")
	f.StringVarP(&tagsToFilterForParallelRun, onlyName, "o", onlyDefault, "Specify number of parallel execution streams")
	err := f.MarkHidden(onlyName)
	if err != nil {
		logger.Errorf(false, fmt.Sprintf("Unable to mark '%s' flag as hidden: %s", onlyName, err.Error()))
	}
	f.IntVarP(&group, groupName, "g", groupDefault, "Specify which group of specification to execute based on -n flag")
	f.StringVarP(&strategy, strategyName, "", strategyDefault, "Set the parallelization strategy for execution. Possible options are: `eager`, `lazy`")
	f.BoolVarP(&sort, sortName, "s", sortDefault, "Run specs in Alphabetical Order")
	f.BoolVarP(&installPlugins, installPluginsName, "i", installPluginsDefault, "Install All Missing Plugins")
	f.BoolVarP(&failed, failedName, "f", failedDefault, "Run only the scenarios failed in previous run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&repeat, repeatName, "", repeatDefault, "Repeat last run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&hideSuggestion, hideSuggestionName, "", hideSuggestionDefault, "Hide step implementation stub for every unimplemented step")
	f.BoolVarP(&failSafe, failSafeName, "", failSafeDefault, "Force return 0 exit code, even in case of failures.")
	f.BoolVarP(&skipCommandSave, skipCommandSaveName, "", skipCommandSaveDefault, "Skip saving last command in lastRunCmd.json")
	err = f.MarkHidden(skipCommandSaveName)
	if err != nil {
		logger.Errorf(false, fmt.Sprintf("Unable to mark '%s' flag as hidden: %s", skipCommandSaveName, err.Error()))
	}

	f.StringArrayVar(&scenarios, scenarioName, scenarioNameDefault, "Set scenarios for running specs with scenario name")
}

func executeFailed(cmd *cobra.Command) {
	lastState, err := rerun.GetLastFailedState()
	if err != nil {
		exit(err, "")
	}
	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	handleFlags(cmd, append([]string{"gauge"}, lastState...))
	err = cmd.Flags().Set(skipCommandSaveName, "true")
	if err != nil {
		logger.Errorf(false, fmt.Sprintf("Unable to set '%s' flag as 'true': %s", skipCommandSaveName, err.Error()))
	}
	logger.Debugf(true, "Executing => %s\n", strings.Join(os.Args, " "))
	err = cmd.Execute()
	if err != nil {
		logger.Errorf(true, fmt.Sprintf("Unable to execute command %s: %s", cmd.Name(), err.Error()))
	}
}

func handleFlags(cmd *cobra.Command, args []string) {
	cmd.Flags().Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.Changed {
			err := flag.Value.Set(flag.DefValue)
			if err != nil {
				logger.Errorf(false, fmt.Sprintf("Unable to set default value in '%s' flag: %s", flag.Name, err.Error()))
			}
		}
	})

	for i := 0; i <= len(args)-1; i++ {
		f := lookupFlagFromArgs(cmd, args[i])
		if f == nil {
			continue
		}
		v := f.Value.String()
		_, err := strconv.ParseBool(v)
		if err != nil && f.Changed {
			if strings.Contains(args[i], "=") {
				args[i] = strings.SplitAfter(args[i], "=")[0] + f.Value.String()
			} else {
				args[i+1] = v
				i = i + 1
			}
		}
	}
	os.Args = args
}

func lookupFlagFromArgs(cmd *cobra.Command, arg string) *pflag.Flag {
	fName := strings.Split(strings.TrimLeft(arg, "-"), "=")[0]
	flags := cmd.Flags()
	f := flags.Lookup(fName)
	if f == nil && len(fName) == 1 {
		f = flags.ShorthandLookup(fName)
	}
	return f
}

func addFlagsToExecutionArgs(flags *pflag.FlagSet) {
	flags.Visit(func(flag *pflag.Flag) {
		execution.ExecutionArgs = append(execution.ExecutionArgs, &gauge.ExecutionArg{
			Name:  flag.Name,
			Value: []string{flag.Value.String()},
		})
	})
}

func installMissingPlugins(flag, languageOnly bool) {
	if flag && os.Getenv("GAUGE_PLUGIN_INSTALL") != "false" {
		install.AllPlugins(machineReadable, languageOnly)
	}
}

func execute(cmd *cobra.Command, args []string) {
	for _, arg := range execution.ExecutionArgs {
		logger.Debugf(true, "%s : %v", arg.Name, arg.Value)
	}
	loadEnvAndReinitLogger(cmd)
	ensureScreenshotsDir()
	if parallel && tagsToFilterForParallelRun != "" && !env.AllowFilteredParallelExecution() {
		logger.Fatal(true, "Filtered parallel execution is a experimental feature. It can be enabled via allow_filtered_parallel_execution property.")
	}
	specs := getSpecsDir(args)
	rerun.SaveState(os.Args[1:], specs)

	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	installMissingPlugins(installPlugins, false)
	exitCode := execution.ExecuteSpecs(specs)
	if failSafe && exitCode != execution.ParseFailed {
		exitCode = 0
	}
	os.Exit(exitCode)
}

var repeatLastExecution = func(cmd *cobra.Command) {
	lastState := rerun.ReadPrevArgs()
	handleFlags(cmd, lastState)
	logger.Debugf(true, "Executing => %s\n", strings.Join(lastState, " "))
	err := cmd.Execute()
	if err != nil {
		logger.Errorf(true, fmt.Sprintf("Unable to execute command %s: %s", cmd.Name(), err.Error()))
	}
}

func handleConflictingParams(setFlags *pflag.FlagSet, args []string) error {
	flagDiffCount := 0
	setFlags.Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.DefValue != flag.Value.String() {
			flagDiffCount++
		}
	})
	if repeat && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --repeat")
	}
	if failed && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --failed")
	}
	if !parallel && tagsToFilterForParallelRun != "" {
		return fmt.Errorf("Invalid Command. flag --only can be used only with --parallel")
	}
	if maxRetriesCount == 1 && retryOnlyTags != "" {
		return fmt.Errorf("Invalid Command. flag --retry-only can be used only with --max-retry-count")
	}
	return nil
}
<commit_msg>fix help message for --only flag (#1716)<commit_after>/*----------------------------------------------------------------
 *  Copyright (c) ThoughtWorks, Inc.
 *  Licensed under the Apache License, Version 2.0
 *  See LICENSE in the project root for license information.
 *----------------------------------------------------------------*/

package cmd

import (
	"fmt"
	"os"
	"strconv"

	"github.com/getgauge/gauge/gauge"

	"strings"

	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/env"
	"github.com/getgauge/gauge/execution"
	"github.com/getgauge/gauge/execution/rerun"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

const (
	verboseDefault         = false
	simpleConsoleDefault   = false
	failedDefault          = false
	repeatDefault          = false
	parallelDefault        = false
	sortDefault            = false
	installPluginsDefault  = true
	environmentDefault     = "default"
	tagsDefault            = ""
	rowsDefault            = ""
	strategyDefault        = "lazy"
	onlyDefault            = ""
	groupDefault           = -1
	maxRetriesCountDefault = 1
	retryOnlyTagsDefault   = ""
	failSafeDefault        = false
	skipCommandSaveDefault = false

	verboseName         = "verbose"
	simpleConsoleName   = "simple-console"
	failedName          = "failed"
	repeatName          = "repeat"
	parallelName        = "parallel"
	sortName            = "sort"
	installPluginsName  = "install-plugins"
	environmentName     = "env"
	tagsName            = "tags"
	rowsName            = "table-rows"
	strategyName        = "strategy"
	groupName           = "group"
	maxRetriesCountName = "max-retries-count"
	retryOnlyTagsName   = "retry-only"
	streamsName         = "n"
	onlyName            = "only"
	failSafeName        = "fail-safe"
	skipCommandSaveName = "skip-save"
	scenarioName        = "scenario"
)

var overrideRerunFlags = []string{verboseName, simpleConsoleName, machineReadableName, dirName, logLevelName}
var streamsDefault = util.NumberOfCores()

var (
	runCmd = &cobra.Command{
		Use:   "run [flags] [args]",
		Short: "Run specs",
		Long:  `Run specs.`,
		Example: `  gauge run specs/
  gauge run --tags "login" -s -p specs/`,
		Run: func(cmd *cobra.Command, args []string) {
			logger.Debugf(true, "gauge %s %v", cmd.Name(), strings.Join(args, " "))
			if err := config.SetProjectRoot(args); err != nil {
				exit(err, cmd.UsageString())
			}
			if er := handleConflictingParams(cmd.Flags(), args); er != nil {
				exit(er, "")
			}
			if repeat {
				repeatLastExecution(cmd)
			} else if failed {
				executeFailed(cmd)
			} else {
				addFlagsToExecutionArgs(cmd.Flags())
				execute(cmd, args)
			}
		},
		DisableAutoGenTag: true,
	}
	verbose                    bool
	simpleConsole              bool
	failed                     bool
	repeat                     bool
	parallel                   bool
	sort                       bool
	installPlugins             bool
	environment                string
	tags                       string
	tagsToFilterForParallelRun string
	rows                       string
	strategy                   string
	streams                    int
	maxRetriesCount            int
	retryOnlyTags              string
	group                      int
	failSafe                   bool
	skipCommandSave            bool
	scenarios                  []string
	scenarioNameDefault        []string
)

func init() {
	GaugeCmd.AddCommand(runCmd)
	f := runCmd.Flags()
	f.BoolVarP(&verbose, verboseName, "v", verboseDefault, "Enable step level reporting on console, default being scenario level")
	f.BoolVarP(&simpleConsole, simpleConsoleName, "", simpleConsoleDefault, "Removes colouring and simplifies the console output")
	f.StringVarP(&environment, environmentName, "e", environmentDefault, "Specifies the environment to use")
	f.StringVarP(&tags, tagsName, "t", tagsDefault, "Executes the specs and scenarios tagged with given tags")
	f.StringVarP(&rows, rowsName, "r", rowsDefault, "Executes the specs and scenarios only for the selected rows. It can be specified by range as 2-4 or as list 2,4")
	f.BoolVarP(&parallel, parallelName, "p", parallelDefault, "Execute specs in parallel")
	f.IntVarP(&streams, streamsName, "n", streamsDefault, "Specify number of parallel execution streams")
	f.IntVarP(&maxRetriesCount, maxRetriesCountName, "c", maxRetriesCountDefault, "Max count of iterations for failed scenario")
	f.StringVarP(&retryOnlyTags, retryOnlyTagsName, "", retryOnlyTagsDefault, "Retries the specs and scenarios tagged with given tags")
	f.StringVarP(&tagsToFilterForParallelRun, onlyName, "o", onlyDefault, "Execute only the specs and scenarios tagged with given tags in parallel, rest will be run in serial. Applicable only if run in parallel.")
	err := f.MarkHidden(onlyName)
	if err != nil {
		logger.Errorf(false, fmt.Sprintf("Unable to mark '%s' flag as hidden: %s", onlyName, err.Error()))
	}
	f.IntVarP(&group, groupName, "g", groupDefault, "Specify which group of specification to execute based on -n flag")
	f.StringVarP(&strategy, strategyName, "", strategyDefault, "Set the parallelization strategy for execution. Possible options are: `eager`, `lazy`")
	f.BoolVarP(&sort, sortName, "s", sortDefault, "Run specs in Alphabetical Order")
	f.BoolVarP(&installPlugins, installPluginsName, "i", installPluginsDefault, "Install All Missing Plugins")
	f.BoolVarP(&failed, failedName, "f", failedDefault, "Run only the scenarios failed in previous run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&repeat, repeatName, "", repeatDefault, "Repeat last run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&hideSuggestion, hideSuggestionName, "", hideSuggestionDefault, "Hide step implementation stub for every unimplemented step")
	f.BoolVarP(&failSafe, failSafeName, "", failSafeDefault, "Force return 0 exit code, even in case of failures.")
	f.BoolVarP(&skipCommandSave, skipCommandSaveName, "", skipCommandSaveDefault, "Skip saving last command in lastRunCmd.json")
	err = f.MarkHidden(skipCommandSaveName)
	if err != nil {
		logger.Errorf(false, fmt.Sprintf("Unable to mark '%s' flag as hidden: %s", skipCommandSaveName, err.Error()))
	}

	f.StringArrayVar(&scenarios, scenarioName, scenarioNameDefault, "Set scenarios for running specs with scenario name")
}

func executeFailed(cmd *cobra.Command) {
	lastState, err := rerun.GetLastFailedState()
	if err != nil {
		exit(err, "")
	}
	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	handleFlags(cmd, append([]string{"gauge"}, lastState...))
	err = cmd.Flags().Set(skipCommandSaveName, "true")
	if err != nil {
		logger.Errorf(false, fmt.Sprintf("Unable to set '%s' flag as 'true': %s", skipCommandSaveName, err.Error()))
	}
	logger.Debugf(true, "Executing => %s\n", strings.Join(os.Args, " "))
	err = cmd.Execute()
	if err != nil {
		logger.Errorf(true, fmt.Sprintf("Unable to execute command %s: %s", cmd.Name(), err.Error()))
	}
}

func handleFlags(cmd *cobra.Command, args []string) {
	cmd.Flags().Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.Changed {
			err := flag.Value.Set(flag.DefValue)
			if err != nil {
				logger.Errorf(false, fmt.Sprintf("Unable to set default value in '%s' flag: %s", flag.Name, err.Error()))
			}
		}
	})

	for i := 0; i <= len(args)-1; i++ {
		f := lookupFlagFromArgs(cmd, args[i])
		if f == nil {
			continue
		}
		v := f.Value.String()
		_, err := strconv.ParseBool(v)
		if err != nil && f.Changed {
			if strings.Contains(args[i], "=") {
				args[i] = strings.SplitAfter(args[i], "=")[0] + f.Value.String()
			} else {
				args[i+1] = v
				i = i + 1
			}
		}
	}
	os.Args = args
}

func lookupFlagFromArgs(cmd *cobra.Command, arg string) *pflag.Flag {
	fName := strings.Split(strings.TrimLeft(arg, "-"), "=")[0]
	flags := cmd.Flags()
	f := flags.Lookup(fName)
	if f == nil && len(fName) == 1 {
		f = flags.ShorthandLookup(fName)
	}
	return f
}

func addFlagsToExecutionArgs(flags *pflag.FlagSet) {
	flags.Visit(func(flag *pflag.Flag) {
		execution.ExecutionArgs = append(execution.ExecutionArgs, &gauge.ExecutionArg{
			Name:  flag.Name,
			Value: []string{flag.Value.String()},
		})
	})
}

func installMissingPlugins(flag, languageOnly bool) {
	if flag && os.Getenv("GAUGE_PLUGIN_INSTALL") != "false" {
		install.AllPlugins(machineReadable, languageOnly)
	}
}

func execute(cmd *cobra.Command, args []string) {
	for _, arg := range execution.ExecutionArgs {
		logger.Debugf(true, "%s : %v", arg.Name, arg.Value)
	}
	loadEnvAndReinitLogger(cmd)
	ensureScreenshotsDir()
	if parallel && tagsToFilterForParallelRun != "" && !env.AllowFilteredParallelExecution() {
		logger.Fatal(true, "Filtered parallel execution is a experimental feature. It can be enabled via allow_filtered_parallel_execution property.")
	}
	specs := getSpecsDir(args)
	rerun.SaveState(os.Args[1:], specs)

	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	installMissingPlugins(installPlugins, false)
	exitCode := execution.ExecuteSpecs(specs)
	if failSafe && exitCode != execution.ParseFailed {
		exitCode = 0
	}
	os.Exit(exitCode)
}

var repeatLastExecution = func(cmd *cobra.Command) {
	lastState := rerun.ReadPrevArgs()
	handleFlags(cmd, lastState)
	logger.Debugf(true, "Executing => %s\n", strings.Join(lastState, " "))
	err := cmd.Execute()
	if err != nil {
		logger.Errorf(true, fmt.Sprintf("Unable to execute command %s: %s", cmd.Name(), err.Error()))
	}
}

func handleConflictingParams(setFlags *pflag.FlagSet, args []string) error {
	flagDiffCount := 0
	setFlags.Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.DefValue != flag.Value.String() {
			flagDiffCount++
		}
	})
	if repeat && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --repeat")
	}
	if failed && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --failed")
	}
	if !parallel && tagsToFilterForParallelRun != "" {
		return fmt.Errorf("Invalid Command. flag --only can be used only with --parallel")
	}
	if maxRetriesCount == 1 && retryOnlyTags != "" {
		return fmt.Errorf("Invalid Command. flag --retry-only can be used only with --max-retry-count")
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"fmt"
	"os"
	"strconv"

	"github.com/getgauge/gauge/gauge"

	"strings"

	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/env"
	"github.com/getgauge/gauge/execution"
	"github.com/getgauge/gauge/execution/rerun"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

const (
	verboseDefault         = false
	simpleConsoleDefault   = false
	failedDefault          = false
	repeatDefault          = false
	parallelDefault        = false
	sortDefault            = false
	installPluginsDefault  = true
	environmentDefault     = "default"
	tagsDefault            = ""
	rowsDefault            = ""
	strategyDefault        = "lazy"
	onlyDefault            = ""
	groupDefault           = -1
	maxRetriesCountDefault = 1
	retryOnlyTagsDefault   = ""
	failSafeDefault        = false
	skipCommandSaveDefault = false

	verboseName         = "verbose"
	simpleConsoleName   = "simple-console"
	failedName          = "failed"
	repeatName          = "repeat"
	parallelName        = "parallel"
	sortName            = "sort"
	installPluginsName  = "install-plugins"
	environmentName     = "env"
	tagsName            = "tags"
	rowsName            = "table-rows"
	strategyName        = "strategy"
	groupName           = "group"
	maxRetriesCountName = "max-retries-count"
	retryOnlyTagsName   = "retry-only"
	streamsName         = "n"
	onlyName            = "only"
	failSafeName        = "fail-safe"
	skipCommandSaveName = "skip-save"
	scenarioName        = "scenario"
)

var overrideRerunFlags = []string{verboseName, simpleConsoleName, machineReadableName, dirName, logLevelName}
var streamsDefault = util.NumberOfCores()

var (
	runCmd = &cobra.Command{
		Use:   "run [flags] [args]",
		Short: "Run specs",
		Long:  `Run specs.`,
		Example: `  gauge run specs/
  gauge run --tags "login" -s -p specs/`,
		Run: func(cmd *cobra.Command, args []string) {
			if err := config.SetProjectRoot(args); err != nil {
				exit(err, cmd.UsageString())
			}
			if er := handleConflictingParams(cmd.Flags(), args); er != nil {
				exit(er, "")
			}
			if repeat {
				repeatLastExecution(cmd)
			} else if failed {
				executeFailed(cmd)
			} else {
				addFlagsToExecutionArgs(cmd.Flags())
				execute(cmd, args)
			}
		},
		DisableAutoGenTag: true,
	}
	verbose                    bool
	simpleConsole              bool
	failed                     bool
	repeat                     bool
	parallel                   bool
	sort                       bool
	installPlugins             bool
	environment                string
	tags                       string
	tagsToFilterForParallelRun string
	rows                       string
	strategy                   string
	streams                    int
	maxRetriesCount            int
	retryOnlyTags              string
	group                      int
	failSafe                   bool
	skipCommandSave            bool
	scenarios                  []string
	scenarioNameDefault        []string
)

func init() {
	GaugeCmd.AddCommand(runCmd)
	f := runCmd.Flags()
	f.BoolVarP(&verbose, verboseName, "v", verboseDefault, "Enable step level reporting on console, default being scenario level")
	f.BoolVarP(&simpleConsole, simpleConsoleName, "", simpleConsoleDefault, "Removes colouring and simplifies the console output")
	f.StringVarP(&environment, environmentName, "e", environmentDefault, "Specifies the environment to use")
	f.StringVarP(&tags, tagsName, "t", tagsDefault, "Executes the specs and scenarios tagged with given tags")
	f.StringVarP(&rows, rowsName, "r", rowsDefault, "Executes the specs and scenarios only for the selected rows. It can be specified by range as 2-4 or as list 2,4")
	f.BoolVarP(&parallel, parallelName, "p", parallelDefault, "Execute specs in parallel")
	f.IntVarP(&streams, streamsName, "n", streamsDefault, "Specify number of parallel execution streams")
	f.IntVarP(&maxRetriesCount, maxRetriesCountName, "c", maxRetriesCountDefault, "Max count of iterations for failed scenario")
	f.StringVarP(&retryOnlyTags, retryOnlyTagsName, "", retryOnlyTagsDefault, "Retries the specs and scenarios tagged with given tags")
	f.StringVarP(&tagsToFilterForParallelRun, onlyName, "o", onlyDefault, "Specify number of parallel execution streams")
	f.MarkHidden(onlyName)
	f.IntVarP(&group, groupName, "g", groupDefault, "Specify which group of specification to execute based on -n flag")
	f.StringVarP(&strategy, strategyName, "", strategyDefault, "Set the parallelization strategy for execution. Possible options are: `eager`, `lazy`")
	f.BoolVarP(&sort, sortName, "s", sortDefault, "Run specs in Alphabetical Order")
	f.BoolVarP(&installPlugins, installPluginsName, "i", installPluginsDefault, "Install All Missing Plugins")
	f.BoolVarP(&failed, failedName, "f", failedDefault, "Run only the scenarios failed in previous run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&repeat, repeatName, "", repeatDefault, "Repeat last run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&hideSuggestion, hideSuggestionName, "", hideSuggestionDefault, "Prints a step implementation stub for every unimplemented step")
	f.BoolVarP(&failSafe, failSafeName, "", failSafeDefault, "Force return 0 exit code, even in case of failures.")
	f.BoolVarP(&skipCommandSave, skipCommandSaveName, "", skipCommandSaveDefault, "Skip saving last command in lastRunCmd.json")
	f.MarkHidden(skipCommandSaveName)
	f.StringArrayVar(&scenarios, scenarioName, scenarioNameDefault, "Set scenarios for running specs with scenario name")
}

func executeFailed(cmd *cobra.Command) {
	lastState, err := rerun.GetLastFailedState()
	if err != nil {
		exit(err, "")
	}
	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	handleFlags(cmd, append([]string{"gauge"}, lastState...))
	cmd.Flags().Set(skipCommandSaveName, "true")
	logger.Debugf(true, "Executing => %s\n", strings.Join(os.Args, " "))
	cmd.Execute()
}

func handleFlags(cmd *cobra.Command, args []string) {
	cmd.Flags().Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.Changed {
			flag.Value.Set(flag.DefValue)
		}
	})

	for i := 0; i <= len(args)-1; i++ {
		f := lookupFlagFromArgs(cmd, args[i])
		if f == nil {
			continue
		}
		v := f.Value.String()
		_, err := strconv.ParseBool(v)
		if err != nil && f.Changed {
			if strings.Contains(args[i], "=") {
				args[i] = strings.SplitAfter(args[i], "=")[0] + f.Value.String()
			} else {
				args[i+1] = v
				i = i + 1
			}
		}
	}
	os.Args = args
}

func lookupFlagFromArgs(cmd *cobra.Command, arg string) *pflag.Flag {
	fName := strings.Split(strings.TrimLeft(arg, "-"), "=")[0]
	flags := cmd.Flags()
	f := flags.Lookup(fName)
	if f == nil && len(fName) == 1 {
		f = flags.ShorthandLookup(fName)
	}
	return f
}

func addFlagsToExecutionArgs(flags *pflag.FlagSet) {
	flags.Visit(func(flag *pflag.Flag) {
		execution.ExecutionArgs = append(execution.ExecutionArgs, &gauge.ExecutionArg{
			Name:  flag.Name,
			Value: []string{flag.Value.String()},
		})
	})
}

func installMissingPlugins(flag, languageOnly bool) {
	if flag && os.Getenv("GAUGE_PLUGIN_INSTALL") != "false" {
		install.AllPlugins(machineReadable, languageOnly)
	}
}

func execute(cmd *cobra.Command, args []string) {
	loadEnvAndReinitLogger(cmd)
	if parallel && tagsToFilterForParallelRun != "" && !env.AllowFilteredParallelExecution() {
		logger.Fatal(true, "Filtered parallel execution is a experimental feature. It can be enabled via allow_filtered_parallel_execution property.")
	}
	specs := getSpecsDir(args)
	rerun.SaveState(os.Args[1:], specs)

	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	installMissingPlugins(installPlugins, false)
	exitCode := execution.ExecuteSpecs(specs)
	if failSafe && exitCode != execution.ParseFailed {
		exitCode = 0
	}
	os.Exit(exitCode)
}

var repeatLastExecution = func(cmd *cobra.Command) {
	lastState := rerun.ReadPrevArgs()
	handleFlags(cmd, lastState)
	logger.Debugf(true, "Executing => %s\n", strings.Join(lastState, " "))
	cmd.Execute()
}

func handleConflictingParams(setFlags *pflag.FlagSet, args []string) error {
	flagDiffCount := 0
	setFlags.Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.DefValue != flag.Value.String() {
			flagDiffCount++
		}
	})
	if repeat && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --repeat")
	}
	if failed && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --failed")
	}
	if !parallel && tagsToFilterForParallelRun != "" {
		return fmt.Errorf("Invalid Command. flag --only can be used only with --parallel")
	}
	if maxRetriesCount == 1 && retryOnlyTags != "" {
		return fmt.Errorf("Invalid Command. flag --retry-only can be used only with --max-retry-count")
	}
	return nil
}
<commit_msg>changed --hide-suggestion information #1469<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"fmt"
	"os"
	"strconv"

	"github.com/getgauge/gauge/gauge"

	"strings"

	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/env"
	"github.com/getgauge/gauge/execution"
	"github.com/getgauge/gauge/execution/rerun"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

const (
	verboseDefault         = false
	simpleConsoleDefault   = false
	failedDefault          = false
	repeatDefault          = false
	parallelDefault        = false
	sortDefault            = false
	installPluginsDefault  = true
	environmentDefault     = "default"
	tagsDefault            = ""
	rowsDefault            = ""
	strategyDefault        = "lazy"
	onlyDefault            = ""
	groupDefault           = -1
	maxRetriesCountDefault = 1
	retryOnlyTagsDefault   = ""
	failSafeDefault        = false
	skipCommandSaveDefault = false

	verboseName         = "verbose"
	simpleConsoleName   = "simple-console"
	failedName          = "failed"
	repeatName          = "repeat"
	parallelName        = "parallel"
	sortName            = "sort"
	installPluginsName  = "install-plugins"
	environmentName     = "env"
	tagsName            = "tags"
	rowsName            = "table-rows"
	strategyName        = "strategy"
	groupName           = "group"
	maxRetriesCountName = "max-retries-count"
	retryOnlyTagsName   = "retry-only"
	streamsName         = "n"
	onlyName            = "only"
	failSafeName        = "fail-safe"
	skipCommandSaveName = "skip-save"
	scenarioName        = "scenario"
)

var overrideRerunFlags = []string{verboseName, simpleConsoleName, machineReadableName, dirName, logLevelName}
var streamsDefault = util.NumberOfCores()

var (
	runCmd = &cobra.Command{
		Use:   "run [flags] [args]",
		Short: "Run specs",
		Long:  `Run specs.`,
		Example: `  gauge run specs/
  gauge run --tags "login" -s -p specs/`,
		Run: func(cmd *cobra.Command, args []string) {
			if err := config.SetProjectRoot(args); err != nil {
				exit(err, cmd.UsageString())
			}
			if er := handleConflictingParams(cmd.Flags(), args); er != nil {
				exit(er, "")
			}
			if repeat {
				repeatLastExecution(cmd)
			} else if failed {
				executeFailed(cmd)
			} else {
				addFlagsToExecutionArgs(cmd.Flags())
				execute(cmd, args)
			}
		},
		DisableAutoGenTag: true,
	}
	verbose                    bool
	simpleConsole              bool
	failed                     bool
	repeat                     bool
	parallel                   bool
	sort                       bool
	installPlugins             bool
	environment                string
	tags                       string
	tagsToFilterForParallelRun string
	rows                       string
	strategy                   string
	streams                    int
	maxRetriesCount            int
	retryOnlyTags              string
	group                      int
	failSafe                   bool
	skipCommandSave            bool
	scenarios                  []string
	scenarioNameDefault        []string
)

func init() {
	GaugeCmd.AddCommand(runCmd)
	f := runCmd.Flags()
	f.BoolVarP(&verbose, verboseName, "v", verboseDefault, "Enable step level reporting on console, default being scenario level")
	f.BoolVarP(&simpleConsole, simpleConsoleName, "", simpleConsoleDefault, "Removes colouring and simplifies the console output")
	f.StringVarP(&environment, environmentName, "e", environmentDefault, "Specifies the environment to use")
	f.StringVarP(&tags, tagsName, "t", tagsDefault, "Executes the specs and scenarios tagged with given tags")
	f.StringVarP(&rows, rowsName, "r", rowsDefault, "Executes the specs and scenarios only for the selected rows. It can be specified by range as 2-4 or as list 2,4")
	f.BoolVarP(&parallel, parallelName, "p", parallelDefault, "Execute specs in parallel")
	f.IntVarP(&streams, streamsName, "n", streamsDefault, "Specify number of parallel execution streams")
	f.IntVarP(&maxRetriesCount, maxRetriesCountName, "c", maxRetriesCountDefault, "Max count of iterations for failed scenario")
	f.StringVarP(&retryOnlyTags, retryOnlyTagsName, "", retryOnlyTagsDefault, "Retries the specs and scenarios tagged with given tags")
	f.StringVarP(&tagsToFilterForParallelRun, onlyName, "o", onlyDefault, "Specify number of parallel execution streams")
	f.MarkHidden(onlyName)
	f.IntVarP(&group, groupName, "g", groupDefault, "Specify which group of specification to execute based on -n flag")
	f.StringVarP(&strategy, strategyName, "", strategyDefault, "Set the parallelization strategy for execution. Possible options are: `eager`, `lazy`")
	f.BoolVarP(&sort, sortName, "s", sortDefault, "Run specs in Alphabetical Order")
	f.BoolVarP(&installPlugins, installPluginsName, "i", installPluginsDefault, "Install All Missing Plugins")
	f.BoolVarP(&failed, failedName, "f", failedDefault, "Run only the scenarios failed in previous run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&repeat, repeatName, "", repeatDefault, "Repeat last run. This cannot be used in conjunction with any other argument")
	f.BoolVarP(&hideSuggestion, hideSuggestionName, "", hideSuggestionDefault, "Hide step implementation stub for every unimplemented step")
	f.BoolVarP(&failSafe, failSafeName, "", failSafeDefault, "Force return 0 exit code, even in case of failures.")
	f.BoolVarP(&skipCommandSave, skipCommandSaveName, "", skipCommandSaveDefault, "Skip saving last command in lastRunCmd.json")
	f.MarkHidden(skipCommandSaveName)
	f.StringArrayVar(&scenarios, scenarioName, scenarioNameDefault, "Set scenarios for running specs with scenario name")
}

func executeFailed(cmd *cobra.Command) {
	lastState, err := rerun.GetLastFailedState()
	if err != nil {
		exit(err, "")
	}
	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	handleFlags(cmd, append([]string{"gauge"}, lastState...))
	cmd.Flags().Set(skipCommandSaveName, "true")
	logger.Debugf(true, "Executing => %s\n", strings.Join(os.Args, " "))
	cmd.Execute()
}

func handleFlags(cmd *cobra.Command, args []string) {
	cmd.Flags().Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.Changed {
			flag.Value.Set(flag.DefValue)
		}
	})

	for i := 0; i <= len(args)-1; i++ {
		f := lookupFlagFromArgs(cmd, args[i])
		if f == nil {
			continue
		}
		v := f.Value.String()
		_, err := strconv.ParseBool(v)
		if err != nil && f.Changed {
			if strings.Contains(args[i], "=") {
				args[i] = strings.SplitAfter(args[i], "=")[0] + f.Value.String()
			} else {
				args[i+1] = v
				i = i + 1
			}
		}
	}
	os.Args = args
}

func lookupFlagFromArgs(cmd *cobra.Command, arg string) *pflag.Flag {
	fName := strings.Split(strings.TrimLeft(arg, "-"), "=")[0]
	flags := cmd.Flags()
	f := flags.Lookup(fName)
	if f == nil && len(fName) == 1 {
		f = flags.ShorthandLookup(fName)
	}
	return f
}

func addFlagsToExecutionArgs(flags *pflag.FlagSet) {
	flags.Visit(func(flag *pflag.Flag) {
		execution.ExecutionArgs = append(execution.ExecutionArgs, &gauge.ExecutionArg{
			Name:  flag.Name,
			Value: []string{flag.Value.String()},
		})
	})
}

func installMissingPlugins(flag, languageOnly bool) {
	if flag && os.Getenv("GAUGE_PLUGIN_INSTALL") != "false" {
		install.AllPlugins(machineReadable, languageOnly)
	}
}

func execute(cmd *cobra.Command, args []string) {
	loadEnvAndReinitLogger(cmd)
	if parallel && tagsToFilterForParallelRun != "" && !env.AllowFilteredParallelExecution() {
		logger.Fatal(true, "Filtered parallel execution is a experimental feature. It can be enabled via allow_filtered_parallel_execution property.")
	}
	specs := getSpecsDir(args)
	rerun.SaveState(os.Args[1:], specs)

	if !skipCommandSave {
		rerun.WritePrevArgs(os.Args)
	}
	installMissingPlugins(installPlugins, false)
	exitCode := execution.ExecuteSpecs(specs)
	if failSafe && exitCode != execution.ParseFailed {
		exitCode = 0
	}
	os.Exit(exitCode)
}

var repeatLastExecution = func(cmd *cobra.Command) {
	lastState := rerun.ReadPrevArgs()
	handleFlags(cmd, lastState)
	logger.Debugf(true, "Executing => %s\n", strings.Join(lastState, " "))
	cmd.Execute()
}

func handleConflictingParams(setFlags *pflag.FlagSet, args []string) error {
	flagDiffCount := 0
	setFlags.Visit(func(flag *pflag.Flag) {
		if !util.ListContains(overrideRerunFlags, flag.Name) && flag.DefValue != flag.Value.String() {
			flagDiffCount++
		}
	})
	if repeat && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --repeat")
	}
	if failed && len(args)+flagDiffCount > 1 {
		return fmt.Errorf("Invalid Command. Usage: gauge run --failed")
	}
	if !parallel && tagsToFilterForParallelRun != "" {
		return fmt.Errorf("Invalid Command. flag --only can be used only with --parallel")
	}
	if maxRetriesCount == 1 && retryOnlyTags != "" {
		return fmt.Errorf("Invalid Command. flag --retry-only can be used only with --max-retry-count")
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright 2016, 2017 zebra project.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sysrib

import (
	"context"
	"net"
	"syscall"
	"testing"
	"time"

	"github.com/coreswitch/netutil"
	"github.com/openconfig/lemming/gnmi"
	pb "github.com/openconfig/lemming/proto/sysrib"
	"github.com/openconfig/ygnmi/ygnmi"
	"github.com/wenovus/gobgp/v3/pkg/zebra"
	"google.golang.org/grpc"
)

func SendMessage(t *testing.T, conn net.Conn, msg *zebra.Message) error {
	s, err := msg.Serialize(zebra.MaxSoftware)
	if err != nil {
		return err
	}
	n, err := conn.Write(s)
	t.Logf("SendMessage: %d bytes written", n)
	return err
}

func Dial() (net.Conn, error) {
	conn, err := net.Dial("unix", "/tmp/zserv.api")
	if err != nil {
		return nil, err
	}
	return conn, err
}

func ZAPIServerStart(t *testing.T) *ZServer {
	t.Helper()
	dp := NewFakeDataplane()
	sysribServer, err := New(dp)
	if err != nil {
		t.Fatal(err)
	}

	s, err := ZServerStart("unix", "/tmp/zserv.api", 0, sysribServer)
	if err != nil {
		t.Fatal(err)
	}
	return s
}

func TestZServer(t *testing.T) {
	// Need to test these serially since they all use the same UDS address.
	testHello(t)
	testRouteAdd(t)
	testRouteRedistribution(t, true)
	testRouteRedistribution(t, false)
}

func testHello(t *testing.T) {
	s := ZAPIServerStart(t)
	defer s.Stop()

	conn, err := Dial()
	if err != nil {
		t.Errorf("Dial failed %v\n", err)
		return
	}
	defer conn.Close()

	serverVersion := zebra.MaxZapiVer
	serverSoftware := zebra.MaxSoftware
	msg := zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(serverVersion),
			Marker:  zebra.HeaderMarker(serverVersion),
			Version: serverVersion,
			Command: zebra.Hello.ToEach(serverVersion, serverSoftware),
		},
		Body: &zebra.HelloBody{},
	}
	if err := SendMessage(t, conn, &msg); err != nil {
		t.Error(err)
	}
}

func testRouteAdd(t *testing.T) {
	s := ZAPIServerStart(t)
	defer s.Stop()

	conn, err := Dial()
	if err != nil {
		t.Errorf("Dial failed %v\n", err)
		return
	}
	defer conn.Close()

	addr := netutil.ParseIPv4("10.0.0.0")
	body := &zebra.IPRouteBody{Prefix: zebra.Prefix{
		Family:    syscall.AF_INET,
		PrefixLen: 24,
		Prefix:    addr,
	}}

	serverVersion := zebra.MaxZapiVer
	serverSoftware := zebra.MaxSoftware
	helloMsg := zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(serverVersion),
			Marker:  zebra.HeaderMarker(serverVersion),
			Version: serverVersion,
			Command: zebra.Hello.ToEach(serverVersion, serverSoftware),
		},
		Body: &zebra.HelloBody{},
	}
	if err := SendMessage(t, conn, &helloMsg); err != nil {
		t.Error(err)
	}

	msg := zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(serverVersion),
			Marker:  zebra.HeaderMarker(serverVersion),
			Version: serverVersion,
			Command: zebra.RouteAdd.ToEach(serverVersion, serverSoftware),
		},
		Body: body,
	}
	if err := SendMessage(t, conn, &msg); err != nil {
		t.Error(err)
	}
}

func testRouteRedistribution(t *testing.T, routeReadyBeforeDial bool) {
	dp := NewFakeDataplane()
	s, err := New(dp)
	if err != nil {
		t.Fatal(err)
	}

	grpcServer := grpc.NewServer()
	gnmiServer, err := gnmi.New(grpcServer, "local")
	if err != nil {
		t.Fatal(err)
	}
	client := gnmiServer.LocalClient()
	if err := s.Start(client, "local", "unix:/tmp/zserv.api"); err != nil {
		t.Fatalf("cannot start sysrib server, %v", err)
	}
	defer s.Stop()

	c, err := ygnmi.NewClient(client, ygnmi.WithTarget("local"))
	if err != nil {
		t.Fatalf("cannot create ygnmi client: %v", err)
	}
	configureInterface(t, AddIntfAction{
		name:    "eth0",
		ifindex: 0,
		enabled: true,
		prefix:  "192.168.1.1/24",
		niName:  "DEFAULT",
	}, c)

	routeReq := &pb.SetRouteRequest{
		AdminDistance: 10,
		Metric:        10,
		Prefix: &pb.Prefix{
			Family:     pb.Prefix_FAMILY_IPV4,
			Address:    "10.0.0.0",
			MaskLength: 8,
		},
		Nexthops: []*pb.Nexthop{{
			Type:    pb.Nexthop_TYPE_IPV4,
			Address: "192.168.1.42",
			Weight:  1,
		}},
	}

	if routeReadyBeforeDial {
		if _, err := s.SetRoute(context.Background(), routeReq); err != nil {
			t.Fatalf("Got unexpected error during call to SetRoute: %v", err)
		}
		for i := 0; i != maxGNMIWaitQuanta; i++ {
			if len(dp.GetRoutes()) != 0 {
				break
			}
			time.Sleep(100 * time.Millisecond)
		}
		if len(dp.GetRoutes()) == 0 {
			t.Fatalf("Route not resolved in time limit.")
		}
	}

	conn, err := Dial()
	if err != nil {
		t.Errorf("Dial failed %v\n", err)
		return
	}
	defer conn.Close()

	version := zebra.MaxZapiVer
	software := zebra.MaxSoftware
	logger := newLogger()

	SendMessage(t, conn, &zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(version),
			Marker:  zebra.HeaderMarker(version),
			Version: version,
			Command: zebra.Hello.ToEach(version, software),
		},
		Body: &zebra.HelloBody{},
	})

	_, err = zebra.ReceiveSingleMsg(logger, conn, version, software, "test-client")

	if !routeReadyBeforeDial {
		if _, err := s.SetRoute(context.Background(), routeReq); err != nil {
			t.Fatalf("Got unexpected error during call to SetRoute: %v", err)
		}
	}

	m, err := zebra.ReceiveSingleMsg(logger, conn, version, software, "test-client")
	if err != nil {
		t.Fatal(err)
	} else if m == nil {
		t.Fatal("got empty message")
	}
	if got, want := m.Header.Command.ToCommon(version, software), zebra.RedistributeRouteAdd; got != want {
		t.Errorf("Got message %s, want %s", got, want)
	}
}
<commit_msg>fix lint<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright 2016, 2017 zebra project.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sysrib

import (
	"context"
	"net"
	"syscall"
	"testing"
	"time"

	"github.com/coreswitch/netutil"
	"github.com/openconfig/lemming/gnmi"
	pb "github.com/openconfig/lemming/proto/sysrib"
	"github.com/openconfig/ygnmi/ygnmi"
	"github.com/wenovus/gobgp/v3/pkg/zebra"
	"google.golang.org/grpc"
)

func SendMessage(t *testing.T, conn net.Conn, msg *zebra.Message) error {
	s, err := msg.Serialize(zebra.MaxSoftware)
	if err != nil {
		return err
	}
	n, err := conn.Write(s)
	t.Logf("SendMessage: %d bytes written", n)
	return err
}

func Dial() (net.Conn, error) {
	conn, err := net.Dial("unix", "/tmp/zserv.api")
	if err != nil {
		return nil, err
	}
	return conn, err
}

func ZAPIServerStart(t *testing.T) *ZServer {
	t.Helper()
	dp := NewFakeDataplane()
	sysribServer, err := New(dp)
	if err != nil {
		t.Fatal(err)
	}

	s, err := ZServerStart("unix", "/tmp/zserv.api", 0, sysribServer)
	if err != nil {
		t.Fatal(err)
	}
	return s
}

func TestZServer(t *testing.T) {
	// Need to test these serially since they all use the same UDS address.
	testHello(t)
	testRouteAdd(t)
	testRouteRedistribution(t, true)
	testRouteRedistribution(t, false)
}

func testHello(t *testing.T) {
	s := ZAPIServerStart(t)
	defer s.Stop()

	conn, err := Dial()
	if err != nil {
		t.Errorf("Dial failed %v\n", err)
		return
	}
	defer conn.Close()

	serverVersion := zebra.MaxZapiVer
	serverSoftware := zebra.MaxSoftware
	msg := zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(serverVersion),
			Marker:  zebra.HeaderMarker(serverVersion),
			Version: serverVersion,
			Command: zebra.Hello.ToEach(serverVersion, serverSoftware),
		},
		Body: &zebra.HelloBody{},
	}
	if err := SendMessage(t, conn, &msg); err != nil {
		t.Error(err)
	}
}

func testRouteAdd(t *testing.T) {
	s := ZAPIServerStart(t)
	defer s.Stop()

	conn, err := Dial()
	if err != nil {
		t.Errorf("Dial failed %v\n", err)
		return
	}
	defer conn.Close()

	addr := netutil.ParseIPv4("10.0.0.0")
	body := &zebra.IPRouteBody{Prefix: zebra.Prefix{
		Family:    syscall.AF_INET,
		PrefixLen: 24,
		Prefix:    addr,
	}}

	serverVersion := zebra.MaxZapiVer
	serverSoftware := zebra.MaxSoftware
	helloMsg := zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(serverVersion),
			Marker:  zebra.HeaderMarker(serverVersion),
			Version: serverVersion,
			Command: zebra.Hello.ToEach(serverVersion, serverSoftware),
		},
		Body: &zebra.HelloBody{},
	}
	if err := SendMessage(t, conn, &helloMsg); err != nil {
		t.Error(err)
	}

	msg := zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(serverVersion),
			Marker:  zebra.HeaderMarker(serverVersion),
			Version: serverVersion,
			Command: zebra.RouteAdd.ToEach(serverVersion, serverSoftware),
		},
		Body: body,
	}
	if err := SendMessage(t, conn, &msg); err != nil {
		t.Error(err)
	}
}

func testRouteRedistribution(t *testing.T, routeReadyBeforeDial bool) {
	dp := NewFakeDataplane()
	s, err := New(dp)
	if err != nil {
		t.Fatal(err)
	}

	grpcServer := grpc.NewServer()
	gnmiServer, err := gnmi.New(grpcServer, "local")
	if err != nil {
		t.Fatal(err)
	}
	client := gnmiServer.LocalClient()
	if err := s.Start(client, "local", "unix:/tmp/zserv.api"); err != nil {
		t.Fatalf("cannot start sysrib server, %v", err)
	}
	defer s.Stop()

	c, err := ygnmi.NewClient(client, ygnmi.WithTarget("local"))
	if err != nil {
		t.Fatalf("cannot create ygnmi client: %v", err)
	}
	configureInterface(t, AddIntfAction{
		name:    "eth0",
		ifindex: 0,
		enabled: true,
		prefix:  "192.168.1.1/24",
		niName:  "DEFAULT",
	}, c)

	routeReq := &pb.SetRouteRequest{
		AdminDistance: 10,
		Metric:        10,
		Prefix: &pb.Prefix{
			Family:     pb.Prefix_FAMILY_IPV4,
			Address:    "10.0.0.0",
			MaskLength: 8,
		},
		Nexthops: []*pb.Nexthop{{
			Type:    pb.Nexthop_TYPE_IPV4,
			Address: "192.168.1.42",
			Weight:  1,
		}},
	}

	if routeReadyBeforeDial {
		if _, err := s.SetRoute(context.Background(), routeReq); err != nil {
			t.Fatalf("Got unexpected error during call to SetRoute: %v", err)
		}
		for i := 0; i != maxGNMIWaitQuanta; i++ {
			if len(dp.GetRoutes()) != 0 {
				break
			}
			time.Sleep(100 * time.Millisecond)
		}
		if len(dp.GetRoutes()) == 0 {
			t.Fatalf("Route not resolved in time limit.")
		}
	}

	conn, err := Dial()
	if err != nil {
		t.Errorf("Dial failed %v\n", err)
		return
	}
	defer conn.Close()

	version := zebra.MaxZapiVer
	software := zebra.MaxSoftware
	logger := newLogger()

	SendMessage(t, conn, &zebra.Message{
		Header: zebra.Header{
			Len:     zebra.HeaderSize(version),
			Marker:  zebra.HeaderMarker(version),
			Version: version,
			Command: zebra.Hello.ToEach(version, software),
		},
		Body: &zebra.HelloBody{},
	})

	// The first message is expected to be a capabilities message which is
	// discarded since no client uses it.
	if _, err := zebra.ReceiveSingleMsg(logger, conn, version, software, "test-client"); err != nil {
		t.Fatalf("Got error during call to first ReceiveSingleMsg: %v", err)
	}

	if !routeReadyBeforeDial {
		if _, err := s.SetRoute(context.Background(), routeReq); err != nil {
			t.Fatalf("Got unexpected error during call to SetRoute: %v", err)
		}
	}

	m, err := zebra.ReceiveSingleMsg(logger, conn, version, software, "test-client")
	if err != nil {
		t.Fatal(err)
	} else if m == nil {
		t.Fatal("got empty message")
	}
	if got, want := m.Header.Command.ToCommon(version, software), zebra.RedistributeRouteAdd; got != want {
		t.Errorf("Got message %s, want %s", got, want)
	}
}
<|endoftext|>