<commit_before>package sparse

import (
	"os"
	"os/exec"
	"testing"

	"github.com/rancher/sparse-tools/log"
)

const localPath = "foo1.bar"
const remotePath = "foo2.bar"
const localhost = "127.0.0.1"
const timeout = 5 //seconds

var remoteAddr = TCPEndPoint{localhost, 5000}

func TestSyncFile1(t *testing.T) {
	// D H D => D D H
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseData, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile2(t *testing.T) {
	// H D H  => D H H
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile3(t *testing.T) {
	// D H D => D D
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseData, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile4(t *testing.T) {
	// H D H  => D H
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile5(t *testing.T) {
	// H D H  => H D
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile6(t *testing.T) {
	// H D H  => D
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile7(t *testing.T) {
	// H D H  => H
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile8(t *testing.T) {
	// D H D =>
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseData, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile9(t *testing.T) {
	// H D H  =>
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncHash1(t *testing.T) {
	var hash1, hash2 []byte
	{
		layoutLocal := []FileInterval{
			{SparseData, Interval{0, 1 * Blocks}},
			{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		}
		layoutRemote := layoutLocal
		hash1 = testSyncFile(t, layoutLocal, layoutRemote)
	}
	{

		layoutLocal := []FileInterval{
			{SparseData, Interval{0, 1 * Blocks}},
			{SparseHole, Interval{1 * Blocks, 3 * Blocks}},
		}
		layoutRemote := layoutLocal
		hash2 = testSyncFile(t, layoutLocal, layoutRemote)
	}
    if !isHashDifferent(hash1, hash2) {
        t.Fatal("Files with same data content but different layouts should have unique hashes")
    }
}

func testSyncFile(t *testing.T, layoutLocal, layoutRemote []FileInterval) (hashLocal []byte) {
	// Only log errors
	log.LevelPush(log.LevelError)
	defer log.LevelPop()

	// Create test files
	filesCleanup()
	createTestSparseFile(localPath, layoutLocal)
	if len(layoutRemote) > 0 {
		// only create destination test file if layout is speciifed
		createTestSparseFile(remotePath, layoutRemote)
	}

	// Sync
	go TestServer(remoteAddr, timeout)
	hashLocal, err := SyncFile(localPath, remoteAddr, remotePath, timeout)

	// Verify
	if err != nil {
		t.Fatal("sync error")
	}
	if !filesAreEqual(localPath, remotePath) {
		t.Fatal("file content diverged")
	}
	filesCleanup()
    return
}

func Benchmark_1G_InitFiles(b *testing.B) {
	// Setup files
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, (256 << 10) * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, (256 << 10) * Blocks}},
	}

	filesCleanup()
	createTestSparseFile(localPath, layoutLocal)
	createTestSparseFile(remotePath, layoutRemote)
}

func Benchmark_1G_SendFiles(b *testing.B) {
	log.LevelPush(log.LevelInfo)
	defer log.LevelPop()

	go TestServer(remoteAddr, timeout)
	_, err := SyncFile(localPath, remoteAddr, remotePath, timeout)

	if err != nil {
		b.Fatal("sync error")
	}
}

func Benchmark_1G_CheckFiles(b *testing.B) {
	if !filesAreEqual(localPath, remotePath) {
		b.Error("file content diverged")
		return
	}
	filesCleanup()
}

func filesAreEqual(aPath, bPath string) bool {
	cmd := exec.Command("diff", aPath, bPath)
	err := cmd.Run()
	return nil == err
}

func filesCleanup() {
	os.Remove(localPath)
	os.Remove(remotePath)
}
<commit_msg>test: added hole hash test with absent dst files<commit_after>package sparse

import (
	"os"
	"os/exec"
	"testing"

	"github.com/rancher/sparse-tools/log"
)

const localPath = "foo1.bar"
const remotePath = "foo2.bar"
const localhost = "127.0.0.1"
const timeout = 5 //seconds

var remoteAddr = TCPEndPoint{localhost, 5000}

func TestSyncFile1(t *testing.T) {
	// D H D => D D H
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseData, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile2(t *testing.T) {
	// H D H  => D H H
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile3(t *testing.T) {
	// D H D => D D
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseData, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile4(t *testing.T) {
	// H D H  => D H
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile5(t *testing.T) {
	// H D H  => H D
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile6(t *testing.T) {
	// H D H  => D
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile7(t *testing.T) {
	// H D H  => H
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
	}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile8(t *testing.T) {
	// D H D =>
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, 1 * Blocks}},
		{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		{SparseData, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncFile9(t *testing.T) {
	// H D H  =>
	layoutLocal := []FileInterval{
		{SparseHole, Interval{0, 1 * Blocks}},
		{SparseData, Interval{1 * Blocks, 2 * Blocks}},
		{SparseHole, Interval{2 * Blocks, 3 * Blocks}},
	}
	layoutRemote := []FileInterval{}
	testSyncFile(t, layoutLocal, layoutRemote)
}

func TestSyncHash1(t *testing.T) {
	var hash1, hash2 []byte
	{
		layoutLocal := []FileInterval{
			{SparseData, Interval{0, 1 * Blocks}},
			{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		}
		layoutRemote := layoutLocal
		hash1 = testSyncFile(t, layoutLocal, layoutRemote)
	}
	{

		layoutLocal := []FileInterval{
			{SparseData, Interval{0, 1 * Blocks}},
			{SparseHole, Interval{1 * Blocks, 3 * Blocks}},
		}
		layoutRemote := layoutLocal
		hash2 = testSyncFile(t, layoutLocal, layoutRemote)
	}
    if !isHashDifferent(hash1, hash2) {
        t.Fatal("Files with same data content but different layouts should have unique hashes")
    }
}

func TestSyncHash2(t *testing.T) {
	var hash1, hash2 []byte
	{
		layoutLocal := []FileInterval{
			{SparseData, Interval{0, 1 * Blocks}},
			{SparseHole, Interval{1 * Blocks, 2 * Blocks}},
		}
		layoutRemote := []FileInterval{}
		hash1 = testSyncFile(t, layoutLocal, layoutRemote)
	}
	{

		layoutLocal := []FileInterval{
			{SparseData, Interval{0, 1 * Blocks}},
			{SparseHole, Interval{1 * Blocks, 3 * Blocks}},
		}
		layoutRemote := []FileInterval{}
		hash2 = testSyncFile(t, layoutLocal, layoutRemote)
	}
    if !isHashDifferent(hash1, hash2) {
        t.Fatal("Files with same data content but different layouts should have unique hashes")
    }
}

func testSyncFile(t *testing.T, layoutLocal, layoutRemote []FileInterval) (hashLocal []byte) {
	// Only log errors
	log.LevelPush(log.LevelError)
	defer log.LevelPop()

	// Create test files
	filesCleanup()
	createTestSparseFile(localPath, layoutLocal)
	if len(layoutRemote) > 0 {
		// only create destination test file if layout is speciifed
		createTestSparseFile(remotePath, layoutRemote)
	}

	// Sync
	go TestServer(remoteAddr, timeout)
	hashLocal, err := SyncFile(localPath, remoteAddr, remotePath, timeout)

	// Verify
	if err != nil {
		t.Fatal("sync error")
	}
	if !filesAreEqual(localPath, remotePath) {
		t.Fatal("file content diverged")
	}
	filesCleanup()
    return
}

func Benchmark_1G_InitFiles(b *testing.B) {
	// Setup files
	layoutLocal := []FileInterval{
		{SparseData, Interval{0, (256 << 10) * Blocks}},
	}
	layoutRemote := []FileInterval{
		{SparseData, Interval{0, (256 << 10) * Blocks}},
	}

	filesCleanup()
	createTestSparseFile(localPath, layoutLocal)
	createTestSparseFile(remotePath, layoutRemote)
}

func Benchmark_1G_SendFiles(b *testing.B) {
	log.LevelPush(log.LevelInfo)
	defer log.LevelPop()

	go TestServer(remoteAddr, timeout)
	_, err := SyncFile(localPath, remoteAddr, remotePath, timeout)

	if err != nil {
		b.Fatal("sync error")
	}
}

func Benchmark_1G_CheckFiles(b *testing.B) {
	if !filesAreEqual(localPath, remotePath) {
		b.Error("file content diverged")
		return
	}
	filesCleanup()
}

func filesAreEqual(aPath, bPath string) bool {
	cmd := exec.Command("diff", aPath, bPath)
	err := cmd.Run()
	return nil == err
}

func filesCleanup() {
	os.Remove(localPath)
	os.Remove(remotePath)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strings"

	dgo "github.com/bwmarrin/discordgo"
	trash "github.com/therealfakemoot/trash-talk"
)

// ErrUnexpectedEvent is thrown when discordgo gives me an unexpected or unhandled event.
type ErrUnexpectedEvent struct {
	event interface{}
}

func (e ErrUnexpectedEvent) Error() string {
	return fmt.Sprintf("%+v", e.event)
}

var (
	// ErrIncorrectArgs is a custom error type so I can eventually gracefully handle specific errors I guess.
	ErrIncorrectArgs = errors.New("incorrect arguments supplied")
	// ErrNoCmdFound indicates the cmds map doesn't have a matching key.
	ErrNoCmdFound = errors.New("no matching command found")
	// ErrNoCmdGiven indicates the message is not attempting to execute a command.
	ErrNoCmdGiven = errors.New("no command requested")
)

// Command blah blah
type Command func(args []string, conf Conf, s *dgo.Session, e interface{}) error

// Route blah blah
func Route(input string, conf Conf, cmds map[string]Command, s *dgo.Session, e interface{}) error {
	switch e.(type) {
	case *dgo.MessageCreate:
		args := strings.Split(input, " ")

		if string(args[0][0]) == "!" {
			cmd, ok := cmds[args[0][1:]]
			if !ok {
				return ErrNoCmdFound
			}
			return cmd(args[1:], conf, s, e)
		}

		return ErrNoCmdGiven
	case *dgo.Ready:
	case *dgo.Connect:
	case *dgo.Resumed:
		s.UpdateStatus(0, conf.Status)
	default:
		return ErrUnexpectedEvent{event: e}
	}
	return nil
}

// Mock is a Command that makes fun of the last message a given user sent.
func Mock(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	msgMap := conf.State["msgMap"].(map[string]*dgo.Message)
	m := e.(*dgo.MessageCreate)
	if len(m.Message.Mentions) == 0 {
		s.ChannelMessageSend(m.ChannelID, "You didn't mention anyone.")
		return ErrIncorrectArgs
	}

	target := m.Message.Mentions[0].ID
	targetMsg, ok := msgMap[target]
	if !ok {
		s.ChannelMessageSend(m.ChannelID, "They haven't said anything yet.")
		return ErrIncorrectArgs
	}

	s.ChannelMessageSend(m.ChannelID, trash.Mock(targetMsg.Content))
	return nil
}

func Complain(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	m := e.(*dgo.MessageCreate)
	s.ChannelMessageSend(m.ChannelID, "Life is hard.")

	return nil
}
<commit_msg>Switch statements don't work the way I thought they did.<commit_after>package main

import (
	"errors"
	"fmt"
	"strings"

	dgo "github.com/bwmarrin/discordgo"
	trash "github.com/therealfakemoot/trash-talk"
)

// ErrUnexpectedEvent is thrown when discordgo gives me an unexpected or unhandled event.
type ErrUnexpectedEvent struct {
	event interface{}
}

func (e ErrUnexpectedEvent) Error() string {
	return fmt.Sprintf("%+v", e.event)
}

var (
	// ErrIncorrectArgs is a custom error type so I can eventually gracefully handle specific errors I guess.
	ErrIncorrectArgs = errors.New("incorrect arguments supplied")
	// ErrNoCmdFound indicates the cmds map doesn't have a matching key.
	ErrNoCmdFound = errors.New("no matching command found")
	// ErrNoCmdGiven indicates the message is not attempting to execute a command.
	ErrNoCmdGiven = errors.New("no command requested")
)

// Command blah blah
type Command func(args []string, conf Conf, s *dgo.Session, e interface{}) error

// Route blah blah
func Route(input string, conf Conf, cmds map[string]Command, s *dgo.Session, e interface{}) error {
	switch e.(type) {
	case *dgo.MessageCreate:
		args := strings.Split(input, " ")

		if string(args[0][0]) == "!" {
			cmd, ok := cmds[args[0][1:]]
			if !ok {
				return ErrNoCmdFound
			}
			return cmd(args[1:], conf, s, e)
		}

		return ErrNoCmdGiven
	case *dgo.Ready:
		fallthrough
	case *dgo.Connect:
		fallthrough
	case *dgo.Resumed:
		s.UpdateStatus(0, conf.Status)
	default:
		return ErrUnexpectedEvent{event: e}
	}
	return nil
}

// Mock is a Command that makes fun of the last message a given user sent.
func Mock(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	msgMap := conf.State["msgMap"].(map[string]*dgo.Message)
	m := e.(*dgo.MessageCreate)
	if len(m.Message.Mentions) == 0 {
		s.ChannelMessageSend(m.ChannelID, "You didn't mention anyone.")
		return ErrIncorrectArgs
	}

	target := m.Message.Mentions[0].ID
	targetMsg, ok := msgMap[target]
	if !ok {
		s.ChannelMessageSend(m.ChannelID, "They haven't said anything yet.")
		return ErrIncorrectArgs
	}

	s.ChannelMessageSend(m.ChannelID, trash.Mock(targetMsg.Content))
	return nil
}

func Complain(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	m := e.(*dgo.MessageCreate)
	s.ChannelMessageSend(m.ChannelID, "Life is hard.")

	return nil
}
<|endoftext|>


<commit_before>// -*- tab-width: 4; -*-

package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"time"

	"gopkg.in/readline.v1"
)

func timeline_command(args []string) error {
	fs := flag.NewFlagSet("timeline", flag.ExitOnError)
	durationFlag := fs.Duration("d", 0, "only show tweets created at most `duration` back in time. Example: -d 12h")
	sourceFlag := fs.String("s", "", "only show timeline for given nick")
	fs.Usage = func() {
		fmt.Printf("usage: %s timeline [arguments]\n\nDisplays the timeline.\n\n", progname)
		fs.PrintDefaults()
	}
	fs.Parse(args) // currently using flag.ExitOnError, so we won't get an error on -h
	if fs.NArg() > 0 {
		return errors.New("too many arguments given")
	}
	if *durationFlag < 0 {
		return errors.New("negative duration doesn't make sense")
	}

	var sources map[string]string = conf.Following
	if *sourceFlag != "" {
		url, ok := conf.Following[*sourceFlag]
		if !ok {
			return errors.New(fmt.Sprintf("no source with nick %q", *sourceFlag))
		}
		sources = make(map[string]string)
		sources[*sourceFlag] = url
	}

	cache := Loadcache(configpath)

	alltweets := get_tweets(cache, sources)
	sort.Sort(alltweets)
	now := time.Now().Round(time.Second)
	for _, tweet := range alltweets {
		if *durationFlag == 0 || (now.Sub(tweet.Created)) <= *durationFlag {
			print_tweet(tweet, now)
			fmt.Println()
		}
	}

	cache.Store(configpath)

	return nil
}

func tweet_command(args []string) error {
	fs := flag.NewFlagSet("tweet", flag.ExitOnError)
	fs.Usage = func() {
		fmt.Printf(`usage: %s tweet [words]
   or: %s twet [words]

Adds a new tweet to your twtfile. Words are joined together with a single
space. If no words are given, user will be prompted to input the text
interactively.
`, progname, progname)
		fs.PrintDefaults()
	}
	fs.Parse(args) // currently using flag.ExitOnError, so we won't get an error on -h

	twtfile := conf.Twtfile
	if len(twtfile) == 0 {
		return errors.New("cannot tweet without twtfile set in config")
	}
	// We don't support shell style ~user/foo.txt :P
	if strings.HasPrefix(twtfile, "~/") {
		twtfile = strings.Replace(twtfile, "~", homedir, 1)
	}

	var text string
	if fs.NArg() == 0 {
		var err error
		if text, err = getline(); err != nil {
			return fmt.Errorf("readline: %v", err)
		}
	} else {
		text = strings.Join(fs.Args(), " ")
	}
	text = strings.TrimSpace(text)
	if len(text) == 0 {
		return errors.New("cowardly refusing to tweet empty text, or only spaces")
	}
	text = fmt.Sprintf("%s\t%s\n", time.Now().Format(time.RFC3339), expand_mentions(text))
	f, err := os.OpenFile(twtfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer f.Close()

	var n int
	if n, err = f.WriteString(text); err != nil {
		return err
	}
	fmt.Printf("appended %d bytes to %s:\n%s", n, conf.Twtfile, text)

	return nil
}

func getline() (string, error) {
	rl, err := readline.New("> ")
	if err != nil {
		panic(err)
	}
	defer rl.Close()

	line, err := rl.Readline()
	if err != nil { // io.EOF, readline.ErrInterrupt
		return "", err
	}
	return line, nil
}

// Turns "@nick" into "@<nick URL>" if we're following nick.
func expand_mentions(text string) string {
	re := regexp.MustCompile(`@([_a-zA-Z0-9]+)`)
	return re.ReplaceAllStringFunc(text, func(match string) string {
		parts := re.FindStringSubmatch(match)
		mentionednick := parts[1]

		for followednick, followedurl := range conf.Following {
			if mentionednick == followednick {
				return fmt.Sprintf("@<%s %s>", followednick, followedurl)
			}
		}
		// Not expanding if we're not following
		return match
	})
}
<commit_msg>Store cache right after refreshing it<commit_after>// -*- tab-width: 4; -*-

package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"time"

	"gopkg.in/readline.v1"
)

func timeline_command(args []string) error {
	fs := flag.NewFlagSet("timeline", flag.ExitOnError)
	durationFlag := fs.Duration("d", 0, "only show tweets created at most `duration` back in time. Example: -d 12h")
	sourceFlag := fs.String("s", "", "only show timeline for given nick")
	fs.Usage = func() {
		fmt.Printf("usage: %s timeline [arguments]\n\nDisplays the timeline.\n\n", progname)
		fs.PrintDefaults()
	}
	fs.Parse(args) // currently using flag.ExitOnError, so we won't get an error on -h
	if fs.NArg() > 0 {
		return errors.New("too many arguments given")
	}
	if *durationFlag < 0 {
		return errors.New("negative duration doesn't make sense")
	}

	var sources map[string]string = conf.Following
	if *sourceFlag != "" {
		url, ok := conf.Following[*sourceFlag]
		if !ok {
			return errors.New(fmt.Sprintf("no source with nick %q", *sourceFlag))
		}
		sources = make(map[string]string)
		sources[*sourceFlag] = url
	}

	cache := Loadcache(configpath)

	alltweets := get_tweets(cache, sources)

	cache.Store(configpath)

	sort.Sort(alltweets)
	now := time.Now().Round(time.Second)
	for _, tweet := range alltweets {
		if *durationFlag == 0 || (now.Sub(tweet.Created)) <= *durationFlag {
			print_tweet(tweet, now)
			fmt.Println()
		}
	}

	return nil
}

func tweet_command(args []string) error {
	fs := flag.NewFlagSet("tweet", flag.ExitOnError)
	fs.Usage = func() {
		fmt.Printf(`usage: %s tweet [words]
   or: %s twet [words]

Adds a new tweet to your twtfile. Words are joined together with a single
space. If no words are given, user will be prompted to input the text
interactively.
`, progname, progname)
		fs.PrintDefaults()
	}
	fs.Parse(args) // currently using flag.ExitOnError, so we won't get an error on -h

	twtfile := conf.Twtfile
	if len(twtfile) == 0 {
		return errors.New("cannot tweet without twtfile set in config")
	}
	// We don't support shell style ~user/foo.txt :P
	if strings.HasPrefix(twtfile, "~/") {
		twtfile = strings.Replace(twtfile, "~", homedir, 1)
	}

	var text string
	if fs.NArg() == 0 {
		var err error
		if text, err = getline(); err != nil {
			return fmt.Errorf("readline: %v", err)
		}
	} else {
		text = strings.Join(fs.Args(), " ")
	}
	text = strings.TrimSpace(text)
	if len(text) == 0 {
		return errors.New("cowardly refusing to tweet empty text, or only spaces")
	}
	text = fmt.Sprintf("%s\t%s\n", time.Now().Format(time.RFC3339), expand_mentions(text))
	f, err := os.OpenFile(twtfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		return err
	}
	defer f.Close()

	var n int
	if n, err = f.WriteString(text); err != nil {
		return err
	}
	fmt.Printf("appended %d bytes to %s:\n%s", n, conf.Twtfile, text)

	return nil
}

func getline() (string, error) {
	rl, err := readline.New("> ")
	if err != nil {
		panic(err)
	}
	defer rl.Close()

	line, err := rl.Readline()
	if err != nil { // io.EOF, readline.ErrInterrupt
		return "", err
	}
	return line, nil
}

// Turns "@nick" into "@<nick URL>" if we're following nick.
func expand_mentions(text string) string {
	re := regexp.MustCompile(`@([_a-zA-Z0-9]+)`)
	return re.ReplaceAllStringFunc(text, func(match string) string {
		parts := re.FindStringSubmatch(match)
		mentionednick := parts[1]

		for followednick, followedurl := range conf.Following {
			if mentionednick == followednick {
				return fmt.Sprintf("@<%s %s>", followednick, followedurl)
			}
		}
		// Not expanding if we're not following
		return match
	})
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strings"

	dgo "github.com/bwmarrin/discordgo"
	trash "github.com/therealfakemoot/trash-talk"
)

// ErrUnexpectedEvent is thrown when discordgo gives me an unexpected or unhandled event.
type ErrUnexpectedEvent struct {
	event interface{}
}

func (e ErrUnexpectedEvent) Error() string {
	return fmt.Sprintf("%+v", e.event)
}

var (
	// ErrIncorrectArgs is a custom error type so I can eventually gracefully handle specific errors I guess.
	ErrIncorrectArgs = errors.New("incorrect arguments supplied")
	// ErrNoCmdFound indicates the cmds map doesn't have a matching key.
	ErrNoCmdFound = errors.New("no matching command found")
	// ErrNoCmdGiven indicates the message is not attempting to execute a command.
	ErrNoCmdGiven = errors.New("no command requested")
)

// Command blah blah
type Command func(args []string, conf Conf, s *dgo.Session, e interface{}) error

// Route blah blah
func Route(input string, conf Conf, cmds map[string]Command, s *dgo.Session, e interface{}) error {
	switch e.(type) {
	case *dgo.MessageCreate:
		args := strings.Split(input, " ")

		if string(args[0][0]) == "!" {
			cmd, ok := cmds[args[0][1:]]
			if !ok {
				return ErrNoCmdFound
			}
			return cmd(args[1:], conf, s, e)
		}
	case *dgo.Ready:
	case *dgo.Connect:
	case *dgo.Resumed:
		s.UpdateStatus(0, conf.Status)
	default:
		return ErrUnexpectedEvent{event: e}
	}
	return nil
}

// Mock is a Command that makes fun of the last message a given user sent.
func Mock(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	msgMap := conf.State["msgMap"].(map[string]*dgo.Message)
	m := e.(*dgo.MessageCreate)
	if len(m.Message.Mentions) == 0 {
		s.ChannelMessageSend(m.ChannelID, "You didn't mention anyone.")
		return ErrIncorrectArgs
	}

	target := m.Message.Mentions[0].ID
	targetMsg, ok := msgMap[target]
	if !ok {
		s.ChannelMessageSend(m.ChannelID, "They haven't said anything yet.")
		return ErrIncorrectArgs
	}

	s.ChannelMessageSend(m.ChannelID, trash.Mock(targetMsg.Content))
	return nil
}

func Complain(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	m := e.(*dgo.MessageCreate)
	s.ChannelMessageSend(m.ChannelID, "Life is hard.")

	return nil
}
<commit_msg>This error indicates complete omission of a command from a message.<commit_after>package main

import (
	"errors"
	"fmt"
	"strings"

	dgo "github.com/bwmarrin/discordgo"
	trash "github.com/therealfakemoot/trash-talk"
)

// ErrUnexpectedEvent is thrown when discordgo gives me an unexpected or unhandled event.
type ErrUnexpectedEvent struct {
	event interface{}
}

func (e ErrUnexpectedEvent) Error() string {
	return fmt.Sprintf("%+v", e.event)
}

var (
	// ErrIncorrectArgs is a custom error type so I can eventually gracefully handle specific errors I guess.
	ErrIncorrectArgs = errors.New("incorrect arguments supplied")
	// ErrNoCmdFound indicates the cmds map doesn't have a matching key.
	ErrNoCmdFound = errors.New("no matching command found")
	// ErrNoCmdGiven indicates the message is not attempting to execute a command.
	ErrNoCmdGiven = errors.New("no command requested")
)

// Command blah blah
type Command func(args []string, conf Conf, s *dgo.Session, e interface{}) error

// Route blah blah
func Route(input string, conf Conf, cmds map[string]Command, s *dgo.Session, e interface{}) error {
	switch e.(type) {
	case *dgo.MessageCreate:
		args := strings.Split(input, " ")

		if string(args[0][0]) == "!" {
			cmd, ok := cmds[args[0][1:]]
			if !ok {
				return ErrNoCmdFound
			}
			return cmd(args[1:], conf, s, e)
		}

		return ErrNoCmdGiven
	case *dgo.Ready:
	case *dgo.Connect:
	case *dgo.Resumed:
		s.UpdateStatus(0, conf.Status)
	default:
		return ErrUnexpectedEvent{event: e}
	}
	return nil
}

// Mock is a Command that makes fun of the last message a given user sent.
func Mock(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	msgMap := conf.State["msgMap"].(map[string]*dgo.Message)
	m := e.(*dgo.MessageCreate)
	if len(m.Message.Mentions) == 0 {
		s.ChannelMessageSend(m.ChannelID, "You didn't mention anyone.")
		return ErrIncorrectArgs
	}

	target := m.Message.Mentions[0].ID
	targetMsg, ok := msgMap[target]
	if !ok {
		s.ChannelMessageSend(m.ChannelID, "They haven't said anything yet.")
		return ErrIncorrectArgs
	}

	s.ChannelMessageSend(m.ChannelID, trash.Mock(targetMsg.Content))
	return nil
}

func Complain(args []string, conf Conf, s *dgo.Session, e interface{}) error {
	m := e.(*dgo.MessageCreate)
	s.ChannelMessageSend(m.ChannelID, "Life is hard.")

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"strconv"
	"strings"
)

type readLiner interface {
	ReadLine() (string, error)
}

type commandContext struct {
	args           []string
	stdin          readLiner
	stdout, stderr io.Writer
	pty            bool
}

type command interface {
	execute(context commandContext) (uint32, error)
}

var commands = map[string]command{
	"sh":    cmdShell{},
	"true":  cmdTrue{},
	"false": cmdFalse{},
	"echo":  cmdEcho{},
	"cat":   cmdCat{},
}

var shellProgram = []string{"sh"}

func executeProgram(context commandContext) (uint32, error) {
	if len(context.args) == 0 {
		return 0, nil
	}
	command := commands[context.args[0]]
	if command == nil {
		fmt.Fprintf(context.stdout, "%v: command not found\n", context.args[0])
		return 127, nil
	}
	return command.execute(context)
}

type cmdShell struct{}

func (cmdShell) execute(context commandContext) (uint32, error) {
	var prompt string
	if context.pty {
		prompt = "$ "
	}
	var line string
	var err error
	for err == nil {
		fmt.Fprint(context.stdout, prompt)
		line, err = context.stdin.ReadLine()
		args := strings.Fields(line)
		if len(args) > 0 && args[0] == "exit" {
			var err error
			var status int
			if len(args) > 1 {
				status, err = strconv.Atoi(args[1])
				if err != nil {
					status = 255
				}
			}
			return uint32(status), nil
		}
		if err == nil {
			newContext := context
			newContext.args = strings.Fields(line)
			_, err = executeProgram(newContext)
		}
	}
	return 0, err
}

type cmdTrue struct{}

func (cmdTrue) execute(context commandContext) (uint32, error) {
	return 0, nil
}

type cmdFalse struct{}

func (cmdFalse) execute(context commandContext) (uint32, error) {
	return 1, nil
}

type cmdEcho struct{}

func (cmdEcho) execute(context commandContext) (uint32, error) {
	_, err := fmt.Fprintln(context.stdout, strings.Join(context.args[1:], " "))
	return 0, err
}

type cmdCat struct{}

func (cmdCat) execute(context commandContext) (uint32, error) {
	var line string
	var err error
	for err == nil {
		line, err = context.stdin.ReadLine()
		fmt.Fprintln(context.stdout, line)
	}
	return 0, err
}
<commit_msg>Improved command error handling + not found errors for cat<commit_after>package main

import (
	"fmt"
	"io"
	"strconv"
	"strings"
)

type readLiner interface {
	ReadLine() (string, error)
}

type commandContext struct {
	args           []string
	stdin          readLiner
	stdout, stderr io.Writer
	pty            bool
}

type command interface {
	execute(context commandContext) (uint32, error)
}

var commands = map[string]command{
	"sh":    cmdShell{},
	"true":  cmdTrue{},
	"false": cmdFalse{},
	"echo":  cmdEcho{},
	"cat":   cmdCat{},
}

var shellProgram = []string{"sh"}

func executeProgram(context commandContext) (uint32, error) {
	if len(context.args) == 0 {
		return 0, nil
	}
	command := commands[context.args[0]]
	if command == nil {
		_, err := fmt.Fprintf(context.stderr, "%v: command not found\n", context.args[0])
		return 127, err
	}
	return command.execute(context)
}

type cmdShell struct{}

func (cmdShell) execute(context commandContext) (uint32, error) {
	var prompt string
	if context.pty {
		prompt = "$ "
	}
	var line string
	var err error
	for {
		_, err = fmt.Fprint(context.stdout, prompt)
		if err != nil {
			return 0, err
		}
		line, err = context.stdin.ReadLine()
		if err != nil {
			return 0, err
		}
		args := strings.Fields(line)
		if len(args) > 0 && args[0] == "exit" {
			var err error
			var status int
			if len(args) > 1 {
				status, err = strconv.Atoi(args[1])
				if err != nil {
					status = 255
				}
			}
			return uint32(status), nil
		}
		newContext := context
		newContext.args = strings.Fields(line)
		if _, err = executeProgram(newContext); err != nil {
			return 0, err
		}
	}
}

type cmdTrue struct{}

func (cmdTrue) execute(context commandContext) (uint32, error) {
	return 0, nil
}

type cmdFalse struct{}

func (cmdFalse) execute(context commandContext) (uint32, error) {
	return 1, nil
}

type cmdEcho struct{}

func (cmdEcho) execute(context commandContext) (uint32, error) {
	_, err := fmt.Fprintln(context.stdout, strings.Join(context.args[1:], " "))
	return 0, err
}

type cmdCat struct{}

func (cmdCat) execute(context commandContext) (uint32, error) {
	if len(context.args) > 1 {
		for _, file := range context.args[1:] {
			if _, err := fmt.Fprintf(context.stderr, "%v: %v: No such file or directory\n", context.args[0], file); err != nil {
				return 0, err
			}
		}
		return 1, nil
	}
	var line string
	var err error
	for err == nil {
		line, err = context.stdin.ReadLine()
		if err == nil {
			_, err = fmt.Fprintln(context.stdout, line)
		}
	}
	return 0, err
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"

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

var Commands = []cli.Command{
	commandGet,
	commandList,
	commandLook,
	commandImport,
}

var commandGet = cli.Command{
	Name:  "get",
	Usage: "Clone/sync with a remote repository",
	Description: `
    Clone a GitHub repository under ghq root direcotry. If the repository is
    already cloned to local, nothing will happen unless '-u' ('--update')
    flag is supplied, in which case 'git remote update' is executed.
    When you use '-p' option, the repository is cloned via SSH.
`,
	Action: doGet,
	Flags: []cli.Flag{
		cli.BoolFlag{Name: "update, u", Usage: "Update local repository if cloned already"},
		cli.BoolFlag{Name: "p", Usage: "Clone with SSH"},
		cli.BoolFlag{Name: "shallow", Usage: "Do a shallow clone"},
	},
}

var commandList = cli.Command{
	Name:  "list",
	Usage: "List local repositories",
	Description: `
    List locally cloned repositories. If a query argument is given, only
    repositories whose names contain that query text are listed. '-e'
    ('--exact') forces the match to be an exact one (i.e. the query equals to
    _project_ or _user_/_project_) If '-p' ('--full-path') is given, the full paths
    to the repository root are printed instead of relative ones.
`,
	Action: doList,
	Flags: []cli.Flag{
		cli.BoolFlag{Name: "exact, e", Usage: "Perform an exact match"},
		cli.BoolFlag{Name: "full-path, p", Usage: "Print full paths"},
		cli.BoolFlag{Name: "unique", Usage: "Print unique subpaths"},
	},
}

var commandLook = cli.Command{
	Name:  "look",
	Usage: "Look into a local repository",
	Description: `
    Look into a locally cloned repository with the shell.
`,
	Action: doLook,
}

var commandImport = cli.Command{
	Name:   "import",
	Usage:  "Bulk get repositories from a file or stdin",
	Action: doImport,
}

type commandDoc struct {
	Parent    string
	Arguments string
}

var commandDocs = map[string]commandDoc{
	"get":    {"", "[-u] <repository URL> | [-u] [-p] <user>/<project>"},
	"list":   {"", "[-p] [-e] [<query>]"},
	"look":   {"", "<project> | <user>/<project> | <host>/<user>/<project>"},
	"import": {"", "< file"},
}

// Makes template conditionals to generate per-command documents.
func mkCommandsTemplate(genTemplate func(commandDoc) string) string {
	template := "{{if false}}"
	for _, command := range append(Commands) {
		template = template + fmt.Sprintf("{{else if (eq .Name %q)}}%s", command.Name, genTemplate(commandDocs[command.Name]))
	}
	return template + "{{end}}"
}

func init() {
	argsTemplate := mkCommandsTemplate(func(doc commandDoc) string { return doc.Arguments })
	parentTemplate := mkCommandsTemplate(func(doc commandDoc) string { return string(strings.TrimLeft(doc.Parent+" ", " ")) })

	cli.CommandHelpTemplate = `NAME:
    {{.Name}} - {{.Usage}}

USAGE:
    ghq ` + parentTemplate + `{{.Name}} ` + argsTemplate + `
{{if (len .Description)}}
DESCRIPTION: {{.Description}}
{{end}}{{if (len .Flags)}}
OPTIONS:
    {{range .Flags}}{{.}}
    {{end}}
{{end}}`
}

func doGet(c *cli.Context) {
	argURL := c.Args().Get(0)
	doUpdate := c.Bool("update")
	isShallow := c.Bool("shallow")

	if argURL == "" {
		cli.ShowCommandHelp(c, "get")
		os.Exit(1)
	}

	url, err := NewURL(argURL)
	utils.DieIf(err)

	isSSH := c.Bool("p")
	if isSSH {
		// Assume Git repository if `-p` is given.
		url, err = ConvertGitURLHTTPToSSH(url)
		utils.DieIf(err)
	}

	remote, err := NewRemoteRepository(url)
	utils.DieIf(err)

	if remote.IsValid() == false {
		utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url))
		os.Exit(1)
	}

	getRemoteRepository(remote, doUpdate, isShallow)
}

// getRemoteRepository clones or updates a remote repository remote.
// If doUpdate is true, updates the locally cloned repository. Otherwise does nothing.
// If isShallow is true, does shallow cloning. (no effect if already cloned or the VCS is Mercurial)
func getRemoteRepository(remote RemoteRepository, doUpdate bool, isShallow bool) {
	remoteURL := remote.URL()
	local := LocalRepositoryFromURL(remoteURL)

	path := local.FullPath
	newPath := false

	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			newPath = true
			err = nil
		}
		utils.PanicIf(err)
	}

	if newPath {
		utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path))

		vcs := remote.VCS()
		if vcs == nil {
			utils.Log("error", fmt.Sprintf("Could not find version control system: %s", remoteURL))
			os.Exit(1)
		}

		vcs.Clone(remoteURL, path, isShallow)
	} else {
		if doUpdate {
			utils.Log("update", path)
			local.VCS().Update(path)
		} else {
			utils.Log("exists", path)
		}
	}
}

func doList(c *cli.Context) {
	query := c.Args().First()
	exact := c.Bool("exact")
	printFullPaths := c.Bool("full-path")
	printUniquePaths := c.Bool("unique")

	var filterFn func(*LocalRepository) bool
	if query == "" {
		filterFn = func(_ *LocalRepository) bool {
			return true
		}
	} else if exact {
		filterFn = func(repo *LocalRepository) bool {
			return repo.Matches(query)
		}
	} else {
		filterFn = func(repo *LocalRepository) bool {
			return strings.Contains(repo.NonHostPath(), query)
		}
	}

	repos := []*LocalRepository{}

	walkLocalRepositories(func(repo *LocalRepository) {
		if filterFn(repo) == false {
			return
		}

		repos = append(repos, repo)
	})

	if printUniquePaths {
		subpathCount := map[string]int{} // Count duplicated subpaths (ex. foo/dotfiles and bar/dotfiles)
		reposCount := map[string]int{}   // Check duplicated repositories among roots

		// Primary first
		for _, repo := range repos {
			if reposCount[repo.RelPath] == 0 {
				for _, p := range repo.Subpaths() {
					subpathCount[p] = subpathCount[p] + 1
				}
			}

			reposCount[repo.RelPath] = reposCount[repo.RelPath] + 1
		}

		for _, repo := range repos {
			if reposCount[repo.RelPath] > 1 && repo.IsUnderPrimaryRoot() == false {
				continue
			}

			for _, p := range repo.Subpaths() {
				if subpathCount[p] == 1 {
					fmt.Println(p)
					break
				}
			}
		}
	} else {
		for _, repo := range repos {
			if printFullPaths {
				fmt.Println(repo.FullPath)
			} else {
				fmt.Println(repo.RelPath)
			}
		}
	}
}

func doLook(c *cli.Context) {
	name := c.Args().First()

	if name == "" {
		cli.ShowCommandHelp(c, "look")
		os.Exit(1)
	}

	reposFound := []*LocalRepository{}
	walkLocalRepositories(func(repo *LocalRepository) {
		if repo.Matches(name) {
			reposFound = append(reposFound, repo)
		}
	})

	switch len(reposFound) {
	case 0:
		utils.Log("error", "No repository found")
		os.Exit(1)

	case 1:
		if runtime.GOOS == "windows" {
			cmd := exec.Command(os.Getenv("COMSPEC"))
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Dir = reposFound[0].FullPath
			err := cmd.Start()
			if err == nil {
				cmd.Wait()
				os.Exit(0)
			}
		} else {
			shell := os.Getenv("SHELL")
			if shell == "" {
				shell = "/bin/sh"
			}

			utils.Log("cd", reposFound[0].FullPath)
			err := os.Chdir(reposFound[0].FullPath)
			utils.PanicIf(err)

			syscall.Exec(shell, []string{shell}, syscall.Environ())
		}

	default:
		utils.Log("error", "More than one repositories are found; Try more precise name")
		for _, repo := range reposFound {
			utils.Log("error", "- "+strings.Join(repo.PathParts, "/"))
		}
	}
}

func doImport(c *cli.Context) {
	var (
		doUpdate  = c.Bool("update")
		isSSH     = c.Bool("p")
		isShallow = c.Bool("shallow")
	)

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line := scanner.Text()
		url, err := url.Parse(line)
		if err != nil {
			utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", line, err))
			continue
		}
		if isSSH {
			url, err = ConvertGitURLHTTPToSSH(url)
			if err != nil {
				utils.Log("error", fmt.Sprintf("Could not convert URL <%s>: %s", url, err))
				continue
			}
		}

		remote, err := NewRemoteRepository(url)
		if utils.ErrorIf(err) {
			continue
		}
		if remote.IsValid() == false {
			utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url))
			continue
		}

		getRemoteRepository(remote, doUpdate, isShallow)
	}
	if err := scanner.Err(); err != nil {
		utils.Log("error", fmt.Sprintf("While reading input: %s", err))
		os.Exit(1)
	}
}
<commit_msg>support `ghq import` subcommand<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"net/url"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"

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

var Commands = []cli.Command{
	commandGet,
	commandList,
	commandLook,
	commandImport,
}

var commandGet = cli.Command{
	Name:  "get",
	Usage: "Clone/sync with a remote repository",
	Description: `
    Clone a GitHub repository under ghq root direcotry. If the repository is
    already cloned to local, nothing will happen unless '-u' ('--update')
    flag is supplied, in which case 'git remote update' is executed.
    When you use '-p' option, the repository is cloned via SSH.
`,
	Action: doGet,
	Flags: []cli.Flag{
		cli.BoolFlag{Name: "update, u", Usage: "Update local repository if cloned already"},
		cli.BoolFlag{Name: "p", Usage: "Clone with SSH"},
		cli.BoolFlag{Name: "shallow", Usage: "Do a shallow clone"},
	},
}

var commandList = cli.Command{
	Name:  "list",
	Usage: "List local repositories",
	Description: `
    List locally cloned repositories. If a query argument is given, only
    repositories whose names contain that query text are listed. '-e'
    ('--exact') forces the match to be an exact one (i.e. the query equals to
    _project_ or _user_/_project_) If '-p' ('--full-path') is given, the full paths
    to the repository root are printed instead of relative ones.
`,
	Action: doList,
	Flags: []cli.Flag{
		cli.BoolFlag{Name: "exact, e", Usage: "Perform an exact match"},
		cli.BoolFlag{Name: "full-path, p", Usage: "Print full paths"},
		cli.BoolFlag{Name: "unique", Usage: "Print unique subpaths"},
	},
}

var commandLook = cli.Command{
	Name:  "look",
	Usage: "Look into a local repository",
	Description: `
    Look into a locally cloned repository with the shell.
`,
	Action: doLook,
}

var commandImport = cli.Command{
	Name:   "import",
	Usage:  "Bulk get repositories from a file or stdin",
	Action: doImport,
}

type commandDoc struct {
	Parent    string
	Arguments string
}

var commandDocs = map[string]commandDoc{
	"get":    {"", "[-u] <repository URL> | [-u] [-p] <user>/<project>"},
	"list":   {"", "[-p] [-e] [<query>]"},
	"look":   {"", "<project> | <user>/<project> | <host>/<user>/<project>"},
	"import": {"", "< file"},
}

// Makes template conditionals to generate per-command documents.
func mkCommandsTemplate(genTemplate func(commandDoc) string) string {
	template := "{{if false}}"
	for _, command := range append(Commands) {
		template = template + fmt.Sprintf("{{else if (eq .Name %q)}}%s", command.Name, genTemplate(commandDocs[command.Name]))
	}
	return template + "{{end}}"
}

func init() {
	argsTemplate := mkCommandsTemplate(func(doc commandDoc) string { return doc.Arguments })
	parentTemplate := mkCommandsTemplate(func(doc commandDoc) string { return string(strings.TrimLeft(doc.Parent+" ", " ")) })

	cli.CommandHelpTemplate = `NAME:
    {{.Name}} - {{.Usage}}

USAGE:
    ghq ` + parentTemplate + `{{.Name}} ` + argsTemplate + `
{{if (len .Description)}}
DESCRIPTION: {{.Description}}
{{end}}{{if (len .Flags)}}
OPTIONS:
    {{range .Flags}}{{.}}
    {{end}}
{{end}}`
}

func doGet(c *cli.Context) {
	argURL := c.Args().Get(0)
	doUpdate := c.Bool("update")
	isShallow := c.Bool("shallow")

	if argURL == "" {
		cli.ShowCommandHelp(c, "get")
		os.Exit(1)
	}

	url, err := NewURL(argURL)
	utils.DieIf(err)

	isSSH := c.Bool("p")
	if isSSH {
		// Assume Git repository if `-p` is given.
		url, err = ConvertGitURLHTTPToSSH(url)
		utils.DieIf(err)
	}

	remote, err := NewRemoteRepository(url)
	utils.DieIf(err)

	if remote.IsValid() == false {
		utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url))
		os.Exit(1)
	}

	getRemoteRepository(remote, doUpdate, isShallow)
}

// getRemoteRepository clones or updates a remote repository remote.
// If doUpdate is true, updates the locally cloned repository. Otherwise does nothing.
// If isShallow is true, does shallow cloning. (no effect if already cloned or the VCS is Mercurial)
func getRemoteRepository(remote RemoteRepository, doUpdate bool, isShallow bool) {
	remoteURL := remote.URL()
	local := LocalRepositoryFromURL(remoteURL)

	path := local.FullPath
	newPath := false

	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			newPath = true
			err = nil
		}
		utils.PanicIf(err)
	}

	if newPath {
		utils.Log("clone", fmt.Sprintf("%s -> %s", remoteURL, path))

		vcs := remote.VCS()
		if vcs == nil {
			utils.Log("error", fmt.Sprintf("Could not find version control system: %s", remoteURL))
			os.Exit(1)
		}

		vcs.Clone(remoteURL, path, isShallow)
	} else {
		if doUpdate {
			utils.Log("update", path)
			local.VCS().Update(path)
		} else {
			utils.Log("exists", path)
		}
	}
}

func doList(c *cli.Context) {
	query := c.Args().First()
	exact := c.Bool("exact")
	printFullPaths := c.Bool("full-path")
	printUniquePaths := c.Bool("unique")

	var filterFn func(*LocalRepository) bool
	if query == "" {
		filterFn = func(_ *LocalRepository) bool {
			return true
		}
	} else if exact {
		filterFn = func(repo *LocalRepository) bool {
			return repo.Matches(query)
		}
	} else {
		filterFn = func(repo *LocalRepository) bool {
			return strings.Contains(repo.NonHostPath(), query)
		}
	}

	repos := []*LocalRepository{}

	walkLocalRepositories(func(repo *LocalRepository) {
		if filterFn(repo) == false {
			return
		}

		repos = append(repos, repo)
	})

	if printUniquePaths {
		subpathCount := map[string]int{} // Count duplicated subpaths (ex. foo/dotfiles and bar/dotfiles)
		reposCount := map[string]int{}   // Check duplicated repositories among roots

		// Primary first
		for _, repo := range repos {
			if reposCount[repo.RelPath] == 0 {
				for _, p := range repo.Subpaths() {
					subpathCount[p] = subpathCount[p] + 1
				}
			}

			reposCount[repo.RelPath] = reposCount[repo.RelPath] + 1
		}

		for _, repo := range repos {
			if reposCount[repo.RelPath] > 1 && repo.IsUnderPrimaryRoot() == false {
				continue
			}

			for _, p := range repo.Subpaths() {
				if subpathCount[p] == 1 {
					fmt.Println(p)
					break
				}
			}
		}
	} else {
		for _, repo := range repos {
			if printFullPaths {
				fmt.Println(repo.FullPath)
			} else {
				fmt.Println(repo.RelPath)
			}
		}
	}
}

func doLook(c *cli.Context) {
	name := c.Args().First()

	if name == "" {
		cli.ShowCommandHelp(c, "look")
		os.Exit(1)
	}

	reposFound := []*LocalRepository{}
	walkLocalRepositories(func(repo *LocalRepository) {
		if repo.Matches(name) {
			reposFound = append(reposFound, repo)
		}
	})

	switch len(reposFound) {
	case 0:
		utils.Log("error", "No repository found")
		os.Exit(1)

	case 1:
		if runtime.GOOS == "windows" {
			cmd := exec.Command(os.Getenv("COMSPEC"))
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			cmd.Dir = reposFound[0].FullPath
			err := cmd.Start()
			if err == nil {
				cmd.Wait()
				os.Exit(0)
			}
		} else {
			shell := os.Getenv("SHELL")
			if shell == "" {
				shell = "/bin/sh"
			}

			utils.Log("cd", reposFound[0].FullPath)
			err := os.Chdir(reposFound[0].FullPath)
			utils.PanicIf(err)

			syscall.Exec(shell, []string{shell}, syscall.Environ())
		}

	default:
		utils.Log("error", "More than one repositories are found; Try more precise name")
		for _, repo := range reposFound {
			utils.Log("error", "- "+strings.Join(repo.PathParts, "/"))
		}
	}
}

func doImport(c *cli.Context) {
	var (
		doUpdate  = c.Bool("update")
		isSSH     = c.Bool("p")
		isShallow = c.Bool("shallow")
	)

	var (
		in       io.Reader
		finalize func() error
	)

	if len(c.Args()) == 0 {
		// `ghq import` reads URLs from stdin
		in = os.Stdin
		finalize = func() error { return nil }
	} else {
		// Handle `ghq import starred motemen` case
		// with `git config --global ghq.import.starred "github-list-starred"`
		subCommand := c.Args().First()
		command, err := GitConfigSingle("ghq.import." + subCommand)
		if err == nil && command == "" {
			err = fmt.Errorf("ghq.import.%s configuration not found", subCommand)
		}
		utils.DieIf(err)

		// execute `sh -c 'COMMAND "$@"' -- ARG...`
		// TODO: Windows
		shellCommand := append([]string{"sh", "-c", command + ` "$@"`, "--"}, c.Args().Tail()...)

		utils.Log("run", strings.Join(append([]string{command}, c.Args().Tail()...), " "))

		cmd := exec.Command(shellCommand[0], shellCommand[1:]...)
		cmd.Stderr = os.Stderr

		in, err = cmd.StdoutPipe()
		utils.DieIf(err)

		err = cmd.Start()
		utils.DieIf(err)

		finalize = cmd.Wait
	}

	scanner := bufio.NewScanner(in)
	for scanner.Scan() {
		line := scanner.Text()
		url, err := url.Parse(line)
		if err != nil {
			utils.Log("error", fmt.Sprintf("Could not parse URL <%s>: %s", line, err))
			continue
		}
		if isSSH {
			url, err = ConvertGitURLHTTPToSSH(url)
			if err != nil {
				utils.Log("error", fmt.Sprintf("Could not convert URL <%s>: %s", url, err))
				continue
			}
		}

		remote, err := NewRemoteRepository(url)
		if utils.ErrorIf(err) {
			continue
		}
		if remote.IsValid() == false {
			utils.Log("error", fmt.Sprintf("Not a valid repository: %s", url))
			continue
		}

		getRemoteRepository(remote, doUpdate, isShallow)
	}
	if err := scanner.Err(); err != nil {
		utils.Log("error", fmt.Sprintf("While reading input: %s", err))
		os.Exit(1)
	}

	utils.DieIf(finalize())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/timakin/ts/loader"
	"github.com/codegangsta/cli"
)

var Commands = []cli.Command{
	commandAll,
//	commandBiz,
	commandHack,
}

var commandAll = cli.Command{
	Name:  "pop",
	Usage: "",
	Description: "Show today's news from major tech news sites, HN, PH, and subreddit of /programming.",
	Action: doAll,
}

//var commandBiz = cli.Command{
//	Name:  "biz",
//	Usage: "",
//	Description: `
//`,
//	Action: doBiz,
//}
var commandHack = cli.Command{
	Name:  "test",
	Usage: "",
	Description: `
`,
	Action: doHack,
}

func pp(str string) {
  fmt.Printf(str)
}

func displayRSSFeed(name string, uri string) {
	pp(name + "\n")
	loader.GetRSSFeed(uri)
}

func doAll(c *cli.Context) {
		pp("▁ ▂ ▄ ▅ ▆ ▇ █ тecнѕтacĸ █ ▇ ▆ ▅ ▄ ▂ ▁\n\n")
		ph := make(chan loader.ResultData)
		re := make(chan loader.ResultData)
		go loader.GetPHFeed(ph)
		go loader.GetRedditFeed(re)
		phres := <- ph
		reres := <- re
		var PHData loader.Feed = &phres
		var REData loader.Feed = &reres
		PHData.Display()
		REData.Display()
		displayRSSFeed("[HackerNews]", "https://news.ycombinator.com/rss")
		displayRSSFeed("[TechCrunch]", "http://feeds.feedburner.com/TechCrunch/")
		displayRSSFeed("[Mashable]", "http://feeds.mashable.com/Mashable")
		displayRSSFeed("[Forbes - Tech]", "http://www.forbes.com/technology/feed/")
		displayRSSFeed("[EchoJS]", "http://www.echojs.com/rss")
		displayRSSFeed("[RubyDaily]", "http://feeds.rubydaily.org/RubyDaily")
//		displayRSSFeed("[Hatena]", "http://b.hatena.ne.jp/search/tag?q=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&users=10&mode=rss")
}

//func doBiz(c *cli.Context) {
//}
func doHack(c *cli.Context) {
	displayRSSFeed("[EchoJS]", "http://www.echojs.com/rss")
	displayRSSFeed("[RubyDaily]", "http://feeds.rubydaily.org/RubyDaily")
	displayRSSFeed("[Hatena]", "http://b.hatena.ne.jp/search/tag?q=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&users=10&mode=rss")
}
<commit_msg>Devide ts hack and ts pop<commit_after>package main

import (
	"fmt"
	"github.com/timakin/ts/loader"
	"github.com/codegangsta/cli"
)

var Commands = []cli.Command{
	commandAll,
//	commandBiz,
	commandHack,
}

var commandAll = cli.Command{
	Name:  "pop",
	Usage: "",
	Description: "Show today's news from major tech news sites, HN, PH, and subreddit of /programming.",
	Action: doAll,
}

//var commandBiz = cli.Command{
//	Name:  "biz",
//	Usage: "",
//	Description: `
//`,
//	Action: doBiz,
//}
var commandHack = cli.Command{
	Name:  "hack",
	Usage: "",
	Description: `
`,
	Action: doHack,
}

func pp(str string) {
  fmt.Printf(str)
}

func displayRSSFeed(name string, uri string) {
	pp(name + "\n")
	loader.GetRSSFeed(uri)
}

func doAll(c *cli.Context) {
		pp("▁ ▂ ▄ ▅ ▆ ▇ █ тecнѕтacĸ █ ▇ ▆ ▅ ▄ ▂ ▁\n\n")
		ph := make(chan loader.ResultData)
		re := make(chan loader.ResultData)
		go loader.GetPHFeed(ph)
		go loader.GetRedditFeed(re)
		phres := <- ph
		reres := <- re
		var PHData loader.Feed = &phres
		var REData loader.Feed = &reres
		PHData.Display()
		REData.Display()
		displayRSSFeed("[HackerNews]", "https://news.ycombinator.com/rss")
		displayRSSFeed("[TechCrunch]", "http://feeds.feedburner.com/TechCrunch/")
		displayRSSFeed("[Mashable]", "http://feeds.mashable.com/Mashable")
		displayRSSFeed("[Forbes - Tech]", "http://www.forbes.com/technology/feed/")
		displayRSSFeed("[EchoJS]", "http://www.echojs.com/rss")
		displayRSSFeed("[RubyDaily]", "http://feeds.rubydaily.org/RubyDaily")
//		displayRSSFeed("[Hatena]", "http://b.hatena.ne.jp/search/tag?q=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&users=10&mode=rss")
}

//func doBiz(c *cli.Context) {
//}
func doHack(c *cli.Context) {
	re := make(chan loader.ResultData)
	go loader.GetRedditFeed(re)
	reres := <- re
	var REData loader.Feed = &reres
	REData.Display()
	displayRSSFeed("[HackerNews]", "https://news.ycombinator.com/rss")
	displayRSSFeed("[EchoJS]", "http://www.echojs.com/rss")
	displayRSSFeed("[RubyDaily]", "http://feeds.rubydaily.org/RubyDaily")
	displayRSSFeed("[Hatena]", "http://b.hatena.ne.jp/search/tag?q=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&users=10&mode=rss")
}
<|endoftext|>


<commit_before>package extensions

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
)

type Version struct {
	Major          int
	Minor          int
	Revision       int
	MajorString    string
	MinorString    string
	RevisionString string
	Value          string
}

func TrimSuffix(s, suffix string) string {
	if strings.HasSuffix(s, suffix) {
		s = s[:len(s)-len(suffix)]
	}
	return s
}

func PrintKiloBytes(bytes int64) string {

	var kilobytes float64
	kilobytes = float64(bytes / 1024)

	return fmt.Sprint(FloatToString(kilobytes, 2), " kB")
}

func PrintMegaBytes(bytes int64) string {

	var kilobytes float64
	kilobytes = float64(bytes / 1024)

	var megabytes float64
	megabytes = kilobytes / 1024 // cast to type float64

	return fmt.Sprint(FloatToString(megabytes, 2), " MB")
}

func PrintZettaBytes(bytes int64) string {

	var kilobytes float64
	kilobytes = float64(bytes / 1024)

	var megabytes float64
	megabytes = (kilobytes / 1024) // cast to type float64

	var gigabytes float64
	gigabytes = (megabytes / 1024)

	var terabytes float64
	terabytes = (gigabytes / 1024)

	var petabytes float64
	petabytes = (terabytes / 1024)

	var exabytes float64
	exabytes = (petabytes / 1024)

	var zettabytes float64
	zettabytes = (exabytes / 1024)

	return fmt.Sprint(FloatToString(zettabytes, 2), " ZB")
}

func FloatToString(input_num float64, decimals int) string {
	// to convert a float number to a string
	return strconv.FormatFloat(input_num, 'f', decimals, 64)
}

func StringToInt(val string) int {

	r, err := strconv.Atoi(val)
	if err != nil {
		return 0
	}
	return r
}

func StringToUInt64(val string) uint64 {
	i, err := strconv.ParseUint(val, 10, 64)
	if err != nil {
		return 0
	}
	return i
}

func IntToString(val int) string {
	return strconv.Itoa(val)
}

func (obj *Version) Init(value string) {
	versionInfo := strings.Split(value, ".")

	obj.MajorString = versionInfo[0]
	obj.MinorString = versionInfo[1]
	obj.RevisionString = versionInfo[2]
	obj.Value = value

	if val, err := strconv.Atoi(versionInfo[0]); err == nil {
		obj.Major = val
	}

	if val, err := strconv.Atoi(versionInfo[1]); err == nil {
		obj.Minor = val
	}

	if val, err := strconv.Atoi(versionInfo[2]); err == nil {
		obj.Revision = val
	}
}

func GenPackageImport(name string, imports []string) string {

	val := "package " + name + "\n\n"
	val += "import(\n"
	for _, imp := range imports {
		if imp == "" {
			continue
		}
		val += "\t\"" + imp + "\"\n"
	}
	val += ")\n\n"

	return val
}

func MakeFirstLowerCase(s string) string {

	if len(s) < 2 {
		return strings.ToLower(s)
	}

	bts := []byte(s)

	lc := bytes.ToLower([]byte{bts[0]})
	rest := bts[1:]

	return string(bytes.Join([][]byte{lc, rest}, nil))
}
<commit_msg>Added<commit_after>package extensions

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
)

