<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/functions.go                                   *
 *                                                        *
 * some functions of promise for Go.                      *
 *                                                        *
 * LastModified: Aug 14, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"errors"
	"sync/atomic"
	"time"
)

// Create creates a Promise object containing the result of asynchronously
// calling computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Create(computation func() (interface{}, error)) Promise {
	promise := New()
	go call(promise, computation)
	return promise
}

// Sync creates a Promise object containing the result of immediately calling
// computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Sync(computation func() (interface{}, error)) Promise {
	promise := New()
	call(promise, computation)
	return promise
}

// Delayed creates a Promise object with the given value after a delay.
//
// If the value is a Callable function, it will be executed after the given
// duration has passed, and the Promise object is completed with the result.
func Delayed(duration time.Duration, value interface{}) Promise {
	promise := New()
	go func() {
		time.Sleep(duration)
		switch computation := value.(type) {
		case func() (interface{}, error):
			call(promise, computation)
		case func():
			call1(promise, computation)
		default:
			promise.Resolve(value)
		}
	}()
	return promise
}

// All function returns a promise that resolves when all of the promises in the
// iterable argument have resolved, or rejects with the reason of the first
// passed promise that rejects.
func All(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Resolve(nil)
	}
	result := make([]interface{}, count)
	promise := New()
	for index, value := range iterable {
		ToPromise(value).Then(func(index int) func(value interface{}) {
			return func(value interface{}) {
				result[index] = value
				if atomic.AddInt64(&count, -1) == 0 {
					promise.Resolve(result)
				}
			}
		}(index), promise.Reject)
	}
	return promise
}

// Race function returns a promise that resolves or rejects as soon as one of
// the promises in the iterable resolves or rejects, with the value or reason
// from that promise.
func Race(iterable ...interface{}) Promise {
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Fill(promise)
	}
	return promise
}

// Any function is a competitive race that allows one winner.
//
// The returned promise will fulfill as soon as any one of the input promises
// fulfills, with the value of the fulfilled input promise.
//
// Or reject with a IllegalArgumentError if the input array is empty--i.e. it
// is impossible to have one winner.
//
// Or reject with an array of all the rejection reasons, if the input array is
// non-empty, and all input promises reject.
func Any(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Reject(IllegalArgumentError("any(): array must not be empty"))
	}
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Then(promise.Resolve, func() {
			if atomic.AddInt64(&count, -1) == 0 {
				promise.Reject(errors.New("any(): all promises failed"))
			}
		})
	}
	return promise
}

// Each function executes a provided function once per element of iterable.
//
// The callback parameter is a function to execute for each element:
//
//		func(index int, value interface{})
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Each(callback func(int, interface{}), iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) {
		if a == nil {
			return
		}
		iterable := a.([]interface{})
		for index, value := range iterable {
			callback(index, value)
		}
	})
}

// Every function tests whether all elements in the iterable pass the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with false if the callback function returns
// false for any iterable element immediately. Otherwise, if callback returned
// a true value for all elements, Every will return promise fulfill with true.
//
// If iterable is empty, The returned promise will fulfill with true.
func Every(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return true, nil
		}
		iterable := a.([]interface{})
		for index, value := range iterable {
			if !callback(index, value) {
				return false, nil
			}
		}
		return true, nil
	})
}

// Some function tests whether some element in the iterable passes the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with true if the callback function returns
// true for any iterable element immediately. Otherwise, if callback returned a
// false value for all elements, Some will return promise fulfill with false.
//
// If iterable is empty, The returned promise will fulfill with false.
func Some(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return false, nil
		}
		iterable := a.([]interface{})
		for index, value := range iterable {
			if callback(index, value) {
				return true, nil
			}
		}
		return false, nil
	})
}

// Filter function returns a promise fulfill with a slice that has all elements
// pass the test implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Filter(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		iterable := a.([]interface{})
		result := make([]interface{}, 0, len(iterable))
		for index, value := range iterable {
			if callback(index, value) {
				result = append(result, value)
			}
		}
		return result, nil
	})
}
<commit_msg>Added Map function<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/functions.go                                   *
 *                                                        *
 * some functions of promise for Go.                      *
 *                                                        *
 * LastModified: Aug 14, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"errors"
	"sync/atomic"
	"time"
)

// Create creates a Promise object containing the result of asynchronously
// calling computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Create(computation func() (interface{}, error)) Promise {
	promise := New()
	go call(promise, computation)
	return promise
}

// Sync creates a Promise object containing the result of immediately calling
// computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Sync(computation func() (interface{}, error)) Promise {
	promise := New()
	call(promise, computation)
	return promise
}

// Delayed creates a Promise object with the given value after a delay.
//
// If the value is a Callable function, it will be executed after the given
// duration has passed, and the Promise object is completed with the result.
func Delayed(duration time.Duration, value interface{}) Promise {
	promise := New()
	go func() {
		time.Sleep(duration)
		switch computation := value.(type) {
		case func() (interface{}, error):
			call(promise, computation)
		case func():
			call1(promise, computation)
		default:
			promise.Resolve(value)
		}
	}()
	return promise
}

// All function returns a promise that resolves when all of the promises in the
// iterable argument have resolved, or rejects with the reason of the first
// passed promise that rejects.
func All(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Resolve(nil)
	}
	result := make([]interface{}, count)
	promise := New()
	for index, value := range iterable {
		ToPromise(value).Then(func(index int) func(value interface{}) {
			return func(value interface{}) {
				result[index] = value
				if atomic.AddInt64(&count, -1) == 0 {
					promise.Resolve(result)
				}
			}
		}(index), promise.Reject)
	}
	return promise
}

// Race function returns a promise that resolves or rejects as soon as one of
// the promises in the iterable resolves or rejects, with the value or reason
// from that promise.
func Race(iterable ...interface{}) Promise {
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Fill(promise)
	}
	return promise
}

// Any function is a competitive race that allows one winner.
//
// The returned promise will fulfill as soon as any one of the input promises
// fulfills, with the value of the fulfilled input promise.
//
// Or reject with a IllegalArgumentError if the input iterable is empty--i.e. it
// is impossible to have one winner.
//
// Or reject with an iterable of all the rejection reasons, if the input
// iterable is non-empty, and all input promises reject.
func Any(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Reject(IllegalArgumentError("any(): iterable must not be empty"))
	}
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Then(promise.Resolve, func() {
			if atomic.AddInt64(&count, -1) == 0 {
				promise.Reject(errors.New("any(): all promises failed"))
			}
		})
	}
	return promise
}

// Each function executes a provided function once per element of iterable.
//
// The callback parameter is a function to execute for each element:
//
//		func(index int, value interface{})
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Each(callback func(int, interface{}), iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) {
		if a == nil {
			return
		}
		iterable := a.([]interface{})
		for index, value := range iterable {
			callback(index, value)
		}
	})
}

// Every function tests whether all elements in the iterable pass the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with false if the callback function returns
// false for any iterable element immediately. Otherwise, if callback returned
// a true value for all elements, Every will return promise fulfill with true.
//
// If iterable is empty, The returned promise will fulfill with true.
func Every(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return true, nil
		}
		iterable := a.([]interface{})
		for index, value := range iterable {
			if !callback(index, value) {
				return false, nil
			}
		}
		return true, nil
	})
}

// Some function tests whether some element in the iterable passes the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with true if the callback function returns
// true for any iterable element immediately. Otherwise, if callback returned a
// false value for all elements, Some will return promise fulfill with false.
//
// If iterable is empty, The returned promise will fulfill with false.
func Some(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return false, nil
		}
		iterable := a.([]interface{})
		for index, value := range iterable {
			if callback(index, value) {
				return true, nil
			}
		}
		return false, nil
	})
}

// Filter function returns a promise fulfill with a slice that has all elements
// pass the test implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Filter(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		iterable := a.([]interface{})
		result := make([]interface{}, 0, len(iterable))
		for index, value := range iterable {
			if callback(index, value) {
				result = append(result, value)
			}
		}
		return result, nil
	})
}

// Map function returns a promise fulfill with a slice that has the results of
// calling a provided function on every element in iterable.
//
// The callback parameter produces an element of the new slice:
//
//		func(index int, value interface{}) interface{}
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Map(callback func(int, interface{}) interface{}, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		iterable := a.([]interface{})
		result := make([]interface{}, len(iterable))
		for index, value := range iterable {
			result[index] = callback(index, value)
		}
		return result, nil
	})
}
<|endoftext|>


<commit_before>// Copyright 2015 Unknwon
//
// 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 models

import (
	"os"

	"github.com/Unknwon/com"
	"github.com/Unknwon/log"

	"github.com/peachdocs/peach/modules/setting"
)

func initLangDocs(tocs map[string]*Toc, localRoot, lang string) {
	toc := tocs[lang]

	for _, dir := range toc.Nodes {
		if err := dir.ReloadContent(); err != nil {
			log.Error("Fail to load doc file: %v", err)
			continue
		}

		for _, file := range dir.Nodes {
			if com.IsFile(file.FileName) {
				if err := file.ReloadContent(); err != nil {
					log.Error("Fail to load doc file: %v", err)
					continue
				}
			}
		}
	}

	for _, page := range toc.Pages {
		if err := page.ReloadContent(); err != nil {
			log.Error("Fail to load doc file: %v", err)
			continue
		}
	}
}

func initDocs(tocs map[string]*Toc, localRoot string) {
	for _, lang := range setting.Docs.Langs {
		initLangDocs(tocs, localRoot, lang)
	}
}

func NewContext() {
	if com.IsExist(HTMLRoot) {
		if err := os.RemoveAll(HTMLRoot); err != nil {
			log.Fatal("Fail to clean up HTMLRoot: %v", err)
		}
	}

	if err := ReloadDocs(); err != nil {
		log.Fatal("Fail to init docs: %v", err)
	}
}
<commit_msg>minor fix<commit_after>// Copyright 2015 Unknwon
//
// 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 models

