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

package models

import (
	"bufio"
	"bytes"
	"container/list"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/Unknwon/com"

	"github.com/gogits/git"

	"github.com/gogits/gogs/modules/base"
)

// RepoFile represents a file object in git repository.
type RepoFile struct {
	*git.TreeEntry
	Path   string
	Size   int64
	Repo   *git.Repository
	Commit *git.Commit
}

// LookupBlob returns the content of an object.
func (file *RepoFile) LookupBlob() (*git.Blob, error) {
	if file.Repo == nil {
		return nil, ErrRepoFileNotLoaded
	}

	return file.Repo.LookupBlob(file.Id)
}

// GetBranches returns all branches of given repository.
func GetBranches(userName, repoName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	refs, err := repo.AllReferences()
	if err != nil {
		return nil, err
	}

	brs := make([]string, len(refs))
	for i, ref := range refs {
		brs[i] = ref.BranchName()
	}
	return brs, nil
}

// GetTags returns all tags of given repository.
func GetTags(userName, repoName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	refs, err := repo.AllTags()
	if err != nil {
		return nil, err
	}

	tags := make([]string, len(refs))
	for i, ref := range refs {
		tags[i] = ref.Name
	}
	return tags, nil
}

func IsBranchExist(userName, repoName, branchName string) bool {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return false
	}
	return repo.IsBranchExist(branchName)
}

func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommitOfBranch(branchName)
	if err != nil {
		commit, err = repo.GetCommit(commitId)
		if err != nil {
			return nil, err
		}
	}

	parts := strings.Split(path.Clean(rpath), "/")

	var entry *git.TreeEntry
	tree := commit.Tree
	for i, part := range parts {
		if i == len(parts)-1 {
			entry = tree.EntryByName(part)
			if entry == nil {
				return nil, ErrRepoFileNotExist
			}
		} else {
			tree, err = repo.SubTree(tree, part)
			if err != nil {
				return nil, err
			}
		}
	}

	size, err := repo.ObjectSize(entry.Id)
	if err != nil {
		return nil, err
	}

	repoFile := &RepoFile{
		entry,
		rpath,
		size,
		repo,
		commit,
	}

	return repoFile, nil
}

// GetReposFiles returns a list of file object in given directory of repository.
// func GetReposFilesOfBranch(userName, repoName, branchName, rpath string) ([]*RepoFile, error) {
// 	return getReposFiles(userName, repoName, commitId, rpath)
// }

// GetReposFiles returns a list of file object in given directory of repository.
func GetReposFiles(userName, repoName, commitId, rpath string) ([]*RepoFile, error) {
	return getReposFiles(userName, repoName, commitId, rpath)
}

func getReposFiles(userName, repoName, commitId string, rpath string) ([]*RepoFile, error) {
	repopath := RepoPath(userName, repoName)
	repo, err := git.OpenRepository(repopath)
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(commitId)
	if err != nil {
		return nil, err
	}

	var repodirs []*RepoFile
	var repofiles []*RepoFile
	commit.Tree.Walk(func(dirname string, entry *git.TreeEntry) int {
		if dirname == rpath {
			// TODO: size get method shoule be improved
			size, err := repo.ObjectSize(entry.Id)
			if err != nil {
				return 0
			}

			stdout, _, err := com.ExecCmdDir(repopath, "git", "log", "-1", "--pretty=format:%H", commitId, "--", path.Join(dirname, entry.Name))
			if err != nil {
				return 0
			}
			filecm, err := repo.GetCommit(string(stdout))
			if err != nil {
				return 0
			}

			rp := &RepoFile{
				entry,
				path.Join(dirname, entry.Name),
				size,
				repo,
				filecm,
			}

			if entry.IsFile() {
				repofiles = append(repofiles, rp)
			} else if entry.IsDir() {
				repodirs = append(repodirs, rp)
			}
		}
		return 0
	})

	return append(repodirs, repofiles...), nil
}

func GetCommit(userName, repoName, commitId string) (*git.Commit, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	return repo.GetCommit(commitId)
}

// GetCommitsByBranch returns all commits of given branch of repository.
func GetCommitsByBranch(userName, repoName, branchName string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}
	r, err := repo.LookupReference(fmt.Sprintf("refs/heads/%s", branchName))
	if err != nil {
		return nil, err
	}
	return r.AllCommits()
}

// GetCommitsByCommitId returns all commits of given commitId of repository.
func GetCommitsByCommitId(userName, repoName, commitId string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}
	oid, err := git.NewOidFromString(commitId)
	if err != nil {
		return nil, err
	}
	return repo.CommitsBefore(oid)
}

// Diff line types.
const (
	DIFF_LINE_PLAIN = iota + 1
	DIFF_LINE_ADD
	DIFF_LINE_DEL
	DIFF_LINE_SECTION
)

const (
	DIFF_FILE_ADD = iota + 1
	DIFF_FILE_CHANGE
	DIFF_FILE_DEL
)

type DiffLine struct {
	LeftIdx  int
	RightIdx int
	Type     int
	Content  string
}

func (d DiffLine) GetType() int {
	return d.Type
}

type DiffSection struct {
	Name  string
	Lines []*DiffLine
}

type DiffFile struct {
	Name               string
	Addition, Deletion int
	Type               int
	Sections           []*DiffSection
}

type Diff struct {
	TotalAddition, TotalDeletion int
	Files                        []*DiffFile
}

func (diff *Diff) NumFiles() int {
	return len(diff.Files)
}

const DIFF_HEAD = "diff --git "

func ParsePatch(reader io.Reader) (*Diff, error) {
	scanner := bufio.NewScanner(reader)
	var (
		curFile    *DiffFile
		curSection = &DiffSection{
			Lines: make([]*DiffLine, 0, 10),
		}

		leftLine, rightLine int
	)

	diff := &Diff{Files: make([]*DiffFile, 0)}
	var i int
	for scanner.Scan() {
		line := scanner.Text()
		// fmt.Println(i, line)
		if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
			continue
		}

		i = i + 1

		// Diff data too large.
		if i == 2000 {
			return &Diff{}, nil
		}

		if line == "" {
			continue
		}
		if line[0] == ' ' {
			diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
			leftLine++
			rightLine++
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '@' {
			curSection = &DiffSection{}
			curFile.Sections = append(curFile.Sections, curSection)
			ss := strings.Split(line, "@@")
			diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line}
			curSection.Lines = append(curSection.Lines, diffLine)

			// Parse line number.
			ranges := strings.Split(ss[len(ss)-2][1:], " ")
			leftLine, _ = base.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
			rightLine, _ = base.StrTo(strings.Split(ranges[1], ",")[0]).Int()
			continue
		} else if line[0] == '+' {
			curFile.Addition++
			diff.TotalAddition++
			diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine}
			rightLine++
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '-' {
			curFile.Deletion++
			diff.TotalDeletion++
			diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine}
			if leftLine > 0 {
				leftLine++
			}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		}

		// Get new file.
		if strings.HasPrefix(line, DIFF_HEAD) {
			fs := strings.Split(line[len(DIFF_HEAD):], " ")
			a := fs[0]

			curFile = &DiffFile{
				Name:     a[strings.Index(a, "/")+1:],
				Type:     DIFF_FILE_CHANGE,
				Sections: make([]*DiffSection, 0, 10),
			}
			diff.Files = append(diff.Files, curFile)

			// Check file diff type.
			for scanner.Scan() {
				switch {
				case strings.HasPrefix(scanner.Text(), "new file"):
					curFile.Type = DIFF_FILE_ADD
				case strings.HasPrefix(scanner.Text(), "deleted"):
					curFile.Type = DIFF_FILE_DEL
				case strings.HasPrefix(scanner.Text(), "index"):
					curFile.Type = DIFF_FILE_CHANGE
				}
				if curFile.Type > 0 {
					break
				}
			}
		}
	}

	return diff, nil
}

func GetDiff(repoPath, commitid string) (*Diff, error) {
	repo, err := git.OpenRepository(repoPath)
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(commitid)
	if err != nil {
		return nil, err
	}

	// First commit of repository.
	if commit.ParentCount() == 0 {
		rd, wr := io.Pipe()
		go func() {
			cmd := exec.Command("git", "show", commitid)
			cmd.Dir = repoPath
			cmd.Stdout = wr
			cmd.Stdin = os.Stdin
			cmd.Stderr = os.Stderr
			cmd.Run()
			wr.Close()
		}()
		defer rd.Close()
		return ParsePatch(rd)
	}

	rd, wr := io.Pipe()
	go func() {
		cmd := exec.Command("git", "diff", commit.Parent(0).Oid.String(), commitid)
		cmd.Dir = repoPath
		cmd.Stdout = wr
		cmd.Stdin = os.Stdin
		cmd.Stderr = os.Stderr
		cmd.Run()
		wr.Close()
	}()
	defer rd.Close()
	return ParsePatch(rd)
}

const prettyLogFormat = `--pretty=format:%H%n%an <%ae> %at%n%s`

func parsePrettyFormatLog(logByts []byte) (*list.List, error) {
	l := list.New()
	buf := bytes.NewBuffer(logByts)
	if buf.Len() == 0 {
		return l, nil
	}

	idx := 0
	var commit *git.Commit

	for {
		line, err := buf.ReadString('\n')
		if err != nil && err != io.EOF {
			return nil, err
		}
		line = strings.TrimSpace(line)
		// fmt.Println(line)

		var parseErr error
		switch idx {
		case 0: // SHA1.
			commit = &git.Commit{}
			commit.Oid, parseErr = git.NewOidFromString(line)
		case 1: // Signature.
			commit.Author, parseErr = git.NewSignatureFromCommitline([]byte(line + " "))
		case 2: // Commit message.
			commit.CommitMessage = line
			l.PushBack(commit)
			idx = -1
		}

		if parseErr != nil {
			return nil, parseErr
		}

		idx++

		if err == io.EOF {
			break
		}
	}

	return l, nil
}

// SearchCommits searches commits in given branch and keyword of repository.
func SearchCommits(repoPath, branch, keyword string) (*list.List, error) {
	stdout, stderr, err := com.ExecCmdDirBytes(repoPath, "git", "log", branch, "-100",
		"-i", "--grep="+keyword, prettyLogFormat)
	if err != nil {
		return nil, err
	} else if len(stderr) > 0 {
		return nil, errors.New(string(stderr))
	}
	return parsePrettyFormatLog(stdout)
}

// GetCommitsByRange returns certain number of commits with given page of repository.
func GetCommitsByRange(repoPath, branch string, page int) (*list.List, error) {
	stdout, stderr, err := com.ExecCmdDirBytes(repoPath, "git", "log", branch,
		"--skip="+base.ToStr((page-1)*50), "--max-count=50", prettyLogFormat)
	if err != nil {
		return nil, err
	} else if len(stderr) > 0 {
		return nil, errors.New(string(stderr))
	}
	return parsePrettyFormatLog(stdout)
}

// GetCommitsCount returns the commits count of given branch of repository.
func GetCommitsCount(repoPath, branch string) (int, error) {
	stdout, stderr, err := com.ExecCmdDir(repoPath, "git", "rev-list", "--count", branch)
	if err != nil {
		return 0, err
	} else if len(stderr) > 0 {
		return 0, errors.New(stderr)
	}
	return base.StrTo(strings.TrimSpace(stdout)).Int()
}
<commit_msg>Mirror fix<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"bufio"
	"bytes"
	"container/list"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/Unknwon/com"

	"github.com/gogits/git"

	"github.com/gogits/gogs/modules/base"
	"github.com/gogits/gogs/modules/log"
)

// RepoFile represents a file object in git repository.
type RepoFile struct {
	*git.TreeEntry
	Path   string
	Size   int64
	Repo   *git.Repository
	Commit *git.Commit
}

// LookupBlob returns the content of an object.
func (file *RepoFile) LookupBlob() (*git.Blob, error) {
	if file.Repo == nil {
		return nil, ErrRepoFileNotLoaded
	}

	return file.Repo.LookupBlob(file.Id)
}

// GetBranches returns all branches of given repository.
func GetBranches(userName, repoName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	refs, err := repo.AllReferences()
	if err != nil {
		return nil, err
	}

	brs := make([]string, len(refs))
	for i, ref := range refs {
		brs[i] = ref.BranchName()
	}
	return brs, nil
}

// GetTags returns all tags of given repository.
func GetTags(userName, repoName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	refs, err := repo.AllTags()
	if err != nil {
		return nil, err
	}

	tags := make([]string, len(refs))
	for i, ref := range refs {
		tags[i] = ref.Name
	}
	return tags, nil
}

func IsBranchExist(userName, repoName, branchName string) bool {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return false
	}
	return repo.IsBranchExist(branchName)
}