type Version struct {
	Major          int
	Minor          int
	Revision       int
	MajorString    string
	MinorString    string
	RevisionString string
	Value          string
}

func TrimSuffix(s, suffix string) string {
	if strings.HasSuffix(s, suffix) {
		s = s[:len(s)-len(suffix)]
	}
	return s
}

func PrintKiloBytes(bytes int64) string {

	var kilobytes float64
	kilobytes = float64(bytes / 1024)

	return fmt.Sprint(FloatToString(kilobytes, 2), " kB")
}

func PrintMegaBytes(bytes int64) string {

	var kilobytes float64
	kilobytes = float64(bytes / 1024)

	var megabytes float64
	megabytes = kilobytes / 1024 // cast to type float64

	return fmt.Sprint(FloatToString(megabytes, 2), " MB")
}

func PrintZettaBytes(bytes int64) string {

	var kilobytes float64
	kilobytes = float64(bytes / 1024)

	var megabytes float64
	megabytes = (kilobytes / 1024) // cast to type float64

	var gigabytes float64
	gigabytes = (megabytes / 1024)

	var terabytes float64
	terabytes = (gigabytes / 1024)

	var petabytes float64
	petabytes = (terabytes / 1024)

	var exabytes float64
	exabytes = (petabytes / 1024)

	var zettabytes float64
	zettabytes = (exabytes / 1024)

	return fmt.Sprint(FloatToString(zettabytes, 2), " ZB")
}