import (
	"os"

	"github.com/Unknwon/com"
	"github.com/Unknwon/log"

	"github.com/peachdocs/peach/modules/setting"
)

func initLangDocs(tocs map[string]*Toc, localRoot, lang string) {
	toc := tocs[lang]

	for _, dir := range toc.Nodes {
		if !com.IsFile(dir.FileName) {
			continue
		}

		if err := dir.ReloadContent(); err != nil {
			log.Error("Fail to load doc file: %v", err)
			continue
		}

		for _, file := range dir.Nodes {
			if !com.IsFile(file.FileName) {
				continue
			}

			if err := file.ReloadContent(); err != nil {
				log.Error("Fail to load doc file: %v", err)
				continue
			}
		}
	}

	for _, page := range toc.Pages {
		if !com.IsFile(page.FileName) {
			continue
		}

		if err := page.ReloadContent(); err != nil {
			log.Error("Fail to load doc file: %v", err)
			continue
		}
	}
}

func initDocs(tocs map[string]*Toc, localRoot string) {
	for _, lang := range setting.Docs.Langs {
		initLangDocs(tocs, localRoot, lang)
	}
}

func NewContext() {
	if com.IsExist(HTMLRoot) {
		if err := os.RemoveAll(HTMLRoot); err != nil {
			log.Fatal("Fail to clean up HTMLRoot: %v", err)
		}
	}

	if err := ReloadDocs(); err != nil {
		log.Fatal("Fail to init docs: %v", err)
	}
}
<|endoftext|>


<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 (
	"container/list"
	"fmt"
	"path"
	"strings"
	"io"
	"bufio"
	"os"
	"os/exec"

	"github.com/gogits/git"
)

// 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, reposName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	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.Name
	}
	return brs, nil
}

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

	commit, err := repo.GetCommit(branchName, 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 GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(branchName, 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
			}

			var cm = commit
			var i int
			for {
				i = i + 1
				//fmt.Println(".....", i, cm.Id(), cm.ParentCount())
				if cm.ParentCount() == 0 {
					break
				} else if cm.ParentCount() == 1 {
					pt, _ := repo.SubTree(cm.Parent(0).Tree, dirname)
					if pt == nil {
						break
					}
					pEntry := pt.EntryByName(entry.Name)
					if pEntry == nil || !pEntry.Id.Equal(entry.Id) {
						break
					} else {
						cm = cm.Parent(0)
					}
				} else {
					var emptyCnt = 0
					var sameIdcnt = 0
					var lastSameCm *git.Commit
					//fmt.Println(".....", cm.ParentCount())
					for i := 0; i < cm.ParentCount(); i++ {
						//fmt.Println("parent", i, cm.Parent(i).Id())
						p := cm.Parent(i)
						pt, _ := repo.SubTree(p.Tree, dirname)
						var pEntry *git.TreeEntry
						if pt != nil {
							pEntry = pt.EntryByName(entry.Name)
						}

						//fmt.Println("pEntry", pEntry)

						if pEntry == nil {
							emptyCnt = emptyCnt + 1
							if emptyCnt+sameIdcnt == cm.ParentCount() {
								if lastSameCm == nil {
									goto loop
								} else {
									cm = lastSameCm
									break
								}
							}
						} else {
							//fmt.Println(i, "pEntry", pEntry.Id, "entry", entry.Id)
							if !pEntry.Id.Equal(entry.Id) {
								goto loop
							} else {
								lastSameCm = cm.Parent(i)
								sameIdcnt = sameIdcnt + 1
								if emptyCnt+sameIdcnt == cm.ParentCount() {
									// TODO: now follow the first parent commit?
									cm = lastSameCm
									//fmt.Println("sameId...")
									break
								}
							}
						}
					}
				}
			}

		loop:

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

			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, branchname, commitid string) (*git.Commit, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	return repo.GetCommit(branchname, commitid)
}

// GetCommits returns all commits of given branch of repository.
func GetCommits(userName, reposName, branchname string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	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()
}

const (
	PlainLine = iota + 1
	AddLine
	DelLine
	SectionLine
)

const (
	AddFile = iota + 1
	ChangeFile
	DelFile
)

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

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 diffHead = "diff --git "

func ParsePatch(reader io.Reader) (*Diff, error) {
	scanner := bufio.NewScanner(reader)
	var totalAdd, totalDel int
	var curFile *DiffFile
	var curSection * DiffSection
	//var leftLine, rightLine int
	diff := &Diff{Files:make([]*DiffFile, 0)}
	var i int
	for scanner.Scan() {
		line := scanner.Text()
		fmt.Println(i, line)
		i = i + 1
		if line == "" {
			continue
		}
		if line[0] == ' ' {
			diffLine := &DiffLine{Type: PlainLine, Content:line}
			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: SectionLine, Content:"@@ "+ss[len(ss)-2]}
			curSection.Lines = append(curSection.Lines, diffLine)

			diffLine = &DiffLine{Type: PlainLine, Content:ss[len(ss)-1]}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '+' {
			diffLine := &DiffLine{Type: AddLine, Content:line}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '-' {
			diffLine := &DiffLine{Type: DelLine, Content:line}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		}

		if strings.HasPrefix(line, diffHead) {
			if curFile != nil {
				curFile.Addition, totalAdd = totalAdd, 0
				curFile.Deletion, totalDel = totalDel, 0
				curFile = nil
			}
			fs := strings.Split(line[len(diffHead):], " ")
			a := fs[0]

			curFile = &DiffFile{
				Name:a[strings.Index(a, "/")+1:],
				Type: ChangeFile,
				Sections:make([]*DiffSection, 0),
			}
			diff.Files = append(diff.Files, curFile)
			scanner.Scan()
			scanner.Scan()
			if scanner.Text() == "--- /dev/null" {
				curFile.Type = AddFile
			}
			scanner.Scan()
		}
	}

	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
	}

	if commit.ParentCount() == 0 {
		return nil, err
	}

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

	defer rd.Close()

	return ParsePatch(rd)
}

/*func GetDiff(repoPath, commitid string) (*Diff, error) {
	stdout, _, err := com.ExecCmdDir(repoPath, "git", "show", commitid)
	if err != nil {
		return nil, err
	}

	// Sperate parts by file.
	startIndex := strings.Index(stdout, "diff --git ") + 12

	// First part is commit information.
	// Check if it's a merge.
	mergeIndex := strings.Index(stdout[:startIndex], "merge")
	if mergeIndex > -1 {
		mergeCommit := strings.SplitN(strings.Split(stdout[:startIndex], "\n")[1], "", 3)[2]
		return GetDiff(repoPath, mergeCommit)
	}

	parts := strings.Split(stdout[startIndex:], "diff --git ")
	diff := &Diff{NumFiles: len(parts)}
	diff.Files = make([]*DiffFile, 0, diff.NumFiles)
	for _, part := range parts {
		infos := strings.SplitN(part, "\n", 6)
		maxIndex := len(infos) - 1
		infos[maxIndex] = strings.TrimSuffix(strings.TrimSuffix(infos[maxIndex], "\n"), "\n\\ No newline at end of file")

		file := &DiffFile{
			Name:    strings.TrimPrefix(strings.Split(infos[0], " ")[0], "a/"),
			Content: strings.Split(infos[maxIndex], "\n"),
		}
		diff.Files = append(diff.Files, file)
	}
	return diff, nil
}*/
<commit_msg>Make it compile<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"
	"container/list"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/gogits/git"
)

// 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, reposName string) ([]string, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	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.Name
	}
	return brs, nil
}

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

	commit, err := repo.GetCommit(branchName, 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 GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]*RepoFile, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	if err != nil {
		return nil, err
	}

	commit, err := repo.GetCommit(branchName, 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
			}

			var cm = commit
			var i int
			for {
				i = i + 1
				//fmt.Println(".....", i, cm.Id(), cm.ParentCount())
				if cm.ParentCount() == 0 {
					break
				} else if cm.ParentCount() == 1 {
					pt, _ := repo.SubTree(cm.Parent(0).Tree, dirname)
					if pt == nil {
						break
					}
					pEntry := pt.EntryByName(entry.Name)
					if pEntry == nil || !pEntry.Id.Equal(entry.Id) {
						break
					} else {
						cm = cm.Parent(0)
					}
				} else {
					var emptyCnt = 0
					var sameIdcnt = 0
					var lastSameCm *git.Commit
					//fmt.Println(".....", cm.ParentCount())
					for i := 0; i < cm.ParentCount(); i++ {
						//fmt.Println("parent", i, cm.Parent(i).Id())
						p := cm.Parent(i)
						pt, _ := repo.SubTree(p.Tree, dirname)
						var pEntry *git.TreeEntry
						if pt != nil {
							pEntry = pt.EntryByName(entry.Name)
						}

						//fmt.Println("pEntry", pEntry)

						if pEntry == nil {
							emptyCnt = emptyCnt + 1
							if emptyCnt+sameIdcnt == cm.ParentCount() {
								if lastSameCm == nil {
									goto loop
								} else {
									cm = lastSameCm
									break
								}
							}
						} else {
							//fmt.Println(i, "pEntry", pEntry.Id, "entry", entry.Id)
							if !pEntry.Id.Equal(entry.Id) {
								goto loop
							} else {
								lastSameCm = cm.Parent(i)
								sameIdcnt = sameIdcnt + 1
								if emptyCnt+sameIdcnt == cm.ParentCount() {
									// TODO: now follow the first parent commit?
									cm = lastSameCm
									//fmt.Println("sameId...")
									break
								}
							}
						}
					}
				}
			}

		loop:

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

			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, branchname, commitid string) (*git.Commit, error) {
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
	if err != nil {
		return nil, err
	}

	return repo.GetCommit(branchname, commitid)
}