func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommitOfBranch(branchName)
	if err != nil {
		commit, err = repo.GetCommit(commitId)
		if err != nil {
			return nil, err
		}
	}

	parts := strings.Split(path.Clean(rpath), "/")

	var entry *git.TreeEntry
	tree := commit.Tree
	for i, part := range parts {
		if i == len(parts)-1 {
			entry = tree.EntryByName(part)
			if entry == nil {
				return nil, ErrRepoFileNotExist
			}
		} else {
			tree, err = repo.SubTree(tree, part)
			if err != nil {
				return nil, err
			}
		}
	}

	size, err := repo.ObjectSize(entry.Id)
	if err != nil {
		return nil, err
	}

	repoFile := &RepoFile{
		entry,
		rpath,
		size,
		repo,
		commit,
	}

	return repoFile, nil
}

// GetReposFiles returns a list of file object in given directory of repository.
// func GetReposFilesOfBranch(userName, repoName, branchName, rpath string) ([]*RepoFile, error) {
// 	return getReposFiles(userName, repoName, commitId, rpath)
// }

// GetReposFiles returns a list of file object in given directory of repository.
func GetReposFiles(userName, repoName, commitId, rpath string) ([]*RepoFile, error) {
	return getReposFiles(userName, repoName, commitId, rpath)
}

func getReposFiles(userName, repoName, commitId string, rpath string) ([]*RepoFile, error) {
	repopath := RepoPath(userName, repoName)
	repo, err := git.OpenRepository(repopath)
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(commitId)
	if err != nil {
		return nil, err
	}

	var repodirs []*RepoFile
	var repofiles []*RepoFile
	commit.Tree.Walk(func(dirname string, entry *git.TreeEntry) int {
		if dirname == rpath {
			// TODO: size get method shoule be improved
			size, err := repo.ObjectSize(entry.Id)
			if err != nil {
				return 0
			}

			stdout, _, err := com.ExecCmdDir(repopath, "git", "log", "-1", "--pretty=format:%H", commitId, "--", path.Join(dirname, entry.Name))
			if err != nil {
				return 0
			}
			filecm, err := repo.GetCommit(string(stdout))
			if err != nil {
				return 0
			}

			rp := &RepoFile{
				entry,
				path.Join(dirname, entry.Name),
				size,
				repo,
				filecm,
			}

			if entry.IsFile() {
				repofiles = append(repofiles, rp)
			} else if entry.IsDir() {
				repodirs = append(repodirs, rp)
			}
		}
		return 0
	})

	return append(repodirs, repofiles...), nil
}

func GetCommit(userName, repoName, commitId string) (*git.Commit, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	return repo.GetCommit(commitId)
}

// GetCommitsByBranch returns all commits of given branch of repository.
func GetCommitsByBranch(userName, repoName, branchName string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}
	r, err := repo.LookupReference(fmt.Sprintf("refs/heads/%s", branchName))
	if err != nil {
		return nil, err
	}
	return r.AllCommits()
}

// GetCommitsByCommitId returns all commits of given commitId of repository.
func GetCommitsByCommitId(userName, repoName, commitId string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}
	oid, err := git.NewOidFromString(commitId)
	if err != nil {
		return nil, err
	}
	return repo.CommitsBefore(oid)
}

// Diff line types.
const (
	DIFF_LINE_PLAIN = iota + 1
	DIFF_LINE_ADD
	DIFF_LINE_DEL
	DIFF_LINE_SECTION
)

const (
	DIFF_FILE_ADD = iota + 1
	DIFF_FILE_CHANGE
	DIFF_FILE_DEL
)

type DiffLine struct {
	LeftIdx  int
	RightIdx int
	Type     int
	Content  string
}

func (d DiffLine) GetType() int {
	return d.Type
}

type DiffSection struct {
	Name  string
	Lines []*DiffLine
}

type DiffFile struct {
	Name               string
	Addition, Deletion int
	Type               int
	Sections           []*DiffSection
}

type Diff struct {
	TotalAddition, TotalDeletion int
	Files                        []*DiffFile
}

func (diff *Diff) NumFiles() int {
	return len(diff.Files)
}

const DIFF_HEAD = "diff --git "

func ParsePatch(reader io.Reader) (*Diff, error) {
	scanner := bufio.NewScanner(reader)
	var (
		curFile    *DiffFile
		curSection = &DiffSection{
			Lines: make([]*DiffLine, 0, 10),
		}

		leftLine, rightLine int
	)

	diff := &Diff{Files: make([]*DiffFile, 0)}
	var i int
	for scanner.Scan() {
		line := scanner.Text()
		// fmt.Println(i, line)
		if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") {
			continue
		}

		i = i + 1

		// Diff data too large.
		if i == 5000 {
			log.Warn("Diff data too large")
			return &Diff{}, nil
		}

		if line == "" {
			continue
		}
		if line[0] == ' ' {
			diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
			leftLine++
			rightLine++
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '@' {
			curSection = &DiffSection{}
			curFile.Sections = append(curFile.Sections, curSection)
			ss := strings.Split(line, "@@")
			diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line}
			curSection.Lines = append(curSection.Lines, diffLine)

			// Parse line number.
			ranges := strings.Split(ss[len(ss)-2][1:], " ")
			leftLine, _ = base.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
			rightLine, _ = base.StrTo(strings.Split(ranges[1], ",")[0]).Int()
			continue
		} else if line[0] == '+' {
			curFile.Addition++
			diff.TotalAddition++
			diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine}
			rightLine++
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '-' {
			curFile.Deletion++
			diff.TotalDeletion++
			diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine}
			if leftLine > 0 {
				leftLine++
			}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		}

		// Get new file.
		if strings.HasPrefix(line, DIFF_HEAD) {
			fs := strings.Split(line[len(DIFF_HEAD):], " ")
			a := fs[0]

			curFile = &DiffFile{
				Name:     a[strings.Index(a, "/")+1:],
				Type:     DIFF_FILE_CHANGE,
				Sections: make([]*DiffSection, 0, 10),
			}
			diff.Files = append(diff.Files, curFile)

			// Check file diff type.
			for scanner.Scan() {
				switch {
				case strings.HasPrefix(scanner.Text(), "new file"):
					curFile.Type = DIFF_FILE_ADD
				case strings.HasPrefix(scanner.Text(), "deleted"):
					curFile.Type = DIFF_FILE_DEL
				case strings.HasPrefix(scanner.Text(), "index"):
					curFile.Type = DIFF_FILE_CHANGE
				}
				if curFile.Type > 0 {
					break
				}
			}
		}
	}

	return diff, nil
}

func GetDiff(repoPath, commitid string) (*Diff, error) {
	repo, err := git.OpenRepository(repoPath)
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(commitid)
	if err != nil {
		return nil, err
	}

	// First commit of repository.
	if commit.ParentCount() == 0 {
		rd, wr := io.Pipe()
		go func() {
			cmd := exec.Command("git", "show", commitid)
			cmd.Dir = repoPath
			cmd.Stdout = wr
			cmd.Stdin = os.Stdin
			cmd.Stderr = os.Stderr
			cmd.Run()
			wr.Close()
		}()
		defer rd.Close()
		return ParsePatch(rd)
	}

	rd, wr := io.Pipe()
	go func() {
		cmd := exec.Command("git", "diff", commit.Parent(0).Oid.String(), commitid)
		cmd.Dir = repoPath
		cmd.Stdout = wr
		cmd.Stdin = os.Stdin
		cmd.Stderr = os.Stderr
		cmd.Run()
		wr.Close()
	}()
	defer rd.Close()
	return ParsePatch(rd)
}

const prettyLogFormat = `--pretty=format:%H%n%an <%ae> %at%n%s`

func parsePrettyFormatLog(logByts []byte) (*list.List, error) {
	l := list.New()
	buf := bytes.NewBuffer(logByts)
	if buf.Len() == 0 {
		return l, nil
	}

	idx := 0
	var commit *git.Commit

	for {
		line, err := buf.ReadString('\n')
		if err != nil && err != io.EOF {
			return nil, err
		}
		line = strings.TrimSpace(line)
		// fmt.Println(line)

		var parseErr error
		switch idx {
		case 0: // SHA1.
			commit = &git.Commit{}
			commit.Oid, parseErr = git.NewOidFromString(line)
		case 1: // Signature.
			commit.Author, parseErr = git.NewSignatureFromCommitline([]byte(line + " "))
		case 2: // Commit message.
			commit.CommitMessage = line
			l.PushBack(commit)
			idx = -1
		}

		if parseErr != nil {
			return nil, parseErr
		}

		idx++

		if err == io.EOF {
			break
		}
	}

	return l, nil
}

// SearchCommits searches commits in given branch and keyword of repository.
func SearchCommits(repoPath, branch, keyword string) (*list.List, error) {
	stdout, stderr, err := com.ExecCmdDirBytes(repoPath, "git", "log", branch, "-100",
		"-i", "--grep="+keyword, prettyLogFormat)
	if err != nil {
		return nil, err
	} else if len(stderr) > 0 {
		return nil, errors.New(string(stderr))
	}
	return parsePrettyFormatLog(stdout)
}

// GetCommitsByRange returns certain number of commits with given page of repository.
func GetCommitsByRange(repoPath, branch string, page int) (*list.List, error) {
	stdout, stderr, err := com.ExecCmdDirBytes(repoPath, "git", "log", branch,
		"--skip="+base.ToStr((page-1)*50), "--max-count=50", prettyLogFormat)
	if err != nil {
		return nil, err
	} else if len(stderr) > 0 {
		return nil, errors.New(string(stderr))
	}
	return parsePrettyFormatLog(stdout)
}

// GetCommitsCount returns the commits count of given branch of repository.
func GetCommitsCount(repoPath, branch string) (int, error) {
	stdout, stderr, err := com.ExecCmdDir(repoPath, "git", "rev-list", "--count", branch)
	if err != nil {
		return 0, err
	} else if len(stderr) > 0 {
		return 0, errors.New(stderr)
	}
	return base.StrTo(strings.TrimSpace(stdout)).Int()
}
<|endoftext|>


<commit_before>// This file was generated by counterfeiter
package fake_bbs

import (
	"github.com/cloudfoundry-incubator/runtime-schema/bbs"

	"github.com/cloudfoundry-incubator/runtime-schema/models"

	"sync"
)

type FakeNsyncBBS struct {
	DesireLRPStub        func(models.DesiredLRP) error
	desireLRPMutex       sync.RWMutex
	desireLRPArgsForCall []struct {
		arg1 models.DesiredLRP
	}
	desireLRPReturns struct {
		result1 error
	}
	RemoveDesiredLRPByProcessGuidStub        func(guid string) error
	removeDesiredLRPByProcessGuidMutex       sync.RWMutex
	removeDesiredLRPByProcessGuidArgsForCall []struct {
		guid string
	}
	removeDesiredLRPByProcessGuidReturns struct {
		result1 error
	}
	GetAllDesiredLRPsByDomainStub        func(domain string) ([]models.DesiredLRP, error)
	getAllDesiredLRPsByDomainMutex       sync.RWMutex
	getAllDesiredLRPsByDomainArgsForCall []struct {
		domain string
	}
	getAllDesiredLRPsByDomainReturns struct {
		result1 []models.DesiredLRP
		result2 error
	}
	ChangeDesiredLRPStub        func(change models.DesiredLRPChange) error
	changeDesiredLRPMutex       sync.RWMutex
	changeDesiredLRPArgsForCall []struct {
		change models.DesiredLRPChange
	}
	changeDesiredLRPReturns struct {
		result1 error
	}
}

func (fake *FakeNsyncBBS) DesireLRP(arg1 models.DesiredLRP) error {
	fake.desireLRPMutex.Lock()
	defer fake.desireLRPMutex.Unlock()
	fake.desireLRPArgsForCall = append(fake.desireLRPArgsForCall, struct {
		arg1 models.DesiredLRP
	}{arg1})
	if fake.DesireLRPStub != nil {
		return fake.DesireLRPStub(arg1)
	} else {
		return fake.desireLRPReturns.result1
	}
}

func (fake *FakeNsyncBBS) DesireLRPCallCount() int {
	fake.desireLRPMutex.RLock()
	defer fake.desireLRPMutex.RUnlock()
	return len(fake.desireLRPArgsForCall)
}

func (fake *FakeNsyncBBS) DesireLRPArgsForCall(i int) models.DesiredLRP {
	fake.desireLRPMutex.RLock()
	defer fake.desireLRPMutex.RUnlock()
	return fake.desireLRPArgsForCall[i].arg1
}

