<commit_before>package lsx

import (
	"bytes"
	"encoding"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/codedellemc/libstorage/api/context"
	"github.com/codedellemc/libstorage/api/registry"
	apitypes "github.com/codedellemc/libstorage/api/types"
	"github.com/codedellemc/libstorage/api/utils"
	apiconfig "github.com/codedellemc/libstorage/api/utils/config"

	// load these packages
	_ "github.com/codedellemc/libstorage/imports/config"
	_ "github.com/codedellemc/libstorage/imports/executors"
)

var cmdRx = regexp.MustCompile(
	`(?i)^(?:un?)?mount|supported|instanceid|nextdevice|localdevices|wait$`)

// Run runs the executor CLI.
func Run() {

	args := os.Args
	if len(args) < 3 {
		printUsageAndExit()
	}

	d, err := registry.NewStorageExecutor(args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	driverName := strings.ToLower(d.Name())

	config, err := apiconfig.NewConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	apiconfig.UpdateLogLevel(config)
	ctx := context.Background()

	if err := d.Init(ctx, config); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	cmd := cmdRx.FindString(args[2])
	if cmd == "" {
		printUsageAndExit()
	}
	store := utils.NewStore()

	var (
		result   interface{}
		op       string
		exitCode int
	)

	if strings.EqualFold(cmd, apitypes.LSXCmdSupported) {
		op = "supported"
		if dws, ok := d.(apitypes.StorageExecutorWithSupported); ok {
			opResult, opErr := dws.Supported(ctx, store)
			if opErr != nil {
				err = opErr
			} else if opResult {
				if _, ok := dws.(apitypes.StorageExecutorWithMount); ok {
					result = apitypes.LSXOpAll
				} else {
					result = apitypes.LSXOpAllNoMount
				}
			} else {
				result = apitypes.LSXSOpNone
			}
		} else {
			err = apitypes.ErrNotImplemented
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdMount) {
		op = "mount"

		dd, ok := d.(apitypes.StorageExecutorWithMount)
		if !ok {
			err = apitypes.ErrNotImplemented
		} else {
			var (
				deviceName string
				mountPath  string
				mountOpts  = &apitypes.DeviceMountOpts{Opts: store}
			)
			mountArgs := args[3:]
			if len(mountArgs) == 0 {
				printUsageAndExit()
			}

			remArgs := []string{}
			for x := 0; x < len(mountArgs); {
				a := mountArgs[x]
				if x < len(mountArgs)-1 {
					switch a {
					case "-l":
						mountOpts.MountLabel = mountArgs[x+1]
						x = x + 2
						continue
					case "-o":
						mountOpts.MountOptions = mountArgs[x+1]
						x = x + 2
						continue
					}
				}
				remArgs = append(remArgs, a)
				x++
			}

			if len(remArgs) != 2 {
				printUsageAndExit()
			}

			deviceName = remArgs[0]
			mountPath = remArgs[1]

			opErr := dd.Mount(ctx, deviceName, mountPath, mountOpts)
			if opErr != nil {
				err = opErr
			} else {
				result = mountPath
			}
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdUmount) ||
		strings.EqualFold(cmd, "unmount") {
		op = "umount"
		dd, ok := d.(apitypes.StorageExecutorWithMount)
		if !ok {
			err = apitypes.ErrNotImplemented
		} else {
			if len(args) < 4 {
				printUsageAndExit()
			}
			mountPath := args[3]
			opErr := dd.Unmount(ctx, mountPath, store)
			if opErr != nil {
				err = opErr
			} else {
				result = mountPath
			}
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdInstanceID) {
		op = "instance ID"
		opResult, opErr := d.InstanceID(ctx, store)
		if opErr != nil {
			err = opErr
		} else {
			opResult.Driver = driverName
			result = opResult
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdNextDevice) {
		op = "next device"
		opResult, opErr := d.NextDevice(ctx, store)
		if opErr != nil && opErr != apitypes.ErrNotImplemented {
			err = opErr
		} else {
			result = opResult
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdLocalDevices) {
		if len(args) < 4 {
			printUsageAndExit()
		}
		op = "local devices"
		opResult, opErr := d.LocalDevices(ctx, &apitypes.LocalDevicesOpts{
			ScanType: apitypes.ParseDeviceScanType(args[3]),
			Opts:     store,
		})
		if opErr != nil {
			err = opErr
		} else {
			opResult.Driver = driverName
			result = opResult
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdWaitForDevice) {
		if len(args) < 5 {
			printUsageAndExit()
		}
		op = "wait"
		opts := &apitypes.WaitForDeviceOpts{
			LocalDevicesOpts: apitypes.LocalDevicesOpts{
				ScanType: apitypes.ParseDeviceScanType(args[3]),
				Opts:     store,
			},
			Token:   strings.ToLower(args[4]),
			Timeout: utils.DeviceAttachTimeout(args[5]),
		}

		ldl := func() (bool, *apitypes.LocalDevices, error) {
			ldm, err := d.LocalDevices(ctx, &opts.LocalDevicesOpts)
			if err != nil {
				return false, nil, err
			}
			for k := range ldm.DeviceMap {
				if strings.ToLower(k) == opts.Token {
					return true, ldm, nil
				}
			}
			return false, ldm, nil
		}

		var (
			found    bool
			opErr    error
			opResult *apitypes.LocalDevices
			timeoutC = time.After(opts.Timeout)
			tick     = time.Tick(500 * time.Millisecond)
		)

	TimeoutLoop:

		for {
			select {
			case <-timeoutC:
				exitCode = apitypes.LSXExitCodeTimedOut
				break TimeoutLoop
			case <-tick:
				if found, opResult, opErr = ldl(); found || opErr != nil {
					break TimeoutLoop
				}
			}
		}

		if opErr != nil {
			err = opErr
		} else {
			opResult.Driver = driverName
			result = opResult
		}
	}

	if err != nil {
		// if the function is not implemented then exit with
		// apitypes.LSXExitCodeNotImplemented to let callers
		// know that the function is unsupported on this system
		exitCode = 1
		if strings.EqualFold(err.Error(), apitypes.ErrNotImplemented.Error()) {
			exitCode = apitypes.LSXExitCodeNotImplemented
		}
		fmt.Fprintf(os.Stderr,
			"error: error getting %s: %v\n", op, err)
		os.Exit(exitCode)
	}

	switch tr := result.(type) {
	case bool:
		fmt.Fprintf(os.Stdout, "%v", result)
	case string:
		fmt.Fprintln(os.Stdout, result)
	case encoding.TextMarshaler:
		buf, err := tr.MarshalText()
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err)
			os.Exit(1)
		}
		os.Stdout.Write(buf)
	default:
		buf, err := json.Marshal(result)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err)
			os.Exit(1)
		}
		if isNullBuf(buf) {
			os.Stdout.Write(emptyJSONBuff)
		} else {
			os.Stdout.Write(buf)
		}
	}

	os.Exit(exitCode)
}

const (
	newline = 10
)

var (
	nullBuff      = []byte{110, 117, 108, 108}
	emptyJSONBuff = []byte{123, 125}
)

func isNullBuf(buf []byte) bool {
	return len(buf) == len(nullBuff) &&
		buf[0] == nullBuff[0] && buf[1] == nullBuff[1] &&
		buf[2] == nullBuff[2] && buf[3] == nullBuff[3]
}

func executorNames() <-chan string {
	c := make(chan string)
	go func() {
		for se := range registry.StorageExecutors() {
			c <- strings.ToLower(se.Name())
		}
		close(c)
	}()
	return c
}

func printUsage() {
	buf := &bytes.Buffer{}
	w := io.MultiWriter(buf, os.Stderr)

	fmt.Fprintf(w, "usage: ")
	lpad1 := buf.Len()
	fmt.Fprintf(w, "%s <executor> ", os.Args[0])
	lpad2 := buf.Len()
	fmt.Fprintf(w, "supported\n")
	printUsageLeftPadded(w, lpad2, "instanceID\n")
	printUsageLeftPadded(w, lpad2, "nextDevice\n")
	printUsageLeftPadded(w, lpad2, "localDevices <scanType>\n")
	printUsageLeftPadded(w, lpad2, "wait <scanType> <attachToken> <timeout>\n")
	printUsageLeftPadded(w, lpad2, "mount [-l label] [-o options] device path\n")
	printUsageLeftPadded(w, lpad2, "umount path\n")
	fmt.Fprintln(w)
	executorVar := "executor:    "
	printUsageLeftPadded(w, lpad1, executorVar)
	lpad3 := lpad1 + len(executorVar)

	execNames := []string{}
	for en := range executorNames() {
		execNames = append(execNames, en)
	}

	if len(execNames) > 0 {
		execNames = utils.SortByString(execNames)
		fmt.Fprintf(w, "%s\n", execNames[0])
		if len(execNames) > 1 {
			for x, en := range execNames {
				if x == 0 {
					continue
				}
				printUsageLeftPadded(w, lpad3, "%s\n", en)
			}
		}
		fmt.Fprintln(w)
	}

	printUsageLeftPadded(w, lpad1, "scanType:    0,quick | 1,deep\n\n")
	printUsageLeftPadded(w, lpad1, "attachToken: <token>\n\n")
	printUsageLeftPadded(w, lpad1, "timeout:     30s | 1h | 5m\n\n")
}

func printUsageLeftPadded(
	w io.Writer, lpadLen int, format string, args ...interface{}) {
	text := fmt.Sprintf(format, args...)
	lpadFmt := fmt.Sprintf("%%%ds", lpadLen+len(text))
	fmt.Fprintf(w, lpadFmt, text)
}

func printUsageAndExit() {
	printUsage()
	os.Exit(1)
}
<commit_msg>Fix num arg checking for lsx wait<commit_after>package lsx

import (
	"bytes"
	"encoding"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/codedellemc/libstorage/api/context"
	"github.com/codedellemc/libstorage/api/registry"
	apitypes "github.com/codedellemc/libstorage/api/types"
	"github.com/codedellemc/libstorage/api/utils"
	apiconfig "github.com/codedellemc/libstorage/api/utils/config"

	// load these packages
	_ "github.com/codedellemc/libstorage/imports/config"
	_ "github.com/codedellemc/libstorage/imports/executors"
)

var cmdRx = regexp.MustCompile(
	`(?i)^(?:un?)?mount|supported|instanceid|nextdevice|localdevices|wait$`)

// Run runs the executor CLI.
func Run() {

	args := os.Args
	if len(args) < 3 {
		printUsageAndExit()
	}

	d, err := registry.NewStorageExecutor(args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	driverName := strings.ToLower(d.Name())

	config, err := apiconfig.NewConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	apiconfig.UpdateLogLevel(config)
	ctx := context.Background()

	if err := d.Init(ctx, config); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	cmd := cmdRx.FindString(args[2])
	if cmd == "" {
		printUsageAndExit()
	}
	store := utils.NewStore()

	var (
		result   interface{}
		op       string
		exitCode int
	)

	if strings.EqualFold(cmd, apitypes.LSXCmdSupported) {
		op = "supported"
		if dws, ok := d.(apitypes.StorageExecutorWithSupported); ok {
			opResult, opErr := dws.Supported(ctx, store)
			if opErr != nil {
				err = opErr
			} else if opResult {
				if _, ok := dws.(apitypes.StorageExecutorWithMount); ok {
					result = apitypes.LSXOpAll
				} else {
					result = apitypes.LSXOpAllNoMount
				}
			} else {
				result = apitypes.LSXSOpNone
			}
		} else {
			err = apitypes.ErrNotImplemented
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdMount) {
		op = "mount"

		dd, ok := d.(apitypes.StorageExecutorWithMount)
		if !ok {
			err = apitypes.ErrNotImplemented
		} else {
			var (
				deviceName string
				mountPath  string
				mountOpts  = &apitypes.DeviceMountOpts{Opts: store}
			)
			mountArgs := args[3:]
			if len(mountArgs) == 0 {
				printUsageAndExit()
			}

			remArgs := []string{}
			for x := 0; x < len(mountArgs); {
				a := mountArgs[x]
				if x < len(mountArgs)-1 {
					switch a {
					case "-l":
						mountOpts.MountLabel = mountArgs[x+1]
						x = x + 2
						continue
					case "-o":
						mountOpts.MountOptions = mountArgs[x+1]
						x = x + 2
						continue
					}
				}
				remArgs = append(remArgs, a)
				x++
			}

			if len(remArgs) != 2 {
				printUsageAndExit()
			}

			deviceName = remArgs[0]
			mountPath = remArgs[1]

			opErr := dd.Mount(ctx, deviceName, mountPath, mountOpts)
			if opErr != nil {
				err = opErr
			} else {
				result = mountPath
			}
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdUmount) ||
		strings.EqualFold(cmd, "unmount") {
		op = "umount"
		dd, ok := d.(apitypes.StorageExecutorWithMount)
		if !ok {
			err = apitypes.ErrNotImplemented
		} else {
			if len(args) < 4 {
				printUsageAndExit()
			}
			mountPath := args[3]
			opErr := dd.Unmount(ctx, mountPath, store)
			if opErr != nil {
				err = opErr
			} else {
				result = mountPath
			}
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdInstanceID) {
		op = "instance ID"
		opResult, opErr := d.InstanceID(ctx, store)
		if opErr != nil {
			err = opErr
		} else {
			opResult.Driver = driverName
			result = opResult
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdNextDevice) {
		op = "next device"
		opResult, opErr := d.NextDevice(ctx, store)
		if opErr != nil && opErr != apitypes.ErrNotImplemented {
			err = opErr
		} else {
			result = opResult
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdLocalDevices) {
		if len(args) < 4 {
			printUsageAndExit()
		}
		op = "local devices"
		opResult, opErr := d.LocalDevices(ctx, &apitypes.LocalDevicesOpts{
			ScanType: apitypes.ParseDeviceScanType(args[3]),
			Opts:     store,
		})
		if opErr != nil {
			err = opErr
		} else {
			opResult.Driver = driverName
			result = opResult
		}
	} else if strings.EqualFold(cmd, apitypes.LSXCmdWaitForDevice) {
		if len(args) < 6 {
			printUsageAndExit()
		}
		op = "wait"
		opts := &apitypes.WaitForDeviceOpts{
			LocalDevicesOpts: apitypes.LocalDevicesOpts{
				ScanType: apitypes.ParseDeviceScanType(args[3]),
				Opts:     store,
			},
			Token:   strings.ToLower(args[4]),
			Timeout: utils.DeviceAttachTimeout(args[5]),
		}

		ldl := func() (bool, *apitypes.LocalDevices, error) {
			ldm, err := d.LocalDevices(ctx, &opts.LocalDevicesOpts)
			if err != nil {
				return false, nil, err
			}
			for k := range ldm.DeviceMap {
				if strings.ToLower(k) == opts.Token {
					return true, ldm, nil
				}
			}
			return false, ldm, nil
		}

		var (
			found    bool
			opErr    error
			opResult *apitypes.LocalDevices
			timeoutC = time.After(opts.Timeout)
			tick     = time.Tick(500 * time.Millisecond)
		)

	TimeoutLoop:

		for {
			select {
			case <-timeoutC:
				exitCode = apitypes.LSXExitCodeTimedOut
				break TimeoutLoop
			case <-tick:
				if found, opResult, opErr = ldl(); found || opErr != nil {
					break TimeoutLoop
				}
			}
		}

		if opErr != nil {
			err = opErr
		} else {
			opResult.Driver = driverName
			result = opResult
		}
	}

	if err != nil {
		// if the function is not implemented then exit with
		// apitypes.LSXExitCodeNotImplemented to let callers
		// know that the function is unsupported on this system
		exitCode = 1
		if strings.EqualFold(err.Error(), apitypes.ErrNotImplemented.Error()) {
			exitCode = apitypes.LSXExitCodeNotImplemented
		}
		fmt.Fprintf(os.Stderr,
			"error: error getting %s: %v\n", op, err)
		os.Exit(exitCode)
	}

	switch tr := result.(type) {
	case bool:
		fmt.Fprintf(os.Stdout, "%v", result)
	case string:
		fmt.Fprintln(os.Stdout, result)
	case encoding.TextMarshaler:
		buf, err := tr.MarshalText()
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err)
			os.Exit(1)
		}
		os.Stdout.Write(buf)
	default:
		buf, err := json.Marshal(result)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err)
			os.Exit(1)
		}
		if isNullBuf(buf) {
			os.Stdout.Write(emptyJSONBuff)
		} else {
			os.Stdout.Write(buf)
		}
	}

	os.Exit(exitCode)
}

const (
	newline = 10
)

var (
	nullBuff      = []byte{110, 117, 108, 108}
	emptyJSONBuff = []byte{123, 125}
)

func isNullBuf(buf []byte) bool {
	return len(buf) == len(nullBuff) &&
		buf[0] == nullBuff[0] && buf[1] == nullBuff[1] &&
		buf[2] == nullBuff[2] && buf[3] == nullBuff[3]
}

func executorNames() <-chan string {
	c := make(chan string)
	go func() {
		for se := range registry.StorageExecutors() {
			c <- strings.ToLower(se.Name())
		}
		close(c)
	}()
	return c
}

func printUsage() {
	buf := &bytes.Buffer{}
	w := io.MultiWriter(buf, os.Stderr)

	fmt.Fprintf(w, "usage: ")
	lpad1 := buf.Len()
	fmt.Fprintf(w, "%s <executor> ", os.Args[0])
	lpad2 := buf.Len()
	fmt.Fprintf(w, "supported\n")
	printUsageLeftPadded(w, lpad2, "instanceID\n")
	printUsageLeftPadded(w, lpad2, "nextDevice\n")
	printUsageLeftPadded(w, lpad2, "localDevices <scanType>\n")
	printUsageLeftPadded(w, lpad2, "wait <scanType> <attachToken> <timeout>\n")
	printUsageLeftPadded(w, lpad2, "mount [-l label] [-o options] device path\n")
	printUsageLeftPadded(w, lpad2, "umount path\n")
	fmt.Fprintln(w)
	executorVar := "executor:    "
	printUsageLeftPadded(w, lpad1, executorVar)
	lpad3 := lpad1 + len(executorVar)

	execNames := []string{}
	for en := range executorNames() {
		execNames = append(execNames, en)
	}

	if len(execNames) > 0 {
		execNames = utils.SortByString(execNames)
		fmt.Fprintf(w, "%s\n", execNames[0])
		if len(execNames) > 1 {
			for x, en := range execNames {
				if x == 0 {
					continue
				}
				printUsageLeftPadded(w, lpad3, "%s\n", en)
			}
		}
		fmt.Fprintln(w)
	}

	printUsageLeftPadded(w, lpad1, "scanType:    0,quick | 1,deep\n\n")
	printUsageLeftPadded(w, lpad1, "attachToken: <token>\n\n")
	printUsageLeftPadded(w, lpad1, "timeout:     30s | 1h | 5m\n\n")
}

func printUsageLeftPadded(
	w io.Writer, lpadLen int, format string, args ...interface{}) {
	text := fmt.Sprintf(format, args...)
	lpadFmt := fmt.Sprintf("%%%ds", lpadLen+len(text))
	fmt.Fprintf(w, lpadFmt, text)
}

func printUsageAndExit() {
	printUsage()
	os.Exit(1)
}
<|endoftext|>


<commit_before>package fbapi_test

import (
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"testing"
	"time"

	"github.com/daaku/go.fbapi"
	"github.com/daaku/go.flagconfig"
	"github.com/daaku/go.httpcontrol"
)

var (
	defaultHttpTransport = &httpcontrol.Transport{
		MaxIdleConnsPerHost:   50,
		DialTimeout:           3 * time.Second,
		ResponseHeaderTimeout: 30 * time.Second,
		RequestTimeout:        time.Minute,
		Stats:                 logRequestHandler,
	}
	defaultFbClient = fbapi.ClientFlag("fbapi-test")

	logRequest = flag.Bool(
		"log-requests",
		false,
		"will trigger verbose logging of requests",
	)
)

func init() {
	flag.Usage = flagconfig.Usage
	flagconfig.Parse()
	if err := defaultHttpTransport.Start(); err != nil {
		panic(err)
	}
	defaultFbClient.Transport = defaultHttpTransport
}

func logRequestHandler(stats *httpcontrol.Stats) {
	if *logRequest {
		fmt.Println(stats.String())
		fmt.Println("Header", stats.Request.Header)
	}
}

func TestPublicGet(t *testing.T) {
	t.Parallel()
	user := struct {
		Username string `json:"username"`
	}{}
	res, err := defaultFbClient.Do(
		&http.Request{
			Method: "GET",
			URL: &url.URL{
				Path: "5526183",
			},
		},
		&user,
	)
	if err != nil {
		t.Fatal(err)
	}
	if res.StatusCode != 200 {
		t.Fatalf("was expecting status 200 but got %d", res.StatusCode)
	}
	if user.Username != "naitik" {
		t.Fatalf("was expecting naitik but got %s", user.Username)
	}
}

func TestInvalidGet(t *testing.T) {
	t.Parallel()
	res, err := defaultFbClient.Do(
		&http.Request{
			Method: "GET",
			URL: &url.URL{
				Path: "20aa2519-4745-4522-92a9-4522b8edf6e9",
			},
		},
		nil,
	)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET ` +
		`https://graph.facebook.com/20aa2519-4745-4522-92a9-4522b8edf6e9 got ` +
		`404 Not Found failed with code 803 type OAuthException message (#803) ` +
		`Some of the aliases you requested do not exist: ` +
		`20aa2519-4745-4522-92a9-4522b8edf6e9`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 404 {
		t.Fatalf("was expecting status 404 but got %d", res.StatusCode)
	}
}

func TestNilURLWithDefaultBaseURL(t *testing.T) {
	t.Parallel()
	res, err := defaultFbClient.Do(&http.Request{Method: "GET"}, nil)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET https://graph.facebook.com/ got 400 Bad Request ` +
		`failed with code 100 type GraphMethodException message Unsupported get ` +
		`request`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 400 {
		t.Fatalf("was expecting status 400 but got %d", res.StatusCode)
	}
}

func TestNilURLWithBaseURL(t *testing.T) {
	t.Parallel()
	client := &fbapi.Client{
		BaseURL: &url.URL{
			Scheme: "https",
			Host:   "graph.facebook.com",
			Path:   "/20aa2519-4745-4522-92a9-4522b8edf6e9",
		},
	}
	res, err := client.Do(&http.Request{Method: "GET"}, nil)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET ` +
		`https://graph.facebook.com/20aa2519-4745-4522-92a9-4522b8edf6e9 got ` +
		`404 Not Found failed with code 803 type OAuthException message (#803) ` +
		`Some of the aliases you requested do not exist: ` +
		`20aa2519-4745-4522-92a9-4522b8edf6e9`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 404 {
		t.Fatalf("was expecting status 404 but got %d", res.StatusCode)
	}
}

func TestRelativeToBaseURL(t *testing.T) {
	t.Parallel()
	client := &fbapi.Client{
		BaseURL: &url.URL{
			Scheme: "https",
			Host:   "graph.facebook.com",
			Path:   "/20aa2519-4745-4522-92a9-4522b8edf6e9/",
		},
	}
	res, err := client.Do(
		&http.Request{Method: "GET", URL: &url.URL{Path: "0"}},
		nil,
	)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET ` +
		`https://graph.facebook.com/20aa2519-4745-4522-92a9-4522b8edf6e9/0 got ` +
		`404 Not Found failed with code 803 type OAuthException message (#803) ` +
		`Some of the aliases you requested do not exist: ` +
		`20aa2519-4745-4522-92a9-4522b8edf6e9`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 404 {
		t.Fatalf("was expecting status 404 but got %d", res.StatusCode)
	}
}
<commit_msg>test discarding of response<commit_after>package fbapi_test

import (
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"testing"
	"time"

	"github.com/daaku/go.fbapi"
	"github.com/daaku/go.flagconfig"
	"github.com/daaku/go.httpcontrol"
)

var (
	defaultHttpTransport = &httpcontrol.Transport{
		MaxIdleConnsPerHost:   50,
		DialTimeout:           3 * time.Second,
		ResponseHeaderTimeout: 30 * time.Second,
		RequestTimeout:        time.Minute,
		Stats:                 logRequestHandler,
	}
	defaultFbClient = fbapi.ClientFlag("fbapi-test")

	logRequest = flag.Bool(
		"log-requests",
		false,
		"will trigger verbose logging of requests",
	)
)

func init() {
	flag.Usage = flagconfig.Usage
	flagconfig.Parse()
	if err := defaultHttpTransport.Start(); err != nil {
		panic(err)
	}
	defaultFbClient.Transport = defaultHttpTransport
}

func logRequestHandler(stats *httpcontrol.Stats) {
	if *logRequest {
		fmt.Println(stats.String())
		fmt.Println("Header", stats.Request.Header)
	}
}

func TestPublicGet(t *testing.T) {
	t.Parallel()
	user := struct {
		Username string `json:"username"`
	}{}
	res, err := defaultFbClient.Do(
		&http.Request{
			Method: "GET",
			URL: &url.URL{
				Path: "5526183",
			},
		},
		&user,
	)
	if err != nil {
		t.Fatal(err)
	}
	if res.StatusCode != 200 {
		t.Fatalf("was expecting status 200 but got %d", res.StatusCode)
	}
	if user.Username != "naitik" {
		t.Fatalf("was expecting naitik but got %s", user.Username)
	}
}

func TestInvalidGet(t *testing.T) {
	t.Parallel()
	res, err := defaultFbClient.Do(
		&http.Request{
			Method: "GET",
			URL: &url.URL{
				Path: "20aa2519-4745-4522-92a9-4522b8edf6e9",
			},
		},
		nil,
	)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET ` +
		`https://graph.facebook.com/20aa2519-4745-4522-92a9-4522b8edf6e9 got ` +
		`404 Not Found failed with code 803 type OAuthException message (#803) ` +
		`Some of the aliases you requested do not exist: ` +
		`20aa2519-4745-4522-92a9-4522b8edf6e9`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 404 {
		t.Fatalf("was expecting status 404 but got %d", res.StatusCode)
	}
}

func TestNilURLWithDefaultBaseURL(t *testing.T) {
	t.Parallel()
	res, err := defaultFbClient.Do(&http.Request{Method: "GET"}, nil)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET https://graph.facebook.com/ got 400 Bad Request ` +
		`failed with code 100 type GraphMethodException message Unsupported get ` +
		`request`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 400 {
		t.Fatalf("was expecting status 400 but got %d", res.StatusCode)
	}
}

func TestNilURLWithBaseURL(t *testing.T) {
	t.Parallel()
	client := &fbapi.Client{
		BaseURL: &url.URL{
			Scheme: "https",
			Host:   "graph.facebook.com",
			Path:   "/20aa2519-4745-4522-92a9-4522b8edf6e9",
		},
	}
	res, err := client.Do(&http.Request{Method: "GET"}, nil)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET ` +
		`https://graph.facebook.com/20aa2519-4745-4522-92a9-4522b8edf6e9 got ` +
		`404 Not Found failed with code 803 type OAuthException message (#803) ` +
		`Some of the aliases you requested do not exist: ` +
		`20aa2519-4745-4522-92a9-4522b8edf6e9`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 404 {
		t.Fatalf("was expecting status 404 but got %d", res.StatusCode)
	}
}

func TestRelativeToBaseURL(t *testing.T) {
	t.Parallel()
	client := &fbapi.Client{
		BaseURL: &url.URL{
			Scheme: "https",
			Host:   "graph.facebook.com",
			Path:   "/20aa2519-4745-4522-92a9-4522b8edf6e9/",
		},
	}
	res, err := client.Do(
		&http.Request{Method: "GET", URL: &url.URL{Path: "0"}},
		nil,
	)
	if err == nil {
		t.Fatal("was expecting error")
	}

	const expected = `GET ` +
		`https://graph.facebook.com/20aa2519-4745-4522-92a9-4522b8edf6e9/0 got ` +
		`404 Not Found failed with code 803 type OAuthException message (#803) ` +
		`Some of the aliases you requested do not exist: ` +
		`20aa2519-4745-4522-92a9-4522b8edf6e9`

	if err.Error() != expected {
		t.Fatalf(`expected "%s" got "%s"`, expected, err)
	}

	if res.StatusCode != 404 {
		t.Fatalf("was expecting status 404 but got %d", res.StatusCode)
	}
}

func TestPublicGetDiscardBody(t *testing.T) {
	t.Parallel()
	res, err := defaultFbClient.Do(
		&http.Request{
			Method: "GET",
			URL: &url.URL{
				Path: "5526183",
			},
		},
		nil,
	)
	if err != nil {
		t.Fatal(err)
	}
	if res.StatusCode != 200 {
		t.Fatalf("was expecting status 200 but got %d", res.StatusCode)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"math/rand"

	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v3"
)

var (
	// discordgo session
	discord *discordgo.Session

	me *discordgo.User
)

func onReady(s *discordgo.Session, event *discordgo.Ready) {
	log.Info("Recieved READY payload")
	s.UpdateStatus(0, "League Of Legends")
}

func onGuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if !shardContains(event.Guild.ID) {
		return
	}

	if event.Guild.Unavailable != nil {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			s.ChannelMessageSend(channel.ID, "BEEP BOOP BOOTING")
			s.ChannelMessageSend(channel.ID, "https://media.giphy.com/media/3o85g3yQa2iG2Rdq1O/giphy.gif")
			return
		}
	}
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	var (
		//sound    *Sound
		//stype    int = TYPE_AIRHORN
		//khaled   bool
		ourShard = true
	)

	if len(m.Content) <= 0 || (m.Content[0] != '!' && len(m.Mentions) != 1) {
		return
	}

	parts := strings.Split(strings.ToLower(m.Content), " ")

	channel, _ := discord.State.Channel(m.ChannelID)
	if channel == nil {
		log.WithFields(log.Fields{
			"channel": m.ChannelID,
			"message": m.ID,
		}).Warning("Failed to grab channel")
		return
	}

	guild, _ := discord.State.Guild(channel.GuildID)
	if guild == nil {
		log.WithFields(log.Fields{
			"guild":   channel.GuildID,
			"channel": channel,
			"message": m.ID,
		}).Warning("Failed to grab guild")
		return
	}

	// If we're in sharding mode, test whether this message is relevant to us
	if !shardContains(channel.GuildID) {
		ourShard = false
	}

	if len(m.Mentions) > 0 {
		if m.Mentions[0].ID == s.State.Ready.User.ID && m.Author.ID == OWNER && len(parts) > 0 {
			if scontains(parts[len(parts)-1], "stats") && ourShard {
				users := 0
				for _, guild := range s.State.Ready.Guilds {
					users += len(guild.Members)
				}

				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
					"I'm in %v servers with %v users.",
					len(s.State.Ready.Guilds),
					users))
			} else if scontains(parts[len(parts)-1], "status") {
				guilds := 0
				for _, guild := range s.State.Ready.Guilds {
					if shardContains(guild.ID) {
						guilds += 1
					}
				}
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
					"Shard %v contains %v servers",
					strings.Join(SHARDS, ","),
					guilds))
			} else if len(parts) >= 3 && scontains(parts[len(parts)-2], "die") {
				shard := parts[len(parts)-1]
				if len(SHARDS) == 0 || scontains(shard, SHARDS...) {
					log.Info("Got DIE request, exiting...")
					s.ChannelMessageSend(m.ChannelID, ":ok_hand: goodbye cruel world")
					os.Exit(0)
				}
			} else if scontains(parts[len(parts)-1], "aps") && ourShard {
				s.ChannelMessageSend(m.ChannelID, ":ok_hand: give me a sec m8")
				go calculateAirhornsPerSecond(m.ChannelID)
			} else if scontains(parts[len(parts)-1], "where") && ourShard {
				s.ChannelMessageSend(m.ChannelID,
					fmt.Sprintf("its a me, shard %v", string(guild.ID[len(guild.ID)-5])))
			}
			return
		}
	}

	if !ourShard {
		return
	}

	if parts[0] == "!elo" {
		region := "euw"
		if (len(parts) > 1) {
			if (len(parts) > 2) {
				switch (strings.ToLower(parts[2])) {
					case "na": region = "na"
					case "br": region = "br"
					case "kr": region = ""
					case "eune": region = "eune"
					case "jp": region = "jp"
					case "tr": region = "tr"
					case "oce": region = "oce"
					case "las": region = "las"
					case "ru" : region = "ru"
				}
			}

			name := strings.ToLower(parts[1])
			if len(name) > 0 {
				summoner := GetSummonerElo(parts[1], region)
				if(summoner.rank == "") {
					s.ChannelMessageSend(m.ChannelID, "Could not find player.")
					return
				}
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("http:%s", summoner.rankImage))
				if(summoner.rank != "Unranked") {
					s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("**%s** %sLP", summoner.rank, summoner.lp))
					s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Wins: **%s** Losses: **%s** Winrate: **%s**", summoner.wins, summoner.losses, strings.Join([]string{summoner.winratio, "%"}, "")))
				} else {
					s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("**%s**", summoner.rank))
				}
				if(name == "uznick") {
					s.ChannelMessageSend(m.ChannelID, "But deserves Challenjour, Kappa.")
				}
				if(name == "mehdid") {
					s.ChannelMessageSend(m.ChannelID, "also, best Amumu EUW")
				}
				if(name == "flakelol") {
					s.ChannelMessageSend(m.ChannelID, "also, best Shen EUW")
				}
			}
		return
		} else {
			return
		}
	}

	if parts[0] == "!weather" {
		country := "de"
		days := []string{"Today", "Tomorrow", "In two days", "In three days"}

		if (len(parts) > 2) { //has 2 arguments
			country = parts[2]
		}
		if (len(parts) > 1) {
			city := parts[1]
			weather := --+GetWeather(parts[1], country)

			//print out next 3 days
			if (len(weather.Forecast.Time) > 3) {
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Weather forecast for: **%s**", capitalize(city)))
				for i := 0; i < 3; i++ {
					d := weather.Forecast.Time[i]
					text := fmt.Sprintf("%s: **%s**        min: **%s**°C max: **%s**°C        **%s** from **%s**", days[i], capitalize(d.Symbol.Name), d.Temperature.Min, d.Temperature.Max, strings.ToLower(d.WindSpeed.Name), strings.ToLower(d.WindDirection.Name))
					s.ChannelMessageSend(m.ChannelID, text)
				}
			} else { s.ChannelMessageSend(m.ChannelID, "Can't find information about this city.")
		 }
		}
	}
		if parts[0] == "@J.A.R.V.I.S." {
	log.Info("0")
	rand.Seed(50)
	log.Info("1")
	answers := []string{
	"It is certain",
	"It is decidedly so",
	"Without a doubt",
	"Yes definitely",
	"You may rely on it",
	"As I see it yes",
	"Most likely",
	"Outlook good",
	"Yes",
	"Signs point to yes",
	"Reply hazy try again",
	"Ask again later",
	"Better not tell you now",
	"Cannot predict now",
	"Concentrate and ask again",
	"Don't count on it",
	"My reply is no",
	"My sources say no",
	"Outlook not so good",
	"Very doubtful",
}
s.ChannelMessageSend("J,A.R.V.I.S. says:", answers[rand.Intn(len(answers))])
	log.Info("2")
}

	// if scontains(parts[0], COMMANDS...) {
	// 	// Support !airhorn <sound>
	// 	if len(parts) > 1 {
	// 		for _, s := range AIRHORNS {
	// 			if parts[1] == s.Name {
	// 				sound = s
	// 			}
	// 		}
	//
	// 		if sound == nil {
	// 			return
	// 		}
	// 	}
	//
	// 	// Select mode
	// 	if scontains(parts[0], "!cena", "!johncena", "!nycto") {
	// 		stype = TYPE_CENA
	// 	} else if scontains(parts[0], "!eb", "!ethanbradberry", "!h3h3") {
	// 		stype = TYPE_ETHAN
	// 	} else if scontains(parts[0], "!anotha", "!anothaone") {
	// 		khaled = true
	// 	}
	//
	// 	go enqueuePlay(m.Author, guild, sound, khaled, stype)
	// }
}