// GetCommits returns all commits of given branch of repository.
func GetCommits(userName, reposName, branchname string) (*list.List, error) {
	repo, err := git.OpenRepository(RepoPath(userName, reposName))
	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()
}

// 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
}

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 totalAdd, totalDel int
	var curFile *DiffFile
	curSection := &DiffSection{
		Lines: make([]*DiffLine, 0, 10),
	}
	//var leftLine, rightLine int
	diff := &Diff{Files: make([]*DiffFile, 0)}
	var i int
	for scanner.Scan() {
		line := scanner.Text()
		fmt.Println(i, line)
		i = i + 1
		if line == "" {
			continue
		}
		if line[0] == ' ' {
			diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line}
			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: "@@" + ss[len(ss)-2] + "@@"}
			curSection.Lines = append(curSection.Lines, diffLine)

			diffLine = &DiffLine{Type: DIFF_LINE_PLAIN, Content: ss[len(ss)-1]}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '+' {
			diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		} else if line[0] == '-' {
			diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line}
			curSection.Lines = append(curSection.Lines, diffLine)
			continue
		}

		if strings.HasPrefix(line, DIFF_HEAD) {
			if curFile != nil {
				curFile.Addition, totalAdd = totalAdd, 0
				curFile.Deletion, totalDel = totalDel, 0
				curFile = nil
			}
			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),
			}
			diff.Files = append(diff.Files, curFile)
			scanner.Scan()
			scanner.Scan()
			if scanner.Text() == "--- /dev/null" {
				curFile.Type = DIFF_FILE_ADD
			}
			scanner.Scan()
		}
	}

	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
	}

	if commit.ParentCount() == 0 {
		return nil, err
	}

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

	defer rd.Close()

	return ParsePatch(rd)
}

/*func GetDiff(repoPath, commitid string) (*Diff, error) {
	stdout, _, err := com.ExecCmdDir(repoPath, "git", "show", commitid)
	if err != nil {
		return nil, err
	}

	// Sperate parts by file.
	startIndex := strings.Index(stdout, "diff --git ") + 12

	// First part is commit information.
	// Check if it's a merge.
	mergeIndex := strings.Index(stdout[:startIndex], "merge")
	if mergeIndex > -1 {
		mergeCommit := strings.SplitN(strings.Split(stdout[:startIndex], "\n")[1], "", 3)[2]
		return GetDiff(repoPath, mergeCommit)
	}

	parts := strings.Split(stdout[startIndex:], "diff --git ")
	diff := &Diff{NumFiles: len(parts)}
	diff.Files = make([]*DiffFile, 0, diff.NumFiles)
	for _, part := range parts {
		infos := strings.SplitN(part, "\n", 6)
		maxIndex := len(infos) - 1
		infos[maxIndex] = strings.TrimSuffix(strings.TrimSuffix(infos[maxIndex], "\n"), "\n\\ No newline at end of file")

		file := &DiffFile{
			Name:    strings.TrimPrefix(strings.Split(infos[0], " ")[0], "a/"),
			Content: strings.Split(infos[maxIndex], "\n"),
		}
		diff.Files = append(diff.Files, file)
	}
	return diff, nil
}*/
<|endoftext|>


<commit_before>// Copyright 2012-2013 Andreas Louca <andreas@louca.org>. All rights reserved.
// Use of this source code is governed by the 2-clause BSD license
// license that can be found in the LICENSE file.

/*
Package mongoqueue provides a job queue, which uses Mongo as a backend storage engine.
It supports a sophisticated feature set,  facilitating fine-grained job queueing.

See: https://github.com/alouca/MongoQueue
*/
package mongoqueue

import (
	"code.google.com/p/go-uuid/uuid"
	"github.com/alouca/goconfig"
	"github.com/alouca/gologger"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"math/rand"
	"time"
)

var (
	l *logger.Logger
	c *config.Config
)

type MongoQueue struct {
	C            *mgo.Collection
	Settings     *MongoQueueSettings
	MongoSession *mgo.Session
}

type MongoQueueSettings struct {
	Cleanup   int // The interval for the cleanup process
	LockLimit int // The maximum number of seconds a job can remain locked to a pid
	// Retry parameters
	RetryLimit   int // The maximum number of retry attempts for a failed task
	MinBackoff   int // The minimum number of seconds to wait before retrying a task after it fails.
	MaxBackoff   int // The maximum number of seconds to wait before retrying a task after it fails.
	MaxDoublings int // The maximum number of times that the interval between failed task retries will be doubled before the increase becomes constant. The constant is: 2**(max_doublings - 1) * min_backoff_seconds.
	AgeLimit     int // The time limit for retrying a failed task, in seconds, measured from the time the task was created.
}

type MongoQueueStats struct {
	Total      int
	InProgress int
	Failed     int
}

func init() {
	l = logger.GetDefaultLogger()

	if l == nil {
		l = logger.CreateLogger(false, false)
	}
}

func NewMongoQueue(database, queue, server string, settings *MongoQueueSettings) *MongoQueue {
	mq := new(MongoQueue)

	var err error

	mq.MongoSession, err = mgo.Dial(server)

	if err != nil {
		l.Fatal("Error establishing connection to mongo server\n")
		return nil
	}

	mq.C = mq.MongoSession.DB(database).C(queue)

	mq.Settings = settings

	go func() {
		ticker := time.NewTicker(time.Duration(settings.Cleanup) * time.Second)

		for {
			select {
			case <-ticker.C:
				mq.Cleanup()
			}
		}
	}()

	return mq
}

// Returns the total number of tasks in the queue
func (q *MongoQueue) Count() (c int, err error) {
	c, err = q.C.Count()

	return
}

// Returns the total number of free jobs in the queue
func (q *MongoQueue) CountFree() (c int, err error) {
	now := time.Now().Unix()
	c, err = q.C.Find(bson.M{
		"inprogress": false,
		"failed":     false,
		"runat":      bson.M{"$lte": now},
		"retries":    bson.M{"$lte": q.Settings.RetryLimit}}).Count()

	return
}

// Drops all outstanding tasks in the queue
func (q *MongoQueue) Truncate() error {
	err := q.C.DropCollection()

	if err != nil {
		l.Fatal("Error dropping collection: %s\n", err.Error())
	}
	return err
}

// Adds a new job in the queue. Higher priority number means higher priority
// In order to make the queue to act as FIFO instead of a priority queue, specify for all jobs priority 0
func (q *MongoQueue) Add(x interface{}, id string, p int) (string, error) {
	if id == "" {
		id = uuid.NewRandom().String()
	}
	now := time.Now().Unix()
	err := q.C.Insert(bson.M{
		"id":         id,
		"inprogress": false,
		"failed":     false,
		"priority":   p,
		"retries":    0,
		"added":      now,
		"runat":      now,
		"data":       x})

	if err != nil {
		l.Fatal("Error inserting new task: %s\n", err.Error())
	}

	return id, err
}

// Pop removes the top-most job from the Priority queue, and returns it back.
func (q *MongoQueue) Pop() (string, interface{}, error) {
	now := time.Now().Unix()

	change := mgo.Change{
		Update:    bson.M{"$set": bson.M{"inprogress": true, "started": time.Now().Unix()}},
		ReturnNew: true,
	}

	var res bson.M
	_, err := q.C.Find(bson.M{"inprogress": false, "runat": bson.M{"$lte": now}}).Sort("-priority").Limit(1).Apply(change, &res)

	l.Debug("Debug: %v\n", res)

	if err != nil {
		l.Error("Error retrieving data for Pop(): %s\n", err)
		return "", nil, err
	}
	if res != nil {
		id := res["id"].(string)

		q.C.Remove(res)
		return id, res["data"], nil
	}

	return "", nil, nil
}

// Lock gets the top-most job from the Priority Queue, and locks it to a worker. The job is not deleted from the
// queue unless it is marked as completed.
func (q *MongoQueue) Lock(pid string) (string, interface{}, error) {
	now := time.Now().Unix()

	change := mgo.Change{
		Update:    bson.M{"$set": bson.M{"inprogress": true, "started": time.Now().Unix(), "process-id": pid}},
		ReturnNew: true,
	}
	/*
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"retries":1})
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"runat": 1, "inprogress": 1, "failed": 1, "retries": 1})

	*/
	var res bson.M
	info, err := q.C.Find(bson.M{
		"inprogress": false,
		"failed":     false,
		"runat":      bson.M{"$lte": now},
		"retries":    bson.M{"$lte": q.Settings.RetryLimit},
	}).Sort("-priority").Limit(1).Apply(change, &res)

	l.Printf("Debug: %v\n", res)

	if info != nil {
		if info.Updated == 0 {
			return "", nil, nil
		}
	} else if err != nil {
		l.Error("Error retrieving data for Lock(): %s\n", err)
		return "", nil, err
	}
	id := res["id"].(string)
	return id, res["data"], nil
}

// MassLock gets the top-most job from the Priority Queue, and locks it to a worker. The job is not deleted from the
// queue unless it is marked as completed. It locks and returns N results
func (q *MongoQueue) MassLock(pid string, n int) ([]string, []interface{}, error) {
	now := time.Now().Unix()

	change := mgo.Change{
		Update:    bson.M{"$set": bson.M{"inprogress": true, "started": time.Now().Unix(), "process-id": pid}},
		ReturnNew: true,
	}
	/*
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"retries":1})
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"runat": 1, "inprogress": 1, "failed": 1, "retries": 1})

	*/
	res := make([]bson.M, n)
	info, err := q.C.Find(bson.M{
		"inprogress": false,
		"failed":     false,
		"runat":      bson.M{"$lte": now},
		"retries":    bson.M{"$lte": q.Settings.RetryLimit},
	}).Sort("-priority").Limit(n).Apply(change, &res)

	l.Printf("Debug: %v\n", res)

	if info != nil {
		if info.Updated == 0 {
			return nil, nil, nil
		}
	} else if err != nil {
		l.Error("Error retrieving data for Lock(): %s\n", err)
		return nil, nil, err
	}

	ids := make([]string, n)
	data := make([]interface{}, n)
	for i, r := range res {
		if r != nil {
			ids[i] = r["id"].(string)
			data[i] = r["data"]
		}
	}

	return ids, data, nil
}