func (fake *FakeNsyncBBS) DesireLRPReturns(result1 error) {
	fake.desireLRPReturns = struct {
		result1 error
	}{result1}
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuid(guid string) error {
	fake.removeDesiredLRPByProcessGuidMutex.Lock()
	defer fake.removeDesiredLRPByProcessGuidMutex.Unlock()
	fake.removeDesiredLRPByProcessGuidArgsForCall = append(fake.removeDesiredLRPByProcessGuidArgsForCall, struct {
		guid string
	}{guid})
	if fake.RemoveDesiredLRPByProcessGuidStub != nil {
		return fake.RemoveDesiredLRPByProcessGuidStub(guid)
	} else {
		return fake.removeDesiredLRPByProcessGuidReturns.result1
	}
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuidCallCount() int {
	fake.removeDesiredLRPByProcessGuidMutex.RLock()
	defer fake.removeDesiredLRPByProcessGuidMutex.RUnlock()
	return len(fake.removeDesiredLRPByProcessGuidArgsForCall)
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuidArgsForCall(i int) string {
	fake.removeDesiredLRPByProcessGuidMutex.RLock()
	defer fake.removeDesiredLRPByProcessGuidMutex.RUnlock()
	return fake.removeDesiredLRPByProcessGuidArgsForCall[i].guid
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuidReturns(result1 error) {
	fake.removeDesiredLRPByProcessGuidReturns = struct {
		result1 error
	}{result1}
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomain(domain string) ([]models.DesiredLRP, error) {
	fake.getAllDesiredLRPsByDomainMutex.Lock()
	defer fake.getAllDesiredLRPsByDomainMutex.Unlock()
	fake.getAllDesiredLRPsByDomainArgsForCall = append(fake.getAllDesiredLRPsByDomainArgsForCall, struct {
		domain string
	}{domain})
	if fake.GetAllDesiredLRPsByDomainStub != nil {
		return fake.GetAllDesiredLRPsByDomainStub(domain)
	} else {
		return fake.getAllDesiredLRPsByDomainReturns.result1, fake.getAllDesiredLRPsByDomainReturns.result2
	}
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomainCallCount() int {
	fake.getAllDesiredLRPsByDomainMutex.RLock()
	defer fake.getAllDesiredLRPsByDomainMutex.RUnlock()
	return len(fake.getAllDesiredLRPsByDomainArgsForCall)
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomainArgsForCall(i int) string {
	fake.getAllDesiredLRPsByDomainMutex.RLock()
	defer fake.getAllDesiredLRPsByDomainMutex.RUnlock()
	return fake.getAllDesiredLRPsByDomainArgsForCall[i].domain
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomainReturns(result1 []models.DesiredLRP, result2 error) {
	fake.getAllDesiredLRPsByDomainReturns = struct {
		result1 []models.DesiredLRP
		result2 error
	}{result1, result2}
}

func (fake *FakeNsyncBBS) ChangeDesiredLRP(change models.DesiredLRPChange) error {
	fake.changeDesiredLRPMutex.Lock()
	defer fake.changeDesiredLRPMutex.Unlock()
	fake.changeDesiredLRPArgsForCall = append(fake.changeDesiredLRPArgsForCall, struct {
		change models.DesiredLRPChange
	}{change})
	if fake.ChangeDesiredLRPStub != nil {
		return fake.ChangeDesiredLRPStub(change)
	} else {
		return fake.changeDesiredLRPReturns.result1
	}
}

func (fake *FakeNsyncBBS) ChangeDesiredLRPCallCount() int {
	fake.changeDesiredLRPMutex.RLock()
	defer fake.changeDesiredLRPMutex.RUnlock()
	return len(fake.changeDesiredLRPArgsForCall)
}

func (fake *FakeNsyncBBS) ChangeDesiredLRPArgsForCall(i int) models.DesiredLRPChange {
	fake.changeDesiredLRPMutex.RLock()
	defer fake.changeDesiredLRPMutex.RUnlock()
	return fake.changeDesiredLRPArgsForCall[i].change
}

func (fake *FakeNsyncBBS) ChangeDesiredLRPReturns(result1 error) {
	fake.changeDesiredLRPReturns = struct {
		result1 error
	}{result1}
}

var _ bbs.NsyncBBS = new(FakeNsyncBBS)
<commit_msg>update nsync bbs<commit_after>// This file was generated by counterfeiter
package fake_bbs

import (
	"github.com/cloudfoundry-incubator/runtime-schema/bbs"

	"github.com/cloudfoundry-incubator/runtime-schema/models"

	"sync"
	"time"
)

type FakeNsyncBBS struct {
	DesireLRPStub        func(models.DesiredLRP) error
	desireLRPMutex       sync.RWMutex
	desireLRPArgsForCall []struct {
		arg1 models.DesiredLRP
	}
	desireLRPReturns struct {
		result1 error
	}
	RemoveDesiredLRPByProcessGuidStub        func(guid string) error
	removeDesiredLRPByProcessGuidMutex       sync.RWMutex
	removeDesiredLRPByProcessGuidArgsForCall []struct {
		guid string
	}
	removeDesiredLRPByProcessGuidReturns struct {
		result1 error
	}
	GetAllDesiredLRPsByDomainStub        func(domain string) ([]models.DesiredLRP, error)
	getAllDesiredLRPsByDomainMutex       sync.RWMutex
	getAllDesiredLRPsByDomainArgsForCall []struct {
		domain string
	}
	getAllDesiredLRPsByDomainReturns struct {
		result1 []models.DesiredLRP
		result2 error
	}
	ChangeDesiredLRPStub        func(change models.DesiredLRPChange) error
	changeDesiredLRPMutex       sync.RWMutex
	changeDesiredLRPArgsForCall []struct {
		change models.DesiredLRPChange
	}
	changeDesiredLRPReturns struct {
		result1 error
	}
	BumpFreshnessStub        func(domain string, ttl time.Duration) error
	bumpFreshnessMutex       sync.RWMutex
	bumpFreshnessArgsForCall []struct {
		domain string
		ttl    time.Duration
	}
	bumpFreshnessReturns struct {
		result1 error
	}
}

func (fake *FakeNsyncBBS) DesireLRP(arg1 models.DesiredLRP) error {
	fake.desireLRPMutex.Lock()
	defer fake.desireLRPMutex.Unlock()
	fake.desireLRPArgsForCall = append(fake.desireLRPArgsForCall, struct {
		arg1 models.DesiredLRP
	}{arg1})
	if fake.DesireLRPStub != nil {
		return fake.DesireLRPStub(arg1)
	} else {
		return fake.desireLRPReturns.result1
	}
}

func (fake *FakeNsyncBBS) DesireLRPCallCount() int {
	fake.desireLRPMutex.RLock()
	defer fake.desireLRPMutex.RUnlock()
	return len(fake.desireLRPArgsForCall)
}

func (fake *FakeNsyncBBS) DesireLRPArgsForCall(i int) models.DesiredLRP {
	fake.desireLRPMutex.RLock()
	defer fake.desireLRPMutex.RUnlock()
	return fake.desireLRPArgsForCall[i].arg1
}

func (fake *FakeNsyncBBS) DesireLRPReturns(result1 error) {
	fake.desireLRPReturns = struct {
		result1 error
	}{result1}
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuid(guid string) error {
	fake.removeDesiredLRPByProcessGuidMutex.Lock()
	defer fake.removeDesiredLRPByProcessGuidMutex.Unlock()
	fake.removeDesiredLRPByProcessGuidArgsForCall = append(fake.removeDesiredLRPByProcessGuidArgsForCall, struct {
		guid string
	}{guid})
	if fake.RemoveDesiredLRPByProcessGuidStub != nil {
		return fake.RemoveDesiredLRPByProcessGuidStub(guid)
	} else {
		return fake.removeDesiredLRPByProcessGuidReturns.result1
	}
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuidCallCount() int {
	fake.removeDesiredLRPByProcessGuidMutex.RLock()
	defer fake.removeDesiredLRPByProcessGuidMutex.RUnlock()
	return len(fake.removeDesiredLRPByProcessGuidArgsForCall)
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuidArgsForCall(i int) string {
	fake.removeDesiredLRPByProcessGuidMutex.RLock()
	defer fake.removeDesiredLRPByProcessGuidMutex.RUnlock()
	return fake.removeDesiredLRPByProcessGuidArgsForCall[i].guid
}

func (fake *FakeNsyncBBS) RemoveDesiredLRPByProcessGuidReturns(result1 error) {
	fake.removeDesiredLRPByProcessGuidReturns = struct {
		result1 error
	}{result1}
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomain(domain string) ([]models.DesiredLRP, error) {
	fake.getAllDesiredLRPsByDomainMutex.Lock()
	defer fake.getAllDesiredLRPsByDomainMutex.Unlock()
	fake.getAllDesiredLRPsByDomainArgsForCall = append(fake.getAllDesiredLRPsByDomainArgsForCall, struct {
		domain string
	}{domain})
	if fake.GetAllDesiredLRPsByDomainStub != nil {
		return fake.GetAllDesiredLRPsByDomainStub(domain)
	} else {
		return fake.getAllDesiredLRPsByDomainReturns.result1, fake.getAllDesiredLRPsByDomainReturns.result2
	}
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomainCallCount() int {
	fake.getAllDesiredLRPsByDomainMutex.RLock()
	defer fake.getAllDesiredLRPsByDomainMutex.RUnlock()
	return len(fake.getAllDesiredLRPsByDomainArgsForCall)
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomainArgsForCall(i int) string {
	fake.getAllDesiredLRPsByDomainMutex.RLock()
	defer fake.getAllDesiredLRPsByDomainMutex.RUnlock()
	return fake.getAllDesiredLRPsByDomainArgsForCall[i].domain
}

func (fake *FakeNsyncBBS) GetAllDesiredLRPsByDomainReturns(result1 []models.DesiredLRP, result2 error) {
	fake.getAllDesiredLRPsByDomainReturns = struct {
		result1 []models.DesiredLRP
		result2 error
	}{result1, result2}
}

func (fake *FakeNsyncBBS) ChangeDesiredLRP(change models.DesiredLRPChange) error {
	fake.changeDesiredLRPMutex.Lock()
	defer fake.changeDesiredLRPMutex.Unlock()
	fake.changeDesiredLRPArgsForCall = append(fake.changeDesiredLRPArgsForCall, struct {
		change models.DesiredLRPChange
	}{change})
	if fake.ChangeDesiredLRPStub != nil {
		return fake.ChangeDesiredLRPStub(change)
	} else {
		return fake.changeDesiredLRPReturns.result1
	}
}

func (fake *FakeNsyncBBS) ChangeDesiredLRPCallCount() int {
	fake.changeDesiredLRPMutex.RLock()
	defer fake.changeDesiredLRPMutex.RUnlock()
	return len(fake.changeDesiredLRPArgsForCall)
}

func (fake *FakeNsyncBBS) ChangeDesiredLRPArgsForCall(i int) models.DesiredLRPChange {
	fake.changeDesiredLRPMutex.RLock()
	defer fake.changeDesiredLRPMutex.RUnlock()
	return fake.changeDesiredLRPArgsForCall[i].change
}

func (fake *FakeNsyncBBS) ChangeDesiredLRPReturns(result1 error) {
	fake.changeDesiredLRPReturns = struct {
		result1 error
	}{result1}
}

func (fake *FakeNsyncBBS) BumpFreshness(domain string, ttl time.Duration) error {
	fake.bumpFreshnessMutex.Lock()
	defer fake.bumpFreshnessMutex.Unlock()
	fake.bumpFreshnessArgsForCall = append(fake.bumpFreshnessArgsForCall, struct {
		domain string
		ttl    time.Duration
	}{domain, ttl})
	if fake.BumpFreshnessStub != nil {
		return fake.BumpFreshnessStub(domain, ttl)
	} else {
		return fake.bumpFreshnessReturns.result1
	}
}

func (fake *FakeNsyncBBS) BumpFreshnessCallCount() int {
	fake.bumpFreshnessMutex.RLock()
	defer fake.bumpFreshnessMutex.RUnlock()
	return len(fake.bumpFreshnessArgsForCall)
}

func (fake *FakeNsyncBBS) BumpFreshnessArgsForCall(i int) (string, time.Duration) {
	fake.bumpFreshnessMutex.RLock()
	defer fake.bumpFreshnessMutex.RUnlock()
	return fake.bumpFreshnessArgsForCall[i].domain, fake.bumpFreshnessArgsForCall[i].ttl
}

func (fake *FakeNsyncBBS) BumpFreshnessReturns(result1 error) {
	fake.bumpFreshnessReturns = struct {
		result1 error
	}{result1}
}

var _ bbs.NsyncBBS = new(FakeNsyncBBS)
<|endoftext|>


<commit_before>// This example shows how to use encoder package to handle rotary encoder. It
// uses semihosting to print encoder events. Use Black Magic Probe
// (../debug-bmp.sh) or OpenOCD (../semihosting.sh) to see program output.
package main

import (
	"bufio"
	"bytes"
	"debug/semihosting"
	"fmt"
	"rtos"

	"nrf5/input"
	"nrf5/input/button"
	"nrf5/input/encoder"

	"nrf5/hal/clock"
	"nrf5/hal/gpio"
	"nrf5/hal/gpiote"
	"nrf5/hal/irq"
	"nrf5/hal/rtc"
	"nrf5/hal/system"
	"nrf5/hal/system/timer/rtcst"
)

const (
	Enc = iota
	Btn
)

var (
	inpCh = make(chan input.Event, 4)
	enc   *encoder.Driver
	btn   *button.Driver
)

func init() {
	// Initialize system and runtime.
	system.Setup(clock.XTAL, clock.XTAL, true)
	rtcst.Setup(rtc.RTC1, 0)

	// Allocate pins (always do it in one place to avoid conflicts).

	p0 := gpio.P0
	bt := p0.Pin(4)
	a := p0.Pin(5)
	b := p0.Pin(7)

	// Configure peripherals.

	enc = encoder.New(a, b, true, true, inpCh, Enc)
	btn = button.New(bt, gpiote.Chan(0), true, rtc.RTC1, 1, inpCh, Btn)

	// Configure interrupts.

	rtos.IRQ(irq.QDEC).Enable()
	rtos.IRQ(irq.GPIOTE).Enable()

	// Semihosting console.

	f, err := semihosting.OpenFile(":tt", semihosting.W)
	for err != nil {
	}
	fmt.DefaultWriter = lineWriter{bufio.NewWriterSize(f, 40)}
}

func main() {
	for ev := range inpCh {
		fmt.Printf("src=%d val=%d\n", ev.Src(), ev.Val())
	}
}

func qdecISR() {
	enc.ISR()
}

func gpioteISR() {
	btn.ISR()
}

func rtcISR() {
	rtcst.ISR()
	btn.RTCISR()
}

//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
	irq.RTC1:   rtcISR,
	irq.QDEC:   qdecISR,
	irq.GPIOTE: gpioteISR,
}

type lineWriter struct {
	w *bufio.Writer
}

func (b lineWriter) Write(s []byte) (int, error) {
	n, err := b.w.Write(s)
	if err != nil {
		return n, err
	}
	if bytes.IndexByte(s, '\n') >= 0 {
		err = b.w.Flush()
	}
	return n, err
}
<commit_msg>examples/core51822/encoder: Fix program description.<commit_after>// This example shows how to use input/encoder and input/button packages to
// handle rotary encoder. It uses semihosting to print encoder events. Use
// Black Magic Probe (../debug-bmp.sh) or OpenOCD (../semihosting.sh) to see
// program output.
package main

import (
	"bufio"
	"bytes"
	"debug/semihosting"
	"fmt"
	"rtos"

	"nrf5/input"
	"nrf5/input/button"
	"nrf5/input/encoder"

	"nrf5/hal/clock"
	"nrf5/hal/gpio"
	"nrf5/hal/gpiote"
	"nrf5/hal/irq"
	"nrf5/hal/rtc"
	"nrf5/hal/system"
	"nrf5/hal/system/timer/rtcst"
)

const (
	Enc = iota
	Btn
)

var (
	inpCh = make(chan input.Event, 4)
	enc   *encoder.Driver
	btn   *button.Driver
)

func init() {
	// Initialize system and runtime.
	system.Setup(clock.XTAL, clock.XTAL, true)
	rtcst.Setup(rtc.RTC1, 0)

	// Allocate pins (always do it in one place to avoid conflicts).

	p0 := gpio.P0
	bt := p0.Pin(4)
	a := p0.Pin(5)
	b := p0.Pin(7)

	// Configure peripherals.

	enc = encoder.New(a, b, true, true, inpCh, Enc)
	btn = button.New(bt, gpiote.Chan(0), true, rtc.RTC1, 1, inpCh, Btn)

	// Configure interrupts.

	rtos.IRQ(irq.QDEC).Enable()
	rtos.IRQ(irq.GPIOTE).Enable()

	// Semihosting console.

	f, err := semihosting.OpenFile(":tt", semihosting.W)
	for err != nil {
	}
	fmt.DefaultWriter = lineWriter{bufio.NewWriterSize(f, 40)}
}

func main() {
	for ev := range inpCh {
		fmt.Printf("src=%d val=%d\n", ev.Src(), ev.Val())
	}
}

func qdecISR() {
	enc.ISR()
}

func gpioteISR() {
	btn.ISR()
}

func rtcISR() {
	rtcst.ISR()
	btn.RTCISR()
}

//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
	irq.RTC1:   rtcISR,
	irq.QDEC:   qdecISR,
	irq.GPIOTE: gpioteISR,
}

type lineWriter struct {
	w *bufio.Writer
}

func (b lineWriter) Write(s []byte) (int, error) {
	n, err := b.w.Write(s)
	if err != nil {
		return n, err
	}
	if bytes.IndexByte(s, '\n') >= 0 {
		err = b.w.Flush()
	}
	return n, err
}
<|endoftext|>


<commit_before>package papaBot

// Full message handling routines.

import (
	"fmt"
	"github.com/pawelszydlo/papa-bot/events"
	"github.com/pawelszydlo/papa-bot/utils"
	"log"
	"mvdan.cc/xurls"
	"os"
	"regexp"
	"time"
)

var titleRe = regexp.MustCompile("(?is)<title.*?>(.+?)</title>")
var metaRe = regexp.MustCompile(`(?is)<\s*?meta.*?content\s*?=\s*?"(.*?)".*?>`)
var descRe = regexp.MustCompile(`(?is)(property|name)\s*?=.*?description`)

// messageListener looks for commands in messages.
func (bot *Bot) messageListener(message events.EventMessage) {
	// Increase lines count for all announcements.
	for k := range bot.lastURLAnnouncedLinesPassed {
		bot.lastURLAnnouncedLinesPassed[k] += 1
		// After 100 lines pass, forget it ever happened.
		if bot.lastURLAnnouncedLinesPassed[k] > 100 {
			delete(bot.lastURLAnnouncedLinesPassed, k)
			delete(bot.lastURLAnnouncedTime, k)
		}
	}

	// Handles the commands.
	if message.AtBot {
		bot.handleBotCommand(message)
	}
}

// handleURLsListener finds all URLs in the message and fires URL events on them.
func (bot *Bot) handleURLsListener(message events.EventMessage) {

	// Find all URLs in the message.
	links := xurls.Strict().FindAllString(message.Message, -1)
	// Remove multiple same links from one message.
	links = utils.RemoveDuplicates(links)
	for i := range links {
		// Validate the url.
		bot.Log.Infof("Got link %s", links[i])
		link := utils.StandardizeURL(links[i])
		bot.Log.Debugf("Standardized to: %s", link)

		// Try to get the body of the page.
		err, finalLink, body := bot.GetPageBody(link, map[string]string{})
		if err != nil {
			bot.Log.Warningf("Could't fetch the body: %s", err)
		}

		// Iterate over meta tags to get the description
		description := ""
		metas := metaRe.FindAllStringSubmatch(string(body), -1)
		for i := range metas {
			if len(metas[i]) > 1 {
				isDesc := descRe.FindString(metas[i][0])
				if isDesc != "" && (len(metas[i][1]) > len(description)) {
					description = utils.CleanString(metas[i][1], true)
				}
			}
		}
		// Get the title
		title := ""
		match := titleRe.FindStringSubmatch(string(body))
		if len(match) > 1 {
			title = utils.CleanString(match[1], true)
		}

		// Insert URL into the db.
		if _, err := bot.Db.Exec(`INSERT INTO urls(transport, channel, nick, link, quote, title) VALUES(?, ?, ?, ?, ?, ?)`,
			message.SourceTransport, message.Channel, message.Nick, finalLink, message.Message, title); err != nil {
			bot.Log.Warningf("Can't add url to database: %s", err)
		}

		// Trigger url found message.
		bot.EventDispatcher.Trigger(events.EventMessage{
			message.SourceTransport,
			events.EventURLFound,
			message.Nick,
			message.FullName,
			message.Channel,
			finalLink,
			message.Context,
			message.AtBot,
		})

		linkKey := finalLink + message.Channel
		// If we can't announce yet, skip this link.
		if time.Since(bot.lastURLAnnouncedTime[linkKey]) < bot.Config.UrlAnnounceIntervalMinutes*time.Minute {
			continue
		}
		if lines, exists := bot.lastURLAnnouncedLinesPassed[linkKey]; exists && lines < bot.Config.UrlAnnounceIntervalLines {
			continue
		}

		// Announce the title, save the description.
		if title != "" {
			if description != "" {
				bot.SendNotice(message.SourceTransport, message.Channel, title+" …", message.Context)
			} else {
				bot.SendNotice(message.SourceTransport, message.Channel, title, message.Context)
			}
			bot.lastURLAnnouncedTime[linkKey] = time.Now()
			bot.lastURLAnnouncedLinesPassed[linkKey] = 0
			// Keep the long info for later.
			bot.AddMoreInfo(message.SourceTransport, message.Channel, description)
		}
	}
}

// scribe saves the message into appropriate channel log file.
func (bot *Bot) scribeListener(message events.EventMessage) {
	if !bot.Config.ChatLogging {
		return
	}
	go func() {
		logFileName := fmt.Sprintf(
			"logs/%s_%s_%s.txt", message.SourceTransport, message.Channel, time.Now().Format("2006-01-02"))
		f, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			bot.Log.Errorf("Error opening log file: %s", err)
			return
		}
		defer f.Close()

		scribe := log.New(f, "", log.Ldate|log.Ltime)
		if message.EventCode == events.EventChatMessage {
			scribe.Println(fmt.Sprintf("%s: %s", message.Nick, message.Message))
		} else if message.EventCode == events.EventChatNotice {
			scribe.Println(fmt.Sprintf("Notice from %s: %s", message.Nick, message.Message))
		} else if message.EventCode == events.EventJoinedChannel {
			scribe.Println(fmt.Sprintf("* %s joined.", message.Nick))
		} else if message.EventCode == events.EventPartChannel {
			scribe.Println(fmt.Sprintf("* %s left.", message.Nick))
		} else { // Must be channel activity.
			scribe.Println(fmt.Sprintf("* %s %s", message.Nick, message.Message))
		}
	}()
}
<commit_msg>Skip URL meta info announce on mattermost.<commit_after>package papaBot

// Full message handling routines.

import (
	"fmt"
	"github.com/pawelszydlo/papa-bot/events"
	"github.com/pawelszydlo/papa-bot/utils"
	"log"
	"mvdan.cc/xurls"
	"os"
	"regexp"
	"time"
)

var titleRe = regexp.MustCompile("(?is)<title.*?>(.+?)</title>")
var metaRe = regexp.MustCompile(`(?is)<\s*?meta.*?content\s*?=\s*?"(.*?)".*?>`)
var descRe = regexp.MustCompile(`(?is)(property|name)\s*?=.*?description`)

// messageListener looks for commands in messages.
func (bot *Bot) messageListener(message events.EventMessage) {
	// Increase lines count for all announcements.
	for k := range bot.lastURLAnnouncedLinesPassed {
		bot.lastURLAnnouncedLinesPassed[k] += 1
		// After 100 lines pass, forget it ever happened.
		if bot.lastURLAnnouncedLinesPassed[k] > 100 {
			delete(bot.lastURLAnnouncedLinesPassed, k)
			delete(bot.lastURLAnnouncedTime, k)
		}
	}

	// Handles the commands.
	if message.AtBot {
		bot.handleBotCommand(message)
	}
}

// handleURLsListener finds all URLs in the message and fires URL events on them.
func (bot *Bot) handleURLsListener(message events.EventMessage) {

	// Find all URLs in the message.
	links := xurls.Strict().FindAllString(message.Message, -1)
	// Remove multiple same links from one message.
	links = utils.RemoveDuplicates(links)
	for i := range links {
		// Validate the url.
		bot.Log.Infof("Got link %s", links[i])
		link := utils.StandardizeURL(links[i])
		bot.Log.Debugf("Standardized to: %s", link)

		// Try to get the body of the page.
		err, finalLink, body := bot.GetPageBody(link, map[string]string{})
		if err != nil {
			bot.Log.Warningf("Could't fetch the body: %s", err)
		}

		// Iterate over meta tags to get the description
		description := ""
		metas := metaRe.FindAllStringSubmatch(string(body), -1)
		for i := range metas {
			if len(metas[i]) > 1 {
				isDesc := descRe.FindString(metas[i][0])
				if isDesc != "" && (len(metas[i][1]) > len(description)) {
					description = utils.CleanString(metas[i][1], true)
				}
			}
		}
		// Get the title
		title := ""
		match := titleRe.FindStringSubmatch(string(body))
		if len(match) > 1 {
			title = utils.CleanString(match[1], true)
		}

		// Insert URL into the db.
		if _, err := bot.Db.Exec(`INSERT INTO urls(transport, channel, nick, link, quote, title) VALUES(?, ?, ?, ?, ?, ?)`,
			message.SourceTransport, message.Channel, message.Nick, finalLink, message.Message, title); err != nil {
			bot.Log.Warningf("Can't add url to database: %s", err)
		}

		// Trigger url found message.
		bot.EventDispatcher.Trigger(events.EventMessage{
			message.SourceTransport,
			events.EventURLFound,
			message.Nick,
			message.FullName,
			message.Channel,
			finalLink,
			message.Context,
			message.AtBot,
		})

		linkKey := finalLink + message.Channel
		// If we can't announce yet, skip this link.
		if time.Since(bot.lastURLAnnouncedTime[linkKey]) < bot.Config.UrlAnnounceIntervalMinutes*time.Minute {
			continue
		}
		if lines, exists := bot.lastURLAnnouncedLinesPassed[linkKey]; exists && lines < bot.Config.UrlAnnounceIntervalLines {
			continue
		}

		// On mattermost we can skip all link info display.
		if message.SourceTransport == "mattermost" {
			return
		}

		// Announce the title, save the description.
		if title != "" {
			if description != "" {
				bot.SendNotice(message.SourceTransport, message.Channel, title+" …", message.Context)
			} else {
				bot.SendNotice(message.SourceTransport, message.Channel, title, message.Context)
			}
			bot.lastURLAnnouncedTime[linkKey] = time.Now()
			bot.lastURLAnnouncedLinesPassed[linkKey] = 0
			// Keep the long info for later.
			bot.AddMoreInfo(message.SourceTransport, message.Channel, description)
		}
	}
}

// scribe saves the message into appropriate channel log file.
func (bot *Bot) scribeListener(message events.EventMessage) {
	if !bot.Config.ChatLogging {
		return
	}
	go func() {
		logFileName := fmt.Sprintf(
			"logs/%s_%s_%s.txt", message.SourceTransport, message.Channel, time.Now().Format("2006-01-02"))
		f, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			bot.Log.Errorf("Error opening log file: %s", err)
			return
		}
		defer f.Close()

		scribe := log.New(f, "", log.Ldate|log.Ltime)
		if message.EventCode == events.EventChatMessage {
			scribe.Println(fmt.Sprintf("%s: %s", message.Nick, message.Message))
		} else if message.EventCode == events.EventChatNotice {
			scribe.Println(fmt.Sprintf("Notice from %s: %s", message.Nick, message.Message))
		} else if message.EventCode == events.EventJoinedChannel {
			scribe.Println(fmt.Sprintf("* %s joined.", message.Nick))
		} else if message.EventCode == events.EventPartChannel {
			scribe.Println(fmt.Sprintf("* %s left.", message.Nick))
		} else { // Must be channel activity.
			scribe.Println(fmt.Sprintf("* %s %s", message.Nick, message.Message))
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. 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 martian

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

// responseWriter is a lightweight http.ResponseWriter designed to allow
// Martian to support in-proxy endpoints.
//
// responseWriter does not support all of the functionality of the net/http
// ResponseWriter; in particular, it does not sniff Content-Types.
type responseWriter struct {
	ow          io.Writer // original writer
	w           io.Writer // current writer
	hdr         http.Header
	wroteHeader bool
}

// newResponseWriter returns a new http.ResponseWriter.
func newResponseWriter(w io.Writer) *responseWriter {
	return &responseWriter{
		ow:  w,
		w:   w,
		hdr: http.Header{},
	}
}

// Header returns the headers for the response writer.
func (rw *responseWriter) Header() http.Header {
	return rw.hdr
}

// Write writes b to the response body; if the header has yet to be written it
// will write that before the body.
func (rw *responseWriter) Write(b []byte) (int, error) {
	if !rw.wroteHeader {
		rw.WriteHeader(200)
	}

	return rw.w.Write(b)
}

// WriteHeader writes the status line and headers.
func (rw *responseWriter) WriteHeader(status int) {
	if rw.wroteHeader {
		return
	}
	rw.wroteHeader = true

	fmt.Fprintf(rw.w, "HTTP/1.1 %d %s\r\n", status, http.StatusText(status))

	var chunked bool
	if rw.hdr.Get("Content-Length") == "" {
		rw.hdr.Set("Transfer-Encoding", "chunked")
		chunked = true
	}
	rw.hdr.Write(rw.w)

	rw.w.Write([]byte("\r\n"))

	if chunked {
		rw.w = httputil.NewChunkedWriter(rw.w)
	}
}

// Close closes the underlying writer if it is also an io.Closer.
func (rw *responseWriter) Close() error {
	var err error

	wc, ok := rw.w.(io.Closer)
	if ok {
		err = wc.Close()
	}

	rw.ow.Write([]byte("\r\n"))

	return err
}
<commit_msg>response_writer: only add additional CRLF for chunked responses; signals empty trailers.<commit_after>// Copyright 2015 Google Inc. 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 martian

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

// responseWriter is a lightweight http.ResponseWriter designed to allow
// Martian to support in-proxy endpoints.
//
// responseWriter does not support all of the functionality of the net/http
// ResponseWriter; in particular, it does not sniff Content-Types.
type responseWriter struct {
	ow          io.Writer // original writer
	w           io.Writer // current writer
	hdr         http.Header
	wroteHeader bool
}

// newResponseWriter returns a new http.ResponseWriter.
func newResponseWriter(w io.Writer) *responseWriter {
	return &responseWriter{
		ow:  w,
		w:   w,
		hdr: http.Header{},
	}
}

// Header returns the headers for the response writer.
func (rw *responseWriter) Header() http.Header {
	return rw.hdr
}

// Write writes b to the response body; if the header has yet to be written it
// will write that before the body.
func (rw *responseWriter) Write(b []byte) (int, error) {
	if !rw.wroteHeader {
		rw.WriteHeader(200)
	}

	return rw.w.Write(b)
}

// WriteHeader writes the status line and headers.
func (rw *responseWriter) WriteHeader(status int) {
	if rw.wroteHeader {
		return
	}
	rw.wroteHeader = true

	fmt.Fprintf(rw.w, "HTTP/1.1 %d %s\r\n", status, http.StatusText(status))

	var chunked bool
	if rw.hdr.Get("Content-Length") == "" {
		rw.hdr.Set("Transfer-Encoding", "chunked")
		chunked = true
	}
	rw.hdr.Write(rw.w)

	rw.w.Write([]byte("\r\n"))

	if chunked {
		rw.w = httputil.NewChunkedWriter(rw.w)
	}
}

// Close closes the underlying writer if it is also an io.Closer.
func (rw *responseWriter) Close() error {
	var err error

	wc, ok := rw.w.(io.Closer)
	if ok {
		err = wc.Close()
		// Write additional CRLF to signal empty trailers.
		rw.ow.Write([]byte("\r\n"))
	}

	return err
}
<|endoftext|>


<commit_before>package rest

import (
	"reflect"
	"testing"

	"github.com/lfq7413/tomato/types"
)

func Test_Execute(t *testing.T) {
	// BuildRestWhere
	// runFind
	// runCount
	// handleInclude
	// TODO
}

func Test_BuildRestWhere(t *testing.T) {
	// getUserAndRoleACL
	// redirectClassNameForKey
	// validateClientClassCreation
	// replaceSelect
	// replaceDontSelect
	// replaceInQuery
	// replaceNotInQuery
	// TODO
}

func Test_getUserAndRoleACL(t *testing.T) {
	// TODO
}

func Test_redirectClassNameForKey(t *testing.T) {
	// TODO
}

func Test_validateClientClassCreation(t *testing.T) {
	// TODO
}

func Test_replaceSelect(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformSelect
	// TODO
}

func Test_replaceDontSelect(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformDontSelect
	// TODO
}

func Test_replaceInQuery(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformInQuery
	// TODO
}

func Test_replaceNotInQuery(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformNotInQuery
	// TODO
}

func Test_runFind(t *testing.T) {
	// TODO
}

func Test_runCount(t *testing.T) {
	// TODO
}

func Test_handleInclude(t *testing.T) {
	// includePath
	// TODO
}

/////////////////////////////////////////////////////////////////

func Test_NewQuery(t *testing.T) {
	// TODO
}

func Test_includePath(t *testing.T) {
	// findPointers
	// NewQuery
	// Execute
	// replacePointers
	// TODO
}

func Test_findPointers(t *testing.T) {
	// TODO
}

func Test_replacePointers(t *testing.T) {
	// TODO
}

func Test_findObjectWithKey(t *testing.T) {
	// TODO
}

func Test_transformSelect(t *testing.T) {
	// TODO
}

func Test_transformDontSelect(t *testing.T) {
	// TODO
}

func Test_transformInQuery(t *testing.T) {
	// TODO
}

func Test_transformNotInQuery(t *testing.T) {
	var notInQueryObject types.M
	var className string
	var results []types.M
	var expect types.M
	/**********************************************************/
	notInQueryObject = nil
	className = "user"
	results = nil
	transformNotInQuery(notInQueryObject, className, results)
	expect = nil
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{}
	className = "user"
	results = nil
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	// TODO
}
<commit_msg>添加 transformNotInQuery 的单元测试<commit_after>package rest

import (
	"reflect"
	"testing"

	"github.com/lfq7413/tomato/types"
)

func Test_Execute(t *testing.T) {
	// BuildRestWhere
	// runFind
	// runCount
	// handleInclude
	// TODO
}

func Test_BuildRestWhere(t *testing.T) {
	// getUserAndRoleACL
	// redirectClassNameForKey
	// validateClientClassCreation
	// replaceSelect
	// replaceDontSelect
	// replaceInQuery
	// replaceNotInQuery
	// TODO
}

func Test_getUserAndRoleACL(t *testing.T) {
	// TODO
}

func Test_redirectClassNameForKey(t *testing.T) {
	// TODO
}

func Test_validateClientClassCreation(t *testing.T) {
	// TODO
}

func Test_replaceSelect(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformSelect
	// TODO
}

func Test_replaceDontSelect(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformDontSelect
	// TODO
}

func Test_replaceInQuery(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformInQuery
	// TODO
}

func Test_replaceNotInQuery(t *testing.T) {
	// findObjectWithKey
	// NewQuery
	// Execute
	// transformNotInQuery
	// TODO
}

func Test_runFind(t *testing.T) {
	// TODO
}

func Test_runCount(t *testing.T) {
	// TODO
}

func Test_handleInclude(t *testing.T) {
	// includePath
	// TODO
}

/////////////////////////////////////////////////////////////////

func Test_NewQuery(t *testing.T) {
	// TODO
}

func Test_includePath(t *testing.T) {
	// findPointers
	// NewQuery
	// Execute
	// replacePointers
	// TODO
}

func Test_findPointers(t *testing.T) {
	// TODO
}

func Test_replacePointers(t *testing.T) {
	// TODO
}

func Test_findObjectWithKey(t *testing.T) {
	// TODO
}

func Test_transformSelect(t *testing.T) {
	// TODO
}

func Test_transformDontSelect(t *testing.T) {
	// TODO
}

func Test_transformInQuery(t *testing.T) {
	// TODO
}

func Test_transformNotInQuery(t *testing.T) {
	var notInQueryObject types.M
	var className string
	var results []types.M
	var expect types.M
	/**********************************************************/
	notInQueryObject = nil
	className = "user"
	results = nil
	transformNotInQuery(notInQueryObject, className, results)
	expect = nil
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{}
	className = "user"
	results = nil
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{
		"$notInQuery": "string",
	}
	className = "user"
	results = nil
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{
		"$nin": types.S{},
	}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{
		"$notInQuery": "string",
	}
	className = "user"
	results = []types.M{}
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{
		"$nin": types.S{},
	}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{
		"$notInQuery": "string",
	}
	className = "user"
	results = []types.M{
		types.M{
			"objectId": "1001",
		},
		types.M{
			"key": "1002",
		},
	}
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{
		"$nin": types.S{
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1001",
			},
		},
	}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{
		"$notInQuery": "string",
	}
	className = "user"
	results = []types.M{
		types.M{
			"objectId": "1001",
		},
		types.M{
			"objectId": "1002",
		},
	}
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{
		"$nin": types.S{
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1001",
			},
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1002",
			},
		},
	}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
	/**********************************************************/
	notInQueryObject = types.M{
		"$notInQuery": "string",
		"$nin": types.S{
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1003",
			},
		},
	}
	className = "user"
	results = []types.M{
		types.M{
			"objectId": "1001",
		},
		types.M{
			"objectId": "1002",
		},
	}
	transformNotInQuery(notInQueryObject, className, results)
	expect = types.M{
		"$nin": types.S{
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1003",
			},
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1001",
			},
			types.M{
				"__type":    "Pointer",
				"className": "user",
				"objectId":  "1002",
			},
		},
	}
	if reflect.DeepEqual(expect, notInQueryObject) == false {
		t.Error("expect:", expect, "result:", notInQueryObject)
	}
}
<|endoftext|>


<commit_before>package parse

import (
	"fmt"
	"reflect"
	"strings"
)

func objectGoType(t reflect.Type, structT reflect.Type) string {
	switch t.Kind() {
	case reflect.Ptr:
		return "*" + objectGoType(t.Elem(), structT)
	}

	s := t.String()

	// drop package name from qualified identifier if type is defined in the same package
	if strings.Contains(s, ".") && t.PkgPath() == structT.PkgPath() {
		s = strings.Join(strings.Split(s, ".")[1:], ".")
	}

	return s
}

// Object extracts struct information from given object.
func Object(obj interface{}, schema, table string) (res *StructInfo, err error) {
	// convert any panic to error
	defer func() {
		p := recover()
		switch p := p.(type) {
		case error:
			err = p
		case nil:
			// nothing
		default:
			err = fmt.Errorf("%s", p)
		}
	}()

	t := reflect.ValueOf(obj).Elem().Type()
	res = &StructInfo{
		Type:         t.Name(),
		SQLSchema:    schema,
		SQLName:      table,
		PKFieldIndex: -1,
	}

	var n int
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		tag := f.Tag.Get("reform")
		if tag == "" || tag == "-" {
			continue
		}

		// check for anonymous fields
		if f.Anonymous {
			return nil, fmt.Errorf(`reform: %s has anonymous field %s with "reform:" tag, it is not allowed`, res.Type, f.Name)
		}

		// check for exported name
		if f.PkgPath != "" {
			return nil, fmt.Errorf(`reform: %s has non-exported field %s with "reform:" tag, it is not allowed`, res.Type, f.Name)
		}

		// parse tag and type
		column, isPK := parseStructFieldTag(tag)
		if column == "" {
			return nil, fmt.Errorf(`reform: %s has field %s with invalid "reform:" tag value, it is not allowed`, res.Type, f.Name)
		}
		typ := objectGoType(f.Type, t)
		if isPK {
			if strings.HasPrefix(typ, "*") {
				return nil, fmt.Errorf(`reform: %s has pointer field %s with with "pk" label in "reform:" tag, it is not allowed`, res.Type, f.Name)
			}
			if strings.HasPrefix(typ, "[") {
				return nil, fmt.Errorf(`reform: %s has slice field %s with with "pk" label in "reform:" tag, it is not allowed`, res.Type, f.Name)
			}
			if res.PKFieldIndex >= 0 {
				return nil, fmt.Errorf(`reform: %s has field %s with with duplicate "pk" label in "reform:" tag (first used by %s), it is not allowed`, res.Type, f.Name, res.Fields[res.PKFieldIndex].Name)
			}
		}

		res.Fields = append(res.Fields, FieldInfo{
			Name:   f.Name,
			Type:   typ,
			Column: column,
		})
		if isPK {
			res.PKFieldIndex = n
		}
		n++
	}

	if err = checkFields(res); err != nil {
		return nil, err
	}

	return
}
<commit_msg>parse: replace 1 case switch with if<commit_after>package parse

import (
	"fmt"
	"reflect"
	"strings"
)

func objectGoType(t reflect.Type, structT reflect.Type) string {
	if t.Kind() == reflect.Ptr {
		return "*" + objectGoType(t.Elem(), structT)
	}

	s := t.String()

	// drop package name from qualified identifier if type is defined in the same package
	if strings.Contains(s, ".") && t.PkgPath() == structT.PkgPath() {
		s = strings.Join(strings.Split(s, ".")[1:], ".")
	}

	return s
}

// Object extracts struct information from given object.
func Object(obj interface{}, schema, table string) (res *StructInfo, err error) {
	// convert any panic to error
	defer func() {
		p := recover()
		switch p := p.(type) {
		case error:
			err = p
		case nil:
			// nothing
		default:
			err = fmt.Errorf("%s", p)
		}
	}()

	t := reflect.ValueOf(obj).Elem().Type()
	res = &StructInfo{
		Type:         t.Name(),
		SQLSchema:    schema,
		SQLName:      table,
		PKFieldIndex: -1,
	}

	var n int
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		tag := f.Tag.Get("reform")
		if tag == "" || tag == "-" {
			continue
		}

		// check for anonymous fields
		if f.Anonymous {
			return nil, fmt.Errorf(`reform: %s has anonymous field %s with "reform:" tag, it is not allowed`, res.Type, f.Name)
		}

		// check for exported name
		if f.PkgPath != "" {
			return nil, fmt.Errorf(`reform: %s has non-exported field %s with "reform:" tag, it is not allowed`, res.Type, f.Name)
		}

		// parse tag and type
		column, isPK := parseStructFieldTag(tag)
		if column == "" {
			return nil, fmt.Errorf(`reform: %s has field %s with invalid "reform:" tag value, it is not allowed`, res.Type, f.Name)
		}
		typ := objectGoType(f.Type, t)
		if isPK {
			if strings.HasPrefix(typ, "*") {
				return nil, fmt.Errorf(`reform: %s has pointer field %s with with "pk" label in "reform:" tag, it is not allowed`, res.Type, f.Name)
			}
			if strings.HasPrefix(typ, "[") {
				return nil, fmt.Errorf(`reform: %s has slice field %s with with "pk" label in "reform:" tag, it is not allowed`, res.Type, f.Name)
			}
			if res.PKFieldIndex >= 0 {
				return nil, fmt.Errorf(`reform: %s has field %s with with duplicate "pk" label in "reform:" tag (first used by %s), it is not allowed`, res.Type, f.Name, res.Fields[res.PKFieldIndex].Name)
			}
		}

		res.Fields = append(res.Fields, FieldInfo{
			Name:   f.Name,
			Type:   typ,
			Column: column,
		})
		if isPK {
			res.PKFieldIndex = n
		}
		n++
	}

	if err = checkFields(res); err != nil {
		return nil, err
	}

	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package nilstore implements a walletstore without any abilities.
package nilstore

import (
	"github.com/agl/ed25519"
	"github.com/mutecomm/mute/serviceguard/client"
	"github.com/mutecomm/mute/util/times"
)

// NilStore is a walletstore without abilities
type NilStore struct {
	AuthToken      []byte
	AuthTokenTries int
	LastToken      *client.TokenEntry
	VerifyKeys     [][ed25519.PublicKeySize]byte
}

// SetAuthToken without persistance
func (ns *NilStore) SetAuthToken(authToken []byte, tries int) error {
	ns.AuthToken = authToken
	ns.AuthTokenTries = tries
	// spew.Dump(ns.AuthToken)
	return nil
}

// GetAuthToken without persistance
func (ns *NilStore) GetAuthToken() (authToken []byte, tries int) {
	return ns.AuthToken, ns.AuthTokenTries
}

// SetToken without persistance
func (ns *NilStore) SetToken(tokenEntry client.TokenEntry) error {
	ns.LastToken = &tokenEntry
	// fmt.Printf("Token: %+v\n", ns.LastToken)
	// spew.Dump(ns.LastToken)
	return nil
}

// GetToken without persistance
func (ns *NilStore) GetToken(tokenHash []byte, lockID int64) (tokenEntry *client.TokenEntry, err error) {
	return ns.LastToken, nil
}

// SetVerifyKeys without persistance
func (ns *NilStore) SetVerifyKeys(keys [][ed25519.PublicKeySize]byte) {
	ns.VerifyKeys = keys
	// fmt.Printf("VerifyKeys: %+v\n", ns.VerifyKeys)
	// spew.Dump(ns.VerifyKeys)
}

// GetVerifyKeys without persistance
func (ns *NilStore) GetVerifyKeys() [][ed25519.PublicKeySize]byte {
	return ns.VerifyKeys
}

// DelToken without function
func (ns *NilStore) DelToken(tokenHash []byte) {}

// LockToken without function
func (ns *NilStore) LockToken(tokenHash []byte) int64 {
	return times.NowNano()
}

// UnlockToken without function
func (ns *NilStore) UnlockToken(tokenHash []byte) {}

// GetAndLockToken without persistance
func (ns *NilStore) GetAndLockToken(usage string, owner *[ed25519.PublicKeySize]byte) (*client.TokenEntry, error) {
	return ns.LastToken, nil
}

// FindToken without persistance
func (ns *NilStore) FindToken(usage string) (*client.TokenEntry, error) {
	return ns.LastToken, nil
}

// GetExpire without function
func (ns *NilStore) GetExpire() []byte {
	return nil
}

//GetInReissue without function
func (ns *NilStore) GetInReissue() []byte {
	return nil
}

//GetBalanceOwn without function
func (ns *NilStore) GetBalanceOwn(usage string) int64 {
	return 0
}

//GetBalance without function
func (ns *NilStore) GetBalance(usage string, owner *[ed25519.PublicKeySize]byte) int64 {
	return 0
}

// ExpireUnusable without function
func (ns *NilStore) ExpireUnusable() bool {
	return false
}
<commit_msg>nilstore: fix typos & style<commit_after>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package nilstore implements a walletstore without any abilities.
package nilstore

import (
	"github.com/agl/ed25519"
	"github.com/mutecomm/mute/serviceguard/client"
	"github.com/mutecomm/mute/util/times"
)

// NilStore is a walletstore without abilities.
type NilStore struct {
	AuthToken      []byte
	AuthTokenTries int
	LastToken      *client.TokenEntry
	VerifyKeys     [][ed25519.PublicKeySize]byte
}

// SetAuthToken without persistence.
func (ns *NilStore) SetAuthToken(authToken []byte, tries int) error {
	ns.AuthToken = authToken
	ns.AuthTokenTries = tries
	// spew.Dump(ns.AuthToken)
	return nil
}

// GetAuthToken without persistence.
func (ns *NilStore) GetAuthToken() (authToken []byte, tries int) {
	return ns.AuthToken, ns.AuthTokenTries
}

// SetToken without persistence.
func (ns *NilStore) SetToken(tokenEntry client.TokenEntry) error {
	ns.LastToken = &tokenEntry
	// fmt.Printf("Token: %+v\n", ns.LastToken)
	// spew.Dump(ns.LastToken)
	return nil
}

// GetToken without persistence.
func (ns *NilStore) GetToken(tokenHash []byte, lockID int64) (tokenEntry *client.TokenEntry, err error) {
	return ns.LastToken, nil
}

// SetVerifyKeys without persistence.
func (ns *NilStore) SetVerifyKeys(keys [][ed25519.PublicKeySize]byte) {
	ns.VerifyKeys = keys
	// fmt.Printf("VerifyKeys: %+v\n", ns.VerifyKeys)
	// spew.Dump(ns.VerifyKeys)
}

// GetVerifyKeys without persistence.
func (ns *NilStore) GetVerifyKeys() [][ed25519.PublicKeySize]byte {
	return ns.VerifyKeys
}

// DelToken without function.
func (ns *NilStore) DelToken(tokenHash []byte) {}

// LockToken without function.
func (ns *NilStore) LockToken(tokenHash []byte) int64 {
	return times.NowNano()
}

// UnlockToken without function.
func (ns *NilStore) UnlockToken(tokenHash []byte) {}

// GetAndLockToken without persistence.
func (ns *NilStore) GetAndLockToken(usage string, owner *[ed25519.PublicKeySize]byte) (*client.TokenEntry, error) {
	return ns.LastToken, nil
}

// FindToken without persistence.
func (ns *NilStore) FindToken(usage string) (*client.TokenEntry, error) {
	return ns.LastToken, nil
}

// GetExpire without function.
func (ns *NilStore) GetExpire() []byte {
	return nil
}

//GetInReissue without function.
func (ns *NilStore) GetInReissue() []byte {
	return nil
}

//GetBalanceOwn without function.
func (ns *NilStore) GetBalanceOwn(usage string) int64 {
	return 0
}

//GetBalance without function.
func (ns *NilStore) GetBalance(usage string, owner *[ed25519.PublicKeySize]byte) int64 {
	return 0
}

// ExpireUnusable without function.
func (ns *NilStore) ExpireUnusable() bool {
	return false
}
<|endoftext|>


<commit_before>package parser

import (
	"errors"
	"log"

	"github.com/tmc/graphql"
	"github.com/tmc/graphql/internal/parser"
)

var (
	// ErrMalformedOperation means there was a parsing error with the provided query
	ErrMalformedOperation = errors.New("parser: malformed graphql operation")
	// ErrMultipleOperations
	ErrMultipleOperations = errors.New("parser: multiple graphql operations")
)

// ParseOperation attempts to parse a graphql.Operation from a byte slice.
func ParseOperation(query []byte) (*graphql.Operation, error) {
	result, err := parser.Parse("", query)
	if err != nil {
		log.Println("parse error:", err)
		return nil, ErrMalformedOperation
	}
	doc, ok := result.(graphql.Document)
	if !ok {
		return nil, ErrMalformedOperation
	}
	switch len(doc.Operations) {
	case 1:
		return &doc.Operations[0], nil
	case 0:
		return nil, ErrMalformedOperation
	default:
		return nil, ErrMultipleOperations
	}
}
<commit_msg>Surface parse errors.<commit_after>package parser

import (
	"errors"
	"fmt"
	"log"

	"github.com/tmc/graphql"
	"github.com/tmc/graphql/internal/parser"
)

var (
	// ErrMultipleOperations
	ErrMultipleOperations = errors.New("parser: multiple graphql operations")
)

// ErrMalformedOperation means there was a parsing error with the provided query
type ErrMalformedOperation struct {
	underlying error
}

func IsMalformedOperation(err error) bool {
	_, ok := err.(ErrMalformedOperation)
	return ok
}

func (e ErrMalformedOperation) Error() string {
	return fmt.Sprintf("parser: malformed graphql operation: %v", e.underlying)
}

// ParseOperation attempts to parse a graphql.Operation from a byte slice.
func ParseOperation(query []byte) (*graphql.Operation, error) {
	result, err := parser.Parse("", query)
	if err != nil {
		log.Println("parse error:", err)
		return nil, ErrMalformedOperation{err}
	}
	doc, ok := result.(graphql.Document)
	if !ok {
		return nil, ErrMalformedOperation{err}
	}
	switch len(doc.Operations) {
	case 1:
		return &doc.Operations[0], nil
	case 0:
		return nil, ErrMalformedOperation{fmt.Errorf("no operations")}
	default:
		return nil, ErrMultipleOperations
	}
}
<|endoftext|>


<commit_before>package tests

import (
	"fmt"
	"testing"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/portworx/torpedo/drivers/node"
	"github.com/portworx/torpedo/drivers/scheduler"
	. "github.com/portworx/torpedo/tests"
)

func TestBasic(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Torpedo : Basic")
}

var _ = BeforeSuite(func() {
	InitInstance()
})

// This test performs basic test of starting an application and destroying it (along with storage)
var _ = Describe("SetupTeardown", func() {
	It("has to setup, validate and teardown apps", func() {
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("setupteardown-%d", i))...)
		}

		opts := make(map[string]bool)
		opts[scheduler.OptionsWaitForResourceLeakCleanup] = true

		for _, ctx := range contexts {
			TearDownContext(ctx, opts)
		}
	})
})

// Volume Driver Plugin is down, unavailable - and the client container should not be impacted.
var _ = Describe("VolumeDriverDown", func() {
	It("has to schedule apps and stop volume driver on app nodes", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("voldriverdown-%d", i))...)
		}

		Step("get nodes for all apps in test and bounce volume driver", func() {
			for _, ctx := range contexts {
				var appNodes []node.Node
				Step(fmt.Sprintf("get nodes for %s app", ctx.App.Key), func() {
					appNodes, err = Inst().S.GetNodesForApp(ctx)
					Expect(err).NotTo(HaveOccurred())
					Expect(appNodes).NotTo(BeEmpty())
				})

				Step(
					fmt.Sprintf("stop volume driver %s on app %s's nodes: %v",
						Inst().V.String(), ctx.App.Key, appNodes),
					func() {
						StopVolDriverAndWait(appNodes)
					})

				Step("starting volume driver", func() {
					StartVolDriverAndWait(appNodes)
				})

				Step("Giving few seconds for volume driver to stabilize", func() {
					time.Sleep(20 * time.Second)
				})
			}
		})

		Step("destroy apps", func() {
			opts := make(map[string]bool)
			opts[scheduler.OptionsWaitForResourceLeakCleanup] = true
			for _, ctx := range contexts {
				TearDownContext(ctx, opts)
			}
		})

	})
})