func main() {
	var (
		Token = flag.String("t", "", "Discord Authentication Token")
		Redis = flag.String("r", "", "Redis Connection String")
		Shard = flag.String("s", "", "Integers to shard by")
		Owner = flag.String("o", "", "Owner ID")
		err   error
	)
	flag.Parse()

	if *Owner != "" {
		OWNER = *Owner
	}

	// Make sure shard is either empty, or an integer
	if *Shard != "" {
		SHARDS = strings.Split(*Shard, ",")

		for _, shard := range SHARDS {
			if _, err := strconv.Atoi(shard); err != nil {
				log.WithFields(log.Fields{
					"shard": shard,
					"error": err,
				}).Fatal("Invalid Shard")
				return
			}
		}
	}

	// Preload all the sounds
	log.Info("Preloading sounds...")
	for _, sound := range AIRHORNS {
		AIRHORN_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	log.Info("Preloading loyalty...")
	for _, sound := range KHALED {
		KHALED_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	log.Info("PRELOADING THE JOHN CENA")
	for _, sound := range CENA {
		CENA_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	log.Info("I'm ethan bradberry!")
	for _, sound := range ETHAN {
		ETHAN_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	// If we got passed a redis server, try to connect
	if *Redis != "" {
		log.Info("Connecting to redis...")
		rcli = redis.NewClient(&redis.Options{Addr: *Redis, DB: 0})
		_, err = rcli.Ping().Result()

		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Fatal("Failed to connect to redis")
			return
		}
	}

	// Create a discord session
	log.Info("Starting discord session...")
	discord, err = discordgo.New(*Token)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord session")
		return
	}

	discord.AddHandler(onReady)
	discord.AddHandler(onGuildCreate)
	discord.AddHandler(onMessageCreate)

	err = discord.Open()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord websocket connection")
		return
	}

	// We're running!
	log.Info("AIRHORNBOT is ready to horn it up.")

	// Wait for a signal to quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<commit_msg>jarvis command fix<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"math/rand"

	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v3"
)

var (
	// discordgo session
	discord *discordgo.Session

	me *discordgo.User
)

func onReady(s *discordgo.Session, event *discordgo.Ready) {
	log.Info("Recieved READY payload")
	s.UpdateStatus(0, "League Of Legends")
}

func onGuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if !shardContains(event.Guild.ID) {
		return
	}

	if event.Guild.Unavailable != nil {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			s.ChannelMessageSend(channel.ID, "BEEP BOOP BOOTING")
			s.ChannelMessageSend(channel.ID, "https://media.giphy.com/media/3o85g3yQa2iG2Rdq1O/giphy.gif")
			return
		}
	}
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	var (
		//sound    *Sound
		//stype    int = TYPE_AIRHORN
		//khaled   bool
		ourShard = true
	)

	if len(m.Content) <= 0 || (m.Content[0] != '!' && len(m.Mentions) != 1) {
		return
	}

	parts := strings.Split(strings.ToLower(m.Content), " ")

	channel, _ := discord.State.Channel(m.ChannelID)
	if channel == nil {
		log.WithFields(log.Fields{
			"channel": m.ChannelID,
			"message": m.ID,
		}).Warning("Failed to grab channel")
		return
	}

	guild, _ := discord.State.Guild(channel.GuildID)
	if guild == nil {
		log.WithFields(log.Fields{
			"guild":   channel.GuildID,
			"channel": channel,
			"message": m.ID,
		}).Warning("Failed to grab guild")
		return
	}

	// If we're in sharding mode, test whether this message is relevant to us
	if !shardContains(channel.GuildID) {
		ourShard = false
	}

	if len(m.Mentions) > 0 {
		if m.Mentions[0].ID == s.State.Ready.User.ID && m.Author.ID == OWNER && len(parts) > 0 {
			if scontains(parts[len(parts)-1], "stats") && ourShard {
				users := 0
				for _, guild := range s.State.Ready.Guilds {
					users += len(guild.Members)
				}

				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
					"I'm in %v servers with %v users.",
					len(s.State.Ready.Guilds),
					users))
			} else if scontains(parts[len(parts)-1], "status") {
				guilds := 0
				for _, guild := range s.State.Ready.Guilds {
					if shardContains(guild.ID) {
						guilds += 1
					}
				}
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf(
					"Shard %v contains %v servers",
					strings.Join(SHARDS, ","),
					guilds))
			} else if len(parts) >= 3 && scontains(parts[len(parts)-2], "die") {
				shard := parts[len(parts)-1]
				if len(SHARDS) == 0 || scontains(shard, SHARDS...) {
					log.Info("Got DIE request, exiting...")
					s.ChannelMessageSend(m.ChannelID, ":ok_hand: goodbye cruel world")
					os.Exit(0)
				}
			} else if scontains(parts[len(parts)-1], "aps") && ourShard {
				s.ChannelMessageSend(m.ChannelID, ":ok_hand: give me a sec m8")
				go calculateAirhornsPerSecond(m.ChannelID)
			} else if scontains(parts[len(parts)-1], "where") && ourShard {
				s.ChannelMessageSend(m.ChannelID,
					fmt.Sprintf("its a me, shard %v", string(guild.ID[len(guild.ID)-5])))
			}
			return
		}
	}

	if !ourShard {
		return
	}

	if parts[0] == "!elo" {
		region := "euw"
		if (len(parts) > 1) {
			if (len(parts) > 2) {
				switch (strings.ToLower(parts[2])) {
					case "na": region = "na"
					case "br": region = "br"
					case "kr": region = ""
					case "eune": region = "eune"
					case "jp": region = "jp"
					case "tr": region = "tr"
					case "oce": region = "oce"
					case "las": region = "las"
					case "ru" : region = "ru"
				}
			}

			name := strings.ToLower(parts[1])
			if len(name) > 0 {
				summoner := GetSummonerElo(parts[1], region)
				if(summoner.rank == "") {
					s.ChannelMessageSend(m.ChannelID, "Could not find player.")
					return
				}
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("http:%s", summoner.rankImage))
				if(summoner.rank != "Unranked") {
					s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("**%s** %sLP", summoner.rank, summoner.lp))
					s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Wins: **%s** Losses: **%s** Winrate: **%s**", summoner.wins, summoner.losses, strings.Join([]string{summoner.winratio, "%"}, "")))
				} else {
					s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("**%s**", summoner.rank))
				}
				if(name == "uznick") {
					s.ChannelMessageSend(m.ChannelID, "But deserves Challenjour, Kappa.")
				}
				if(name == "mehdid") {
					s.ChannelMessageSend(m.ChannelID, "also, best Amumu EUW")
				}
				if(name == "flakelol") {
					s.ChannelMessageSend(m.ChannelID, "also, best Shen EUW")
				}
			}
		return
		} else {
			return
		}
	}

	if parts[0] == "!weather" {
		country := "de"
		days := []string{"Today", "Tomorrow", "In two days", "In three days"}

		if (len(parts) > 2) { //has 2 arguments
			country = parts[2]
		}
		if (len(parts) > 1) {
			city := parts[1]
			weather := GetWeather(parts[1], country)

			//print out next 3 days
			if (len(weather.Forecast.Time) > 3) {
				s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Weather forecast for: **%s**", capitalize(city)))
				for i := 0; i < 3; i++ {
					d := weather.Forecast.Time[i]
					text := fmt.Sprintf("%s: **%s**        min: **%s**°C max: **%s**°C        **%s** from **%s**", days[i], capitalize(d.Symbol.Name), d.Temperature.Min, d.Temperature.Max, strings.ToLower(d.WindSpeed.Name), strings.ToLower(d.WindDirection.Name))
					s.ChannelMessageSend(m.ChannelID, text)
				}
			} else { s.ChannelMessageSend(m.ChannelID, "Can't find information about this city.")
		 }
		}
	}

	if (parts[0] == "!jarvis") {
		rand.Seed(50)
		answers := []string {
			"It is certain.",
			"It is decidedly so.",
			"Without a doubt.",
			"Yes definitely.",
			"You may rely on it.",
			"As I see it yes.",
			"Most likely.",
			"Outlook good.",
			"Yes.",
			"Signs point to yes.",
			"Reply hazy try again.",
			"Ask again later.",
			"Better not tell you now.",
			"Cannot predict now.",
			"Concentrate and ask again.",
			"Don't count on it.",
			"My reply is no.",
			"My sources say no.",
			"Outlook not so good.",
			"Very doubtful.",
		}
	s.ChannelMessageSend(m.ChannelID, answers[rand.Intn(len(answers))])
	}

	// if scontains(parts[0], COMMANDS...) {
	// 	// Support !airhorn <sound>
	// 	if len(parts) > 1 {
	// 		for _, s := range AIRHORNS {
	// 			if parts[1] == s.Name {
	// 				sound = s
	// 			}
	// 		}
	//
	// 		if sound == nil {
	// 			return
	// 		}
	// 	}
	//
	// 	// Select mode
	// 	if scontains(parts[0], "!cena", "!johncena", "!nycto") {
	// 		stype = TYPE_CENA
	// 	} else if scontains(parts[0], "!eb", "!ethanbradberry", "!h3h3") {
	// 		stype = TYPE_ETHAN
	// 	} else if scontains(parts[0], "!anotha", "!anothaone") {
	// 		khaled = true
	// 	}
	//
	// 	go enqueuePlay(m.Author, guild, sound, khaled, stype)
	// }
}