// Complete call removes the job from the priority queue
func (q *MongoQueue) Complete(id string) error {
	err := q.C.Remove(bson.M{"inprogress": true, "id": id})

	if err != nil {
		l.Error("Unable to find job to mark as complete for Job ID %s\n", id)
		return err
	}

	l.Debug("Removed job as completed from id %s\n", id)
	return nil
}

// Marks a job as failed, and keeps in the queue for re-execution at a later stage
func (q *MongoQueue) Fail(id string) error {
	now := time.Now().Unix()

	// Calculate next retry time
	backoff := rand.Int63n(int64(q.Settings.MaxBackoff - q.Settings.MinBackoff))
	runat := now + backoff
	change := mgo.Change{
		Update: bson.M{
			"$inc": bson.M{"retries": 1},
			"$set": bson.M{
				"started":    time.Now().Unix(),
				"inprogress": false,
				"runat":      runat,
			},
		},
		ReturnNew: true,
	}
	var res bson.M

	info, err := q.C.Find(bson.M{"inprogress": true, "id": id}).Limit(1).Apply(change, &res)

	if info != nil && info.Updated == 1 {
		l.Printf("Marked job as failed for ID %s\n", id)
	}
	return err
}

// Cleanup seeks for jobs where the lock has expired, and releases it
func (q *MongoQueue) Cleanup() error {
	now := time.Now().Unix()
	// Set the deadline in relevant time. All tasks before the deadline will be unlocked, and re-scheduled for execution
	deadline := now - int64(q.Settings.LockLimit)

	// Release locks
	info, err := q.C.UpdateAll(bson.M{"inprogress": true, "started": bson.M{"$lte": deadline}}, bson.M{"$set": bson.M{"inprogress": false, "process-id": nil, "started": nil}})

	if err != nil {
		l.Error("Error executing expire locks query: %s\n", err.Error())
	} else {
		l.Debug("Removed total %d lock(s)\n", info.Updated)
	}

	deadline = now - int64(q.Settings.AgeLimit)

	// Failed jobs
	info, err = q.C.UpdateAll(
		bson.M{
			"inprogress": false,
			"failed":     false,
			"added":      bson.M{"$lte": deadline}},
		bson.M{
			"$set": bson.M{"failed": true}},
	)
	if err != nil {
		l.Error("Error executing expire jobs query: %s\n", err.Error())
	} else {
		l.Debug("Failed total %d jobs(s)\n", info.Updated)
	}
	return err
}

// Stats
func (q *MongoQueue) Stats() (*MongoQueueStats, error) {
	mqs := new(MongoQueueStats)
	var err error

	mqs.Total, err = q.C.Find(bson.M{}).Count()
	if err != nil {
		l.Error("Error counting records: %s\n", err.Error())
		return nil, err
	}

	mqs.InProgress, err = q.C.Find(bson.M{"inprogress": true}).Count()
	if err != nil {
		l.Error("Error counting records: %s\n", err.Error())
		return nil, err
	}

	return mqs, nil
}
<commit_msg>Added MassLock()<commit_after>// Copyright 2012-2013 Andreas Louca <andreas@louca.org>. All rights reserved.
// Use of this source code is governed by the 2-clause BSD license
// license that can be found in the LICENSE file.

/*
Package mongoqueue provides a job queue, which uses Mongo as a backend storage engine.
It supports a sophisticated feature set,  facilitating fine-grained job queueing.

See: https://github.com/alouca/MongoQueue
*/
package mongoqueue

import (
	"code.google.com/p/go-uuid/uuid"
	"github.com/alouca/goconfig"
	"github.com/alouca/gologger"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"math/rand"
	"time"
)

var (
	l *logger.Logger
	c *config.Config
)

type MongoQueue struct {
	C            *mgo.Collection
	Settings     *MongoQueueSettings
	MongoSession *mgo.Session
}

type MongoQueueSettings struct {
	Cleanup   int // The interval for the cleanup process
	LockLimit int // The maximum number of seconds a job can remain locked to a pid
	// Retry parameters
	RetryLimit   int // The maximum number of retry attempts for a failed task
	MinBackoff   int // The minimum number of seconds to wait before retrying a task after it fails.
	MaxBackoff   int // The maximum number of seconds to wait before retrying a task after it fails.
	MaxDoublings int // The maximum number of times that the interval between failed task retries will be doubled before the increase becomes constant. The constant is: 2**(max_doublings - 1) * min_backoff_seconds.
	AgeLimit     int // The time limit for retrying a failed task, in seconds, measured from the time the task was created.
}

type MongoQueueStats struct {
	Total      int
	InProgress int
	Failed     int
}

func init() {
	l = logger.GetDefaultLogger()

	if l == nil {
		l = logger.CreateLogger(false, false)
	}
}

func NewMongoQueue(database, queue, server string, settings *MongoQueueSettings) *MongoQueue {
	mq := new(MongoQueue)

	var err error

	mq.MongoSession, err = mgo.Dial(server)

	if err != nil {
		l.Fatal("Error establishing connection to mongo server\n")
		return nil
	}

	mq.C = mq.MongoSession.DB(database).C(queue)

	mq.Settings = settings

	go func() {
		ticker := time.NewTicker(time.Duration(settings.Cleanup) * time.Second)

		for {
			select {
			case <-ticker.C:
				mq.Cleanup()
			}
		}
	}()

	return mq
}

// Returns the total number of tasks in the queue
func (q *MongoQueue) Count() (c int, err error) {
	c, err = q.C.Count()

	return
}

// Returns the total number of free jobs in the queue
func (q *MongoQueue) CountFree() (c int, err error) {
	now := time.Now().Unix()
	c, err = q.C.Find(bson.M{
		"inprogress": false,
		"failed":     false,
		"runat":      bson.M{"$lte": now},
		"retries":    bson.M{"$lte": q.Settings.RetryLimit}}).Count()

	return
}

// Drops all outstanding tasks in the queue
func (q *MongoQueue) Truncate() error {
	err := q.C.DropCollection()

	if err != nil {
		l.Fatal("Error dropping collection: %s\n", err.Error())
	}
	return err
}

// Adds a new job in the queue. Higher priority number means higher priority
// In order to make the queue to act as FIFO instead of a priority queue, specify for all jobs priority 0
func (q *MongoQueue) Add(x interface{}, id string, p int) (string, error) {
	if id == "" {
		id = uuid.NewRandom().String()
	}
	now := time.Now().Unix()
	err := q.C.Insert(bson.M{
		"id":         id,
		"inprogress": false,
		"failed":     false,
		"priority":   p,
		"retries":    0,
		"added":      now,
		"runat":      now,
		"data":       x})

	if err != nil {
		l.Fatal("Error inserting new task: %s\n", err.Error())
	}

	return id, err
}

// Pop removes the top-most job from the Priority queue, and returns it back.
func (q *MongoQueue) Pop() (string, interface{}, error) {
	now := time.Now().Unix()

	change := mgo.Change{
		Update:    bson.M{"$set": bson.M{"inprogress": true, "started": time.Now().Unix()}},
		ReturnNew: true,
	}

	var res bson.M
	_, err := q.C.Find(bson.M{"inprogress": false, "runat": bson.M{"$lte": now}}).Sort("-priority").Limit(1).Apply(change, &res)

	l.Debug("Debug: %v\n", res)

	if err != nil {
		l.Error("Error retrieving data for Pop(): %s\n", err)
		return "", nil, err
	}
	if res != nil {
		id := res["id"].(string)

		q.C.Remove(res)
		return id, res["data"], nil
	}

	return "", nil, nil
}

// Lock gets the top-most job from the Priority Queue, and locks it to a worker. The job is not deleted from the
// queue unless it is marked as completed.
func (q *MongoQueue) Lock(pid string) (string, interface{}, error) {
	now := time.Now().Unix()

	change := mgo.Change{
		Update:    bson.M{"$set": bson.M{"inprogress": true, "started": time.Now().Unix(), "process-id": pid}},
		ReturnNew: true,
	}
	/*
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"retries":1})
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"runat": 1, "inprogress": 1, "failed": 1, "retries": 1})

	*/
	var res bson.M
	info, err := q.C.Find(bson.M{
		"inprogress": false,
		"failed":     false,
		"runat":      bson.M{"$lte": now},
		"retries":    bson.M{"$lte": q.Settings.RetryLimit},
	}).Sort("-priority").Limit(1).Apply(change, &res)

	l.Printf("Debug: %v\n", res)

	if info != nil {
		if info.Updated == 0 {
			return "", nil, nil
		}
	} else if err != nil {
		l.Error("Error retrieving data for Lock(): %s\n", err)
		return "", nil, err
	}
	id := res["id"].(string)
	return id, res["data"], nil
}

// MassLock gets the top-most job from the Priority Queue, and locks it to a worker. The job is not deleted from the
// queue unless it is marked as completed. It locks and returns N results
func (q *MongoQueue) MassLock(pid string, n int) ([]string, []interface{}, error) {
	now := time.Now().Unix()

	change := bson.M{"$set": bson.M{"inprogress": true, "started": time.Now().Unix(), "process-id": pid}}
	/*
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"retries":1})
		> db["/f2e61aad-0f28-43a2-baa3-ed7a80b66c9c/snmppoller/requests"].ensureIndex({"runat": 1, "inprogress": 1, "failed": 1, "retries": 1})

	*/
	res := make([]bson.M, n)
	err := q.C.Find(bson.M{
		"inprogress": false,
		"failed":     false,
		"runat":      bson.M{"$lte": now},
		"retries":    bson.M{"$lte": q.Settings.RetryLimit},
	}).Sort("-priority").Limit(n).All(&res)

	ids := make([]string, n)
	data := make([]interface{}, n)
	for i, r := range res {
		if r != nil {
			ids[i] = r["id"].(string)
			data[i] = r["data"]
			q.C.Update(bson.M{"_id": r["id"]}, change)
		}
	}

	return ids, data, nil
}