// Volume Driver Plugin has crashed - and the client container should not be impacted.
var _ = Describe("VolumeDriverCrash", func() {
	It("has to schedule apps and crash volume driver on app nodes", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("voldrivercrash-%d", i))...)
		}

		Step("get nodes for all apps in test and crash volume driver", func() {
			for _, ctx := range contexts {
				var appNodes []node.Node
				Step(fmt.Sprintf("get nodes for %s app", ctx.App.Key), func() {
					appNodes, err = Inst().S.GetNodesForApp(ctx)
					Expect(err).NotTo(HaveOccurred())
					Expect(appNodes).NotTo(BeEmpty())
				})

				Step(
					fmt.Sprintf("crash volume driver %s on app %s's nodes: %v",
						Inst().V.String(), ctx.App.Key, appNodes),
					func() {
						CrashVolDriverAndWait(appNodes)
					})
			}
		})

		opts := make(map[string]bool)
		opts[scheduler.OptionsWaitForResourceLeakCleanup] = true
		ValidateAndDestroy(contexts, opts)
	})
})

// Volume driver plugin is down and the client container gets terminated.
// There is a lost unmount call in this case. When the volume driver is
// back up, we should be able to detach and delete the volume.
var _ = Describe("VolumeDriverAppDown", func() {
	It("has to schedule apps, stop volume driver on app nodes and destroy apps", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("voldriverappdown-%d", i))...)
		}

		Step("get nodes for all apps in test and bounce volume driver", func() {
			for _, ctx := range contexts {
				var appNodes []node.Node
				Step(fmt.Sprintf("get nodes for %s app", ctx.App.Key), func() {
					appNodes, err = Inst().S.GetNodesForApp(ctx)
					Expect(err).NotTo(HaveOccurred())
					Expect(appNodes).NotTo(BeEmpty())
				})

				Step(fmt.Sprintf("stop volume driver %s on app %s's nodes: %v",
					Inst().V.String(), ctx.App.Key, appNodes), func() {
					StopVolDriverAndWait(appNodes)
				})

				Step(fmt.Sprintf("destroy app: %s", ctx.App.Key), func() {
					err = Inst().S.Destroy(ctx, nil)
					Expect(err).NotTo(HaveOccurred())

					Step("wait for few seconds for app destroy to trigger", func() {
						time.Sleep(10 * time.Second)
					})
				})

				Step("restarting volume driver", func() {
					StartVolDriverAndWait(appNodes)
				})

				Step(fmt.Sprintf("wait for destroy of app: %s", ctx.App.Key), func() {
					err = Inst().S.WaitForDestroy(ctx)
					Expect(err).NotTo(HaveOccurred())
				})

				DeleteVolumesAndWait(ctx)
			}
		})
	})
})