func main() {
	var (
		Token = flag.String("t", "", "Discord Authentication Token")
		Redis = flag.String("r", "", "Redis Connection String")
		Shard = flag.String("s", "", "Integers to shard by")
		Owner = flag.String("o", "", "Owner ID")
		err   error
	)
	flag.Parse()

	if *Owner != "" {
		OWNER = *Owner
	}

	// Make sure shard is either empty, or an integer
	if *Shard != "" {
		SHARDS = strings.Split(*Shard, ",")

		for _, shard := range SHARDS {
			if _, err := strconv.Atoi(shard); err != nil {
				log.WithFields(log.Fields{
					"shard": shard,
					"error": err,
				}).Fatal("Invalid Shard")
				return
			}
		}
	}

	// Preload all the sounds
	log.Info("Preloading sounds...")
	for _, sound := range AIRHORNS {
		AIRHORN_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	log.Info("Preloading loyalty...")
	for _, sound := range KHALED {
		KHALED_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	log.Info("PRELOADING THE JOHN CENA")
	for _, sound := range CENA {
		CENA_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	log.Info("I'm ethan bradberry!")
	for _, sound := range ETHAN {
		ETHAN_SOUND_RANGE += sound.Weight
		sound.Load()
	}

	// If we got passed a redis server, try to connect
	if *Redis != "" {
		log.Info("Connecting to redis...")
		rcli = redis.NewClient(&redis.Options{Addr: *Redis, DB: 0})
		_, err = rcli.Ping().Result()

		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Fatal("Failed to connect to redis")
			return
		}
	}

	// Create a discord session
	log.Info("Starting discord session...")
	discord, err = discordgo.New(*Token)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord session")
		return
	}

	discord.AddHandler(onReady)
	discord.AddHandler(onGuildCreate)
	discord.AddHandler(onMessageCreate)

	err = discord.Open()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord websocket connection")
		return
	}

	// We're running!
	log.Info("AIRHORNBOT is ready to horn it up.")

	// Wait for a signal to quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"

	"github.com/kisom/goutils/lib"
)