// Complete call removes the job from the priority queue
func (q *MongoQueue) Complete(id string) error {
	err := q.C.Remove(bson.M{"inprogress": true, "id": id})

	if err != nil {
		l.Error("Unable to find job to mark as complete for Job ID %s\n", id)
		return err
	}

	l.Debug("Removed job as completed from id %s\n", id)
	return nil
}

// Marks a job as failed, and keeps in the queue for re-execution at a later stage
func (q *MongoQueue) Fail(id string) error {
	now := time.Now().Unix()

	// Calculate next retry time
	backoff := rand.Int63n(int64(q.Settings.MaxBackoff - q.Settings.MinBackoff))
	runat := now + backoff
	change := mgo.Change{
		Update: bson.M{
			"$inc": bson.M{"retries": 1},
			"$set": bson.M{
				"started":    time.Now().Unix(),
				"inprogress": false,
				"runat":      runat,
			},
		},
		ReturnNew: true,
	}
	var res bson.M

	info, err := q.C.Find(bson.M{"inprogress": true, "id": id}).Limit(1).Apply(change, &res)

	if info != nil && info.Updated == 1 {
		l.Printf("Marked job as failed for ID %s\n", id)
	}
	return err
}

// Cleanup seeks for jobs where the lock has expired, and releases it
func (q *MongoQueue) Cleanup() error {
	now := time.Now().Unix()
	// Set the deadline in relevant time. All tasks before the deadline will be unlocked, and re-scheduled for execution
	deadline := now - int64(q.Settings.LockLimit)

	// Release locks
	info, err := q.C.UpdateAll(bson.M{"inprogress": true, "started": bson.M{"$lte": deadline}}, bson.M{"$set": bson.M{"inprogress": false, "process-id": nil, "started": nil}})

	if err != nil {
		l.Error("Error executing expire locks query: %s\n", err.Error())
	} else {
		l.Debug("Removed total %d lock(s)\n", info.Updated)
	}

	deadline = now - int64(q.Settings.AgeLimit)

	// Failed jobs
	info, err = q.C.UpdateAll(
		bson.M{
			"inprogress": false,
			"failed":     false,
			"added":      bson.M{"$lte": deadline}},
		bson.M{
			"$set": bson.M{"failed": true}},
	)
	if err != nil {
		l.Error("Error executing expire jobs query: %s\n", err.Error())
	} else {
		l.Debug("Failed total %d jobs(s)\n", info.Updated)
	}
	return err
}