func FloatToString(input_num float64, decimals int) string {
	// to convert a float number to a string
	return strconv.FormatFloat(input_num, 'f', decimals, 64)
}

func StringToInt(val string) int {

	r, err := strconv.Atoi(val)
	if err != nil {
		return 0
	}
	return r
}

func StringToUInt64(val string) uint64 {
	i, err := strconv.ParseUint(val, 10, 64)
	if err != nil {
		return 0
	}
	return i
}

func IntToString(val int) string {
	return strconv.Itoa(val)
}

func BoolToString(val bool) string {
	return strconv.FormatBool(val)
}

func StringToBool(val string) bool {
	r, err := strconv.ParseBool(val)
	if err != nil {
		return false
	}
	return r
}

func (obj *Version) Init(value string) {
	versionInfo := strings.Split(value, ".")

	obj.MajorString = versionInfo[0]
	obj.MinorString = versionInfo[1]
	obj.RevisionString = versionInfo[2]
	obj.Value = value

	if val, err := strconv.Atoi(versionInfo[0]); err == nil {
		obj.Major = val
	}

	if val, err := strconv.Atoi(versionInfo[1]); err == nil {
		obj.Minor = val
	}

	if val, err := strconv.Atoi(versionInfo[2]); err == nil {
		obj.Revision = val
	}
}