func prettify(file string) error {
	in, err := ioutil.ReadFile(file)
	if err != nil {
		lib.Warn(err, "ReadFile")
		return err
	}

	var buf = &bytes.Buffer{}
	err = json.Indent(buf, in, "", "    ")
	if err != nil {
		lib.Warn(err, "%s", file)
		return err
	}

	err = ioutil.WriteFile(file, buf.Bytes(), 0644)
	if err != nil {
		lib.Warn(err, "WriteFile")
	}

	return err
}

func compact(file string) error {
	in, err := ioutil.ReadFile(file)
	if err != nil {
		lib.Warn(err, "ReadFile")
		return err
	}

	var buf = &bytes.Buffer{}
	err = json.Compact(buf, in)
	if err != nil {
		lib.Warn(err, "%s", file)
		return err
	}

	err = ioutil.WriteFile(file, buf.Bytes(), 0644)
	if err != nil {
		lib.Warn(err, "WriteFile")
	}

	return err
}

func usage() {
	progname := lib.ProgName()
	fmt.Printf(`Usage: %s [-h] files...
	%s is used to lint and prettify (or compact) JSON files. The
	files will be updated in-place.

	Flags:
	-c	Compact files.
	-h	Print this help message.
`, progname, progname)

}

func init() {
	flag.Usage = usage
}

func main() {
	var shouldCompact bool
	flag.BoolVar(&shouldCompact, "c", false, "Compact files instead of prettifying.")
	flag.Parse()

	action := prettify
	if shouldCompact {
		action = compact
	}

	var errCount int
	for _, fileName := range flag.Args() {
		err := action(fileName)
		if err != nil {
			errCount++
		}
	}

	if errCount > 0 {
		lib.Errx(lib.ExitFailure, "Not all files succeeded.")
	}
}
<commit_msg>Add no-write option to jlp.<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"

	"github.com/kisom/goutils/lib"
)

func prettify(file string, validateOnly bool) error {
	in, err := ioutil.ReadFile(file)
	if err != nil {
		lib.Warn(err, "ReadFile")
		return err
	}

	var buf = &bytes.Buffer{}
	err = json.Indent(buf, in, "", "    ")
	if err != nil {
		lib.Warn(err, "%s", file)
		return err
	}

	if validateOnly {
		return nil
	}

	err = ioutil.WriteFile(file, buf.Bytes(), 0644)
	if err != nil {
		lib.Warn(err, "WriteFile")
	}

	return err
}

func compact(file string, validateOnly bool) error {
	in, err := ioutil.ReadFile(file)
	if err != nil {
		lib.Warn(err, "ReadFile")
		return err
	}

	var buf = &bytes.Buffer{}
	err = json.Compact(buf, in)
	if err != nil {
		lib.Warn(err, "%s", file)
		return err
	}

	if validateOnly {
		return nil
	}

	err = ioutil.WriteFile(file, buf.Bytes(), 0644)
	if err != nil {
		lib.Warn(err, "WriteFile")
	}

	return err
}

func usage() {
	progname := lib.ProgName()
	fmt.Printf(`Usage: %s [-h] files...
	%s is used to lint and prettify (or compact) JSON files. The
	files will be updated in-place.

	Flags:
	-c	Compact files.
	-h	Print this help message.
	-n	Don't prettify; only perform validation.
`, progname, progname)

}

func init() {
	flag.Usage = usage
}