// Stats
func (q *MongoQueue) Stats() (*MongoQueueStats, error) {
	mqs := new(MongoQueueStats)
	var err error

	mqs.Total, err = q.C.Find(bson.M{}).Count()
	if err != nil {
		l.Error("Error counting records: %s\n", err.Error())
		return nil, err
	}

	mqs.InProgress, err = q.C.Find(bson.M{"inprogress": true}).Count()
	if err != nil {
		l.Error("Error counting records: %s\n", err.Error())
		return nil, err
	}

	return mqs, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func main() {
	if err := mongostats(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func mongostats() error {
	url := os.Getenv("MONGO_URL")
	session, err := mgo.Dial(url)
	if err != nil {
		return err
	}
	log.Println(session)
	var serverStatus = &bson.M{}
	if err := session.Run("serverStatus", serverStatus); err != nil {
		return err
	}
	out, err := json.MarshalIndent(serverStatus, "", "  ")
	if err != nil {
		return err
	}
	var ss ServerStatus

	if err := json.Unmarshal(out, &ss); err != nil {
		return err
	}
	fmt.Println(string(out))
	return nil
}
<commit_msg>Remove log line<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func main() {
	if err := mongostats(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func mongostats() error {
	url := os.Getenv("MONGO_URL")
	session, err := mgo.Dial(url)
	if err != nil {
		return err
	}
	var serverStatus = &bson.M{}
	if err := session.Run("serverStatus", serverStatus); err != nil {
		return err
	}
	out, err := json.MarshalIndent(serverStatus, "", "  ")
	if err != nil {
		return err
	}
	var ss ServerStatus

	if err := json.Unmarshal(out, &ss); err != nil {
		return err
	}
	fmt.Println(string(out))
	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/nsf/termbox-go"
    "encoding/json"
    "net/http"
    "io/ioutil"
    "strconv"
    "strings"
    "log"
    "sort"
)

type Entries struct {
    Title string
    Year string
    ImdbID string
}

type Data struct {
    Search []Entries
}

type MoviesTab struct {
    a *Apollo
    name string
    status string

    movies []Movie
    view string
    sorter string
    offset int
    cursor int
    omdb Data
    ratings bool
}

func CreateMoviesTab(a *Apollo) *MoviesTab {
    t := &MoviesTab{
        a: a,
        name: "movies",
        status: "movies",
        view: "watched",
        sorter: "title",
    }

    t.refreshSlice()

    return t
}

func (t *MoviesTab) Name() string {
    return t.name
}

func (t *MoviesTab) Status() string {
    return t.status
}

func (t *MoviesTab) HandleKeyEvent(ev *termbox.Event) bool {
    if len(t.omdb.Search) > 0 {
        indexes := map[rune]int{'0': 0, '1': 1, '2': 2, '3': 3,
                                '4': 4, '5': 5, '6': 6, '7': 7,
                                '8': 8, '9': 9,}
        if index, exist := indexes[ev.Ch]; exist {
            if index < len(t.omdb.Search) {
                log.Print(t.omdb.Search[index])
                dbIndex := t.index()
                t.a.d.Movies[dbIndex].Year = t.omdb.Search[index].Year
                t.a.d.Movies[dbIndex].Title = t.omdb.Search[index].Title
                t.a.d.Movies[dbIndex].ImdbID = t.omdb.Search[index].ImdbID
            }
        }

        t.omdb.Search = t.omdb.Search[:0]
        t.a.d.save()
        t.refreshSlice()

        return true
    }

    switch ev.Ch {
    case '1':
        t.view = "watched"
        t.cursor = 0
        t.offset = 0
        t.refreshSlice()
    case '2':
        t.view = "unwatched"
        t.cursor = 0
        t.offset = 0
        t.refreshSlice()
    case '3':
        t.view = "all"
        t.cursor = 0
        t.offset = 0
        t.refreshSlice()
    case 's':
        t.cursor = 0
        t.offset = 0
        t.sort()
    case 'D':
        if len(t.movies) > 0 {
            t.a.d.Movies = append(t.a.d.Movies[:t.index()], t.a.d.Movies[t.index()+1:]...)
            t.a.d.save()
            t.refreshSlice()
        }
    case 't':
        t.autoTag()
    case 'r':
        if t.ratings {
            t.ratings = false
        } else {
            t.ratings = true
        }
    case 'a':
        if t.a.d.Movies[t.index()].State == "Watched" {
            t.a.d.Movies[t.index()].State = "Unwatched"
        } else {
            t.a.d.Movies[t.index()].State = "Watched"
        }
        t.a.d.Movies[t.index()].Rating = 0
        t.a.d.save()
        t.refreshSlice()
    case 'q':
        if len(t.movies) > 0 {
            if t.a.d.Movies[t.index()].Rating > 0 {
                t.a.d.Movies[t.index()].Rating--
                t.a.d.save()
                t.refreshSlice()
            }
        }
    case 'e':
        if len(t.movies) > 0 {
            if t.a.d.Movies[t.index()].Rating < 6 {
                t.a.d.Movies[t.index()].Rating++
                t.a.d.save()
                t.refreshSlice()
            }
        }
    }

    switch ev.Key {
    case termbox.KeyArrowUp:
        t.cursor--
        if t.cursor < 0 {
            t.cursor = 0
        } else if t.cursor - t.offset < 0 {
            t.offset--
        }
    case termbox.KeyPgup:
        t.cursor -= 5
        if t.cursor < 0 {
            t.cursor = 0
            t.offset = 0
        } else if t.cursor - t.offset < 0 {
            t.offset -= 5
            if t.offset < 0 {
                t.offset = 0
            }
        }
    case termbox.KeyArrowDown:
        t.cursor++
        if t.cursor > len(t.movies) - 1 {
            t.cursor--
        } else if t.cursor - t.offset > t.a.height - 4 {
            t.offset++
        }
    case termbox.KeyPgdn:
        t.cursor += 5
        if t.cursor > len(t.movies) - 1 {
            t.cursor = len(t.movies) - 1
            if len(t.movies) > t.a.height - 3 {
                t.offset = len(t.movies) - (t.a.height - 3)
            }
        } else if t.cursor - t.offset > t.a.height - 4 {
            t.offset += 5
            if t.cursor - t.offset < t.a.height - 3 {
                t.offset = t.cursor - (t.a.height - 4)
            }
        }
    default:
        return false
    }

    log.Print("cursor: " + strconv.Itoa(t.cursor) + " offset: " + strconv.Itoa(t.offset) +
    " len:" + strconv.Itoa(len(t.movies)) + " height:" + strconv.Itoa(t.a.height))

    return true
}

func (t *MoviesTab) Draw() {
    if len(t.omdb.Search) == 0 {
        for j := 0; j < t.a.height - 3; j++ {
            if j < len(t.movies) {
                if t.ratings {
                    for i := 0; i < t.movies[j + t.offset].Rating; i++ {
                        if t.movies[j + t.offset].State == "Watched" {
                            termbox.SetCell(i + 3, j + 1, '*', color['y'], color['d'])
                        } else {
                            termbox.SetCell(i + 3, j + 1, '*', color['B'], color['d'])
                        }
                    }
                }

                runes := []rune(t.movies[j + t.offset].Year + " " + t.movies[j + t.offset].Title)
                for i := 0; i < len(runes); i++ {
                    fg := color['d']
                    if i < 4 {
                        if t.movies[j + t.offset].State == "Watched" {
                            fg = color['g']
                        } else {
                            fg = color['b']
                        }
                    }

                    if t.ratings {
                        termbox.SetCell(i + 10, j + 1, runes[i], fg, color['d'])
                    } else {
                        termbox.SetCell(i + 3, j + 1, runes[i], fg, color['d'])
                    }
                }
            }
        }

        termbox.SetCell(1, t.cursor - t.offset + 1, '*', color['d'], color['d'])
    } else {
        for j := 0; j < len(t.omdb.Search); j++ {
            runes := []rune(strconv.Itoa(j) + ". [" + t.omdb.Search[j].Year + "] " + t.omdb.Search[j].Title)
            for i := 0; i < len(runes); i++ {
                termbox.SetCell(i, j + 1, runes[i], color['d'], color['d'])
            }
        }
    }
}

func (t *MoviesTab) Query(query string) {
    t.a.d.Movies = append(t.a.d.Movies, Movie{Title: query, State: "Watched"})
    t.a.d.save()
    t.refreshSlice()

    for i := 0; i < len(t.movies); i++ {
        if t.movies[i].Title == query {
            t.cursor = i
            if t.cursor > t.a.height - 4 {
                t.offset = t.cursor - (t.a.height - 4)
            }
            t.a.inputActive = false
            t.autoTag()
        }
    }
}

func (t *MoviesTab) index() int {
    for i := 0; i < len(t.a.d.Movies); i++ {
        if t.a.d.Movies[i].Title == t.movies[t.cursor].Title {
            return i
        }
    }

    return -1
}

func (t *MoviesTab) refreshSlice() {
    t.movies = t.movies[:0]
    for i := 0; i < len(t.a.d.Movies); i++ {
        if t.a.d.Movies[i].State == "Watched" {
            if t.view == "watched" || t.view == "all" {
                t.movies = append(t.movies, t.a.d.Movies[i])
            }
        } else if t.a.d.Movies[i].State == "Unwatched" {
            if t.view == "unwatched" || t.view == "all" {
                t.movies = append(t.movies, t.a.d.Movies[i])
            }
        }
    }
    t.sort()

    if t.cursor > len(t.movies) - 1 {
        t.cursor--
    }

    if t.offset > 0 {
        if len(t.movies) - t.offset < t.a.height - 3 {
            t.offset--
        }
    }

    t.status = "movies - " + t.view + " (" + strconv.Itoa(len(t.movies)) + " entries)"
}

func (t *MoviesTab) sort() {
    var titles []string
    for i := 0; i < len(t.movies); i++ {
        titles = append(titles, t.movies[i].Title)
    }
    sort.Strings(titles)

    var movies []Movie
    for j := 0; j < len(titles); j++ {
        for i := 0; i < len(t.movies); i++ {
            if titles[j] == t.movies[i].Title {
                movies = append(movies, t.movies[i])
            }
        }
    }
    t.movies = movies
}

func (t *MoviesTab) autoTag() {
    title := strings.Replace(t.movies[t.cursor].Title, " ", "+", -1)
    url := "http://www.omdbapi.com/?s=" + title + "&type=movie&y=&plot=full&r=json"
    log.Print(url)

    res, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }

    err = json.Unmarshal(body, &t.omdb)
    if err != nil {
        log.Fatal(err)
    } else {
        for i := 0; i < len(t.omdb.Search); i++ {
            log.Print(t.omdb.Search[i].Title + " - " + t.omdb.Search[i].Year)
        }
        log.Print(t.omdb)
    }
}
<commit_msg>Added sorting by rating for movies<commit_after>package main

import (
    "github.com/nsf/termbox-go"
    "encoding/json"
    "net/http"
    "io/ioutil"
    "strconv"
    "strings"
    "log"
    "sort"
)

type Entries struct {
    Title string
    Year string
    ImdbID string
}

type Data struct {
    Search []Entries
}

type MoviesTab struct {
    a *Apollo
    name string
    status string

    movies []Movie
    view string
    sorter string
    offset int
    cursor int
    omdb Data
    ratings bool
}

func CreateMoviesTab(a *Apollo) *MoviesTab {
    t := &MoviesTab{
        a: a,
        name: "movies",
        status: "movies",
        view: "watched",
        sorter: "title",
    }

    t.refreshSlice()

    return t
}

func (t *MoviesTab) Name() string {
    return t.name
}

func (t *MoviesTab) Status() string {
    return t.status
}

func (t *MoviesTab) HandleKeyEvent(ev *termbox.Event) bool {
    if len(t.omdb.Search) > 0 {
        indexes := map[rune]int{'0': 0, '1': 1, '2': 2, '3': 3,
                                '4': 4, '5': 5, '6': 6, '7': 7,
                                '8': 8, '9': 9,}
        if index, exist := indexes[ev.Ch]; exist {
            if index < len(t.omdb.Search) {
                log.Print(t.omdb.Search[index])
                dbIndex := t.index()
                t.a.d.Movies[dbIndex].Year = t.omdb.Search[index].Year
                t.a.d.Movies[dbIndex].Title = t.omdb.Search[index].Title
                t.a.d.Movies[dbIndex].ImdbID = t.omdb.Search[index].ImdbID
            }
        }

        t.omdb.Search = t.omdb.Search[:0]
        t.a.d.save()
        t.refreshSlice()

        return true
    }

    switch ev.Ch {
    case '1':
        t.view = "watched"
        t.cursor = 0
        t.offset = 0
        t.refreshSlice()
    case '2':
        t.view = "unwatched"
        t.cursor = 0
        t.offset = 0
        t.refreshSlice()
    case '3':
        t.view = "all"
        t.cursor = 0
        t.offset = 0
        t.refreshSlice()
    case 's':
        if t.sorter == "title" {
            t.sorter = "year"
        } else if t.sorter == "year" {
            t.sorter = "rating"
        } else if t.sorter == "rating" {
            t.sorter = "title"
        }
        t.cursor = 0
        t.offset = 0
        t.sort()
    case 'D':
        if len(t.movies) > 0 {
            t.a.d.Movies = append(t.a.d.Movies[:t.index()], t.a.d.Movies[t.index()+1:]...)
            t.a.d.save()
            t.refreshSlice()
        }
    case 't':
        t.autoTag()
    case 'r':
        if t.ratings {
            t.ratings = false
        } else {
            t.ratings = true
        }
    case 'a':
        if t.a.d.Movies[t.index()].State == "Watched" {
            t.a.d.Movies[t.index()].State = "Unwatched"
        } else {
            t.a.d.Movies[t.index()].State = "Watched"
        }
        t.a.d.Movies[t.index()].Rating = 0
        t.a.d.save()
        t.refreshSlice()
    case 'q':
        if len(t.movies) > 0 {
            if t.a.d.Movies[t.index()].Rating > 0 {
                t.a.d.Movies[t.index()].Rating--
                t.a.d.save()
                t.refreshSlice()
            }
        }
    case 'e':
        if len(t.movies) > 0 {
            if t.a.d.Movies[t.index()].Rating < 6 {
                t.a.d.Movies[t.index()].Rating++
                t.a.d.save()
                t.refreshSlice()
            }
        }
    }

    switch ev.Key {
    case termbox.KeyArrowUp:
        t.cursor--
        if t.cursor < 0 {
            t.cursor = 0
        } else if t.cursor - t.offset < 0 {
            t.offset--
        }
    case termbox.KeyPgup:
        t.cursor -= 5
        if t.cursor < 0 {
            t.cursor = 0
            t.offset = 0
        } else if t.cursor - t.offset < 0 {
            t.offset -= 5
            if t.offset < 0 {
                t.offset = 0
            }
        }
    case termbox.KeyArrowDown:
        t.cursor++
        if t.cursor > len(t.movies) - 1 {
            t.cursor--
        } else if t.cursor - t.offset > t.a.height - 4 {
            t.offset++
        }
    case termbox.KeyPgdn:
        t.cursor += 5
        if t.cursor > len(t.movies) - 1 {
            t.cursor = len(t.movies) - 1
            if len(t.movies) > t.a.height - 3 {
                t.offset = len(t.movies) - (t.a.height - 3)
            }
        } else if t.cursor - t.offset > t.a.height - 4 {
            t.offset += 5
            if t.cursor - t.offset < t.a.height - 3 {
                t.offset = t.cursor - (t.a.height - 4)
            }
        }
    default:
        return false
    }

    log.Print("cursor: " + strconv.Itoa(t.cursor) + " offset: " + strconv.Itoa(t.offset) +
    " len:" + strconv.Itoa(len(t.movies)) + " height:" + strconv.Itoa(t.a.height))

    return true
}

func (t *MoviesTab) Draw() {
    if len(t.omdb.Search) == 0 {
        for j := 0; j < t.a.height - 3; j++ {
            if j < len(t.movies) {
                if t.ratings {
                    for i := 0; i < t.movies[j + t.offset].Rating; i++ {
                        if t.movies[j + t.offset].State == "Watched" {
                            termbox.SetCell(i + 3, j + 1, '*', color['y'], color['d'])
                        } else {
                            termbox.SetCell(i + 3, j + 1, '*', color['B'], color['d'])
                        }
                    }
                }

                runes := []rune(t.movies[j + t.offset].Year + " " + t.movies[j + t.offset].Title)
                for i := 0; i < len(runes); i++ {
                    fg := color['d']
                    if i < 4 {
                        if t.movies[j + t.offset].State == "Watched" {
                            fg = color['g']
                        } else {
                            fg = color['b']
                        }
                    }

                    if t.ratings {
                        termbox.SetCell(i + 10, j + 1, runes[i], fg, color['d'])
                    } else {
                        termbox.SetCell(i + 3, j + 1, runes[i], fg, color['d'])
                    }
                }
            }
        }

        termbox.SetCell(1, t.cursor - t.offset + 1, '*', color['d'], color['d'])
    } else {
        for j := 0; j < len(t.omdb.Search); j++ {
            runes := []rune(strconv.Itoa(j) + ". [" + t.omdb.Search[j].Year + "] " + t.omdb.Search[j].Title)
            for i := 0; i < len(runes); i++ {
                termbox.SetCell(i, j + 1, runes[i], color['d'], color['d'])
            }
        }
    }
}

func (t *MoviesTab) Query(query string) {
    t.a.d.Movies = append(t.a.d.Movies, Movie{Title: query, State: "Watched"})
    t.a.d.save()
    t.refreshSlice()

    for i := 0; i < len(t.movies); i++ {
        if t.movies[i].Title == query {
            t.cursor = i
            if t.cursor > t.a.height - 4 {
                t.offset = t.cursor - (t.a.height - 4)
            }
            t.a.inputActive = false
            t.autoTag()
        }
    }
}

func (t *MoviesTab) index() int {
    for i := 0; i < len(t.a.d.Movies); i++ {
        if t.a.d.Movies[i].Title == t.movies[t.cursor].Title {
            return i
        }
    }

    return -1
}

func (t *MoviesTab) refreshSlice() {
    t.movies = t.movies[:0]
    for i := 0; i < len(t.a.d.Movies); i++ {
        if t.a.d.Movies[i].State == "Watched" {
            if t.view == "watched" || t.view == "all" {
                t.movies = append(t.movies, t.a.d.Movies[i])
            }
        } else if t.a.d.Movies[i].State == "Unwatched" {
            if t.view == "unwatched" || t.view == "all" {
                t.movies = append(t.movies, t.a.d.Movies[i])
            }
        }
    }
    t.sort()

    if t.cursor > len(t.movies) - 1 {
        t.cursor--
    }

    if t.offset > 0 {
        if len(t.movies) - t.offset < t.a.height - 3 {
            t.offset--
        }
    }

    t.status = "movies - " + t.view + " (" + strconv.Itoa(len(t.movies)) + " entries)"
}

func (t *MoviesTab) sort() {
    var titles []string
    for i := 0; i < len(t.movies); i++ {
        titles = append(titles, t.movies[i].Title)
    }
    sort.Strings(titles)

    var movies []Movie
    for j := 0; j < len(titles); j++ {
        for i := 0; i < len(t.movies); i++ {
            if titles[j] == t.movies[i].Title {
                movies = append(movies, t.movies[i])
            }
        }
    }
    t.movies = movies

    if t.sorter == "year" {

    } else if t.sorter == "rating" {
        t.sortByRating()
    }
}

func (t *MoviesTab) sortByRating() {
    var movies []Movie
    for j := 0; j < 7; j++ {
        for i := 0; i < len(t.movies); i++ {
            if t.movies[i].Rating == 6 - j {
                movies = append(movies, t.movies[i])
            }
        }
    }
    t.movies = movies
}

func (t *MoviesTab) autoTag() {
    title := strings.Replace(t.movies[t.cursor].Title, " ", "+", -1)
    url := "http://www.omdbapi.com/?s=" + title + "&type=movie&y=&plot=full&r=json"
    log.Print(url)

    res, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }

    err = json.Unmarshal(body, &t.omdb)
    if err != nil {
        log.Fatal(err)
    } else {
        for i := 0; i < len(t.omdb.Search); i++ {
            log.Print(t.omdb.Search[i].Title + " - " + t.omdb.Search[i].Year)
        }
        log.Print(t.omdb)
    }
}
<|endoftext|>


<commit_before>// Package msgpackrpc implements a MessagePack-RPC ClientCodec and ServerCodec
// for the rpc package, using the same API as the Go standard library
// for jsonrpc.
package msgpackrpc

import (
	"github.com/ugorji/go/codec"
	"io"
	"net"
	"net/rpc"
)

// Dial connects to a MessagePack-RPC server at the specified network address.
func Dial(network, address string) (*rpc.Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), err
}

// NewClient returns a new rpc.Client to handle requests to the set of
// services at the other end of the connection.
func NewClient(conn io.ReadWriteCloser) *rpc.Client {
	return rpc.NewClientWithCodec(NewClientCodec(conn))
}

// NewClientCodec returns a new rpc.ClientCodec using MessagePack-RPC on conn.
func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
	handle := new(codec.MsgpackHandle)
	return codec.GoRpc.ClientCodec(conn, handle)
}

// NewServerCodec returns a new rpc.ServerCodec using MessagePack-RPC on conn.
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
	handle := new(codec.MsgpackHandle)
	return codec.GoRpc.ServerCodec(conn, handle)
}