func GenPackageImport(name string, imports []string) string {

	val := "package " + name + "\n\n"
	val += "import(\n"
	for _, imp := range imports {
		if imp == "" {
			continue
		}
		val += "\t\"" + imp + "\"\n"
	}
	val += ")\n\n"

	return val
}

func MakeFirstLowerCase(s string) string {

	if len(s) < 2 {
		return strings.ToLower(s)
	}

	bts := []byte(s)

	lc := bytes.ToLower([]byte{bts[0]})
	rest := bts[1:]

	return string(bytes.Join([][]byte{lc, rest}, nil))
}
<|endoftext|>


<commit_before>/*******************
 *
 * 对database/sql做简单封装，便于使用
 * mysql驱动使用go-sql-driver
 *
 *********************/

package db

import (
    "fmt"
    "log"
    "regexp"
    "strings"
    "database/sql"
    "reflect"
    _ "github.com/go-sql-driver/mysql"
)

type Mysql struct {
    db *sql.DB
}

func NewMysql(host string, port string, uname string, passwd string, db string, charset string) *Mysql{
    dsn := fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=%s", uname, passwd, host, port, db, charset)
    dbObj, err := sql.Open("mysql", dsn)
    if err != nil {
        log.Fatalf("create db obj error for %s:%s/%s", host, port, db)
    }
    err = dbObj.Ping()
    if err != nil {
        log.Fatalf("connect to %s:%s/%s failed. quit...", host, port, db)
    }
    return &Mysql{dbObj}
}