// This test deletes all tasks of an application and checks if app converges back to desired state
var _ = Describe("AppTasksDown", func() {
	It("has to schedule app and delete app tasks", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("apptasksdown-%d", i))...)
		}

		Step("delete all application tasks", func() {
			for _, ctx := range contexts {
				Step(fmt.Sprintf("delete tasks for app: %s", ctx.App.Key), func() {
					err = Inst().S.DeleteTasks(ctx)
					Expect(err).NotTo(HaveOccurred())
				})

				ValidateContext(ctx)
			}
		})

		Step("teardown all apps", func() {
			for _, ctx := range contexts {
				TearDownContext(ctx, nil)
			}
		})
	})
})

// This test scales up and down an application and checks if app has actually scaled accordingly
var _ = Describe("AppScaleUpAndDown", func() {
	It("has to scale up and scale down the app", func() {
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("applicationscaleupdown-%d", i))...)
		}

		Step("scale up all applications", func() {
			for _, ctx := range contexts {
				Step(fmt.Sprintf("updating scale for app: %s", ctx.App.Key), func() {
					applicationScaleUpMap, err := Inst().S.GetScaleFactorMap(ctx)
					Expect(err).NotTo(HaveOccurred())
					for name, scale := range applicationScaleUpMap {
						applicationScaleUpMap[name] = scale + 1
					}
					err = Inst().S.ScaleApplication(ctx, applicationScaleUpMap)
					Expect(err).NotTo(HaveOccurred())
				})

				ValidateContext(ctx)
			}
		})
		Step("scale down all applications", func() {
			for _, ctx := range contexts {
				Step("scale down all deployments/stateful sets ", func() {
					applicationScaleDownMap, err := Inst().S.GetScaleFactorMap(ctx)
					Expect(err).NotTo(HaveOccurred())
					for name, scale := range applicationScaleDownMap {
						applicationScaleDownMap[name] = scale - 1
					}
					err = Inst().S.ScaleApplication(ctx, applicationScaleDownMap)
					Expect(err).NotTo(HaveOccurred())
				})

				ValidateContext(ctx)
			}
		})
		Step("teardown all apps", func() {
			for _, ctx := range contexts {
				TearDownContext(ctx, nil)
			}
		})

	})
})