// ServeConn runs the MessagePack-RPC server on a single connection. ServeConn
// blocks, serving the connection until the client hangs up. The caller
// typically invokes ServeConn in a go statement.
func ServeConn(conn io.ReadWriteCloser) {
	rpc.ServeCodec(NewServerCodec(conn))
}
<commit_msg>Switch msgpack<commit_after>// Package msgpackrpc implements a MessagePack-RPC ClientCodec and ServerCodec
// for the rpc package, using the same API as the Go standard library
// for jsonrpc.
package msgpackrpc

import (
	"github.com/hashicorp/go-msgpack/codec"
	"io"
	"net"
	"net/rpc"
)

// Dial connects to a MessagePack-RPC server at the specified network address.
func Dial(network, address string) (*rpc.Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), err
}

// NewClient returns a new rpc.Client to handle requests to the set of
// services at the other end of the connection.
func NewClient(conn io.ReadWriteCloser) *rpc.Client {
	return rpc.NewClientWithCodec(NewClientCodec(conn))
}

// NewClientCodec returns a new rpc.ClientCodec using MessagePack-RPC on conn.
func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
	handle := new(codec.MsgpackHandle)
	return codec.GoRpc.ClientCodec(conn, handle)
}

// NewServerCodec returns a new rpc.ServerCodec using MessagePack-RPC on conn.
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
	handle := new(codec.MsgpackHandle)
	return codec.GoRpc.ServerCodec(conn, handle)
}

// ServeConn runs the MessagePack-RPC server on a single connection. ServeConn
// blocks, serving the connection until the client hangs up. The caller
// typically invokes ServeConn in a go statement.
func ServeConn(conn io.ReadWriteCloser) {
	rpc.ServeCodec(NewServerCodec(conn))
}
<|endoftext|>


<commit_before>package readraptor

import (
	"crypto/sha1"
	"fmt"
	"os"
	"time"

	stripe "github.com/bradrydzewski/go.stripe"
	"github.com/cupcake/gokiq"
	"github.com/martini-contrib/sessionauth"
	"github.com/technoweenie/grohl"
)

type Account struct {
	Id         int64     `db:"id"          json:"id"`
	Created    time.Time `db:"created_at"  json:"created"`
	Email      string    `db:"email"       json:"email"`
	PublicKey  string    `db:"public_key"  json:"-"`
	PrivateKey string    `db:"private_key" json:"-"`

	// Confirmable
	ConfirmationToken  *string    `db:"confirmation_token"   json:"-"`
	ConfirmationSentAt *time.Time `db:"confirmation_sent_at" json:"-"`
	ConfirmedAt        *time.Time `db:"confirmed_at"         json:"-"`

	// Stripe
	CustomerId *string `db:"customer_id"  json:"-"`
	CardType   *string `db:"card_type"    json:"-"`
	CardLast4  *string `db:"card_last4"   json:"-"`

	// Session
	authenticated bool `db:"-" json:"-"`
}

func NewAccount(email string) *Account {
	return &Account{
		Created:    time.Now(),
		Email:      email,
		PublicKey:  genKey("public" + email),
		PrivateKey: genKey("private" + email),
	}
}

func FindAccount(id int64) (*Account, error) {
	return FindAccountBy("id", id)
}

func FindAccountByPublicKey(key string) (*Account, error) {
	return FindAccountBy("public_key", key)
}

func FindAccountByConfirmationToken(token string) (*Account, error) {
	return FindAccountBy("confirmation_token", token)
}

func FindAccountBy(column string, value interface{}) (*Account, error) {
	var account Account
	err := dbmap.SelectOne(&account, "select * from accounts where "+column+" = $1", value)
	return &account, err
}

func (a *Account) SendNewAccountEmail(client *gokiq.ClientConfig) {
	client.QueueJob(&NewAccountEmailJob{
		AccountId: a.Id,
	})

	grohl.Log(grohl.Data{
		"queue":   "NewAccountEmailJob",
		"account": a.Id,
	})
}

// Session
func GuestAccount() sessionauth.User {
	return &Account{}
}

func (a *Account) IsAuthenticated() bool {
	return a.authenticated
}

func (a *Account) Login() {
	a.authenticated = true
}

func (a *Account) Logout() {
	a.authenticated = true
}

func (a *Account) UniqueId() interface{} {
	return a.Id
}

func (a *Account) GetById(id interface{}) error {
	return dbmap.SelectOne(a, "select * from accounts where id = $1", id)
}

// Stripe
func (a *Account) CreateStripeCustomer(token string) error {
	stripe.SetKey(os.Getenv("STRIPE_SECRET"))

	params := stripe.CustomerParams{
		Email: a.Email,
		Token: token,
	}

	customer, err := stripe.Customers.Create(&params)
	if err != nil {
		return err
	}

	_, err = dbmap.Exec(
		`update accounts set customer_id = $2 where id = $1`,
		a.Id,
		customer.Id,
	)
	return err
}