func (my *Mysql) Query(sqlStr string, args ...interface{} ) (*MysqlResult, error) {
    rows, err := my.db.Query(sqlStr, args...)
    defer func(){
        if rows != nil {
            rows.Close()
        }
    }()

    result := new(MysqlResult)
    if err != nil {
       log.Println(err)
       return result, err
    }

    columns, err := rows.Columns()
    nCols := len(columns)

    //列名与列号的映射
    colIndexMap := make(map[string]int)
    for i, v := range columns {
        colIndexMap[v] = i
    }
    result.ColIndexMap = colIndexMap

    row := make([]interface{}, nCols)
    valueArgs := make([]interface{}, nCols)
    for i, _ := range valueArgs {
        valueArgs[i] = &row[i]       //用于存数据的参数
    }
    var i uint = 0
    for rows.Next() {
        err = rows.Scan(valueArgs...)
        if err == nil {
            strRow := make([]string, nCols)
            for i, v := range row {
                newv, ok := v.([]byte)
                if ok {
                    strRow[i] = string(newv)
                }else{
                    strRow[i] = "<nil>"
                }
            }
            result.Rows = append(result.Rows, strRow)
            i++
        }else{
            log.Printf("scan row %d error\n", i)
        }
    }
    result.NumRows = i
    return result, err
}