var _ = AfterSuite(func() {
	CollectSupport()
	ValidateCleanup()
})

func init() {
	ParseFlags()
}
<commit_msg>Scale app by num of nodes<commit_after>package tests

import (
	"fmt"
	"testing"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/portworx/torpedo/drivers/node"
	"github.com/portworx/torpedo/drivers/scheduler"
	. "github.com/portworx/torpedo/tests"
)

func TestBasic(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Torpedo : Basic")
}

var _ = BeforeSuite(func() {
	InitInstance()
})

// This test performs basic test of starting an application and destroying it (along with storage)
var _ = Describe("SetupTeardown", func() {
	It("has to setup, validate and teardown apps", func() {
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("setupteardown-%d", i))...)
		}

		opts := make(map[string]bool)
		opts[scheduler.OptionsWaitForResourceLeakCleanup] = true

		for _, ctx := range contexts {
			TearDownContext(ctx, opts)
		}
	})
})

// Volume Driver Plugin is down, unavailable - and the client container should not be impacted.
var _ = Describe("VolumeDriverDown", func() {
	It("has to schedule apps and stop volume driver on app nodes", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("voldriverdown-%d", i))...)
		}

		Step("get nodes for all apps in test and bounce volume driver", func() {
			for _, ctx := range contexts {
				var appNodes []node.Node
				Step(fmt.Sprintf("get nodes for %s app", ctx.App.Key), func() {
					appNodes, err = Inst().S.GetNodesForApp(ctx)
					Expect(err).NotTo(HaveOccurred())
					Expect(appNodes).NotTo(BeEmpty())
				})

				Step(
					fmt.Sprintf("stop volume driver %s on app %s's nodes: %v",
						Inst().V.String(), ctx.App.Key, appNodes),
					func() {
						StopVolDriverAndWait(appNodes)
					})

				Step("starting volume driver", func() {
					StartVolDriverAndWait(appNodes)
				})

				Step("Giving few seconds for volume driver to stabilize", func() {
					time.Sleep(20 * time.Second)
				})
			}
		})

		Step("destroy apps", func() {
			opts := make(map[string]bool)
			opts[scheduler.OptionsWaitForResourceLeakCleanup] = true
			for _, ctx := range contexts {
				TearDownContext(ctx, opts)
			}
		})

	})
})