func genKey(input string) string {
	salt := os.Getenv("API_GEN_SECRET") + fmt.Sprintf("%d", time.Now().UnixNano())
	hasher := sha1.New()
	hasher.Write([]byte(salt + input))
	return fmt.Sprintf("%x", hasher.Sum(nil))
}
<commit_msg>remove unused stripe fields<commit_after>package readraptor

import (
	"crypto/sha1"
	"fmt"
	"os"
	"time"

	stripe "github.com/bradrydzewski/go.stripe"
	"github.com/cupcake/gokiq"
	"github.com/martini-contrib/sessionauth"
	"github.com/technoweenie/grohl"
)

type Account struct {
	Id         int64     `db:"id"          json:"id"`
	Created    time.Time `db:"created_at"  json:"created"`
	Email      string    `db:"email"       json:"email"`
	PublicKey  string    `db:"public_key"  json:"-"`
	PrivateKey string    `db:"private_key" json:"-"`

	// Confirmable
	ConfirmationToken  *string    `db:"confirmation_token"   json:"-"`
	ConfirmationSentAt *time.Time `db:"confirmation_sent_at" json:"-"`
	ConfirmedAt        *time.Time `db:"confirmed_at"         json:"-"`

	// Stripe
	CustomerId *string `db:"customer_id"  json:"-"`

	// Session
	authenticated bool `db:"-" json:"-"`
}

func NewAccount(email string) *Account {
	return &Account{
		Created:    time.Now(),
		Email:      email,
		PublicKey:  genKey("public" + email),
		PrivateKey: genKey("private" + email),
	}
}

func FindAccount(id int64) (*Account, error) {
	return FindAccountBy("id", id)
}

func FindAccountByPublicKey(key string) (*Account, error) {
	return FindAccountBy("public_key", key)
}

func FindAccountByConfirmationToken(token string) (*Account, error) {
	return FindAccountBy("confirmation_token", token)
}

func FindAccountBy(column string, value interface{}) (*Account, error) {
	var account Account
	err := dbmap.SelectOne(&account, "select * from accounts where "+column+" = $1", value)
	return &account, err
}

func (a *Account) SendNewAccountEmail(client *gokiq.ClientConfig) {
	client.QueueJob(&NewAccountEmailJob{
		AccountId: a.Id,
	})

	grohl.Log(grohl.Data{
		"queue":   "NewAccountEmailJob",
		"account": a.Id,
	})
}

// Session
func GuestAccount() sessionauth.User {
	return &Account{}
}

func (a *Account) IsAuthenticated() bool {
	return a.authenticated
}

func (a *Account) Login() {
	a.authenticated = true
}

func (a *Account) Logout() {
	a.authenticated = true
}

func (a *Account) UniqueId() interface{} {
	return a.Id
}

func (a *Account) GetById(id interface{}) error {
	return dbmap.SelectOne(a, "select * from accounts where id = $1", id)
}

// Stripe
func (a *Account) CreateStripeCustomer(token string) error {
	stripe.SetKey(os.Getenv("STRIPE_SECRET"))

	params := stripe.CustomerParams{
		Email: a.Email,
		Token: token,
	}

	customer, err := stripe.Customers.Create(&params)
	if err != nil {
		return err
	}

	_, err = dbmap.Exec(
		`update accounts set customer_id = $2 where id = $1`,
		a.Id,
		customer.Id,
	)
	return err
}

func genKey(input string) string {
	salt := os.Getenv("API_GEN_SECRET") + fmt.Sprintf("%d", time.Now().UnixNano())
	hasher := sha1.New()
	hasher.Write([]byte(salt + input))
	return fmt.Sprintf("%x", hasher.Sum(nil))
}
<|endoftext|>


<commit_before>package mux

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

func NewRouter(rootPath string) (*router, error) {
	r := &router{}
	r.routes = make(map[string]map[*regexp.Regexp]http.HandlerFunc)

	r.routes[http.MethodGet] = make(map[*regexp.Regexp]http.HandlerFunc)
	r.routes[http.MethodPost] = make(map[*regexp.Regexp]http.HandlerFunc)

	err := r.SetRootPath(rootPath)
	if err != nil {
		return r, err
	}

	return r, nil
}

type router struct {
	root *url.URL

	routes map[string]map[*regexp.Regexp]http.HandlerFunc

	wrappers []WrapperFunc
}

// Set router root path, other paths will be relative to it
func (r *router) SetRootPath(path string) error {
	newRoot, err := url.Parse(path)
	if err != nil {
		return fmt.Errorf("invalid path format %s: %v", path, err)
	}

	r.root = newRoot

	return nil
}

// Add wrappers to router
func (r *router) AddWrappers(wrappers ...WrapperFunc) {
	r.wrappers = append(r.wrappers, wrappers...)
}

// Adds Get handler
func (r *router) Get(pattern string, handler http.HandlerFunc) error {
	pattern = convertSimplePatternToRegexp(pattern)

	compiledPattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}

	r.routes[http.MethodGet][compiledPattern] = Wrap(handler, r.wrappers...).ServeHTTP

	return nil
}

// Adds Post handler
func (r *router) Post(pattern string, handler http.HandlerFunc) error {
	pattern = convertSimplePatternToRegexp(pattern)

	compiledPattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}

	r.routes[http.MethodPost][compiledPattern] = Wrap(handler, r.wrappers...).ServeHTTP

	return nil
}

// Listen on given port
func (r *router) ListenAndServe(port string) error {
	return http.ListenAndServe(fmt.Sprintf(":%s", port), r)
}

// Implements http.Handler interface
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	relPath, err := relativePath(r.root.Path, req.URL.Path)
	if err != nil {
		http.NotFound(w, req)
	}

	r.handleRequest(w, req, relPath)
}

// Handles request: iterate over all routes before finds first matching route.
func (r *router) handleRequest(w http.ResponseWriter, req *http.Request, path string) {

	if routeMap, ok := r.routes[req.Method]; ok {
		for pattern, handler := range routeMap {
			if pattern.MatchString(path) {
				params, err := newParams(req, pattern, path)

				if err != nil {
					fmt.Printf("error while parsing params: %v", err)
					w.WriteHeader(http.StatusBadRequest)
					return
				}

				handler.ServeHTTP(w, putParams(req, params))

				return
			}
		}

		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method: %s not allowed on path: %s", req.Method, req.URL.Path)

		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
	fmt.Fprintf(w, "Method: %s not supported", req.Method)
}

// Pretty prints routes
func (r *router) PrintRoutes() {
	log.Println(strings.Repeat("-", 10))

	for method, list := range r.routes {
		for re := range list {
			log.Printf("'%s': '%s'", method, re)
		}
	}

	log.Println(strings.Repeat("-", 10))
}
<commit_msg>Get rid off nested maps.<commit_after>package mux

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

// Returns new router with root path == rootPath
func NewRouter(rootPath string) (*router, error) {
	r := &router{}
	r.routes = make(map[string]routes)

	r.routes[http.MethodGet] = make(routes, 0, 10)
	r.routes[http.MethodPost] = make(routes, 0, 10)

	err := r.SetRootPath(rootPath)
	if err != nil {
		return r, err
	}

	return r, nil
}

type router struct {
	root *url.URL

	routes map[string]routes

	wrappers []WrapperFunc
}

// Internal structures to store routes
type route struct {
	pattern     *regexp.Regexp
	handlerFunc http.HandlerFunc
}

type routes []route

// Set router root path, other paths will be relative to it
func (r *router) SetRootPath(path string) error {
	newRoot, err := url.Parse(path)
	if err != nil {
		return fmt.Errorf("invalid path format %s: %v", path, err)
	}

	r.root = newRoot

	return nil
}

// Add wrappers to router
func (r *router) AddWrappers(wrappers ...WrapperFunc) {
	r.wrappers = append(r.wrappers, wrappers...)
}

// Adds Get handler
func (r *router) Get(pattern string, handler http.HandlerFunc) error {
	pattern = convertSimplePatternToRegexp(pattern)

	compiledPattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}

	r.routes[http.MethodGet] = append(r.routes[http.MethodGet],
		route{compiledPattern, Wrap(handler, r.wrappers...).ServeHTTP})

	return nil
}

// Adds Post handler
func (r *router) Post(pattern string, handler http.HandlerFunc) error {
	pattern = convertSimplePatternToRegexp(pattern)

	compiledPattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}

	r.routes[http.MethodPost] = append(r.routes[http.MethodPost],
		route{compiledPattern, Wrap(handler, r.wrappers...).ServeHTTP})

	return nil
}

// Listen on given port
func (r *router) ListenAndServe(port string) error {
	return http.ListenAndServe(fmt.Sprintf(":%s", port), r)
}

// Implements http.Handler interface
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	relPath, err := relativePath(r.root.Path, req.URL.Path)
	if err != nil {
		http.NotFound(w, req)
	}

	r.handleRequest(w, req, relPath)
}

// Handles request: iterate over all routes before finds first matching route.
func (r *router) handleRequest(w http.ResponseWriter, req *http.Request, path string) {

	if routes, ok := r.routes[req.Method]; ok {
		for _, route := range routes {
			if route.pattern.MatchString(path) {
				params, err := newParams(req, route.pattern, path)

				if err != nil {
					fmt.Printf("error while parsing params: %v", err)
					w.WriteHeader(http.StatusBadRequest)
					return
				}

				route.handlerFunc(w, putParams(req, params))

				return
			}
		}

		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method: %s not allowed on path: %s", req.Method, req.URL.Path)

		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
	fmt.Fprintf(w, "Method: %s not supported", req.Method)
}

// Pretty prints routes
func (r *router) PrintRoutes() {
	log.Println(strings.Repeat("-", 10))

	for method, list := range r.routes {
		for _, r := range list {
			log.Printf("'%s': '%s'", method, r.pattern)
		}
	}

	log.Println(strings.Repeat("-", 10))
}
<|endoftext|>