func (my *Mysql) Exec(sqlStr string, args ...interface{}) (MysqlResult, error) {
    if isInsert(sqlStr) {
        sqlStr, args = makeMultiInsert(sqlStr, args...)
    }
    res, err := my.db.Exec(sqlStr, args...)
    var result MysqlResult
    if err != nil {
        log.Println("Mysql.Exec", err)
    }else{
        iid, _ := res.LastInsertId()
        nRows, _ := res.RowsAffected()
        result.InsertId = uint(iid)
        result.NumRows = uint(nRows)
    }
    return result,err
}

func isInsert(s string) bool {
    s = strings.ToLower(strings.Trim(s, " "))
    return strings.HasPrefix(s, "insert ") || strings.HasPrefix(s, "replace ")
}

func makeMultiInsert(sqlStr string, args ...interface{}) (string, []interface{}) {
    head := ""
    placeHolder := ""
    tail := ""           //on duplicate
    nValues := 0         //有多少组值

    re, _ := regexp.Compile("\\([?, ]+\\)")   //匹配占位符
    loc := re.FindStringIndex(sqlStr)
    if loc != nil {
        head = sqlStr[: loc[0]]
        placeHolder = sqlStr[ loc[0] : loc[1] ]
        tail = sqlStr[ loc[1]: ]
    }

    var data []interface{}
    nArgs := len(args)
    //检查是否二维数组
    if nArgs == 1 {
        value := reflect.ValueOf(args[0])
        kind := value.Kind()
        vLen := value.Len()
        // []byte 要当成一个整体处理
        if (kind == reflect.Slice || kind == reflect.Array) && value.Type().String() != "[]uint8"{
            for i:=0; i<vLen; i++ {
                val := value.Index(i)
                if (reflect.Slice == val.Kind() || reflect.Array == val.Kind()) && val.Type().String() != "[]uint8" {
                    // 处理二维的情况
                    vLen1 := val.Len()
                    for j:=0; j<vLen1; j++{
                        val1 := val.Index(j)
                        data = append(data, val1.Interface())
                    }
                    nValues++
                }else{
                    // 处理一维的情况
                    data = append(data, val.Interface())
                    nValues = 1
                }
            }
        }else{
            // 处理单个值的情况
            data = append(data, value.Interface())
            nValues = 1
        }
    }else if nArgs > 1{
        //如果是多个参数，就当成一维的
        nValues = 1
        data = args
    }
    if nValues > 1 {
        placeHolder = strings.Trim(strings.Repeat(placeHolder + ", ", nValues), ", ")
    }
    sqlStr = fmt.Sprintf("%s %s %s", head, placeHolder, tail)
    return sqlStr, data
}
/***************************
 *
 * mysql查询结果类型
 *
 ****************************/