func main() {
	var shouldCompact, validateOnly bool
	flag.BoolVar(&shouldCompact, "c", false, "Compact files instead of prettifying.")
	flag.BoolVar(&validateOnly, "n", false, "Don't write changes; only perform validation.")
	flag.Parse()

	action := prettify
	if shouldCompact {
		action = compact
	}

	var errCount int
	for _, fileName := range flag.Args() {
		err := action(fileName, validateOnly)
		if err != nil {
			errCount++
		}
	}

	if errCount > 0 {
		lib.Errx(lib.ExitFailure, "Not all files succeeded.")
	}
}
<|endoftext|>


<commit_before>// A useful example app.  You can use this to debug your tokens on the command line.
// This is also a great place to look at how you might use this library.
//
// Example usage:
// The following will create and sign a token, then verify it and output the original claims.
//     echo {\"foo\":\"bar\"} | bin/jwt -key test/sample_key -alg RS256 -sign - | bin/jwt -key test/sample_key.pub -verify -
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"

	"github.com/dgrijalva/jwt-go"
)

var (
	// Options
	flagAlg    = flag.String("alg", "", "signing algorithm identifier")
	flagKey    = flag.String("key", "", "path to key file or '-' to read from stdin")
	flagPretty = flag.Bool("pretty", true, "output pretty JSON")
	flagDebug  = flag.Bool("debug", false, "print out all kinds of debug data")

	// Modes - exactly one of these is required
	flagSign   = flag.String("sign", "", "path to claims object to sign or '-' to read from stdin")
	flagVerify = flag.String("verify", "", "path to JWT token to verify or '-' to read from stdin")
)

func main() {
	// Usage message if you ask for -help or if you mess up inputs.
	// TODO: make this better
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "  One of the following flags is required: sign, verify\n")
		flag.PrintDefaults()
	}

	// Parse command line options
	flag.Parse()

	// Do the thing.  If something goes wrong, print error to stderr
	// and exit with a non-zero status code
	if err := start(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}

// Figure out which thing to do and then do that
func start() error {
	if *flagSign != "" {
		return signToken()
	} else if *flagVerify != "" {
		return verifyToken()
	} else {
		flag.Usage()
		return fmt.Errorf("None of the required flags are present.  What do you want me to do?")
	}
}

// Helper func:  Read input from specified file or stdin
func loadData(p string) ([]byte, error) {
	if p == "" {
		return nil, fmt.Errorf("No path specified")
	}

	var rdr io.Reader
	if p == "-" {
		rdr = os.Stdin
	} else {
		if f, err := os.Open(p); err == nil {
			rdr = f
			defer f.Close()
		} else {
			return nil, err
		}
	}
	return ioutil.ReadAll(rdr)
}

// Verify a token and output the claims.  This is a great example
// of how to verify and view a token.
func verifyToken() error {
	// get the token
	tokData, err := loadData(*flagVerify)
	if err != nil {
		return fmt.Errorf("Couldn't read token: %v", err)
	}

	// trim possible whitespace from token
	tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
	if *flagDebug {
		fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
	}

	// Parse the token.  Load the key from command line option
	token, err := jwt.Parse(string(tokData), func(t *jwt.Token) ([]byte, error) {
		return loadData(*flagKey)
	})

	// Print some debug data
	if *flagDebug && token != nil {
		fmt.Fprintf(os.Stderr, "Header:\n%v\n", token.Header)
		fmt.Fprintf(os.Stderr, "Claims:\n%v\n", token.Claims)
	}

	// Print an error if we can't parse for some reason
	if err != nil {
		return fmt.Errorf("Couldn't parse token: %v", err)
	}

	// Is token invalid?
	if !token.Valid {
		return fmt.Errorf("Token is invalid")
	}

	// Print the token details
	// TODO: observe the pretty flag
	if out, err := json.MarshalIndent(token.Claims, "", "    "); err == nil {
		fmt.Println(string(out))
	} else {
		return fmt.Errorf("Failed to output claims: %v", err)
	}

	return nil
}

// Create, sign, and output a token.  This is a great, simple example of
// how to use this library to create and sign a token.
func signToken() error {
	// get the token data from command line arguments
	tokData, err := loadData(*flagSign)
	if err != nil {
		return fmt.Errorf("Couldn't read token: %v", err)
	} else if *flagDebug {
		fmt.Println("Token: %v bytes", len(tokData))
	}

	// parse the JSON of the claims
	var claims map[string]interface{}
	if err := json.Unmarshal(tokData, &claims); err != nil {
		return fmt.Errorf("Couldn't parse claims JSON: %v", err)
	}

	// get the key
	keyData, err := loadData(*flagKey)
	if err != nil {
		return fmt.Errorf("Couldn't read key: %v", err)
	}

	// get the signing alg
	alg := jwt.GetSigningMethod(*flagAlg)
	if alg == nil {
		return fmt.Errorf("Couldn't find signing method: %v", *flagAlg)
	}

	// create a new token
	token := jwt.New(alg)
	token.Claims = claims

	if out, err := token.SignedString(keyData); err == nil {
		fmt.Println(out)
	} else {
		return fmt.Errorf("Error signing token: %v", err)
	}

	return nil
}
<commit_msg>clean up todos<commit_after>// A useful example app.  You can use this to debug your tokens on the command line.
// This is also a great place to look at how you might use this library.
//
// Example usage:
// The following will create and sign a token, then verify it and output the original claims.
//     echo {\"foo\":\"bar\"} | bin/jwt -key test/sample_key -alg RS256 -sign - | bin/jwt -key test/sample_key.pub -verify -
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"

	"github.com/dgrijalva/jwt-go"
)

var (
	// Options
	flagAlg    = flag.String("alg", "", "signing algorithm identifier")
	flagKey    = flag.String("key", "", "path to key file or '-' to read from stdin")
	flagPretty = flag.Bool("pretty", true, "output pretty JSON")
	flagDebug  = flag.Bool("debug", false, "print out all kinds of debug data")

	// Modes - exactly one of these is required
	flagSign   = flag.String("sign", "", "path to claims object to sign or '-' to read from stdin")
	flagVerify = flag.String("verify", "", "path to JWT token to verify or '-' to read from stdin")
)

func main() {
	// Usage message if you ask for -help or if you mess up inputs.
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "  One of the following flags is required: sign, verify\n")
		flag.PrintDefaults()
	}

	// Parse command line options
	flag.Parse()

	// Do the thing.  If something goes wrong, print error to stderr
	// and exit with a non-zero status code
	if err := start(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}

// Figure out which thing to do and then do that
func start() error {
	if *flagSign != "" {
		return signToken()
	} else if *flagVerify != "" {
		return verifyToken()
	} else {
		flag.Usage()
		return fmt.Errorf("None of the required flags are present.  What do you want me to do?")
	}
}

// Helper func:  Read input from specified file or stdin
func loadData(p string) ([]byte, error) {
	if p == "" {
		return nil, fmt.Errorf("No path specified")
	}

	var rdr io.Reader
	if p == "-" {
		rdr = os.Stdin
	} else {
		if f, err := os.Open(p); err == nil {
			rdr = f
			defer f.Close()
		} else {
			return nil, err
		}
	}
	return ioutil.ReadAll(rdr)
}

// Print a json object in accordance with the prophecy (or the command line options)
func printJSON(j interface{}) error {
	var out []byte
	var err error

	if *flagPretty {
		out, err = json.MarshalIndent(j, "", "    ")
	} else {
		out, err = json.Marshal(j)
	}

	if err == nil {
		fmt.Println(string(out))
	}

	return err
}

// Verify a token and output the claims.  This is a great example
// of how to verify and view a token.
func verifyToken() error {
	// get the token
	tokData, err := loadData(*flagVerify)
	if err != nil {
		return fmt.Errorf("Couldn't read token: %v", err)
	}

	// trim possible whitespace from token
	tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
	if *flagDebug {
		fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
	}

	// Parse the token.  Load the key from command line option
	token, err := jwt.Parse(string(tokData), func(t *jwt.Token) ([]byte, error) {
		return loadData(*flagKey)
	})

	// Print some debug data
	if *flagDebug && token != nil {
		fmt.Fprintf(os.Stderr, "Header:\n%v\n", token.Header)
		fmt.Fprintf(os.Stderr, "Claims:\n%v\n", token.Claims)
	}

	// Print an error if we can't parse for some reason
	if err != nil {
		return fmt.Errorf("Couldn't parse token: %v", err)
	}

	// Is token invalid?
	if !token.Valid {
		return fmt.Errorf("Token is invalid")
	}

	// Print the token details
	if err := printJSON(token.Claims); err != nil {
		return fmt.Errorf("Failed to output claims: %v", err)
	}

	return nil
}

// Create, sign, and output a token.  This is a great, simple example of
// how to use this library to create and sign a token.
func signToken() error {
	// get the token data from command line arguments
	tokData, err := loadData(*flagSign)
	if err != nil {
		return fmt.Errorf("Couldn't read token: %v", err)
	} else if *flagDebug {
		fmt.Fprintf(os.Stderr, "Token: %v bytes", len(tokData))
	}

	// parse the JSON of the claims
	var claims map[string]interface{}
	if err := json.Unmarshal(tokData, &claims); err != nil {
		return fmt.Errorf("Couldn't parse claims JSON: %v", err)
	}

	// get the key
	keyData, err := loadData(*flagKey)
	if err != nil {
		return fmt.Errorf("Couldn't read key: %v", err)
	}

	// get the signing alg
	alg := jwt.GetSigningMethod(*flagAlg)
	if alg == nil {
		return fmt.Errorf("Couldn't find signing method: %v", *flagAlg)
	}

	// create a new token
	token := jwt.New(alg)
	token.Claims = claims

	if out, err := token.SignedString(keyData); err == nil {
		fmt.Println(out)
	} else {
		return fmt.Errorf("Error signing token: %v", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime/pprof"
	"strings"
	"syscall"
	"time"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/vektra/mockery/v2/pkg"
	"github.com/vektra/mockery/v2/pkg/config"
	"github.com/vektra/mockery/v2/pkg/logging"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/tools/go/packages"
)

var (
	cfgFile = ""
	rootCmd = &cobra.Command{
		Use:   "mockery",
		Short: "Generate mock objects for your Golang interfaces",
		RunE: func(cmd *cobra.Command, args []string) error {
			r, err := GetRootAppFromViper(viper.GetViper())
			if err != nil {
				printStackTrace(err)
				return err
			}
			return r.Run()
		},
	}
)

type stackTracer interface {
	StackTrace() errors.StackTrace
}

func printStackTrace(e error) {
	fmt.Printf("%v\n", e)
	if err, ok := e.(stackTracer); ok {
		for _, f := range err.StackTrace() {
			fmt.Printf("%+s:%d\n", f, f)
		}
	}

}

// Execute executes the cobra CLI workflow
func Execute() {
	if err := rootCmd.Execute(); err != nil {
		//printStackTrace(err)
		os.Exit(1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	pFlags := rootCmd.PersistentFlags()
	pFlags.StringVar(&cfgFile, "config", "", "config file to use")
	pFlags.String("name", "", "name or matching regular expression of interface to generate mock for")
	pFlags.Bool("print", false, "print the generated mock to stdout")
	pFlags.String("output", "./mocks", "directory to write mocks to")
	pFlags.String("outpkg", "mocks", "name of generated package")
	pFlags.String("dir", ".", "directory to search for interfaces")
	pFlags.BoolP("recursive", "r", false, "recurse search into sub-directories")
	pFlags.Bool("all", false, "generates mocks for all found interfaces in all sub-directories")
	pFlags.Bool("inpackage", false, "generate a mock that goes inside the original package")
	pFlags.Bool("testonly", false, "generate a mock in a _test.go file")
	pFlags.String("case", "camel", "name the mocked file using casing convention [camel, snake, underscore]")
	pFlags.String("note", "", "comment to insert into prologue of each generated file")
	pFlags.String("cpuprofile", "", "write cpu profile to file")
	pFlags.Bool("version", false, "prints the installed version of mockery")
	pFlags.Bool("quiet", false, "suppress output to stdout")
	pFlags.Bool("keeptree", false, "keep the tree structure of the original interface files into a different repository. Must be used with XX")
	pFlags.String("tags", "", "space-separated list of additional build tags to use")
	pFlags.String("filename", "", "name of generated file (only works with -name and no regex)")
	pFlags.String("structname", "", "name of generated struct (only works with -name and no regex)")
	pFlags.String("log-level", "info", "Level of logging")
	pFlags.String("srcpkg", "", "source pkg to search for interfaces")
	pFlags.BoolP("dry-run", "d", false, "Do a dry run, don't modify any files")

	viper.BindPFlags(pFlags)
}

func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			log.Fatal().Err(err).Msgf("Failed to find homedir")
		}

		// Search config in home directory with name ".cobra" (without extension).
		viper.AddConfigPath(".")
		viper.AddConfigPath(home)
		viper.SetConfigName(".mockery")
	}

	viper.SetEnvPrefix("mockery")
	viper.AutomaticEnv()

	// Note we purposely ignore the error. Don't care if we can't find a config file.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintf(os.Stderr, "Using config file: %s\n", viper.ConfigFileUsed())
	}
}