// Volume Driver Plugin has crashed - and the client container should not be impacted.
var _ = Describe("VolumeDriverCrash", func() {
	It("has to schedule apps and crash volume driver on app nodes", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("voldrivercrash-%d", i))...)
		}

		Step("get nodes for all apps in test and crash volume driver", func() {
			for _, ctx := range contexts {
				var appNodes []node.Node
				Step(fmt.Sprintf("get nodes for %s app", ctx.App.Key), func() {
					appNodes, err = Inst().S.GetNodesForApp(ctx)
					Expect(err).NotTo(HaveOccurred())
					Expect(appNodes).NotTo(BeEmpty())
				})

				Step(
					fmt.Sprintf("crash volume driver %s on app %s's nodes: %v",
						Inst().V.String(), ctx.App.Key, appNodes),
					func() {
						CrashVolDriverAndWait(appNodes)
					})
			}
		})

		opts := make(map[string]bool)
		opts[scheduler.OptionsWaitForResourceLeakCleanup] = true
		ValidateAndDestroy(contexts, opts)
	})
})

// Volume driver plugin is down and the client container gets terminated.
// There is a lost unmount call in this case. When the volume driver is
// back up, we should be able to detach and delete the volume.
var _ = Describe("VolumeDriverAppDown", func() {
	It("has to schedule apps, stop volume driver on app nodes and destroy apps", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("voldriverappdown-%d", i))...)
		}

		Step("get nodes for all apps in test and bounce volume driver", func() {
			for _, ctx := range contexts {
				var appNodes []node.Node
				Step(fmt.Sprintf("get nodes for %s app", ctx.App.Key), func() {
					appNodes, err = Inst().S.GetNodesForApp(ctx)
					Expect(err).NotTo(HaveOccurred())
					Expect(appNodes).NotTo(BeEmpty())
				})

				Step(fmt.Sprintf("stop volume driver %s on app %s's nodes: %v",
					Inst().V.String(), ctx.App.Key, appNodes), func() {
					StopVolDriverAndWait(appNodes)
				})

				Step(fmt.Sprintf("destroy app: %s", ctx.App.Key), func() {
					err = Inst().S.Destroy(ctx, nil)
					Expect(err).NotTo(HaveOccurred())

					Step("wait for few seconds for app destroy to trigger", func() {
						time.Sleep(10 * time.Second)
					})
				})

				Step("restarting volume driver", func() {
					StartVolDriverAndWait(appNodes)
				})

				Step(fmt.Sprintf("wait for destroy of app: %s", ctx.App.Key), func() {
					err = Inst().S.WaitForDestroy(ctx)
					Expect(err).NotTo(HaveOccurred())
				})

				DeleteVolumesAndWait(ctx)
			}
		})
	})
})