type MysqlResult struct {
    Rows [][]string //存结果
    ColIndexMap map[string]int
    InsertId uint       //select时为0
    NumRows uint        //select时是结果行数，insert或update时是影响的行数
}

<commit_msg>fix mysql nil poiter bug<commit_after>/*******************
 *
 * 对database/sql做简单封装，便于使用
 * mysql驱动使用go-sql-driver
 *
 *********************/

package db

import (
    "fmt"
    "log"
    "regexp"
    "strings"
    "database/sql"
    "reflect"
    _ "github.com/go-sql-driver/mysql"
)

type Mysql struct {
    db *sql.DB
}

func NewMysql(host string, port string, uname string, passwd string, db string, charset string) *Mysql{
    dsn := fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=%s", uname, passwd, host, port, db, charset)
    dbObj, err := sql.Open("mysql", dsn)
    if err != nil {
        log.Fatalf("create db obj error for %s:%s/%s", host, port, db)
    }
    err = dbObj.Ping()
    if err != nil {
        log.Fatalf("connect to %s:%s/%s failed. quit...", host, port, db)
    }
    return &Mysql{dbObj}
}

func (my *Mysql) Query(sqlStr string, args ...interface{} ) (result *MysqlResult,  reterr error) {
    defer func(){
        if err := recover(); err != nil {
            log.Println(fmt.Sprintf("Mysql.Query panic:%v", err))
            result = nil
            reterr, _ = err.(error)
        }
    }()

    rows, err := my.db.Query(sqlStr, args...)

    if err != nil {
       log.Println(err)
       return result, err
    }

    columns, err := rows.Columns()
    nCols := len(columns)

    //列名与列号的映射
    colIndexMap := make(map[string]int)
    for i, v := range columns {
        colIndexMap[v] = i
    }
    result.ColIndexMap = colIndexMap

    row := make([]interface{}, nCols)
    valueArgs := make([]interface{}, nCols)
    for i, _ := range valueArgs {
        valueArgs[i] = &row[i]       //用于存数据的参数
    }
    var i uint = 0
    for rows.Next() {
        err = rows.Scan(valueArgs...)
        if err == nil {
            strRow := make([]string, nCols)
            for i, v := range row {
                newv, ok := v.([]byte)
                if ok {
                    strRow[i] = string(newv)
                }else{
                    strRow[i] = "<nil>"
                }
            }
            result.Rows = append(result.Rows, strRow)
            i++
        }else{
            log.Printf("scan row %d error\n", i)
        }
    }
    if rows != nil {
        rows.Close()
    }
    result.NumRows = i
    return result, err
}

func (my *Mysql) Exec(sqlStr string, args ...interface{}) (MysqlResult, error) {
    var result MysqlResult

    defer func(){
        if err := recover(); err != nil {
            log.Println(fmt.Sprintf("Mysql.Exec panic:%v", err))
        }
    }()

    if isInsert(sqlStr) {
        sqlStr, args = makeMultiInsert(sqlStr, args...)
    }
    res, err := my.db.Exec(sqlStr, args...)
    if err != nil {
        log.Println("Mysql.Exec", err)
    }else{
        iid, _ := res.LastInsertId()
        nRows, _ := res.RowsAffected()
        result.InsertId = uint(iid)
        result.NumRows = uint(nRows)
    }
    return result,err
}

func isInsert(s string) bool {
    s = strings.ToLower(strings.Trim(s, " "))
    return strings.HasPrefix(s, "insert ") || strings.HasPrefix(s, "replace ")
}

func makeMultiInsert(sqlStr string, args ...interface{}) (string, []interface{}) {
    head := ""
    placeHolder := ""
    tail := ""           //on duplicate
    nValues := 0         //有多少组值

    re, _ := regexp.Compile("\\([?, ]+\\)")   //匹配占位符
    loc := re.FindStringIndex(sqlStr)
    if loc != nil {
        head = sqlStr[: loc[0]]
        placeHolder = sqlStr[ loc[0] : loc[1] ]
        tail = sqlStr[ loc[1]: ]
    }

    var data []interface{}
    nArgs := len(args)
    //检查是否二维数组
    if nArgs == 1 {
        value := reflect.ValueOf(args[0])
        kind := value.Kind()
        vLen := value.Len()
        // []byte 要当成一个整体处理
        if (kind == reflect.Slice || kind == reflect.Array) && value.Type().String() != "[]uint8"{
            for i:=0; i<vLen; i++ {
                val := value.Index(i)
                if (reflect.Slice == val.Kind() || reflect.Array == val.Kind()) && val.Type().String() != "[]uint8" {
                    // 处理二维的情况
                    vLen1 := val.Len()
                    for j:=0; j<vLen1; j++{
                        val1 := val.Index(j)
                        data = append(data, val1.Interface())
                    }
                    nValues++
                }else{
                    // 处理一维的情况
                    data = append(data, val.Interface())
                    nValues = 1
                }
            }
        }else{
            // 处理单个值的情况
            data = append(data, value.Interface())
            nValues = 1
        }
    }else if nArgs > 1{
        //如果是多个参数，就当成一维的
        nValues = 1
        data = args
    }
    if nValues > 1 {
        placeHolder = strings.Trim(strings.Repeat(placeHolder + ", ", nValues), ", ")
    }
    sqlStr = fmt.Sprintf("%s %s %s", head, placeHolder, tail)
    return sqlStr, data
}
/***************************
 *
 * mysql查询结果类型
 *
 ****************************/
type MysqlResult struct {
    Rows [][]string //存结果
    ColIndexMap map[string]int
    InsertId uint       //select时为0
    NumRows uint        //select时是结果行数，insert或update时是影响的行数
}

<|endoftext|>


<commit_before>package types

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"reflect"
)