const regexMetadataChars = "\\.+*?()|[]{}^$"

type RootApp struct {
	config.Config
}

func GetRootAppFromViper(v *viper.Viper) (*RootApp, error) {
	r := &RootApp{}
	if err := v.UnmarshalExact(&r.Config); err != nil {
		return nil, errors.Wrapf(err, "failed to get config")
	}
	return r, nil
}

func (r *RootApp) Run() error {
	var recursive bool
	var filter *regexp.Regexp
	var err error
	var limitOne bool

	if r.Quiet {
		// if "quiet" flag is set, set os.Stdout to /dev/null to suppress all output to Stdout
		os.Stdout = os.NewFile(uintptr(syscall.Stdout), os.DevNull)
		r.Config.LogLevel = ""
	}

	log, err := getLogger(r.Config.LogLevel)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err)
		return err
	}
	log = log.With().Bool(logging.LogKeyDryRun, r.Config.DryRun).Logger()
	log.Info().Msgf("Starting mockery")
	ctx := log.WithContext(context.Background())

	if r.Config.Version {
		fmt.Println(config.SemVer)
		return nil
	} else if r.Config.Name != "" && r.Config.All {
		log.Fatal().Msgf("Specify --name or --all, but not both")
	} else if (r.Config.FileName != "" || r.Config.StructName != "") && r.Config.All {
		log.Fatal().Msgf("Cannot specify --filename or --structname with --all")
	} else if r.Config.Dir != "" && r.Config.Dir != "." && r.Config.SrcPkg != "" {
		log.Fatal().Msgf("Specify -dir or -srcpkg, but not both")
	} else if r.Config.Name != "" {
		recursive = r.Config.Recursive
		if strings.ContainsAny(r.Config.Name, regexMetadataChars) {
			if filter, err = regexp.Compile(r.Config.Name); err != nil {
				log.Fatal().Err(err).Msgf("Invalid regular expression provided to -name")
			} else if r.Config.FileName != "" || r.Config.StructName != "" {
				log.Fatal().Msgf("Cannot specify --filename or --structname with regex in --name")
			}
		} else {
			filter = regexp.MustCompile(fmt.Sprintf("^%s$", r.Config.Name))
			limitOne = true
		}
	} else if r.Config.All {
		recursive = true
		filter = regexp.MustCompile(".*")
	} else {
		log.Fatal().Msgf("Use --name to specify the name of the interface or --all for all interfaces found")
	}
	if r.Config.KeepTree && r.Config.InPackage {
		log.Fatal().Msgf("--keeptree and --inpackage are mutually exclusive")
	}

	if r.Config.Profile != "" {
		f, err := os.Create(r.Config.Profile)
		if err != nil {
			return errors.Wrapf(err, "Failed to create profile file")
		}

		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	var osp pkg.OutputStreamProvider
	if r.Config.Print {
		osp = &pkg.StdoutStreamProvider{}
	} else {
		osp = &pkg.FileOutputStreamProvider{
			Config:                    r.Config,
			BaseDir:                   r.Config.Output,
			InPackage:                 r.Config.InPackage,
			TestOnly:                  r.Config.TestOnly,
			Case:                      r.Config.Case,
			KeepTree:                  r.Config.KeepTree,
			KeepTreeOriginalDirectory: r.Config.Dir,
			FileName:                  r.Config.FileName,
		}
	}

	baseDir := r.Config.Dir

	if r.Config.SrcPkg != "" {
		pkgs, err := packages.Load(&packages.Config{
			Mode: packages.NeedFiles,
		}, r.Config.SrcPkg)
		if err != nil || len(pkgs) == 0 {
			log.Fatal().Err(err).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		// NOTE: we only pass one package name (config.SrcPkg) to packages.Load
		// it should return one package at most
		pkg := pkgs[0]

		if pkg.Errors != nil {
			log.Fatal().Err(pkg.Errors[0]).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		if len(pkg.GoFiles) == 0 {
			log.Fatal().Msgf("No go files in package %s", r.Config.SrcPkg)
		}
		baseDir = filepath.Dir(pkg.GoFiles[0])
	}

	visitor := &pkg.GeneratorVisitor{
		Config:      r.Config,
		InPackage:   r.Config.InPackage,
		Note:        r.Config.Note,
		Osp:         osp,
		PackageName: r.Config.Outpkg,
		StructName:  r.Config.StructName,
	}

	walker := pkg.Walker{
		Config:    r.Config,
		BaseDir:   baseDir,
		Recursive: recursive,
		Filter:    filter,
		LimitOne:  limitOne,
		BuildTags: strings.Split(r.Config.BuildTags, " "),
	}

	generated := walker.Walk(ctx, visitor)

	if r.Config.Name != "" && !generated {
		log.Fatal().Msgf("Unable to find '%s' in any go files under this path", r.Config.Name)
	}
	return nil
}

type timeHook struct{}

func (t timeHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
	e.Time("time", time.Now())
}

func getLogger(levelStr string) (zerolog.Logger, error) {
	level, err := zerolog.ParseLevel(levelStr)
	if err != nil {
		return zerolog.Logger{}, errors.Wrapf(err, "Couldn't parse log level")
	}
	out := os.Stderr
	writer := zerolog.ConsoleWriter{
		Out:        out,
		TimeFormat: time.RFC822,
	}
	if !terminal.IsTerminal(int(out.Fd())) {
		writer.NoColor = true
	}
	log := zerolog.New(writer).
		Hook(timeHook{}).
		Level(level).
		With().
		Str("version", config.SemVer).
		Logger()

	return log, nil
}
<commit_msg>Fix documentation of "--quiet" flag to reflect behavior<commit_after>package cmd

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime/pprof"
	"strings"
	"time"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/vektra/mockery/v2/pkg"
	"github.com/vektra/mockery/v2/pkg/config"
	"github.com/vektra/mockery/v2/pkg/logging"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/tools/go/packages"
)

var (
	cfgFile = ""
	rootCmd = &cobra.Command{
		Use:   "mockery",
		Short: "Generate mock objects for your Golang interfaces",
		RunE: func(cmd *cobra.Command, args []string) error {
			r, err := GetRootAppFromViper(viper.GetViper())
			if err != nil {
				printStackTrace(err)
				return err
			}
			return r.Run()
		},
	}
)

type stackTracer interface {
	StackTrace() errors.StackTrace
}

func printStackTrace(e error) {
	fmt.Printf("%v\n", e)
	if err, ok := e.(stackTracer); ok {
		for _, f := range err.StackTrace() {
			fmt.Printf("%+s:%d\n", f, f)
		}
	}

}

// Execute executes the cobra CLI workflow
func Execute() {
	if err := rootCmd.Execute(); err != nil {
		//printStackTrace(err)
		os.Exit(1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	pFlags := rootCmd.PersistentFlags()
	pFlags.StringVar(&cfgFile, "config", "", "config file to use")
	pFlags.String("name", "", "name or matching regular expression of interface to generate mock for")
	pFlags.Bool("print", false, "print the generated mock to stdout")
	pFlags.String("output", "./mocks", "directory to write mocks to")
	pFlags.String("outpkg", "mocks", "name of generated package")
	pFlags.String("dir", ".", "directory to search for interfaces")
	pFlags.BoolP("recursive", "r", false, "recurse search into sub-directories")
	pFlags.Bool("all", false, "generates mocks for all found interfaces in all sub-directories")
	pFlags.Bool("inpackage", false, "generate a mock that goes inside the original package")
	pFlags.Bool("testonly", false, "generate a mock in a _test.go file")
	pFlags.String("case", "camel", "name the mocked file using casing convention [camel, snake, underscore]")
	pFlags.String("note", "", "comment to insert into prologue of each generated file")
	pFlags.String("cpuprofile", "", "write cpu profile to file")
	pFlags.Bool("version", false, "prints the installed version of mockery")
	pFlags.Bool("quiet", false, `suppresses logger output (equivalent to --log-level="")`)
	pFlags.Bool("keeptree", false, "keep the tree structure of the original interface files into a different repository. Must be used with XX")
	pFlags.String("tags", "", "space-separated list of additional build tags to use")
	pFlags.String("filename", "", "name of generated file (only works with -name and no regex)")
	pFlags.String("structname", "", "name of generated struct (only works with -name and no regex)")
	pFlags.String("log-level", "info", "Level of logging")
	pFlags.String("srcpkg", "", "source pkg to search for interfaces")
	pFlags.BoolP("dry-run", "d", false, "Do a dry run, don't modify any files")

	viper.BindPFlags(pFlags)
}

func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			log.Fatal().Err(err).Msgf("Failed to find homedir")
		}

		// Search config in home directory with name ".cobra" (without extension).
		viper.AddConfigPath(".")
		viper.AddConfigPath(home)
		viper.SetConfigName(".mockery")
	}

	viper.SetEnvPrefix("mockery")
	viper.AutomaticEnv()

	// Note we purposely ignore the error. Don't care if we can't find a config file.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Fprintf(os.Stderr, "Using config file: %s\n", viper.ConfigFileUsed())
	}
}

const regexMetadataChars = "\\.+*?()|[]{}^$"

type RootApp struct {
	config.Config
}

func GetRootAppFromViper(v *viper.Viper) (*RootApp, error) {
	r := &RootApp{}
	if err := v.UnmarshalExact(&r.Config); err != nil {
		return nil, errors.Wrapf(err, "failed to get config")
	}
	return r, nil
}