// This test deletes all tasks of an application and checks if app converges back to desired state
var _ = Describe("AppTasksDown", func() {
	It("has to schedule app and delete app tasks", func() {
		var err error
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("apptasksdown-%d", i))...)
		}

		Step("delete all application tasks", func() {
			for _, ctx := range contexts {
				Step(fmt.Sprintf("delete tasks for app: %s", ctx.App.Key), func() {
					err = Inst().S.DeleteTasks(ctx)
					Expect(err).NotTo(HaveOccurred())
				})

				ValidateContext(ctx)
			}
		})

		Step("teardown all apps", func() {
			for _, ctx := range contexts {
				TearDownContext(ctx, nil)
			}
		})
	})
})

// This test scales up and down an application and checks if app has actually scaled accordingly
var _ = Describe("AppScaleUpAndDown", func() {
	It("has to scale up and scale down the app", func() {
		var contexts []*scheduler.Context
		for i := 0; i < Inst().ScaleFactor; i++ {
			contexts = append(contexts, ScheduleAndValidate(fmt.Sprintf("applicationscaleupdown-%d", i))...)
		}

		Step("scale up all applications", func() {
			for _, ctx := range contexts {
				Step(fmt.Sprintf("updating scale for app: %s by %d ", ctx.App.Key, len(node.GetWorkerNodes())), func() {
					applicationScaleUpMap, err := Inst().S.GetScaleFactorMap(ctx)
					Expect(err).NotTo(HaveOccurred())
					for name, scale := range applicationScaleUpMap {
						applicationScaleUpMap[name] = scale + int32(len(node.GetWorkerNodes()))
					}
					err = Inst().S.ScaleApplication(ctx, applicationScaleUpMap)
					Expect(err).NotTo(HaveOccurred())
				})

				ValidateContext(ctx)
			}
		})
		Step("scale down all applications", func() {
			for _, ctx := range contexts {
				Step("scale down all deployments/stateful sets ", func() {
					applicationScaleDownMap, err := Inst().S.GetScaleFactorMap(ctx)
					Expect(err).NotTo(HaveOccurred())
					for name, scale := range applicationScaleDownMap {
						applicationScaleDownMap[name] = scale - 1
					}
					err = Inst().S.ScaleApplication(ctx, applicationScaleDownMap)
					Expect(err).NotTo(HaveOccurred())
				})

				ValidateContext(ctx)
			}
		})
		Step("teardown all apps", func() {
			for _, ctx := range contexts {
				TearDownContext(ctx, nil)
			}
		})

	})
})

var _ = AfterSuite(func() {
	CollectSupport()
	ValidateCleanup()
})

func init() {
	ParseFlags()
}
<|endoftext|>


<commit_before>package output

import (
	"bitbucket.org/cswank/gogadgets/models"
	"bitbucket.org/cswank/gogadgets/pins"
	"time"
)

//Heater represnts an electic heating element.  It
//provides a way to heat up something to a target
//temperature. In order to use this there must be
//a thermometer in the same Location.
type Heater struct {
	target      float64
	currentTemp float64
	duration    time.Duration
	status      bool
	doPWM       bool
	pwm         OutputDevice
}

func NewHeater(pin *models.Pin) (OutputDevice, error) {
	var h *Heater
	var err error
	var d OutputDevice
	doPWM := pin.Args["pwm"] == true
	d, err = NewPWM(pin)
	if err == nil {
		h = &Heater{
			pwm:    d,
			target: 100.0,
			doPWM:  doPWM,
		}
	}
	return h, err
}

func (h *Heater) Config() models.ConfigHelper {
	return models.ConfigHelper{
		PinType: "pwm",
		Units: []string{"C", "F"},
		Pins: pins.Pins["pwm"],
	}
}

func (h *Heater) Update(msg *models.Message) {
	if h.status && msg.Name == "temperature" {
		h.readTemperature(msg)
	}
}

func (h *Heater) On(val *models.Value) error {
	if val != nil {
		target, ok := val.ToFloat()
		if ok {
			h.target = target
		} else {
			h.target = 100.0
		}
	}
	h.setPWM()
	h.status = true
	return nil
}

func (h *Heater) Status() interface{} {
	return h.status
}

func (h *Heater) Off() error {
	h.target = 0.0
	h.status = false
	h.pwm.Off()
	return nil
}

func (h *Heater) readTemperature(msg *models.Message) {
	temp, ok := msg.Value.ToFloat()
	if ok {
		h.currentTemp = temp
		if h.status {
			h.setPWM()
		}
	}
}

func (h *Heater) setPWM() {
	if h.doPWM {
		duty := h.getDuty()
		val := &models.Value{Value: duty, Units: "%"}
		h.pwm.On(val)
	} else {
		diff := h.target - h.currentTemp
		if diff > 0 {
			h.pwm.On(nil)
		} else {
			h.pwm.Off()
		}
	}
}

//Once the heater approaches the target temperature the electricity
//is applied PWM style so the target temperature isn't overshot.
func (h *Heater) getDuty() float64 {
	diff := h.target - h.currentTemp
	duty := 100.0
	if diff <= 0.0 {
		duty = 0.0
	} else if diff <= 1.0 {
		duty = 25.0
	} else if diff <= 2.0 {
		duty = 50.0
	}
	return duty
}
<commit_msg>set frequency of heater to 1 if it is not set<commit_after>package output

import (
	"bitbucket.org/cswank/gogadgets/models"
	"bitbucket.org/cswank/gogadgets/pins"
	"time"
)

//Heater represnts an electic heating element.  It
//provides a way to heat up something to a target
//temperature. In order to use this there must be
//a thermometer in the same Location.
type Heater struct {
	target      float64
	currentTemp float64
	duration    time.Duration
	status      bool
	doPWM       bool
	pwm         OutputDevice
}

func NewHeater(pin *models.Pin) (OutputDevice, error) {
	var h *Heater
	var err error
	var d OutputDevice
	doPWM := pin.Args["pwm"] == true
	if pin.Frequency == 0 {
		pin.Frequency = 1
	}
	d, err = NewPWM(pin)
	if err == nil {
		h = &Heater{
			pwm:    d,
			target: 100.0,
			doPWM:  doPWM,
		}
	}
	return h, err
}

func (h *Heater) Config() models.ConfigHelper {
	return models.ConfigHelper{
		PinType: "pwm",
		Units: []string{"C", "F"},
		Pins: pins.Pins["pwm"],
	}
}

func (h *Heater) Update(msg *models.Message) {
	if h.status && msg.Name == "temperature" {
		h.readTemperature(msg)
	}
}

func (h *Heater) On(val *models.Value) error {
	if val != nil {
		target, ok := val.ToFloat()
		if ok {
			h.target = target
		} else {
			h.target = 100.0
		}
	}
	h.setPWM()
	h.status = true
	return nil
}

func (h *Heater) Status() interface{} {
	return h.status
}

func (h *Heater) Off() error {
	h.target = 0.0
	h.status = false
	h.pwm.Off()
	return nil
}

func (h *Heater) readTemperature(msg *models.Message) {
	temp, ok := msg.Value.ToFloat()
	if ok {
		h.currentTemp = temp
		if h.status {
			h.setPWM()
		}
	}
}

func (h *Heater) setPWM() {
	if h.doPWM {
		duty := h.getDuty()
		val := &models.Value{Value: duty, Units: "%"}
		h.pwm.On(val)
	} else {
		diff := h.target - h.currentTemp
		if diff > 0 {
			h.pwm.On(nil)
		} else {
			h.pwm.Off()
		}
	}
}

//Once the heater approaches the target temperature the electricity
//is applied PWM style so the target temperature isn't overshot.
func (h *Heater) getDuty() float64 {
	diff := h.target - h.currentTemp
	duty := 100.0
	if diff <= 0.0 {
		duty = 0.0
	} else if diff <= 1.0 {
		duty = 25.0
	} else if diff <= 2.0 {
		duty = 50.0
	}
	return duty
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"github.com/codegangsta/cli"
)

func (u *SomaUtil) GetCliArgumentCount(c *cli.Context) int {
	a := c.Args()
	if !a.Present() {
		return 0
	}
	return len(a.Tail()) + 1
}

func (u *SomaUtil) ValidateCliArgument(c *cli.Context, pos uint8, s string) {
	a := c.Args()
	if a.Get(int(pos)-1) != s {
		u.Abort(fmt.Sprintf("Syntax error, missing keyword: ", s))
	}
}

func (u *SomaUtil) ValidateCliArgumentCount(c *cli.Context, i uint8) {
	a := c.Args()
	if i == 0 {
		if a.Present() {
			u.Abort("Syntax error, command takes no arguments")
		}
	} else {
		if !a.Present() || len(a.Tail()) != (int(i)-1) {
			u.Abort("Syntax error")
		}
	}
}

func (u *SomaUtil) GetFullArgumentSlice(c *cli.Context) []string {
	sl := []string{c.Args().First()}
	sl = append(sl, c.Args().Tail()...)
	return sl
}

func (u *SomaUtil) ParseVariableArguments(keys []string, rKeys []string, args []string) (map[string]string, []string) {
	// return map of the parse result
	result := make(map[string]string)
	// map to test which required keys were found
	argumentCheck := make(map[string]bool)
	// return slice which optional keys were found
	optionalKeys := make([]string, 0)
	for _, key := range rKeys {
		argumentCheck[key] = false
	}
	skipNext := false

	for pos, val := range args {
		// skip current argument if last argument was a keyword
		if skipNext {
			skipNext = false
			continue
		}

		if u.SliceContainsString(val, keys) {
			// check back-to-back keywords
			u.CheckStringNotAKeyword(args[pos+1], keys)
			result[val] = args[pos+1]
			argumentCheck[val] = true
			skipNext = true
			if !u.SliceContainsString(val, rKeys) {
				optionalKeys = append(optionalKeys, val)
			}
			continue
		}
		// keywords trigger continue, arguments are skipped over.
		// reaching this is an error
		u.Abort(fmt.Sprintf("Syntax error, erroneus argument: %s", val))
	}

	// check we managed to collect all required keywords
	for _, v := range argumentCheck {
		if !v {
			u.Abort(fmt.Sprintf("Syntax error, missing keyword: %s", v))
		}
	}

	return result, optionalKeys
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>ParseVariableArguments: support all optional keys<commit_after>package util

import (
	"fmt"
	"github.com/codegangsta/cli"
)

func (u *SomaUtil) GetCliArgumentCount(c *cli.Context) int {
	a := c.Args()
	if !a.Present() {
		return 0
	}
	return len(a.Tail()) + 1
}

func (u *SomaUtil) ValidateCliArgument(c *cli.Context, pos uint8, s string) {
	a := c.Args()
	if a.Get(int(pos)-1) != s {
		u.Abort(fmt.Sprintf("Syntax error, missing keyword: ", s))
	}
}

func (u *SomaUtil) ValidateCliArgumentCount(c *cli.Context, i uint8) {
	a := c.Args()
	if i == 0 {
		if a.Present() {
			u.Abort("Syntax error, command takes no arguments")
		}
	} else {
		if !a.Present() || len(a.Tail()) != (int(i)-1) {
			u.Abort("Syntax error")
		}
	}
}

func (u *SomaUtil) GetFullArgumentSlice(c *cli.Context) []string {
	sl := []string{c.Args().First()}
	sl = append(sl, c.Args().Tail()...)
	return sl
}

func (u *SomaUtil) ParseVariableArguments(keys []string, rKeys []string, args []string) (map[string]string, []string) {
	// return map of the parse result
	result := make(map[string]string)
	// map to test which required keys were found
	argumentCheck := make(map[string]bool)
	// return slice which optional keys were found
	optionalKeys := make([]string, 0)
	// no required keys is valid
	if len(rKeys) > 0 {
		for _, key := range rKeys {
			argumentCheck[key] = false
		}
	}
	skipNext := false

	for pos, val := range args {
		// skip current argument if last argument was a keyword
		if skipNext {
			skipNext = false
			continue
		}

		if u.SliceContainsString(val, keys) {
			// check back-to-back keywords
			u.CheckStringNotAKeyword(args[pos+1], keys)
			result[val] = args[pos+1]
			argumentCheck[val] = true
			skipNext = true
			if !u.SliceContainsString(val, rKeys) {
				optionalKeys = append(optionalKeys, val)
			}
			continue
		}
		// keywords trigger continue, arguments are skipped over.
		// reaching this is an error
		u.Abort(fmt.Sprintf("Syntax error, erroneus argument: %s", val))
	}

	// check we managed to collect all required keywords
	for _, v := range argumentCheck {
		if !v {
			u.Abort(fmt.Sprintf("Syntax error, missing keyword: %s", v))
		}
	}

	return result, optionalKeys
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>