var _ = Describe("SetupFunction", func() {
	Context("Builder", func() {
		var resultsChan chan FunctionInfo
		BeforeEach(func() {
			resultsChan = make(chan FunctionInfo, 1)
		})

		It("writes the correct information to the channel", func(done Done) {
			defer close(done)

			fake := func(s SetupFunction) {}
			f := NewSetupFunctionBuilder("someName", fake, resultsChan)
			fakeIn := make(chan HashedData)
			fakeOut := make(chan HashedData)

			go func() {
				defer GinkgoRecover()
				in, out := f.AsFilter("someParent", 5)
				var fin ReadOnlyChannel
				var fout WriteOnlyChannel
				fin = fakeIn
				fout = fakeOut
				Expect(in).To(BeEquivalentTo(fin))
				Expect(out).To(BeEquivalentTo(fout))
			}()

			fi := <-resultsChan
			fi.ReadChan() <- fakeIn
			fi.WriteChan() <- fakeOut

			Expect(fi.Name()).To(BeEquivalentTo("someName"))
			Expect(reflect.ValueOf(fi.Function()).Pointer()).To(Equal(reflect.ValueOf(fake).Pointer()))
			Expect(fi.Parent()).To(BeEquivalentTo("someParent"))
			Expect(fi.FuncType()).To(Equal(FILTER))
			Expect(fi.Instances()).To(Equal(5))
		}, 1)

		It("PRODUCER doesn't read from ReadChan", func(done Done) {
			defer close(done)

			fake := func(s SetupFunction) {}
			f := NewSetupFunctionBuilder("someName", fake, resultsChan)

			var fout WriteOnlyChannel
			fakeOut := make(chan HashedData)
			fout = fakeOut

			go func() {
				fi := <-resultsChan
				fi.WriteChan() <- fakeOut
			}()

			out := f.AsProducer(5)

			Expect(out).To(BeEquivalentTo(fout))
		}, 1)

		It("CONSUMER doesn't read from WriteChan", func(done Done) {
			defer close(done)

			fake := func(s SetupFunction) {}
			f := NewSetupFunctionBuilder("someName", fake, resultsChan)

			var fin ReadOnlyChannel
			fakeIn := make(chan HashedData)
			fin = fakeIn

			go func() {
				fi := <-resultsChan
				fi.ReadChan() <- fakeIn
			}()

			in := f.AsConsumer("someParent", 5)

			Expect(in).To(BeEquivalentTo(fin))
		}, 1)
	})

	Context("Interface Implementation", func() {
		var (
			fake      *fakeSetupFunction
			fakeSetup SetupFunction
		)

		BeforeEach(func() {
			fake = NewFakeSetupFunction()
			fakeSetup = setupFunction(fake.setup)
		})

		Context("AsProducer", func() {
			It("Returns the correct channel and FunctionType", func() {
				Expect(fakeSetup.AsProducer(5)).To(Equal(fake.out))
				Expect(fake.funcType).To(Equal(PRODUCER))
				Expect(fake.instances).To(Equal(5))
			})
		})

		Context("AsFilter", func() {
			It("Returns the correct channels, FunctionType and parent", func() {
				in, out := fakeSetup.AsFilter("fakeParent", 5)
				Expect(in).To(Equal(fake.in))
				Expect(out).To(Equal(fake.out))
				Expect(fake.funcType).To(Equal(FILTER))
				Expect(fake.parent).To(Equal("fakeParent"))
				Expect(fake.instances).To(Equal(5))
			})
		})

		Context("AsConsumer", func() {
			It("Returns the correct channel, FunctionType, and parent", func() {
				Expect(fakeSetup.AsConsumer("fakeParent", 5)).To(Equal(fake.in))
				Expect(fake.funcType).To(Equal(CONSUMER))
				Expect(fake.parent).To(Equal("fakeParent"))
				Expect(fake.instances).To(Equal(5))
			})
		})
	})
})

type fakeSetupFunction struct {
	parent    string
	instances int
	funcType  FunctionType
	in        ReadOnlyChannel
	out       WriteOnlyChannel
}

func NewFakeSetupFunction() *fakeSetupFunction {
	return &fakeSetupFunction{
		in:  make(chan HashedData),
		out: make(chan HashedData),
	}
}

func (f *fakeSetupFunction) setup(parent string, instances int, funcType FunctionType) (in ReadOnlyChannel, out WriteOnlyChannel) {
	f.parent = parent
	f.instances = instances
	f.funcType = funcType
	return f.in, f.out
}
<commit_msg>Removes interface tests.<commit_after>package types_test

import (
	. "github.com/apoydence/hydra/types"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"reflect"
)

var _ = Describe("SetupFunction", func() {
	Context("Builder", func() {
		var resultsChan chan FunctionInfo
		BeforeEach(func() {
			resultsChan = make(chan FunctionInfo, 1)
		})

		It("writes the correct information to the channel", func(done Done) {
			defer close(done)

			fake := func(s SetupFunction) {}
			f := NewSetupFunctionBuilder("someName", fake, resultsChan)
			fakeIn := make(chan HashedData)
			fakeOut := make(chan HashedData)

			go func() {
				defer GinkgoRecover()
				in, out := f.AsFilter("someParent", 5)
				var fin ReadOnlyChannel
				var fout WriteOnlyChannel
				fin = fakeIn
				fout = fakeOut
				Expect(in).To(BeEquivalentTo(fin))
				Expect(out).To(BeEquivalentTo(fout))
			}()

			fi := <-resultsChan
			fi.ReadChan() <- fakeIn
			fi.WriteChan() <- fakeOut

			Expect(fi.Name()).To(BeEquivalentTo("someName"))
			Expect(reflect.ValueOf(fi.Function()).Pointer()).To(Equal(reflect.ValueOf(fake).Pointer()))
			Expect(fi.Parent()).To(BeEquivalentTo("someParent"))
			Expect(fi.FuncType()).To(Equal(FILTER))
			Expect(fi.Instances()).To(Equal(5))
		}, 1)

		It("PRODUCER doesn't read from ReadChan", func(done Done) {
			defer close(done)

			fake := func(s SetupFunction) {}
			f := NewSetupFunctionBuilder("someName", fake, resultsChan)

			var fout WriteOnlyChannel
			fakeOut := make(chan HashedData)
			fout = fakeOut

			go func() {
				fi := <-resultsChan
				fi.WriteChan() <- fakeOut
			}()

			out := f.AsProducer(5)

			Expect(out).To(BeEquivalentTo(fout))
		}, 1)

		It("CONSUMER doesn't read from WriteChan", func(done Done) {
			defer close(done)

			fake := func(s SetupFunction) {}
			f := NewSetupFunctionBuilder("someName", fake, resultsChan)

			var fin ReadOnlyChannel
			fakeIn := make(chan HashedData)
			fin = fakeIn

			go func() {
				fi := <-resultsChan
				fi.ReadChan() <- fakeIn
			}()

			in := f.AsConsumer("someParent", 5)

			Expect(in).To(BeEquivalentTo(fin))
		}, 1)
	})
})
<|endoftext|>


<commit_before>package warden

import (
	"net/http"
	"net/url"

	"github.com/ory-am/fosite"
	"github.com/ory-am/hydra/firewall"
	"github.com/ory-am/hydra/pkg"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
)

type HTTPWarden struct {
	Client   *http.Client
	Dry      bool
	Endpoint *url.URL
}

func (w *HTTPWarden) TokenFromRequest(r *http.Request) string {
	return fosite.AccessTokenFromRequest(r)
}

func (w *HTTPWarden) SetClient(c *clientcredentials.Config) {
	w.Client = c.Client(oauth2.NoContext)
}

// TokenAllowed checks if a token is valid and if the token owner is allowed to perform an action on a resource.
// This endpoint requires a token, a scope, a resource name, an action name and a context.
//
// The HTTP API is documented at http://docs.hdyra.apiary.io/#reference/warden:-access-control-for-resource-providers/check-if-an-access-tokens-subject-is-allowed-to-do-something
func (w *HTTPWarden) TokenAllowed(ctx context.Context, token string, a *firewall.TokenAccessRequest, scopes ...string) (*firewall.Context, error) {
	var resp = struct {
		*firewall.Context
		Allowed bool `json:"allowed"`
	}{}

	var ep = *w.Endpoint
	ep.Path = TokenAllowedHandlerPath
	agent := &pkg.SuperAgent{URL: ep.String(), Client: w.Client}
	if err := agent.POST(&wardenAccessRequest{
		wardenAuthorizedRequest: &wardenAuthorizedRequest{
			Token:  token,
			Scopes: scopes,
		},
		TokenAccessRequest: a,
	}, &resp); err != nil {
		return nil, err
	} else if !resp.Allowed {
		return nil, errors.New("Token is not valid")
	}

	return resp.Context, nil
}

// IsAllowed checks if an arbitrary subject is allowed to perform an action on a resource.
//
// The HTTP API is documented at http://docs.hdyra.apiary.io/#reference/warden:-access-control-for-resource-providers/check-if-a-subject-is-allowed-to-do-something
func (w *HTTPWarden) IsAllowed(ctx context.Context, a *firewall.AccessRequest) error {
	var allowed = struct {
		Allowed bool `json:"allowed"`
	}{}

	var ep = *w.Endpoint
	ep.Path = AllowedHandlerPath
	agent := &pkg.SuperAgent{URL: ep.String(), Client: w.Client}
	if err := agent.POST(a, &allowed); err != nil {
		return err
	} else if !allowed.Allowed {
		return errors.New("Forbidden")
	}

	return nil
}
<commit_msg>warden: improve error results<commit_after>package warden

import (
	"net/http"
	"net/url"

	"github.com/ory-am/fosite"
	"github.com/ory-am/hydra/firewall"
	"github.com/ory-am/hydra/pkg"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"
)

type HTTPWarden struct {
	Client   *http.Client
	Dry      bool
	Endpoint *url.URL
}

func (w *HTTPWarden) TokenFromRequest(r *http.Request) string {
	return fosite.AccessTokenFromRequest(r)
}

func (w *HTTPWarden) SetClient(c *clientcredentials.Config) {
	w.Client = c.Client(oauth2.NoContext)
}

// TokenAllowed checks if a token is valid and if the token owner is allowed to perform an action on a resource.
// This endpoint requires a token, a scope, a resource name, an action name and a context.
//
// The HTTP API is documented at http://docs.hdyra.apiary.io/#reference/warden:-access-control-for-resource-providers/check-if-an-access-tokens-subject-is-allowed-to-do-something
func (w *HTTPWarden) TokenAllowed(ctx context.Context, token string, a *firewall.TokenAccessRequest, scopes ...string) (*firewall.Context, error) {
	var resp = struct {
		*firewall.Context
		Allowed bool `json:"allowed"`
	}{}

	var ep = *w.Endpoint
	ep.Path = TokenAllowedHandlerPath
	agent := &pkg.SuperAgent{URL: ep.String(), Client: w.Client}
	if err := agent.POST(&wardenAccessRequest{
		wardenAuthorizedRequest: &wardenAuthorizedRequest{
			Token:  token,
			Scopes: scopes,
		},
		TokenAccessRequest: a,
	}, &resp); err != nil {
		return nil, err
	} else if !resp.Allowed {
		return nil, errors.New("Token is not valid")
	}

	return resp.Context, nil
}

// IsAllowed checks if an arbitrary subject is allowed to perform an action on a resource.
//
// The HTTP API is documented at http://docs.hdyra.apiary.io/#reference/warden:-access-control-for-resource-providers/check-if-a-subject-is-allowed-to-do-something
func (w *HTTPWarden) IsAllowed(ctx context.Context, a *firewall.AccessRequest) error {
	var allowed = struct {
		Allowed bool `json:"allowed"`
	}{}

	var ep = *w.Endpoint
	ep.Path = AllowedHandlerPath
	agent := &pkg.SuperAgent{URL: ep.String(), Client: w.Client}
	if err := agent.POST(a, &allowed); err != nil {
		return err
	} else if !allowed.Allowed {
		return errors.Wrap(fosite.ErrRequestForbidden, "")
	}

	return nil
}
<|endoftext|>