func (r *RootApp) Run() error {
	var recursive bool
	var filter *regexp.Regexp
	var err error
	var limitOne bool

	if r.Quiet {
		// if "quiet" flag is set, disable logging
		r.Config.LogLevel = ""
	}

	log, err := getLogger(r.Config.LogLevel)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize logger: %v\n", err)
		return err
	}
	log = log.With().Bool(logging.LogKeyDryRun, r.Config.DryRun).Logger()
	log.Info().Msgf("Starting mockery")
	ctx := log.WithContext(context.Background())

	if r.Config.Version {
		fmt.Println(config.SemVer)
		return nil
	} else if r.Config.Name != "" && r.Config.All {
		log.Fatal().Msgf("Specify --name or --all, but not both")
	} else if (r.Config.FileName != "" || r.Config.StructName != "") && r.Config.All {
		log.Fatal().Msgf("Cannot specify --filename or --structname with --all")
	} else if r.Config.Dir != "" && r.Config.Dir != "." && r.Config.SrcPkg != "" {
		log.Fatal().Msgf("Specify -dir or -srcpkg, but not both")
	} else if r.Config.Name != "" {
		recursive = r.Config.Recursive
		if strings.ContainsAny(r.Config.Name, regexMetadataChars) {
			if filter, err = regexp.Compile(r.Config.Name); err != nil {
				log.Fatal().Err(err).Msgf("Invalid regular expression provided to -name")
			} else if r.Config.FileName != "" || r.Config.StructName != "" {
				log.Fatal().Msgf("Cannot specify --filename or --structname with regex in --name")
			}
		} else {
			filter = regexp.MustCompile(fmt.Sprintf("^%s$", r.Config.Name))
			limitOne = true
		}
	} else if r.Config.All {
		recursive = true
		filter = regexp.MustCompile(".*")
	} else {
		log.Fatal().Msgf("Use --name to specify the name of the interface or --all for all interfaces found")
	}
	if r.Config.KeepTree && r.Config.InPackage {
		log.Fatal().Msgf("--keeptree and --inpackage are mutually exclusive")
	}

	if r.Config.Profile != "" {
		f, err := os.Create(r.Config.Profile)
		if err != nil {
			return errors.Wrapf(err, "Failed to create profile file")
		}

		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	var osp pkg.OutputStreamProvider
	if r.Config.Print {
		osp = &pkg.StdoutStreamProvider{}
	} else {
		osp = &pkg.FileOutputStreamProvider{
			Config:                    r.Config,
			BaseDir:                   r.Config.Output,
			InPackage:                 r.Config.InPackage,
			TestOnly:                  r.Config.TestOnly,
			Case:                      r.Config.Case,
			KeepTree:                  r.Config.KeepTree,
			KeepTreeOriginalDirectory: r.Config.Dir,
			FileName:                  r.Config.FileName,
		}
	}

	baseDir := r.Config.Dir

	if r.Config.SrcPkg != "" {
		pkgs, err := packages.Load(&packages.Config{
			Mode: packages.NeedFiles,
		}, r.Config.SrcPkg)
		if err != nil || len(pkgs) == 0 {
			log.Fatal().Err(err).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		// NOTE: we only pass one package name (config.SrcPkg) to packages.Load
		// it should return one package at most
		pkg := pkgs[0]

		if pkg.Errors != nil {
			log.Fatal().Err(pkg.Errors[0]).Msgf("Failed to load package %s", r.Config.SrcPkg)
		}

		if len(pkg.GoFiles) == 0 {
			log.Fatal().Msgf("No go files in package %s", r.Config.SrcPkg)
		}
		baseDir = filepath.Dir(pkg.GoFiles[0])
	}

	visitor := &pkg.GeneratorVisitor{
		Config:      r.Config,
		InPackage:   r.Config.InPackage,
		Note:        r.Config.Note,
		Osp:         osp,
		PackageName: r.Config.Outpkg,
		StructName:  r.Config.StructName,
	}

	walker := pkg.Walker{
		Config:    r.Config,
		BaseDir:   baseDir,
		Recursive: recursive,
		Filter:    filter,
		LimitOne:  limitOne,
		BuildTags: strings.Split(r.Config.BuildTags, " "),
	}

	generated := walker.Walk(ctx, visitor)

	if r.Config.Name != "" && !generated {
		log.Fatal().Msgf("Unable to find '%s' in any go files under this path", r.Config.Name)
	}
	return nil
}

type timeHook struct{}

func (t timeHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
	e.Time("time", time.Now())
}

func getLogger(levelStr string) (zerolog.Logger, error) {
	level, err := zerolog.ParseLevel(levelStr)
	if err != nil {
		return zerolog.Logger{}, errors.Wrapf(err, "Couldn't parse log level")
	}
	out := os.Stderr
	writer := zerolog.ConsoleWriter{
		Out:        out,
		TimeFormat: time.RFC822,
	}
	if !terminal.IsTerminal(int(out.Fd())) {
		writer.NoColor = true
	}
	log := zerolog.New(writer).
		Hook(timeHook{}).
		Level(level).
		With().
		Str("version", config.SemVer).
		Logger()

	return log, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core"
	"github.com/richardlehane/siegfried/pkg/loc"
	"github.com/richardlehane/siegfried/pkg/mimeinfo"
	"github.com/richardlehane/siegfried/pkg/pronom"
)

var (
	// BUILD, ADD flag sets
	build       = flag.NewFlagSet("build | add", flag.ExitOnError)
	home        = build.String("home", config.Home(), "override the default home directory")
	droid       = build.String("droid", config.Droid(), "set name/path for DROID signature file")
	mi          = build.String("mi", "", "set name/path for MIMEInfo signature file")
	fdd         = build.String("fdd", "", "set name/path for LOC FDD signature file")
	locfdd      = build.Bool("loc", false, "build a LOC FDD signature file")
	nopronom    = build.Bool("nopronom", false, "don't include PRONOM sigs with LOC signature file")
	container   = build.String("container", config.Container(), "set name/path for Droid Container signature file")
	reports     = build.String("reports", config.Reports(), "set path for PRONOM reports directory")
	name        = build.String("name", "", "set identifier name")
	details     = build.String("details", config.Details(), "set identifier details")
	extend      = build.String("extend", "", "comma separated list of additional signatures")
	extendc     = build.String("extendc", "", "comma separated list of additional container signatures")
	include     = build.String("limit", "", "comma separated list of PRONOM signatures to include")
	exclude     = build.String("exclude", "", "comma separated list of PRONOM signatures to exclude")
	bof         = build.Int("bof", 0, "define a maximum BOF offset")
	eof         = build.Int("eof", 0, "define a maximum EOF offset")
	noeof       = build.Bool("noeof", false, "ignore EOF segments in signatures")
	multi       = build.String("multi", "", "control how identifiers treat multiple results")
	nocontainer = build.Bool("nocontainer", false, "skip container signatures")
	notext      = build.Bool("notext", false, "skip text matcher")
	noname      = build.Bool("noname", false, "skip filename matcher")
	nomime      = build.Bool("nomime", false, "skip MIME matcher")
	noxml       = build.Bool("noxml", false, "skip XML matcher")
	noriff      = build.Bool("noriff", false, "skip RIFF matcher")
	noreports   = build.Bool("noreports", false, "build directly from DROID file rather than PRONOM reports")
	doubleup    = build.Bool("doubleup", false, "include byte signatures for formats that also have container signatures")
	rng         = build.Int("range", config.Range(), "define a maximum range for segmentation")
	distance    = build.Int("distance", config.Distance(), "define a maximum distance for segmentation")
	choices     = build.Int("choices", config.Choices(), "define a maximum number of choices for segmentation")

	// HARVEST
	harvest           = flag.NewFlagSet("harvest", flag.ExitOnError)
	harvestHome       = harvest.String("home", config.Home(), "override the default home directory")
	harvestDroid      = harvest.String("droid", config.Droid(), "set name/path for DROID signature file")
	harvestReports    = harvest.String("reports", config.Reports(), "set path for PRONOM reports directory")
	_, htimeout, _, _ = config.HarvestOptions()
	timeout           = harvest.Duration("timeout", htimeout, "set duration before timing-out harvesting requests e.g. 120s")
	throttlef         = harvest.Duration("throttle", 0, "set a time to wait HTTP requests e.g. 50ms")

	// INSPECT (roy inspect | roy inspect fmt/121 | roy inspect usr/local/mysig.gob | roy inspect 10)
	inspect        = flag.NewFlagSet("inspect", flag.ExitOnError)
	inspectHome    = inspect.String("home", config.Home(), "override the default home directory")
	inspectReports = inspect.String("reports", config.Reports(), "set path for PRONOM reports directory")
	inspectMI      = inspect.String("mi", "", "set name/path for MIMEInfo signature file")
	inspectCType   = inspect.Int("ct", 0, "provide container type to inspect container hits")
	inspectCName   = inspect.String("cn", "", "provide container name to inspect container hits")
)

func savereps() error {
	file, err := os.Open(config.Reports())
	if err != nil {
		err = os.Mkdir(config.Reports(), os.ModePerm)
		if err != nil {
			return fmt.Errorf("roy: error making reports directory")
		}
	}
	file.Close()
	errs := pronom.Harvest()
	if len(errs) > 0 {
		return fmt.Errorf("roy: errors saving reports to disk")
	}
	return nil
}

func makegob(s *siegfried.Siegfried, opts []config.Option) error {
	var id core.Identifier
	var err error
	if *mi != "" {
		id, err = mimeinfo.New(opts...)
	} else if *locfdd || *fdd != "" {
		id, err = loc.New(opts...)
	} else {
		id, err = pronom.New(opts...)
	}
	if err != nil {
		return err
	}
	err = s.Add(id)
	if err != nil {
		return err
	}
	return s.Save(config.Signature())
}

func inspectSig(t core.MatcherType) error {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return err
	}
	fmt.Print(s.Inspect(t))
	return nil
}

func inspectFmt(f string) error {
	var id core.Identifier
	var err error
	if *inspectMI != "" {
		id, err = mimeinfo.New(config.SetMIMEInfo(*inspectMI))
	} else if strings.HasPrefix(f, "fdd") {
		id, err = loc.New(config.SetLOC(""))
	} else {
		id, err = pronom.New()
	}
	if err != nil {
		return err
	}
	fmt.Println(id.Inspect(expandSets(f)...))
	return nil
}

func blameSig(i int) error {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return err
	}
	fmt.Println(s.Blame(i, *inspectCType, *inspectCName))
	return nil
}

func buildOptions() []config.Option {
	if *home != config.Home() {
		config.SetHome(*home)
	}
	opts := []config.Option{}
	if *droid != config.Droid() {
		opts = append(opts, config.SetDroid(*droid))
	}
	if *container != config.Container() {
		opts = append(opts, config.SetContainer(*container))
	}
	if *reports != config.Reports() {
		opts = append(opts, config.SetReports(*reports))
	}
	if *mi != "" {
		opts = append(opts, config.SetMIMEInfo(*mi))
	}
	if *fdd != "" {
		opts = append(opts, config.SetLOC(*fdd))
	}
	if *locfdd {
		opts = append(opts, config.SetLOC(""))
	}
	if *nopronom {
		opts = append(opts, config.SetNoPRONOM())
	}
	if *name != "" {
		opts = append(opts, config.SetName(*name))
	}
	if *details != config.Details() {
		opts = append(opts, config.SetDetails(*details))
	}
	if *extend != "" {
		opts = append(opts, config.SetExtend(expandSets(*extend)))
	}
	if *extendc != "" {
		if *extend == "" {
			fmt.Println(
				`roy: warning! Unless the container extension only extends formats defined in
the DROID signature file you should also include a regular signature extension
(-extend) that includes a FileFormatCollection element defining the new formats.`)
		}
		opts = append(opts, config.SetExtendC(expandSets(*extendc)))
	}
	if *include != "" {
		opts = append(opts, config.SetLimit(expandSets(*include)))
	}
	if *exclude != "" {
		opts = append(opts, config.SetExclude(expandSets(*exclude)))
	}
	if *bof != 0 {
		opts = append(opts, config.SetBOF(*bof))
	}
	if *eof != 0 {
		opts = append(opts, config.SetEOF(*eof))
	}
	if *noeof {
		opts = append(opts, config.SetNoEOF())
	}
	if *multi != "" {
		opts = append(opts, config.SetMulti(strings.ToLower(*multi)))
	}
	if *nocontainer {
		opts = append(opts, config.SetNoContainer())
	}
	if *notext {
		opts = append(opts, config.SetNoText())
	}
	if *noname {
		opts = append(opts, config.SetNoName())
	}
	if *nomime {
		opts = append(opts, config.SetNoMIME())
	}
	if *noxml {
		opts = append(opts, config.SetNoXML())
	}
	if *noriff {
		opts = append(opts, config.SetNoRIFF())
	}
	if *noreports {
		opts = append(opts, config.SetNoReports())
	}
	if *doubleup {
		opts = append(opts, config.SetDoubleUp())
	}
	if *rng != config.Range() {
		opts = append(opts, config.SetRange(*rng))
	}
	if *distance != config.Distance() {
		opts = append(opts, config.SetDistance(*distance))
	}
	if *choices != config.Choices() {
		opts = append(opts, config.SetChoices(*choices))
	}
	return opts
}

func setHarvestOptions() {
	if *harvestHome != config.Home() {
		config.SetHome(*harvestHome)
	}
	if *harvestDroid != config.Droid() {
		config.SetDroid(*harvestDroid)()
	}
	if *harvestReports != config.Reports() {
		config.SetReports(*harvestReports)()
	}
	if *timeout != htimeout {
		config.SetHarvestTimeout(*timeout)
	}
	if *throttlef > 0 {
		config.SetHarvestThrottle(*throttlef)
	}
}

func setInspectOptions() {
	if *inspectHome != config.Home() {
		config.SetHome(*inspectHome)
	}
	if *inspectReports != config.Reports() {
		config.SetReports(*inspectReports)()
	}
}

var usage = `
Usage
   roy build -help
   roy add -help
   roy harvest -help
   roy inspect -help
`

func main() {
	var err error
	if len(os.Args) < 2 {
		log.Fatal(usage)
	}

	switch os.Args[1] {
	case "build":
		err = build.Parse(os.Args[2:])
		if err == nil {
			if build.Arg(0) != "" {
				config.SetSignature(build.Arg(0))
			}
			s := siegfried.New()
			err = makegob(s, buildOptions())
		}
	case "add":
		err = build.Parse(os.Args[2:])
		if err == nil {
			if build.Arg(0) != "" {
				config.SetSignature(build.Arg(0))
			}
			var s *siegfried.Siegfried
			s, err = siegfried.Load(config.Signature())
			if err == nil {
				err = makegob(s, buildOptions())
			}
		}
	case "harvest":
		err = harvest.Parse(os.Args[2:])
		if err == nil {
			setHarvestOptions()
			err = savereps()
		}
	case "inspect":
		err = inspect.Parse(os.Args[2:])
		if err == nil {
			setInspectOptions()
			input := inspect.Arg(0)
			switch {
			case input == "":
				err = inspectSig(-1)
			case input == "bytematcher", input == "bm":
				err = inspectSig(core.ByteMatcher)
			case input == "containermatcher", input == "cm":
				err = inspectSig(core.ContainerMatcher)
			case input == "namematcher", input == "nm":
				err = inspectSig(core.NameMatcher)
			case input == "mimematcher", input == "mm":
				err = inspectSig(core.MIMEMatcher)
			case input == "riffmatcher", input == "rm":
				err = inspectSig(core.RIFFMatcher)
			case filepath.Ext(input) == ".sig":
				config.SetSignature(input)
				err = inspectSig(-1)
			case strings.Contains(input, "fmt"), *inspectMI != "", strings.HasPrefix(input, "fdd"):
				err = inspectFmt(input)
			default:
				var i int
				i, err = strconv.Atoi(input)
				if err != nil {
					log.Fatal(err)
				}
				err = blameSig(i)
			}
		}
	default:
		log.Fatal(usage)
	}
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(0)
}
<commit_msg>speed up roy inspect FMT<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core"
	"github.com/richardlehane/siegfried/pkg/loc"
	"github.com/richardlehane/siegfried/pkg/mimeinfo"
	"github.com/richardlehane/siegfried/pkg/pronom"
)

var (
	// BUILD, ADD flag sets
	build       = flag.NewFlagSet("build | add", flag.ExitOnError)
	home        = build.String("home", config.Home(), "override the default home directory")
	droid       = build.String("droid", config.Droid(), "set name/path for DROID signature file")
	mi          = build.String("mi", "", "set name/path for MIMEInfo signature file")
	fdd         = build.String("fdd", "", "set name/path for LOC FDD signature file")
	locfdd      = build.Bool("loc", false, "build a LOC FDD signature file")
	nopronom    = build.Bool("nopronom", false, "don't include PRONOM sigs with LOC signature file")
	container   = build.String("container", config.Container(), "set name/path for Droid Container signature file")
	reports     = build.String("reports", config.Reports(), "set path for PRONOM reports directory")
	name        = build.String("name", "", "set identifier name")
	details     = build.String("details", config.Details(), "set identifier details")
	extend      = build.String("extend", "", "comma separated list of additional signatures")
	extendc     = build.String("extendc", "", "comma separated list of additional container signatures")
	include     = build.String("limit", "", "comma separated list of PRONOM signatures to include")
	exclude     = build.String("exclude", "", "comma separated list of PRONOM signatures to exclude")
	bof         = build.Int("bof", 0, "define a maximum BOF offset")
	eof         = build.Int("eof", 0, "define a maximum EOF offset")
	noeof       = build.Bool("noeof", false, "ignore EOF segments in signatures")
	multi       = build.String("multi", "", "control how identifiers treat multiple results")
	nocontainer = build.Bool("nocontainer", false, "skip container signatures")
	notext      = build.Bool("notext", false, "skip text matcher")
	noname      = build.Bool("noname", false, "skip filename matcher")
	nomime      = build.Bool("nomime", false, "skip MIME matcher")
	noxml       = build.Bool("noxml", false, "skip XML matcher")
	noriff      = build.Bool("noriff", false, "skip RIFF matcher")
	noreports   = build.Bool("noreports", false, "build directly from DROID file rather than PRONOM reports")
	doubleup    = build.Bool("doubleup", false, "include byte signatures for formats that also have container signatures")
	rng         = build.Int("range", config.Range(), "define a maximum range for segmentation")
	distance    = build.Int("distance", config.Distance(), "define a maximum distance for segmentation")
	choices     = build.Int("choices", config.Choices(), "define a maximum number of choices for segmentation")

	// HARVEST
	harvest           = flag.NewFlagSet("harvest", flag.ExitOnError)
	harvestHome       = harvest.String("home", config.Home(), "override the default home directory")
	harvestDroid      = harvest.String("droid", config.Droid(), "set name/path for DROID signature file")
	harvestReports    = harvest.String("reports", config.Reports(), "set path for PRONOM reports directory")
	_, htimeout, _, _ = config.HarvestOptions()
	timeout           = harvest.Duration("timeout", htimeout, "set duration before timing-out harvesting requests e.g. 120s")
	throttlef         = harvest.Duration("throttle", 0, "set a time to wait HTTP requests e.g. 50ms")

	// INSPECT (roy inspect | roy inspect fmt/121 | roy inspect usr/local/mysig.gob | roy inspect 10)
	inspect        = flag.NewFlagSet("inspect", flag.ExitOnError)
	inspectHome    = inspect.String("home", config.Home(), "override the default home directory")
	inspectReports = inspect.String("reports", config.Reports(), "set path for PRONOM reports directory")
	inspectMI      = inspect.String("mi", "", "set name/path for MIMEInfo signature file")
	inspectCType   = inspect.Int("ct", 0, "provide container type to inspect container hits")
	inspectCName   = inspect.String("cn", "", "provide container name to inspect container hits")
)

func savereps() error {
	file, err := os.Open(config.Reports())
	if err != nil {
		err = os.Mkdir(config.Reports(), os.ModePerm)
		if err != nil {
			return fmt.Errorf("roy: error making reports directory")
		}
	}
	file.Close()
	errs := pronom.Harvest()
	if len(errs) > 0 {
		return fmt.Errorf("roy: errors saving reports to disk")
	}
	return nil
}

func makegob(s *siegfried.Siegfried, opts []config.Option) error {
	var id core.Identifier
	var err error
	if *mi != "" {
		id, err = mimeinfo.New(opts...)
	} else if *locfdd || *fdd != "" {
		id, err = loc.New(opts...)
	} else {
		id, err = pronom.New(opts...)
	}
	if err != nil {
		return err
	}
	err = s.Add(id)
	if err != nil {
		return err
	}
	return s.Save(config.Signature())
}

func inspectSig(t core.MatcherType) error {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return err
	}
	fmt.Print(s.Inspect(t))
	return nil
}

func inspectFmt(f string) error {
	var id core.Identifier
	var err error
	if *inspectMI != "" {
		id, err = mimeinfo.New(config.SetMIMEInfo(*inspectMI))
	} else if strings.HasPrefix(f, "fdd") {
		id, err = loc.New(config.SetLOC(""))
	} else {
		id, err = pronom.New(config.SetNoReports())
	}
	if err != nil {
		return err
	}
	fmt.Println(id.Inspect(expandSets(f)...))
	return nil
}

func blameSig(i int) error {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return err
	}
	fmt.Println(s.Blame(i, *inspectCType, *inspectCName))
	return nil
}

func buildOptions() []config.Option {
	if *home != config.Home() {
		config.SetHome(*home)
	}
	opts := []config.Option{}
	if *droid != config.Droid() {
		opts = append(opts, config.SetDroid(*droid))
	}
	if *container != config.Container() {
		opts = append(opts, config.SetContainer(*container))
	}
	if *reports != config.Reports() {
		opts = append(opts, config.SetReports(*reports))
	}
	if *mi != "" {
		opts = append(opts, config.SetMIMEInfo(*mi))
	}
	if *fdd != "" {
		opts = append(opts, config.SetLOC(*fdd))
	}
	if *locfdd {
		opts = append(opts, config.SetLOC(""))
	}
	if *nopronom {
		opts = append(opts, config.SetNoPRONOM())
	}
	if *name != "" {
		opts = append(opts, config.SetName(*name))
	}
	if *details != config.Details() {
		opts = append(opts, config.SetDetails(*details))
	}
	if *extend != "" {
		opts = append(opts, config.SetExtend(expandSets(*extend)))
	}
	if *extendc != "" {
		if *extend == "" {
			fmt.Println(
				`roy: warning! Unless the container extension only extends formats defined in
the DROID signature file you should also include a regular signature extension
(-extend) that includes a FileFormatCollection element defining the new formats.`)
		}
		opts = append(opts, config.SetExtendC(expandSets(*extendc)))
	}
	if *include != "" {
		opts = append(opts, config.SetLimit(expandSets(*include)))
	}
	if *exclude != "" {
		opts = append(opts, config.SetExclude(expandSets(*exclude)))
	}
	if *bof != 0 {
		opts = append(opts, config.SetBOF(*bof))
	}
	if *eof != 0 {
		opts = append(opts, config.SetEOF(*eof))
	}
	if *noeof {
		opts = append(opts, config.SetNoEOF())
	}
	if *multi != "" {
		opts = append(opts, config.SetMulti(strings.ToLower(*multi)))
	}
	if *nocontainer {
		opts = append(opts, config.SetNoContainer())
	}
	if *notext {
		opts = append(opts, config.SetNoText())
	}
	if *noname {
		opts = append(opts, config.SetNoName())
	}
	if *nomime {
		opts = append(opts, config.SetNoMIME())
	}
	if *noxml {
		opts = append(opts, config.SetNoXML())
	}
	if *noriff {
		opts = append(opts, config.SetNoRIFF())
	}
	if *noreports {
		opts = append(opts, config.SetNoReports())
	}
	if *doubleup {
		opts = append(opts, config.SetDoubleUp())
	}
	if *rng != config.Range() {
		opts = append(opts, config.SetRange(*rng))
	}
	if *distance != config.Distance() {
		opts = append(opts, config.SetDistance(*distance))
	}
	if *choices != config.Choices() {
		opts = append(opts, config.SetChoices(*choices))
	}
	return opts
}

func setHarvestOptions() {
	if *harvestHome != config.Home() {
		config.SetHome(*harvestHome)
	}
	if *harvestDroid != config.Droid() {
		config.SetDroid(*harvestDroid)()
	}
	if *harvestReports != config.Reports() {
		config.SetReports(*harvestReports)()
	}
	if *timeout != htimeout {
		config.SetHarvestTimeout(*timeout)
	}
	if *throttlef > 0 {
		config.SetHarvestThrottle(*throttlef)
	}
}

func setInspectOptions() {
	if *inspectHome != config.Home() {
		config.SetHome(*inspectHome)
	}
	if *inspectReports != config.Reports() {
		config.SetReports(*inspectReports)()
	}
}

var usage = `
Usage
   roy build -help
   roy add -help
   roy harvest -help
   roy inspect -help
`

func main() {
	var err error
	if len(os.Args) < 2 {
		log.Fatal(usage)
	}

	switch os.Args[1] {
	case "build":
		err = build.Parse(os.Args[2:])
		if err == nil {
			if build.Arg(0) != "" {
				config.SetSignature(build.Arg(0))
			}
			s := siegfried.New()
			err = makegob(s, buildOptions())
		}
	case "add":
		err = build.Parse(os.Args[2:])
		if err == nil {
			if build.Arg(0) != "" {
				config.SetSignature(build.Arg(0))
			}
			var s *siegfried.Siegfried
			s, err = siegfried.Load(config.Signature())
			if err == nil {
				err = makegob(s, buildOptions())
			}
		}
	case "harvest":
		err = harvest.Parse(os.Args[2:])
		if err == nil {
			setHarvestOptions()
			err = savereps()
		}
	case "inspect":
		err = inspect.Parse(os.Args[2:])
		if err == nil {
			setInspectOptions()
			input := inspect.Arg(0)
			switch {
			case input == "":
				err = inspectSig(-1)
			case input == "bytematcher", input == "bm":
				err = inspectSig(core.ByteMatcher)
			case input == "containermatcher", input == "cm":
				err = inspectSig(core.ContainerMatcher)
			case input == "namematcher", input == "nm":
				err = inspectSig(core.NameMatcher)
			case input == "mimematcher", input == "mm":
				err = inspectSig(core.MIMEMatcher)
			case input == "riffmatcher", input == "rm":
				err = inspectSig(core.RIFFMatcher)
			case filepath.Ext(input) == ".sig":
				config.SetSignature(input)
				err = inspectSig(-1)
			case strings.Contains(input, "fmt"), *inspectMI != "", strings.HasPrefix(input, "fdd"):
				err = inspectFmt(input)
			default:
				var i int
				i, err = strconv.Atoi(input)
				if err != nil {
					log.Fatal(err)
				}
				err = blameSig(i)
			}
		}
	default:
		log.Fatal(usage)
	}
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.10.0")
	},
}
<commit_msg>Bump version<commit_after>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.10.1")
	},
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const Version = "0.1.0"

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:     "version",
	Aliases: []string{"v"},
	Short:   "Print the version of this tool",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("gitlab-cli %v\n", Version)
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<commit_msg>Bump version<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const Version = "0.2.0"

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:     "version",
	Aliases: []string{"v"},
	Short:   "Print the version of this tool",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("gitlab-cli %v\n", Version)
	},
}

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


<commit_before>package cmd

import (
	"github.com/spf13/cobra"
)

var (
	buildVersion string
	buildCommit  string
	buildDate    string
)

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of Ironman",
	Long:  `All software has versions. This is Ironman's.`,
	Run: func(cmd *cobra.Command, args []string) {
		ilogger().Printf("Ironman v%s-%s Build date: %s\n", buildVersion, buildCommit, buildDate)
	},
}

func init() {
	rootCmd.AddCommand(versionCmd)
}
<commit_msg>fix minor format issue in version command<commit_after>package cmd

import (
	"github.com/spf13/cobra"
)

var (
	buildVersion string
	buildCommit  string
	buildDate    string
)

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of Ironman",
	Long:  `All software has versions. This is Ironman's.`,
	Run: func(cmd *cobra.Command, args []string) {
		ilogger().Printf("Ironman %s-%s Build date: %s\n", buildVersion, buildCommit, buildDate)
	},
}

func init() {
	rootCmd.AddCommand(versionCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const version = "v0.8.15"

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of Terraformer",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Terraformer " + version)
	},
}
<commit_msg>Update version.go (#1026)<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const version = "v0.8.16"

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of Terraformer",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Terraformer " + version)
	},
}
<|endoftext|>