<commit_before>package filecache

import (
	"errors"
	"os"
	"path"
	"path/filepath"
	"sync"
	"time"

	"github.com/anacrolix/log"

	"github.com/anacrolix/missinggo/v2/pproffd"
	"github.com/anacrolix/missinggo/v2/resource"
)

const (
	dirPerm  = 0755
	filePerm = 0644
)

type Cache struct {
	root     string
	mu       sync.Mutex
	capacity int64
	filled   int64
	policy   Policy
	items    map[key]itemState
	dirMu    sync.Mutex
}

type CacheInfo struct {
	Capacity int64
	Filled   int64
	NumItems int
}

type ItemInfo struct {
	Path     key
	Accessed time.Time
	Size     int64
}

// Calls the function for every item known to be in the cache.
func (me *Cache) WalkItems(cb func(ItemInfo)) {
	me.mu.Lock()
	defer me.mu.Unlock()
	for k, ii := range me.items {
		cb(ItemInfo{
			Path:     k,
			Accessed: ii.Accessed,
			Size:     ii.Size,
		})
	}
}

func (me *Cache) Info() (ret CacheInfo) {
	me.mu.Lock()
	defer me.mu.Unlock()
	ret.Capacity = me.capacity
	ret.Filled = me.filled
	ret.NumItems = len(me.items)
	return
}

// Setting a negative capacity means unlimited.
func (me *Cache) SetCapacity(capacity int64) {
	me.mu.Lock()
	defer me.mu.Unlock()
	me.capacity = capacity
}

func NewCache(root string) (ret *Cache, err error) {
	root, err = filepath.Abs(root)
	ret = &Cache{
		root:     root,
		capacity: -1, // unlimited
	}
	ret.mu.Lock()
	go func() {
		defer ret.mu.Unlock()
		ret.rescan()
	}()
	return
}

// An empty return path is an error.
func sanitizePath(p string) (ret key) {
	if p == "" {
		return
	}
	ret = key(path.Clean("/" + p))
	if ret[0] == '/' {
		ret = ret[1:]
	}
	return
}

// Leaf is a descendant of root.
func pruneEmptyDirs(root string, leaf string) (err error) {
	rootInfo, err := os.Stat(root)
	if err != nil {
		return
	}
	for {
		var leafInfo os.FileInfo
		leafInfo, err = os.Stat(leaf)
		if os.IsNotExist(err) {
			goto parent
		}
		if err != nil {
			return
		}
		if !leafInfo.IsDir() {
			return
		}
		if os.SameFile(rootInfo, leafInfo) {
			return
		}
		if os.Remove(leaf) != nil {
			return
		}
	parent:
		leaf = filepath.Dir(leaf)
	}
}

func (me *Cache) Remove(path string) error {
	me.mu.Lock()
	defer me.mu.Unlock()
	return me.remove(sanitizePath(path))
}

var (
	ErrBadPath = errors.New("bad path")
	ErrIsDir   = errors.New("is directory")
)

func (me *Cache) StatFile(path string) (os.FileInfo, error) {
	return os.Stat(me.realpath(sanitizePath(path)))
}

func (me *Cache) OpenFile(path string, flag int) (ret *File, err error) {
	key := sanitizePath(path)
	if key == "" {
		err = ErrIsDir
		return
	}
	f, err := os.OpenFile(me.realpath(key), flag, filePerm)
	if flag&os.O_CREATE != 0 && os.IsNotExist(err) {
		// Ensure intermediate directories and try again.
		me.dirMu.Lock()
		dirErr := os.MkdirAll(filepath.Dir(me.realpath(key)), dirPerm)
		f, err = os.OpenFile(me.realpath(key), flag, filePerm)
		me.dirMu.Unlock()
		if dirErr != nil && os.IsNotExist(err) {
			return nil, dirErr
		}
		if err != nil {
			go me.pruneEmptyDirs(key)
		}
	}
	if err != nil {
		return
	}
	ret = &File{
		path: key,
		f:    pproffd.WrapOSFile(f),
		onRead: func(n int) {
			me.mu.Lock()
			defer me.mu.Unlock()
			me.updateItem(key, func(i *itemState, ok bool) bool {
				i.Accessed = time.Now()
				return ok
			})
		},
		afterWrite: func(endOff int64) {
			me.mu.Lock()
			defer me.mu.Unlock()
			me.updateItem(key, func(i *itemState, ok bool) bool {
				i.Accessed = time.Now()
				if endOff > i.Size {
					i.Size = endOff
				}
				return ok
			})
		},
	}
	me.mu.Lock()
	defer me.mu.Unlock()
	me.updateItem(key, func(i *itemState, ok bool) bool {
		if !ok {
			*i, ok = me.statKey(key)
		}
		i.Accessed = time.Now()
		return ok
	})
	return
}

func (me *Cache) rescan() {
	me.filled = 0
	me.policy = new(lru)
	me.items = make(map[key]itemState)
	err := filepath.Walk(me.root, func(path string, info os.FileInfo, err error) error {
		if os.IsNotExist(err) {
			return nil
		}
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		path, err = filepath.Rel(me.root, path)
		if err != nil {
			log.Print(err)
			return nil
		}
		key := sanitizePath(path)
		me.updateItem(key, func(i *itemState, ok bool) bool {
			if ok {
				panic("scanned duplicate items")
			}
			*i, ok = me.statKey(key)
			return ok
		})
		return nil
	})
	if err != nil {
		panic(err)
	}
}

func (me *Cache) statKey(k key) (i itemState, ok bool) {
	fi, err := os.Stat(me.realpath(k))
	if os.IsNotExist(err) {
		return
	}
	if err != nil {
		panic(err)
	}
	i.FromOSFileInfo(fi)
	ok = true
	return
}

func (me *Cache) updateItem(k key, u func(*itemState, bool) bool) {
	ii, ok := me.items[k]
	me.filled -= ii.Size
	if u(&ii, ok) {
		me.filled += ii.Size
		me.policy.Used(k, ii.Accessed)
		me.items[k] = ii
	} else {
		me.policy.Forget(k)
		delete(me.items, k)
	}
	me.trimToCapacity()
}

func (me *Cache) realpath(path key) string {
	return filepath.Join(me.root, filepath.FromSlash(string(path)))
}

func (me *Cache) TrimToCapacity() {
	me.mu.Lock()
	defer me.mu.Unlock()
	me.trimToCapacity()
}

func (me *Cache) pruneEmptyDirs(path key) {
	me.dirMu.Lock()
	defer me.dirMu.Unlock()
	pruneEmptyDirs(me.root, me.realpath(path))
}

func (me *Cache) remove(path key) error {
	err := os.Remove(me.realpath(path))
	if os.IsNotExist(err) {
		err = nil
	}
	if err != nil {
		return err
	}
	me.pruneEmptyDirs(path)
	me.updateItem(path, func(*itemState, bool) bool {
		return false
	})
	return nil
}

func (me *Cache) trimToCapacity() {
	if me.capacity < 0 {
		return
	}
	for me.filled > me.capacity {
		me.remove(me.policy.Choose().(key))
	}
}

// TODO: Do I need this?
func (me *Cache) pathInfo(p string) itemState {
	return me.items[sanitizePath(p)]
}

func (me *Cache) Rename(from, to string) (err error) {
	_from := sanitizePath(from)
	_to := sanitizePath(to)
	me.mu.Lock()
	defer me.mu.Unlock()
	me.dirMu.Lock()
	err = os.MkdirAll(filepath.Dir(me.realpath(_to)), dirPerm)
	if err != nil {
		return
	}
	err = os.Rename(me.realpath(_from), me.realpath(_to))
	me.dirMu.Unlock()
	if err != nil {
		return
	}
	// We can do a dance here to copy the state from the old item, but lets
	// just stat the new item for now.
	me.updateItem(_from, func(i *itemState, ok bool) bool {
		return false
	})
	me.updateItem(_to, func(i *itemState, ok bool) bool {
		*i, ok = me.statKey(_to)
		return ok
	})
	return
}

func (me *Cache) Stat(path string) (os.FileInfo, error) {
	return os.Stat(me.realpath(sanitizePath(path)))
}

func (me *Cache) AsResourceProvider() resource.Provider {
	return &uniformResourceProvider{me}
}
<commit_msg>Revert "filecache: Synchronize on intermediate directory creation and removal"<commit_after>package filecache

import (
	"errors"
	"os"
	"path"
	"path/filepath"
	"sync"
	"time"

	"github.com/anacrolix/log"

	"github.com/anacrolix/missinggo/v2/pproffd"
	"github.com/anacrolix/missinggo/v2/resource"
)

const (
	dirPerm  = 0755
	filePerm = 0644
)

type Cache struct {
	root     string
	mu       sync.Mutex
	capacity int64
	filled   int64
	policy   Policy
	items    map[key]itemState
}

type CacheInfo struct {
	Capacity int64
	Filled   int64
	NumItems int
}

type ItemInfo struct {
	Path     key
	Accessed time.Time
	Size     int64
}

// Calls the function for every item known to be in the cache.
func (me *Cache) WalkItems(cb func(ItemInfo)) {
	me.mu.Lock()
	defer me.mu.Unlock()
	for k, ii := range me.items {
		cb(ItemInfo{
			Path:     k,
			Accessed: ii.Accessed,
			Size:     ii.Size,
		})
	}
}

func (me *Cache) Info() (ret CacheInfo) {
	me.mu.Lock()
	defer me.mu.Unlock()
	ret.Capacity = me.capacity
	ret.Filled = me.filled
	ret.NumItems = len(me.items)
	return
}

// Setting a negative capacity means unlimited.
func (me *Cache) SetCapacity(capacity int64) {
	me.mu.Lock()
	defer me.mu.Unlock()
	me.capacity = capacity
}

func NewCache(root string) (ret *Cache, err error) {
	root, err = filepath.Abs(root)
	ret = &Cache{
		root:     root,
		capacity: -1, // unlimited
	}
	ret.mu.Lock()
	go func() {
		defer ret.mu.Unlock()
		ret.rescan()
	}()
	return
}

// An empty return path is an error.
func sanitizePath(p string) (ret key) {
	if p == "" {
		return
	}
	ret = key(path.Clean("/" + p))
	if ret[0] == '/' {
		ret = ret[1:]
	}
	return
}

// Leaf is a descendant of root.
func pruneEmptyDirs(root string, leaf string) (err error) {
	rootInfo, err := os.Stat(root)
	if err != nil {
		return
	}
	for {
		var leafInfo os.FileInfo
		leafInfo, err = os.Stat(leaf)
		if os.IsNotExist(err) {
			goto parent
		}
		if err != nil {
			return
		}
		if !leafInfo.IsDir() {
			return
		}
		if os.SameFile(rootInfo, leafInfo) {
			return
		}
		if os.Remove(leaf) != nil {
			return
		}
	parent:
		leaf = filepath.Dir(leaf)
	}
}

func (me *Cache) Remove(path string) error {
	me.mu.Lock()
	defer me.mu.Unlock()
	return me.remove(sanitizePath(path))
}

var (
	ErrBadPath = errors.New("bad path")
	ErrIsDir   = errors.New("is directory")
)

func (me *Cache) StatFile(path string) (os.FileInfo, error) {
	return os.Stat(me.realpath(sanitizePath(path)))
}

func (me *Cache) OpenFile(path string, flag int) (ret *File, err error) {
	key := sanitizePath(path)
	if key == "" {
		err = ErrIsDir
		return
	}
	f, err := os.OpenFile(me.realpath(key), flag, filePerm)
	if flag&os.O_CREATE != 0 && os.IsNotExist(err) {
		// Ensure intermediate directories and try again.
		dirErr := os.MkdirAll(filepath.Dir(me.realpath(key)), dirPerm)
		f, err = os.OpenFile(me.realpath(key), flag, filePerm)
		if dirErr != nil && os.IsNotExist(err) {
			return nil, dirErr
		}
		if err != nil {
			go me.pruneEmptyDirs(key)
		}
	}
	if err != nil {
		return
	}
	ret = &File{
		path: key,
		f:    pproffd.WrapOSFile(f),
		onRead: func(n int) {
			me.mu.Lock()
			defer me.mu.Unlock()
			me.updateItem(key, func(i *itemState, ok bool) bool {
				i.Accessed = time.Now()
				return ok
			})
		},
		afterWrite: func(endOff int64) {
			me.mu.Lock()
			defer me.mu.Unlock()
			me.updateItem(key, func(i *itemState, ok bool) bool {
				i.Accessed = time.Now()
				if endOff > i.Size {
					i.Size = endOff
				}
				return ok
			})
		},
	}
	me.mu.Lock()
	defer me.mu.Unlock()
	me.updateItem(key, func(i *itemState, ok bool) bool {
		if !ok {
			*i, ok = me.statKey(key)
		}
		i.Accessed = time.Now()
		return ok
	})
	return
}

func (me *Cache) rescan() {
	me.filled = 0
	me.policy = new(lru)
	me.items = make(map[key]itemState)
	err := filepath.Walk(me.root, func(path string, info os.FileInfo, err error) error {
		if os.IsNotExist(err) {
			return nil
		}
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		path, err = filepath.Rel(me.root, path)
		if err != nil {
			log.Print(err)
			return nil
		}
		key := sanitizePath(path)
		me.updateItem(key, func(i *itemState, ok bool) bool {
			if ok {
				panic("scanned duplicate items")
			}
			*i, ok = me.statKey(key)
			return ok
		})
		return nil
	})
	if err != nil {
		panic(err)
	}
}

func (me *Cache) statKey(k key) (i itemState, ok bool) {
	fi, err := os.Stat(me.realpath(k))
	if os.IsNotExist(err) {
		return
	}
	if err != nil {
		panic(err)
	}
	i.FromOSFileInfo(fi)
	ok = true
	return
}

func (me *Cache) updateItem(k key, u func(*itemState, bool) bool) {
	ii, ok := me.items[k]
	me.filled -= ii.Size
	if u(&ii, ok) {
		me.filled += ii.Size
		me.policy.Used(k, ii.Accessed)
		me.items[k] = ii
	} else {
		me.policy.Forget(k)
		delete(me.items, k)
	}
	me.trimToCapacity()
}

func (me *Cache) realpath(path key) string {
	return filepath.Join(me.root, filepath.FromSlash(string(path)))
}

func (me *Cache) TrimToCapacity() {
	me.mu.Lock()
	defer me.mu.Unlock()
	me.trimToCapacity()
}

func (me *Cache) pruneEmptyDirs(path key) {
	pruneEmptyDirs(me.root, me.realpath(path))
}

func (me *Cache) remove(path key) error {
	err := os.Remove(me.realpath(path))
	if os.IsNotExist(err) {
		err = nil
	}
	if err != nil {
		return err
	}
	me.pruneEmptyDirs(path)
	me.updateItem(path, func(*itemState, bool) bool {
		return false
	})
	return nil
}

func (me *Cache) trimToCapacity() {
	if me.capacity < 0 {
		return
	}
	for me.filled > me.capacity {
		me.remove(me.policy.Choose().(key))
	}
}

// TODO: Do I need this?
func (me *Cache) pathInfo(p string) itemState {
	return me.items[sanitizePath(p)]
}

func (me *Cache) Rename(from, to string) (err error) {
	_from := sanitizePath(from)
	_to := sanitizePath(to)
	me.mu.Lock()
	defer me.mu.Unlock()
	err = os.MkdirAll(filepath.Dir(me.realpath(_to)), dirPerm)
	if err != nil {
		return
	}
	err = os.Rename(me.realpath(_from), me.realpath(_to))
	if err != nil {
		return
	}
	// We can do a dance here to copy the state from the old item, but lets
	// just stat the new item for now.
	me.updateItem(_from, func(i *itemState, ok bool) bool {
		return false
	})
	me.updateItem(_to, func(i *itemState, ok bool) bool {
		*i, ok = me.statKey(_to)
		return ok
	})
	return
}

func (me *Cache) Stat(path string) (os.FileInfo, error) {
	return os.Stat(me.realpath(sanitizePath(path)))
}

func (me *Cache) AsResourceProvider() resource.Provider {
	return &uniformResourceProvider{me}
}
<|endoftext|>


<commit_before>package pongo2

/* Missing filters:

   center
   dictsort
   dictsortreversed
   escapejs
   filesizeformat
   force_escape
   iriencode
   linebreaks
   linenumbers
   ljust
   make_list
   phone2numeric
   pprint
   rjust
   safeseq
   slice
   timesince
   timeuntil
   truncatechars_html
   truncatewords
   truncatewords_html
   unordered_list
   urlize
   urlizetrunc
   wordcount
   wordwrap

   Filters that won't be added:

   get_static_prefix
   static
   slugify (is provided by github.com/flosch/pongo2-addons)
*/

import (
	"errors"
	"fmt"
	"math/rand"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func init() {
	rand.Seed(time.Now().Unix())

	RegisterFilter("escape", filterEscape)
	RegisterFilter("safe", filterSafe)

	RegisterFilter("add", filterAdd)
	RegisterFilter("addslashes", filterAddslashes)
	RegisterFilter("capfirst", filterCapfirst)
	RegisterFilter("cut", filterCut)
	RegisterFilter("date", filterDate)
	RegisterFilter("default", filterDefault)
	RegisterFilter("default_if_none", filterDefaultIfNone)
	RegisterFilter("divisibleby", filterDivisibleby)
	RegisterFilter("first", filterFirst)
	RegisterFilter("floatformat", filterFloatformat)
	RegisterFilter("get_digit", filterGetdigit)
	RegisterFilter("join", filterJoin)
	RegisterFilter("last", filterLast)
	RegisterFilter("length", filterLength)
	RegisterFilter("length_is", filterLengthis)
	RegisterFilter("linebreaksbr", filterLinebreaksbr)
	RegisterFilter("lower", filterLower)
	RegisterFilter("pluralize", filterPluralize)
	RegisterFilter("random", filterRandom)
	RegisterFilter("removetags", filterRemovetags)
	RegisterFilter("title", filterTitle)
	RegisterFilter("upper", filterUpper)
	RegisterFilter("urlencode", filterUrlencode)
	RegisterFilter("stringformat", filterStringformat)
	RegisterFilter("striptags", filterStriptags)
	RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
	RegisterFilter("truncatechars", filterTruncatechars)
	RegisterFilter("yesno", filterYesno)

	RegisterFilter("float", filterFloat)     // pongo-specific
	RegisterFilter("integer", filterInteger) // pongo-specific
}

func filterTruncatechars(in *Value, param *Value) (*Value, error) {
	s := in.String()
	newLen := param.Integer()
	if newLen < len(s) {
		if newLen >= 3 {
			return AsValue(fmt.Sprintf("%s...", s[:newLen-3])), nil
		}
		// Not enough space for the ellipsis
		return AsValue(s[:newLen]), nil
	}
	return in, nil
}

func filterEscape(in *Value, param *Value) (*Value, error) {
	output := strings.Replace(in.String(), "&", "&", -1)
	output = strings.Replace(output, ">", ">", -1)
	output = strings.Replace(output, "<", "<", -1)
	output = strings.Replace(output, "\"", """, -1)
	output = strings.Replace(output, "'", "'", -1)
	return AsValue(output), nil
}

func filterSafe(in *Value, param *Value) (*Value, error) {
	return in, nil // nothing to do here, just to keep track of the safe application
}

func filterAdd(in *Value, param *Value) (*Value, error) {
	if in.IsNumber() && param.IsNumber() {
		if in.IsFloat() || param.IsFloat() {
			return AsValue(in.Float() + param.Float()), nil
		} else {
			return AsValue(in.Integer() + param.Integer()), nil
		}
	}
	// If in/param is not a number, we're relying on the
	// Value's String() convertion and just add them both together
	return AsValue(in.String() + param.String()), nil
}

func filterAddslashes(in *Value, param *Value) (*Value, error) {
	output := strings.Replace(in.String(), "\\", "\\\\", -1)
	output = strings.Replace(output, "\"", "\\\"", -1)
	output = strings.Replace(output, "'", "\\'", -1)
	return AsValue(output), nil
}

func filterCut(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.Replace(in.String(), param.String(), "", -1)), nil
}

func filterLength(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Len()), nil
}

func filterLengthis(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Len() == param.Integer()), nil
}

func filterDefault(in *Value, param *Value) (*Value, error) {
	if !in.IsTrue() {
		return param, nil
	}
	return in, nil
}

func filterDefaultIfNone(in *Value, param *Value) (*Value, error) {
	if in.IsNil() {
		return param, nil
	}
	return in, nil
}

func filterDivisibleby(in *Value, param *Value) (*Value, error) {
	if param.Integer() == 0 {
		return AsValue(false), nil
	}
	return AsValue(in.Integer()%param.Integer() == 0), nil
}

func filterFirst(in *Value, param *Value) (*Value, error) {
	if in.CanSlice() && in.Len() > 0 {
		return in.Index(0), nil
	}
	return AsValue(""), nil
}

func filterFloatformat(in *Value, param *Value) (*Value, error) {
	val := in.Float()

	decimals := -1
	if !param.IsNil() {
		// Any argument provided?
		decimals = param.Integer()
	}

	// if the argument is not a number (e. g. empty), the default
	// behaviour is trim the result
	trim := !param.IsNumber()

	if decimals <= 0 {
		// argument is negative or zero, so we
		// want the output being trimmed
		decimals = -decimals
		trim = true
	}

	if trim {
		// Remove zeroes
		if float64(int(val)) == val {
			return AsValue(in.Integer()), nil
		}
	}

	return AsValue(strconv.FormatFloat(val, 'f', decimals, 64)), nil
}

func filterGetdigit(in *Value, param *Value) (*Value, error) {
	i := param.Integer()
	l := len(in.String())
	if i <= 0 || i > l {
		return in, nil
	}
	return AsValue(in.String()[l-i] - 48), nil
}

func filterJoin(in *Value, param *Value) (*Value, error) {
	if !in.CanSlice() {
		return in, nil
	}
	sep := param.String()
	sl := make([]string, 0, in.Len())
	for i := 0; i < in.Len(); i++ {
		sl = append(sl, in.Index(i).String())
	}
	return AsValue(strings.Join(sl, sep)), nil
}

func filterLast(in *Value, param *Value) (*Value, error) {
	if in.CanSlice() && in.Len() > 0 {
		return in.Index(in.Len() - 1), nil
	}
	return AsValue(""), nil
}

func filterUpper(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.ToUpper(in.String())), nil
}

func filterLower(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.ToLower(in.String())), nil
}

func filterCapfirst(in *Value, param *Value) (*Value, error) {
	if in.Len() <= 0 {
		return AsValue(""), nil
	}
	t := in.String()
	return AsValue(strings.ToUpper(string(t[0])) + t[1:]), nil
}

func filterDate(in *Value, param *Value) (*Value, error) {
	t, is_time := in.Interface().(time.Time)
	if !is_time {
		return nil, errors.New("Filter input argument must be of type 'time.Time'.")
	}
	return AsValue(t.Format(param.String())), nil
}

func filterFloat(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Float()), nil
}

func filterInteger(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Integer()), nil
}

func filterLinebreaksbr(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.Replace(in.String(), "\n", "
", -1)), nil
}

func filterUrlencode(in *Value, param *Value) (*Value, error) {
	return AsValue(url.QueryEscape(in.String())), nil
}

func filterStringformat(in *Value, param *Value) (*Value, error) {
	return AsValue(fmt.Sprintf(param.String(), in.Interface())), nil
}

var re_striptags = regexp.MustCompile("<[^>]*?>")

func filterStriptags(in *Value, param *Value) (*Value, error) {
	s := in.String()

	// Strip all tags
	s = re_striptags.ReplaceAllString(s, "")

	return AsValue(strings.TrimSpace(s)), nil
}

func filterPluralize(in *Value, param *Value) (*Value, error) {
	if in.IsNumber() {
		// Works only on numbers
		if param.Len() > 0 {
			endings := strings.Split(param.String(), ",")
			if len(endings) > 2 {
				return nil, errors.New("You cannot pass more than 2 arguments to filter 'pluralize'.")
			}
			if len(endings) == 1 {
				// 1 argument
				if in.Integer() != 1 {
					return AsValue(endings[0]), nil
				}
			} else {
				if in.Integer() != 1 {
					// 2 arguments
					return AsValue(endings[1]), nil
				}
				return AsValue(endings[0]), nil
			}
		} else {
			if in.Integer() != 1 {
				// return default 's'
				return AsValue("s"), nil
			}
		}

		return AsValue(""), nil
	} else {
		return nil, errors.New("Filter 'pluralize' does only work on numbers.")
	}
}

func filterRandom(in *Value, param *Value) (*Value, error) {
	if !in.CanSlice() || in.Len() <= 0 {
		return in, nil
	}
	i := rand.Intn(in.Len())
	return in.Index(i), nil
}

func filterRemovetags(in *Value, param *Value) (*Value, error) {
	s := in.String()
	tags := strings.Split(param.String(), ",")

	// Strip only specific tags
	for _, tag := range tags {
		re := regexp.MustCompile(fmt.Sprintf("</?%s/?>", tag))
		s = re.ReplaceAllString(s, "")
	}

	return AsValue(strings.TrimSpace(s)), nil
}

func filterTitle(in *Value, param *Value) (*Value, error) {
	if !in.IsString() {
		return AsValue(""), nil
	}
	return AsValue(strings.Title(strings.ToLower(in.String()))), nil
}

func filterYesno(in *Value, param *Value) (*Value, error) {
	choices := map[int]string{
		0: "yes",
		1: "no",
		2: "maybe",
	}
	param_string := param.String()
	custom_choices := strings.Split(param_string, ",")
	if len(param_string) > 0 {
		if len(custom_choices) > 3 {
			return nil, errors.New(fmt.Sprintf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", param_string))
		}
		if len(custom_choices) < 2 {
			return nil, errors.New(fmt.Sprintf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", param_string))
		}

		// Map to the options now
		choices[0] = custom_choices[0]
		choices[1] = custom_choices[1]
		if len(custom_choices) == 3 {
			choices[2] = custom_choices[2]
		}
	}

	// maybe
	if in.IsNil() {
		return AsValue(choices[2]), nil
	}

	// yes
	if in.IsTrue() {
		return AsValue(choices[0]), nil
	}

	// no
	return AsValue(choices[1]), nil
}
<commit_msg>filters added: filesizeformat,timesince,timeuntil<commit_after>package pongo2

/* Missing filters:

   center
   dictsort
   dictsortreversed
   escapejs
   filesizeformat
   force_escape
   iriencode
   linebreaks
   linenumbers
   ljust
   make_list
   phone2numeric
   pprint
   rjust
   safeseq
   slice
   truncatechars_html
   truncatewords
   truncatewords_html
   unordered_list
   urlize
   urlizetrunc
   wordcount
   wordwrap

   Filters that won't be added:

   get_static_prefix
   static

   Filters that are provided through github.com/flosch/pongo2-addons:

   filesizeformat
   slugify
   timesince
   timeuntil
*/

import (
	"errors"
	"fmt"
	"math/rand"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func init() {
	rand.Seed(time.Now().Unix())

	RegisterFilter("escape", filterEscape)
	RegisterFilter("safe", filterSafe)

	RegisterFilter("add", filterAdd)
	RegisterFilter("addslashes", filterAddslashes)
	RegisterFilter("capfirst", filterCapfirst)
	RegisterFilter("cut", filterCut)
	RegisterFilter("date", filterDate)
	RegisterFilter("default", filterDefault)
	RegisterFilter("default_if_none", filterDefaultIfNone)
	RegisterFilter("divisibleby", filterDivisibleby)
	RegisterFilter("first", filterFirst)
	RegisterFilter("floatformat", filterFloatformat)
	RegisterFilter("get_digit", filterGetdigit)
	RegisterFilter("join", filterJoin)
	RegisterFilter("last", filterLast)
	RegisterFilter("length", filterLength)
	RegisterFilter("length_is", filterLengthis)
	RegisterFilter("linebreaksbr", filterLinebreaksbr)
	RegisterFilter("lower", filterLower)
	RegisterFilter("pluralize", filterPluralize)
	RegisterFilter("random", filterRandom)
	RegisterFilter("removetags", filterRemovetags)
	RegisterFilter("title", filterTitle)
	RegisterFilter("upper", filterUpper)
	RegisterFilter("urlencode", filterUrlencode)
	RegisterFilter("stringformat", filterStringformat)
	RegisterFilter("striptags", filterStriptags)
	RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
	RegisterFilter("truncatechars", filterTruncatechars)
	RegisterFilter("yesno", filterYesno)

	RegisterFilter("float", filterFloat)     // pongo-specific
	RegisterFilter("integer", filterInteger) // pongo-specific
}

func filterTruncatechars(in *Value, param *Value) (*Value, error) {
	s := in.String()
	newLen := param.Integer()
	if newLen < len(s) {
		if newLen >= 3 {
			return AsValue(fmt.Sprintf("%s...", s[:newLen-3])), nil
		}
		// Not enough space for the ellipsis
		return AsValue(s[:newLen]), nil
	}
	return in, nil
}

func filterEscape(in *Value, param *Value) (*Value, error) {
	output := strings.Replace(in.String(), "&", "&", -1)
	output = strings.Replace(output, ">", ">", -1)
	output = strings.Replace(output, "<", "<", -1)
	output = strings.Replace(output, "\"", """, -1)
	output = strings.Replace(output, "'", "'", -1)
	return AsValue(output), nil
}

func filterSafe(in *Value, param *Value) (*Value, error) {
	return in, nil // nothing to do here, just to keep track of the safe application
}

func filterAdd(in *Value, param *Value) (*Value, error) {
	if in.IsNumber() && param.IsNumber() {
		if in.IsFloat() || param.IsFloat() {
			return AsValue(in.Float() + param.Float()), nil
		} else {
			return AsValue(in.Integer() + param.Integer()), nil
		}
	}
	// If in/param is not a number, we're relying on the
	// Value's String() convertion and just add them both together
	return AsValue(in.String() + param.String()), nil
}

func filterAddslashes(in *Value, param *Value) (*Value, error) {
	output := strings.Replace(in.String(), "\\", "\\\\", -1)
	output = strings.Replace(output, "\"", "\\\"", -1)
	output = strings.Replace(output, "'", "\\'", -1)
	return AsValue(output), nil
}

func filterCut(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.Replace(in.String(), param.String(), "", -1)), nil
}

func filterLength(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Len()), nil
}

func filterLengthis(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Len() == param.Integer()), nil
}

func filterDefault(in *Value, param *Value) (*Value, error) {
	if !in.IsTrue() {
		return param, nil
	}
	return in, nil
}

func filterDefaultIfNone(in *Value, param *Value) (*Value, error) {
	if in.IsNil() {
		return param, nil
	}
	return in, nil
}

func filterDivisibleby(in *Value, param *Value) (*Value, error) {
	if param.Integer() == 0 {
		return AsValue(false), nil
	}
	return AsValue(in.Integer()%param.Integer() == 0), nil
}

func filterFirst(in *Value, param *Value) (*Value, error) {
	if in.CanSlice() && in.Len() > 0 {
		return in.Index(0), nil
	}
	return AsValue(""), nil
}

func filterFloatformat(in *Value, param *Value) (*Value, error) {
	val := in.Float()

	decimals := -1
	if !param.IsNil() {
		// Any argument provided?
		decimals = param.Integer()
	}

	// if the argument is not a number (e. g. empty), the default
	// behaviour is trim the result
	trim := !param.IsNumber()

	if decimals <= 0 {
		// argument is negative or zero, so we
		// want the output being trimmed
		decimals = -decimals
		trim = true
	}

	if trim {
		// Remove zeroes
		if float64(int(val)) == val {
			return AsValue(in.Integer()), nil
		}
	}

	return AsValue(strconv.FormatFloat(val, 'f', decimals, 64)), nil
}

func filterGetdigit(in *Value, param *Value) (*Value, error) {
	i := param.Integer()
	l := len(in.String())
	if i <= 0 || i > l {
		return in, nil
	}
	return AsValue(in.String()[l-i] - 48), nil
}

func filterJoin(in *Value, param *Value) (*Value, error) {
	if !in.CanSlice() {
		return in, nil
	}
	sep := param.String()
	sl := make([]string, 0, in.Len())
	for i := 0; i < in.Len(); i++ {
		sl = append(sl, in.Index(i).String())
	}
	return AsValue(strings.Join(sl, sep)), nil
}

func filterLast(in *Value, param *Value) (*Value, error) {
	if in.CanSlice() && in.Len() > 0 {
		return in.Index(in.Len() - 1), nil
	}
	return AsValue(""), nil
}

func filterUpper(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.ToUpper(in.String())), nil
}

func filterLower(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.ToLower(in.String())), nil
}

func filterCapfirst(in *Value, param *Value) (*Value, error) {
	if in.Len() <= 0 {
		return AsValue(""), nil
	}
	t := in.String()
	return AsValue(strings.ToUpper(string(t[0])) + t[1:]), nil
}

func filterDate(in *Value, param *Value) (*Value, error) {
	t, is_time := in.Interface().(time.Time)
	if !is_time {
		return nil, errors.New("Filter input argument must be of type 'time.Time'.")
	}
	return AsValue(t.Format(param.String())), nil
}

func filterFloat(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Float()), nil
}

func filterInteger(in *Value, param *Value) (*Value, error) {
	return AsValue(in.Integer()), nil
}

func filterLinebreaksbr(in *Value, param *Value) (*Value, error) {
	return AsValue(strings.Replace(in.String(), "\n", "
", -1)), nil
}

func filterUrlencode(in *Value, param *Value) (*Value, error) {
	return AsValue(url.QueryEscape(in.String())), nil
}

func filterStringformat(in *Value, param *Value) (*Value, error) {
	return AsValue(fmt.Sprintf(param.String(), in.Interface())), nil
}

var re_striptags = regexp.MustCompile("<[^>]*?>")

func filterStriptags(in *Value, param *Value) (*Value, error) {
	s := in.String()

	// Strip all tags
	s = re_striptags.ReplaceAllString(s, "")

	return AsValue(strings.TrimSpace(s)), nil
}

func filterPluralize(in *Value, param *Value) (*Value, error) {
	if in.IsNumber() {
		// Works only on numbers
		if param.Len() > 0 {
			endings := strings.Split(param.String(), ",")
			if len(endings) > 2 {
				return nil, errors.New("You cannot pass more than 2 arguments to filter 'pluralize'.")
			}
			if len(endings) == 1 {
				// 1 argument
				if in.Integer() != 1 {
					return AsValue(endings[0]), nil
				}
			} else {
				if in.Integer() != 1 {
					// 2 arguments
					return AsValue(endings[1]), nil
				}
				return AsValue(endings[0]), nil
			}
		} else {
			if in.Integer() != 1 {
				// return default 's'
				return AsValue("s"), nil
			}
		}

		return AsValue(""), nil
	} else {
		return nil, errors.New("Filter 'pluralize' does only work on numbers.")
	}
}

func filterRandom(in *Value, param *Value) (*Value, error) {
	if !in.CanSlice() || in.Len() <= 0 {
		return in, nil
	}
	i := rand.Intn(in.Len())
	return in.Index(i), nil
}

func filterRemovetags(in *Value, param *Value) (*Value, error) {
	s := in.String()
	tags := strings.Split(param.String(), ",")

	// Strip only specific tags
	for _, tag := range tags {
		re := regexp.MustCompile(fmt.Sprintf("</?%s/?>", tag))
		s = re.ReplaceAllString(s, "")
	}

	return AsValue(strings.TrimSpace(s)), nil
}

func filterTitle(in *Value, param *Value) (*Value, error) {
	if !in.IsString() {
		return AsValue(""), nil
	}
	return AsValue(strings.Title(strings.ToLower(in.String()))), nil
}

func filterYesno(in *Value, param *Value) (*Value, error) {
	choices := map[int]string{
		0: "yes",
		1: "no",
		2: "maybe",
	}
	param_string := param.String()
	custom_choices := strings.Split(param_string, ",")
	if len(param_string) > 0 {
		if len(custom_choices) > 3 {
			return nil, errors.New(fmt.Sprintf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", param_string))
		}
		if len(custom_choices) < 2 {
			return nil, errors.New(fmt.Sprintf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", param_string))
		}

		// Map to the options now
		choices[0] = custom_choices[0]
		choices[1] = custom_choices[1]
		if len(custom_choices) == 3 {
			choices[2] = custom_choices[2]
		}
	}

	// maybe
	if in.IsNil() {
		return AsValue(choices[2]), nil
	}

	// yes
	if in.IsTrue() {
		return AsValue(choices[0]), nil
	}

	// no
	return AsValue(choices[1]), nil
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package ddl

import (
	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb/column"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/meta"
	"github.com/pingcap/tidb/model"
	"github.com/pingcap/tidb/table"
	"github.com/pingcap/tidb/table/tables"
	"github.com/pingcap/tidb/util/errors2"
)

func (d *ddl) adjustColumnOffset(columns []*model.ColumnInfo, indices []*model.IndexInfo, offset int) {
	offsetChanged := make(map[int]int)
	for i := offset; i < len(columns); i++ {
		offsetChanged[columns[i].Offset] = i
		columns[i].Offset = i
	}

	// Update index column offset info.
	for _, idx := range indices {
		for _, col := range idx.Columns {
			newOffset, ok := offsetChanged[col.Offset]
			if ok {
				col.Offset = newOffset
			}
		}
	}
}

func (d *ddl) addColumn(tblInfo *model.TableInfo, spec *AlterSpecification) (*model.ColumnInfo, int, error) {
	// Check column name duplicate.
	cols := tblInfo.Columns
	position := len(cols)

	// Get column position.
	if spec.Position.Type == ColumnPositionFirst {
		position = 0
	} else if spec.Position.Type == ColumnPositionAfter {
		c := findCol(cols, spec.Position.RelativeColumn)
		if c == nil {
			return nil, 0, errors.Errorf("No such column: %v", spec.Column.Name)
		}

		// Insert position is after the mentioned column.
		position = c.Offset + 1
	}

	// TODO: set constraint
	col, _, err := d.buildColumnAndConstraint(position, spec.Column)
	if err != nil {
		return nil, 0, errors.Trace(err)
	}

	colInfo := &col.ColumnInfo
	colInfo.State = model.StateNone
	// To support add column asynchronous, we should mark its offset as the last column.
	// So that we can use origin column offset to get value from row.
	colInfo.Offset = len(cols)

	// Insert col into the right place of the column list.
	newCols := make([]*model.ColumnInfo, 0, len(cols)+1)
	newCols = append(newCols, cols[:position]...)
	newCols = append(newCols, colInfo)
	newCols = append(newCols, cols[position:]...)

	tblInfo.Columns = newCols
	return colInfo, position, nil
}

func (d *ddl) onColumnAdd(t *meta.Meta, job *model.Job) error {
	schemaID := job.SchemaID
	tblInfo, err := d.getTableInfo(t, job)
	if err != nil {
		return errors.Trace(err)
	}

	spec := &AlterSpecification{}
	offset := 0
	err = job.DecodeArgs(&spec, &offset)
	if err != nil {
		job.State = model.JobCancelled
		return errors.Trace(err)
	}

	var columnInfo *model.ColumnInfo
	columnInfo = findCol(tblInfo.Columns, spec.Column.Name)
	if columnInfo != nil {
		if columnInfo.State == model.StatePublic {
			// we already have a column with same column name
			job.State = model.JobCancelled
			return errors.Errorf("ADD COLUMN: column already exist %s", spec.Column.Name)
		}
	} else {
		columnInfo, offset, err = d.addColumn(tblInfo, spec)
		if err != nil {
			job.State = model.JobCancelled
			return errors.Trace(err)
		}

		// Set offset arg to job.
		if offset != 0 {
			job.Args = []interface{}{spec, offset}
		}
	}

	_, err = t.GenSchemaVersion()
	if err != nil {
		return errors.Trace(err)
	}

	switch columnInfo.State {
	case model.StateNone:
		// none -> delete only
		job.SchemaState = model.StateDeleteOnly
		columnInfo.State = model.StateDeleteOnly
		err = t.UpdateTable(schemaID, tblInfo)
		return errors.Trace(err)
	case model.StateDeleteOnly:
		// delete only -> write only
		job.SchemaState = model.StateWriteOnly
		columnInfo.State = model.StateWriteOnly
		err = t.UpdateTable(schemaID, tblInfo)
		return errors.Trace(err)
	case model.StateWriteOnly:
		// write only -> reorganization
		job.SchemaState = model.StateReorgnization
		columnInfo.State = model.StateReorgnization
		// initialize SnapshotVer to 0 for later reorgnization check.
		job.SnapshotVer = 0
		err = t.UpdateTable(schemaID, tblInfo)
		return errors.Trace(err)
	case model.StateReorgnization:
		// reorganization -> public
		// get the current version for reorgnization if we don't have
		if job.SnapshotVer == 0 {
			var ver kv.Version
			ver, err = d.store.CurrentVersion()
			if err != nil {
				return errors.Trace(err)
			}

			job.SnapshotVer = ver.Ver
		}

		tbl, err := d.getTable(t, schemaID, tblInfo)
		if err != nil {
			return errors.Trace(err)
		}

		err = d.runReorgJob(func() error {
			return d.backfillColumn(tbl, columnInfo, job.SnapshotVer)
		})
		if errors2.ErrorEqual(err, errWaitReorgTimeout) {
			// if timeout, we should return, check for the owner and re-wait job done.
			return nil
		}
		if err != nil {
			return errors.Trace(err)
		}

		// Adjust column offset.
		d.adjustColumnOffset(tblInfo.Columns, tblInfo.Indices, offset)

		columnInfo.State = model.StatePublic

		if err = t.UpdateTable(schemaID, tblInfo); err != nil {
			return errors.Trace(err)
		}

		// finish this job
		job.SchemaState = model.StatePublic
		job.State = model.JobDone
		return nil
	default:
		return errors.Errorf("invalid column state %v", columnInfo.State)
	}
}

func (d *ddl) onColumnDrop(t *meta.Meta, job *model.Job) error {
	// TODO: complete it.
	return nil
}

func (d *ddl) backfillColumn(t table.Table, columnInfo *model.ColumnInfo, version uint64) error {
	seekHandle := int64(0)
	for {
		handles, err := d.getSnapshotRows(t, version, seekHandle)
		if err != nil {
			return errors.Trace(err)
		} else if len(handles) == 0 {
			return nil
		}

		seekHandle = handles[len(handles)-1] + 1
		// TODO: save seekHandle in reorgnization job, so we can resume this job later from this handle.

		err = d.backfillColumnData(t, columnInfo, handles)
		if err != nil {
			return errors.Trace(err)
		}
	}
}

func (d *ddl) backfillColumnData(t table.Table, columnInfo *model.ColumnInfo, handles []int64) error {
	for _, handle := range handles {
		log.Info("backfill column...", handle)

		err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error {
			// First check if row exists.
			exist, err := checkRowExist(txn, t, handle)
			if err != nil {
				return errors.Trace(err)
			} else if !exist {
				// If row doesn't exist, skip it.
				return nil
			}

			backfillKey := t.RecordKey(handle, &column.Col{ColumnInfo: *columnInfo})
			_, err = txn.Get(backfillKey)
			if err != nil && !kv.IsErrNotFound(err) {
				return errors.Trace(err)
			}

			// If row column doesn't exist, we need to backfill column.
			// Lock row first.
			err = txn.LockKeys(t.RecordKey(handle, nil))
			if err != nil {
				return errors.Trace(err)
			}

			value, _, err := tables.GetColDefaultValue(nil, columnInfo)
			if err != nil {
				return errors.Trace(err)
			}

			err = t.SetColValue(txn, backfillKey, value)
			if err != nil {
				return errors.Trace(err)
			}

			return nil
		})

		if err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}
<commit_msg>ddl: add ReOrgHandle to support resume column ddl reorg job.<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package ddl

import (
	"sync/atomic"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb/column"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/meta"
	"github.com/pingcap/tidb/model"
	"github.com/pingcap/tidb/table"
	"github.com/pingcap/tidb/table/tables"
	"github.com/pingcap/tidb/util/errors2"
)

func (d *ddl) adjustColumnOffset(columns []*model.ColumnInfo, indices []*model.IndexInfo, offset int) {
	offsetChanged := make(map[int]int)
	for i := offset; i < len(columns); i++ {
		offsetChanged[columns[i].Offset] = i
		columns[i].Offset = i
	}

	// Update index column offset info.
	for _, idx := range indices {
		for _, col := range idx.Columns {
			newOffset, ok := offsetChanged[col.Offset]
			if ok {
				col.Offset = newOffset
			}
		}
	}
}

func (d *ddl) addColumn(tblInfo *model.TableInfo, spec *AlterSpecification) (*model.ColumnInfo, int, error) {
	// Check column name duplicate.
	cols := tblInfo.Columns
	position := len(cols)

	// Get column position.
	if spec.Position.Type == ColumnPositionFirst {
		position = 0
	} else if spec.Position.Type == ColumnPositionAfter {
		c := findCol(cols, spec.Position.RelativeColumn)
		if c == nil {
			return nil, 0, errors.Errorf("No such column: %v", spec.Column.Name)
		}

		// Insert position is after the mentioned column.
		position = c.Offset + 1
	}

	// TODO: set constraint
	col, _, err := d.buildColumnAndConstraint(position, spec.Column)
	if err != nil {
		return nil, 0, errors.Trace(err)
	}

	colInfo := &col.ColumnInfo
	colInfo.State = model.StateNone
	// To support add column asynchronous, we should mark its offset as the last column.
	// So that we can use origin column offset to get value from row.
	colInfo.Offset = len(cols)

	// Insert col into the right place of the column list.
	newCols := make([]*model.ColumnInfo, 0, len(cols)+1)
	newCols = append(newCols, cols[:position]...)
	newCols = append(newCols, colInfo)
	newCols = append(newCols, cols[position:]...)

	tblInfo.Columns = newCols
	return colInfo, position, nil
}

func (d *ddl) onColumnAdd(t *meta.Meta, job *model.Job) error {
	schemaID := job.SchemaID
	tblInfo, err := d.getTableInfo(t, job)
	if err != nil {
		return errors.Trace(err)
	}

	spec := &AlterSpecification{}
	offset := 0
	err = job.DecodeArgs(&spec, &offset)
	if err != nil {
		job.State = model.JobCancelled
		return errors.Trace(err)
	}

	var columnInfo *model.ColumnInfo
	columnInfo = findCol(tblInfo.Columns, spec.Column.Name)
	if columnInfo != nil {
		if columnInfo.State == model.StatePublic {
			// we already have a column with same column name
			job.State = model.JobCancelled
			return errors.Errorf("ADD COLUMN: column already exist %s", spec.Column.Name)
		}
	} else {
		columnInfo, offset, err = d.addColumn(tblInfo, spec)
		if err != nil {
			job.State = model.JobCancelled
			return errors.Trace(err)
		}

		// Set offset arg to job.
		if offset != 0 {
			job.Args = []interface{}{spec, offset}
		}
	}

	_, err = t.GenSchemaVersion()
	if err != nil {
		return errors.Trace(err)
	}

	switch columnInfo.State {
	case model.StateNone:
		// none -> delete only
		job.SchemaState = model.StateDeleteOnly
		columnInfo.State = model.StateDeleteOnly
		err = t.UpdateTable(schemaID, tblInfo)
		return errors.Trace(err)
	case model.StateDeleteOnly:
		// delete only -> write only
		job.SchemaState = model.StateWriteOnly
		columnInfo.State = model.StateWriteOnly
		err = t.UpdateTable(schemaID, tblInfo)
		return errors.Trace(err)
	case model.StateWriteOnly:
		// write only -> reorganization
		job.SchemaState = model.StateReorgnization
		columnInfo.State = model.StateReorgnization
		// initialize SnapshotVer to 0 for later reorgnization check.
		job.SnapshotVer = 0
		// initialize reorg handle to 0
		job.ReOrgHandle = 0
		atomic.StoreInt64(&d.reOrgHandle, 0)
		err = t.UpdateTable(schemaID, tblInfo)
		return errors.Trace(err)
	case model.StateReorgnization:
		// reorganization -> public
		// get the current version for reorgnization if we don't have
		if job.SnapshotVer == 0 {
			var ver kv.Version
			ver, err = d.store.CurrentVersion()
			if err != nil {
				return errors.Trace(err)
			}

			job.SnapshotVer = ver.Ver
		}

		tbl, err := d.getTable(t, schemaID, tblInfo)
		if err != nil {
			return errors.Trace(err)
		}

		err = d.runReorgJob(func() error {
			return d.backfillColumn(tbl, columnInfo, job.SnapshotVer, job.ReOrgHandle)
		})

		// backfillColumn updates ReOrgHandle after one batch.
		// so we update the job ReOrgHandle here.
		job.ReOrgHandle = atomic.LoadInt64(&d.reOrgHandle)

		if errors2.ErrorEqual(err, errWaitReorgTimeout) {
			// if timeout, we should return, check for the owner and re-wait job done.
			return nil
		}
		if err != nil {
			return errors.Trace(err)
		}

		// Adjust column offset.
		d.adjustColumnOffset(tblInfo.Columns, tblInfo.Indices, offset)

		columnInfo.State = model.StatePublic

		if err = t.UpdateTable(schemaID, tblInfo); err != nil {
			return errors.Trace(err)
		}

		// finish this job
		job.SchemaState = model.StatePublic
		job.State = model.JobDone
		return nil
	default:
		return errors.Errorf("invalid column state %v", columnInfo.State)
	}
}

func (d *ddl) onColumnDrop(t *meta.Meta, job *model.Job) error {
	// TODO: complete it.
	return nil
}

func (d *ddl) backfillColumn(t table.Table, columnInfo *model.ColumnInfo, version uint64, seekHandle int64) error {
	for {
		handles, err := d.getSnapshotRows(t, version, seekHandle)
		if err != nil {
			return errors.Trace(err)
		} else if len(handles) == 0 {
			return nil
		}

		seekHandle = handles[len(handles)-1] + 1
		// TODO: save seekHandle in reorgnization job, so we can resume this job later from this handle.

		err = d.backfillColumnData(t, columnInfo, handles)
		if err != nil {
			return errors.Trace(err)
		}

		// update reOrgHandle here after every successful batch.
		atomic.StoreInt64(&d.reOrgHandle, seekHandle)
	}
}

func (d *ddl) backfillColumnData(t table.Table, columnInfo *model.ColumnInfo, handles []int64) error {
	for _, handle := range handles {
		log.Info("backfill column...", handle)

		err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error {
			// First check if row exists.
			exist, err := checkRowExist(txn, t, handle)
			if err != nil {
				return errors.Trace(err)
			} else if !exist {
				// If row doesn't exist, skip it.
				return nil
			}

			backfillKey := t.RecordKey(handle, &column.Col{ColumnInfo: *columnInfo})
			_, err = txn.Get(backfillKey)
			if err != nil && !kv.IsErrNotFound(err) {
				return errors.Trace(err)
			}

			// If row column doesn't exist, we need to backfill column.
			// Lock row first.
			err = txn.LockKeys(t.RecordKey(handle, nil))
			if err != nil {
				return errors.Trace(err)
			}

			value, _, err := tables.GetColDefaultValue(nil, columnInfo)
			if err != nil {
				return errors.Trace(err)
			}

			err = t.SetColValue(txn, backfillKey, value)
			if err != nil {
				return errors.Trace(err)
			}

			return nil
		})

		if err != nil {
			return errors.Trace(err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
)

type Location struct {
	StatusCode    string `json: "statusCode"`
	StatusMessage string `json: "statusMessage"`
	IpAddress     string `json: "ipAddress"`
	CountryCode   string `json: "countryCode"`
	CountryName   string `json: "countryName"`
	RegionName    string `json: "regionName"`
	CityName      string `json: "cityName"`
	ZipCode       string `json: "zipCode"`
	Latitude      string `json: "latitude"`
	Longitude     string `json: "longitude"`
	TimeZone      string `json: "timeZone"`
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	fmt.Println("Locus: GeoIP Lookup\n")

	api_file, err := os.Open("api")
	defer api_file.Close()
	check(err)
	api_scanner := bufio.NewScanner(api_file)
	check(err)
	api_scanner.Scan()
	if err = api_scanner.Err(); err != nil {
		log.Fatal(err)
	}
	api_key := api_scanner.Text()

	ip_file, err := os.Open("ips")
	defer ip_file.Close()
	check(err)
	ip_scanner := bufio.NewScanner(ip_file)
	check(err)
	ip_scanner.Scan()
	if err = ip_scanner.Err(); err != nil {
		log.Fatal(err)
	}
	ip := ip_scanner.Text()

	request_url := fmt.Sprintf("http://api.ipinfodb.com/v3/ip-city/?key=%s&ip=%s&format=json", api_key, ip)

	resp, err := http.Get(request_url)
	defer resp.Body.Close()
	check(err)

	var location Location
	err = json.NewDecoder(resp.Body).Decode(&location)
	check(err)

	fmt.Printf("\n%v\n", location)
}
<commit_msg>Functions and function composition, ftw<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
)

type Location struct {
	StatusCode    string `json: "statusCode"`
	StatusMessage string `json: "statusMessage"`
	IpAddress     string `json: "ipAddress"`
	CountryCode   string `json: "countryCode"`
	CountryName   string `json: "countryName"`
	RegionName    string `json: "regionName"`
	CityName      string `json: "cityName"`
	ZipCode       string `json: "zipCode"`
	Latitude      string `json: "latitude"`
	Longitude     string `json: "longitude"`
	TimeZone      string `json: "timeZone"`
}

func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func open(filename string) *os.File {
  file, err := os.Open(filename)
  check(err)

  return file
}

func scanner(file *os.File) *bufio.Scanner {
  return bufio.NewScanner(file)
}

func read_line(scanner *bufio.Scanner) string {
	check(scanner.Err())
	scanner.Scan()
	line := scanner.Text()
	check(scanner.Err())

	return line
}

func main() {
	fmt.Println("Locus: GeoIP Lookup")

	api_file := open("api")
	defer api_file.Close()
	api_key := read_line(scanner(api_file))

	ip_file := open("ips")
	defer ip_file.Close()
	ip := read_line(scanner(ip_file))

	request_url := fmt.Sprintf("http://api.ipinfodb.com/v3/ip-city/?key=%s&ip=%s&format=json", api_key, ip)

	resp, err := http.Get(request_url)
	defer resp.Body.Close()
	check(err)

	var location Location
	err = json.NewDecoder(resp.Body).Decode(&location)
	check(err)

	fmt.Printf("\n%v\n", location)
}
<|endoftext|>


<commit_before>package rorm

import redis "gopkg.in/redis.v5"

type RedisQuerier struct {
	Querier
	*redis.Client
	// redis.Cmdable
}
<commit_msg>fix bug.<commit_after>package rorm

import redis "gopkg.in/redis.v5"

type RedisQuerier struct {
	*redis.Client
	// redis.Cmdable
}
<|endoftext|>


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

// +build !appengine

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"

	"code.google.com/p/go.net/websocket"
)

const socketPresent = true

func HandleSocket(path string) {
	http.Handle(path, websocket.Handler(socketHandler))
}

const msgLimit = 1000 // max number of messages to send per session

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()
}

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id   string // client-provided unique id for the process
	Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body string
}

// socketHandler handles the websocket connection for a given present session.
// It handles transcoding Messages to and from JSON format, and starting
// and killing Processes.
func socketHandler(c *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	errc := make(chan error, 1)

	// Decode messages from client and send to the in channel.
	go func() {
		dec := json.NewDecoder(c)
		for {
			var m Message
			if err := dec.Decode(&m); err != nil {
				errc <- err
				return
			}
			in <- &m
		}
	}()

	// Receive messages from the out channel and encode to the client.
	go func() {
		enc := json.NewEncoder(c)
		for m := range out {
			if err := enc.Encode(m); err != nil {
				errc <- err
				return
			}
		}
	}()

	// Start and kill Processes and handle errors.
	proc := make(map[string]*Process)
	for {
		select {
		case m := <-in:
			switch m.Kind {
			case "run":
				proc[m.Id].Kill()
				lOut := limiter(in, out)
				proc[m.Id] = StartProcess(m.Id, m.Body, lOut)
			case "kill":
				proc[m.Id].Kill()
			}
		case err := <-errc:
			// A encode or decode has failed; bail.
			log.Println(err)
			// Shut down any running processes.
			for _, p := range proc {
				p.Kill()
			}
			return
		}
	}
}

// Process represents a running process.
type Process struct {
	id   string
	out  chan<- *Message
	done chan struct{} // closed when wait completes
	run  *exec.Cmd
}

// StartProcess builds and runs the given program, sending its output
// and end event as Messages on the provided channel.
func StartProcess(id, body string, out chan<- *Message) *Process {
	p := &Process{
		id:   id,
		out:  out,
		done: make(chan struct{}),
	}
	cmd, err := p.start(body)
	if err != nil {
		p.end(err)
		return nil
	}
	p.run = cmd
	go p.wait(cmd)
	return p
}

// Kill stops the process if it is running and waits for it to exit.
func (p *Process) Kill() {
	if p == nil {
		return
	}
	if p.run != nil {
		p.run.Process.Kill()
	}
	<-p.done
}

// start builds and starts the given program, sending its output to p.out,
// and returns the associated *exec.Cmd.
func (p *Process) start(body string) (*exec.Cmd, error) {
	// x is the base name for .go and executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// write body to x.go
	defer os.Remove(src)
	if err := ioutil.WriteFile(src, []byte(body), 0666); err != nil {
		return nil, err
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	err := p.cmd(dir, "go", "build", "-o", bin, file).Run()
	defer os.Remove(bin)
	if err != nil {
		return nil, err
	}

	// run x
	cmd := p.cmd("", bin)
	if err = cmd.Start(); err != nil {
		return nil, err
	}
	return cmd, nil
}

// wait waits for the running process to complete and returns its error state.
func (p *Process) wait(cmd *exec.Cmd) {
	defer close(p.done)
	p.end(cmd.Wait())
}

// end sends an "end" message to the client, containing the process id and the
// given error value.
func (p *Process) end(err error) {
	m := &Message{Id: p.id, Kind: "end"}
	if err != nil {
		m.Body = err.Error()
	}
	p.out <- m
}

// cmd builds an *exec.Cmd that writes its standard output and error to the
// Process' output channel.
func (p *Process) cmd(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &messageWriter{p.id, "stdout", p.out}
	cmd.Stderr = &messageWriter{p.id, "stderr", p.out}
	return cmd
}

// messageWriter is an io.Writer that converts all writes to Message sends on
// the out channel with the specified id and kind.
type messageWriter struct {
	id, kind string
	out      chan<- *Message
}

func (w *messageWriter) Write(b []byte) (n int, err error) {
	w.out <- &Message{Id: w.id, Kind: w.kind, Body: string(b)}
	return len(b), nil
}

// limiter returns a channel that wraps dest. Messages sent to the channel are
// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
// is sent to the kill channel, and only "end" messages are passed.
func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
	ch := make(chan *Message)
	go func() {
		n := 0
		for m := range ch {
			switch {
			case n < msgLimit || m.Kind == "end":
				dest <- m
				if m.Kind == "end" {
					return
				}
			case n == msgLimit:
				// Process produced too much output. Kill it.
				kill <- &Message{Id: m.Id, Kind: "kill"}
			}
			n++
		}
	}()
	return ch
}

var tmpdir string

func init() {
	// find real path to temporary directory
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>go.talks/present: code cleanups<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !appengine

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"

	"code.google.com/p/go.net/websocket"
)

const (
	socketPresent = true // tell main.go that socket is implemented
	msgLimit      = 1000 // max number of messages to send per session
)

// HandleSocket registers the websocket handler with http.DefaultServeMux
// under the given path.
func HandleSocket(path string) {
	http.Handle(path, websocket.Handler(socketHandler))
}

// Message is the wire format for the websocket connection to the browser.
// It is used for both sending output messages and receiving commands, as
// distinguished by the Kind field.
type Message struct {
	Id   string // client-provided unique id for the process
	Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
	Body string
}

// socketHandler handles the websocket connection for a given present session.
// It handles transcoding Messages to and from JSON format, and starting
// and killing Processes.
func socketHandler(c *websocket.Conn) {
	in, out := make(chan *Message), make(chan *Message)
	errc := make(chan error, 1)

	// Decode messages from client and send to the in channel.
	go func() {
		dec := json.NewDecoder(c)
		for {
			var m Message
			if err := dec.Decode(&m); err != nil {
				errc <- err
				return
			}
			in <- &m
		}
	}()

	// Receive messages from the out channel and encode to the client.
	go func() {
		enc := json.NewEncoder(c)
		for m := range out {
			if err := enc.Encode(m); err != nil {
				errc <- err
				return
			}
		}
	}()

	// Start and kill Processes and handle errors.
	proc := make(map[string]*Process)
	for {
		select {
		case m := <-in:
			switch m.Kind {
			case "run":
				proc[m.Id].Kill()
				lOut := limiter(in, out)
				proc[m.Id] = StartProcess(m.Id, m.Body, lOut)
			case "kill":
				proc[m.Id].Kill()
			}
		case err := <-errc:
			// A encode or decode has failed; bail.
			log.Println(err)
			// Shut down any running processes.
			for _, p := range proc {
				p.Kill()
			}
			return
		}
	}
}

// Process represents a running process.
type Process struct {
	id   string
	out  chan<- *Message
	done chan struct{} // closed when wait completes
	run  *exec.Cmd
	src  string // source file; to be removed when wait returns
}

// StartProcess builds and runs the given program, sending its output
// and end event as Messages on the provided channel.
func StartProcess(id, body string, out chan<- *Message) *Process {
	p := &Process{
		id:   id,
		out:  out,
		done: make(chan struct{}),
	}
	if err := p.start(body); err != nil {
		p.end(err)
		return nil
	}
	go p.wait()
	return p
}

// Kill stops the process if it is running and waits for it to exit.
func (p *Process) Kill() {
	if p == nil {
		return
	}
	p.run.Process.Kill()
	<-p.done // block until process exits
}

// start runs the given program with "go run", sends its output to p.out,
// and stores the running *exec.Command in the run field.
func (p *Process) start(body string) error {
	// write body to x.go
	src := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq)) + ".go"
	if err := ioutil.WriteFile(src, []byte(body), 0666); err != nil {
		return err
	}

	// run x.go
	dir, file := filepath.Split(src)
	cmd := p.cmd(dir, "go", "run", file)
	if err := cmd.Start(); err != nil {
		os.Remove(src)
		return err
	}

	p.run = cmd
	p.src = src
	return nil
}

// wait waits for the running process to complete
// and sends its error state to the client.
func (p *Process) wait() {
	p.end(p.run.Wait())
	close(p.done) // unblock waiting Kill calls
	os.Remove(p.src)
}

// end sends an "end" message to the client, containing the process id and the
// given error value.
func (p *Process) end(err error) {
	m := &Message{Id: p.id, Kind: "end"}
	if err != nil {
		m.Body = err.Error()
	}
	p.out <- m
}

// cmd builds an *exec.Cmd that writes its standard output and error to the
// Process' output channel.
func (p *Process) cmd(dir string, args ...string) *exec.Cmd {
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &messageWriter{p.id, "stdout", p.out}
	cmd.Stderr = &messageWriter{p.id, "stderr", p.out}
	return cmd
}

// messageWriter is an io.Writer that converts all writes to Message sends on
// the out channel with the specified id and kind.
type messageWriter struct {
	id, kind string
	out      chan<- *Message
}

func (w *messageWriter) Write(b []byte) (n int, err error) {
	w.out <- &Message{Id: w.id, Kind: w.kind, Body: string(b)}
	return len(b), nil
}

// limiter returns a channel that wraps dest. Messages sent to the channel are
// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
// is sent to the kill channel, and only "end" messages are passed.
func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
	ch := make(chan *Message)
	go func() {
		n := 0
		for m := range ch {
			switch {
			case n < msgLimit || m.Kind == "end":
				dest <- m
				if m.Kind == "end" {
					return
				}
			case n == msgLimit:
				// Process produced too much output. Kill it.
				kill <- &Message{Id: m.Id, Kind: "kill"}
			}
			n++
		}
	}()
	return ch
}

var tmpdir string

func init() {
	// find real path to temporary directory
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

var uniq = make(chan int) // a source of numbers for naming temporary files

func init() {
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()
}
<|endoftext|>


<commit_before>package pixelgl

import (
	"fmt"
	"image/color"

	"github.com/faiface/glhf"
	"github.com/faiface/mainthread"
	"github.com/faiface/pixel"
	"github.com/go-gl/mathgl/mgl32"
	"github.com/pkg/errors"
)

// Canvas is an off-screen rectangular BasicTarget and Picture at the same time, that you can draw
// onto.
//
// It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor.
type Canvas struct {
	gf     *GLFrame
	shader *glhf.Shader

	mat    mgl32.Mat3
	col    mgl32.Vec4
	smooth bool
}

// NewCanvas creates a new empty, fully transparent Canvas with given bounds. If the smooth flag is
// set, then stretched Pictures will be smoothed and will not be drawn pixely onto this Canvas.
func NewCanvas(bounds pixel.Rect, smooth bool) *Canvas {
	c := &Canvas{
		gf:     NewGLFrame(bounds),
		mat:    mgl32.Ident3(),
		col:    mgl32.Vec4{1, 1, 1, 1},
		smooth: smooth,
	}

	c.SetBounds(bounds)

	var shader *glhf.Shader
	mainthread.Call(func() {
		var err error
		shader, err = glhf.NewShader(
			canvasVertexFormat,
			canvasUniformFormat,
			canvasVertexShader,
			canvasFragmentShader,
		)
		if err != nil {
			panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader"))
		}
	})
	c.shader = shader

	return c
}

// MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas.
//
// TrianglesPosition, TrianglesColor and TrianglesPicture are supported.
func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
	return &canvasTriangles{
		GLTriangles: NewGLTriangles(c.shader, t),
		dst:         c,
	}
}

// MakePicture create a specialized copy of the supplied Picture that draws onto this Canvas.
//
// PictureColor is supported.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
	if cp, ok := p.(*canvasPicture); ok {
		return &canvasPicture{
			GLPicture: cp.GLPicture,
			dst:       c,
		}
	}
	if gp, ok := p.(GLPicture); ok {
		return &canvasPicture{
			GLPicture: gp,
			dst:       c,
		}
	}
	return &canvasPicture{
		GLPicture: NewGLPicture(p),
		dst:       c,
	}
}

// SetMatrix sets a Matrix that every point will be projected by.
func (c *Canvas) SetMatrix(m pixel.Matrix) {
	for i := range m {
		c.mat[i] = float32(m[i])
	}
}

// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
func (c *Canvas) SetColorMask(col color.Color) {
	rgba := pixel.RGBA{R: 1, G: 1, B: 1, A: 1}
	if col != nil {
		rgba = pixel.ToRGBA(col)
	}
	c.col = mgl32.Vec4{
		float32(rgba.R),
		float32(rgba.G),
		float32(rgba.B),
		float32(rgba.A),
	}
}

// SetBounds resizes the Canvas to the new bounds. Old content will be preserved.
func (c *Canvas) SetBounds(bounds pixel.Rect) {
	c.gf.SetBounds(bounds)
}

// Bounds returns the rectangular bounds of the Canvas.
func (c *Canvas) Bounds() pixel.Rect {
	return c.gf.Bounds()
}

// SetSmooth sets whether stretched Pictures drawn onto this Canvas should be drawn smooth or
// pixely.
func (c *Canvas) SetSmooth(smooth bool) {
	c.smooth = smooth
}

// Smooth returns whether stretched Pictures drawn onto this Canvas are set to be drawn smooth or
// pixely.
func (c *Canvas) Smooth() bool {
	return c.smooth
}

// must be manually called inside mainthread
func (c *Canvas) setGlhfBounds() {
	bx, by, bw, bh := intBounds(c.gf.Bounds())
	glhf.Bounds(bx, by, bw, bh)
}

// Clear fills the whole Canvas with a single color.
func (c *Canvas) Clear(color color.Color) {
	c.gf.Dirty()

	rgba := pixel.ToRGBA(color)

	// color masking
	rgba = rgba.Mul(pixel.RGBA{
		R: float64(c.col[0]),
		G: float64(c.col[1]),
		B: float64(c.col[2]),
		A: float64(c.col[3]),
	})

	mainthread.CallNonBlock(func() {
		c.setGlhfBounds()
		c.gf.Frame().Begin()
		glhf.Clear(
			float32(rgba.R),
			float32(rgba.G),
			float32(rgba.B),
			float32(rgba.A),
		)
		c.gf.Frame().End()
	})
}

// Color returns the color of the pixel over the given position inside the Canvas.
func (c *Canvas) Color(at pixel.Vec) pixel.RGBA {
	return c.gf.Color(at)
}

// Texture returns the underlying OpenGL Texture of this Canvas.
//
// Implements GLPicture interface.
func (c *Canvas) Texture() *glhf.Texture {
	return c.gf.Texture()
}

type canvasTriangles struct {
	*GLTriangles
	dst *Canvas
}

func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
	ct.dst.gf.Dirty()

	// save the current state vars to avoid race condition
	mat := ct.dst.mat
	col := ct.dst.col

	mainthread.CallNonBlock(func() {
		ct.dst.setGlhfBounds()
		glhf.BlendFunc(glhf.One, glhf.OneMinusSrcAlpha)

		frame := ct.dst.gf.Frame()
		shader := ct.dst.shader

		frame.Begin()
		shader.Begin()

		dstBounds := ct.dst.Bounds()
		shader.SetUniformAttr(canvasBounds, mgl32.Vec4{
			float32(dstBounds.Min.X()),
			float32(dstBounds.Min.Y()),
			float32(dstBounds.W()),
			float32(dstBounds.H()),
		})
		shader.SetUniformAttr(canvasTransform, mat)
		shader.SetUniformAttr(canvasColorMask, col)

		if tex == nil {
			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()
		} else {
			tex.Begin()

			bx, by, bw, bh := intBounds(bounds)
			shader.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
				float32(bx),
				float32(by),
				float32(bw),
				float32(bh),
			})

			if tex.Smooth() != ct.dst.smooth {
				tex.SetSmooth(ct.dst.smooth)
			}

			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()

			tex.End()
		}

		shader.End()
		frame.End()
	})
}

func (ct *canvasTriangles) Draw() {
	ct.draw(nil, pixel.Rect{})
}

type canvasPicture struct {
	GLPicture
	dst *Canvas
}

func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
	ct := t.(*canvasTriangles)
	if cp.dst != ct.dst {
		panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Canvas", cp))
	}
	ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds())
}

const (
	canvasPosition int = iota
	canvasColor
	canvasTexture
	canvasIntensity
)

var canvasVertexFormat = glhf.AttrFormat{
	canvasPosition:  {Name: "position", Type: glhf.Vec2},
	canvasColor:     {Name: "color", Type: glhf.Vec4},
	canvasTexture:   {Name: "texture", Type: glhf.Vec2},
	canvasIntensity: {Name: "intensity", Type: glhf.Float},
}

const (
	canvasTransform int = iota
	canvasColorMask
	canvasBounds
	canvasTexBounds
)

var canvasUniformFormat = glhf.AttrFormat{
	canvasTransform: {Name: "transform", Type: glhf.Mat3},
	canvasColorMask: {Name: "colorMask", Type: glhf.Vec4},
	canvasBounds:    {Name: "bounds", Type: glhf.Vec4},
	canvasTexBounds: {Name: "texBounds", Type: glhf.Vec4},
}

var canvasVertexShader = `
#version 330 core

in vec2 position;
in vec4 color;
in vec2 texture;
in float intensity;

out vec4 Color;
out vec2 Texture;
out float Intensity;

uniform mat3 transform;
uniform vec4 bounds;

void main() {
	vec2 transPos = (transform * vec3(position, 1.0)).xy;
	vec2 normPos = (transPos - bounds.xy) / (bounds.zw) * 2 - vec2(1, 1);
	gl_Position = vec4(normPos, 0.0, 1.0);
	Color = color;
	Texture = texture;
	Intensity = intensity;
}
`

var canvasFragmentShader = `
#version 330 core

in vec4 Color;
in vec2 Texture;
in float Intensity;

out vec4 color;

uniform vec4 colorMask;
uniform vec4 texBounds;
uniform sampler2D tex;

void main() {
	if (Intensity == 0) {
		color = colorMask * Color;
	} else {
		color = vec4(0, 0, 0, 0);
		color += (1 - Intensity) * Color;
		vec2 t = (Texture - texBounds.xy) / texBounds.zw;
		color += Intensity * Color * texture(tex, t);
		color *= colorMask;
	}
}
`
<commit_msg>add Canvas.SetComposeMethod<commit_after>package pixelgl

import (
	"fmt"
	"image/color"

	"github.com/faiface/glhf"
	"github.com/faiface/mainthread"
	"github.com/faiface/pixel"
	"github.com/go-gl/mathgl/mgl32"
	"github.com/pkg/errors"
)

// Canvas is an off-screen rectangular BasicTarget and Picture at the same time, that you can draw
// onto.
//
// It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor.
type Canvas struct {
	gf     *GLFrame
	shader *glhf.Shader

	cmp    pixel.ComposeMethod
	mat    mgl32.Mat3
	col    mgl32.Vec4
	smooth bool
}

var _ pixel.ComposeTarget = (*Canvas)(nil)

// NewCanvas creates a new empty, fully transparent Canvas with given bounds. If the smooth flag is
// set, then stretched Pictures will be smoothed and will not be drawn pixely onto this Canvas.
func NewCanvas(bounds pixel.Rect, smooth bool) *Canvas {
	c := &Canvas{
		gf:     NewGLFrame(bounds),
		mat:    mgl32.Ident3(),
		col:    mgl32.Vec4{1, 1, 1, 1},
		smooth: smooth,
	}

	c.SetBounds(bounds)

	var shader *glhf.Shader
	mainthread.Call(func() {
		var err error
		shader, err = glhf.NewShader(
			canvasVertexFormat,
			canvasUniformFormat,
			canvasVertexShader,
			canvasFragmentShader,
		)
		if err != nil {
			panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader"))
		}
	})
	c.shader = shader

	return c
}

// MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas.
//
// TrianglesPosition, TrianglesColor and TrianglesPicture are supported.
func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
	return &canvasTriangles{
		GLTriangles: NewGLTriangles(c.shader, t),
		dst:         c,
	}
}

// MakePicture create a specialized copy of the supplied Picture that draws onto this Canvas.
//
// PictureColor is supported.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
	if cp, ok := p.(*canvasPicture); ok {
		return &canvasPicture{
			GLPicture: cp.GLPicture,
			dst:       c,
		}
	}
	if gp, ok := p.(GLPicture); ok {
		return &canvasPicture{
			GLPicture: gp,
			dst:       c,
		}
	}
	return &canvasPicture{
		GLPicture: NewGLPicture(p),
		dst:       c,
	}
}

// SetMatrix sets a Matrix that every point will be projected by.
func (c *Canvas) SetMatrix(m pixel.Matrix) {
	for i := range m {
		c.mat[i] = float32(m[i])
	}
}

// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
func (c *Canvas) SetColorMask(col color.Color) {
	rgba := pixel.RGBA{R: 1, G: 1, B: 1, A: 1}
	if col != nil {
		rgba = pixel.ToRGBA(col)
	}
	c.col = mgl32.Vec4{
		float32(rgba.R),
		float32(rgba.G),
		float32(rgba.B),
		float32(rgba.A),
	}
}

// SetComposeMethod sets a Porter-Duff composition method to be used in the following draws onto
// this Canvas.
func (c *Canvas) SetComposeMethod(cmp pixel.ComposeMethod) {
	c.cmp = cmp
}

// SetBounds resizes the Canvas to the new bounds. Old content will be preserved.
func (c *Canvas) SetBounds(bounds pixel.Rect) {
	c.gf.SetBounds(bounds)
}

// Bounds returns the rectangular bounds of the Canvas.
func (c *Canvas) Bounds() pixel.Rect {
	return c.gf.Bounds()
}

// SetSmooth sets whether stretched Pictures drawn onto this Canvas should be drawn smooth or
// pixely.
func (c *Canvas) SetSmooth(smooth bool) {
	c.smooth = smooth
}

// Smooth returns whether stretched Pictures drawn onto this Canvas are set to be drawn smooth or
// pixely.
func (c *Canvas) Smooth() bool {
	return c.smooth
}

// must be manually called inside mainthread
func (c *Canvas) setGlhfBounds() {
	bx, by, bw, bh := intBounds(c.gf.Bounds())
	glhf.Bounds(bx, by, bw, bh)
}

// must be manually called inside mainthread
func (c *Canvas) setBlendFunc() {
	switch c.cmp {
	case pixel.ComposeOver:
		glhf.BlendFunc(glhf.One, glhf.OneMinusSrcAlpha)
	case pixel.ComposeIn:
		glhf.BlendFunc(glhf.DstAlpha, glhf.Zero)
	case pixel.ComposeOut:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.Zero)
	case pixel.ComposeAtop:
		glhf.BlendFunc(glhf.DstAlpha, glhf.OneMinusSrcAlpha)
	case pixel.ComposeDstOver:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.One)
	case pixel.ComposeDstIn:
		glhf.BlendFunc(glhf.Zero, glhf.SrcAlpha)
	case pixel.ComposeDstOut:
		glhf.BlendFunc(glhf.Zero, glhf.OneMinusSrcAlpha)
	case pixel.ComposeDstAtop:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.SrcAlpha)
	case pixel.ComposeXor:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.OneMinusSrcAlpha)
	default:
		panic(errors.New("Canvas: invalid compose method"))
	}
}

// Clear fills the whole Canvas with a single color.
func (c *Canvas) Clear(color color.Color) {
	c.gf.Dirty()

	rgba := pixel.ToRGBA(color)

	// color masking
	rgba = rgba.Mul(pixel.RGBA{
		R: float64(c.col[0]),
		G: float64(c.col[1]),
		B: float64(c.col[2]),
		A: float64(c.col[3]),
	})

	mainthread.CallNonBlock(func() {
		c.setGlhfBounds()
		c.gf.Frame().Begin()
		glhf.Clear(
			float32(rgba.R),
			float32(rgba.G),
			float32(rgba.B),
			float32(rgba.A),
		)
		c.gf.Frame().End()
	})
}

// Color returns the color of the pixel over the given position inside the Canvas.
func (c *Canvas) Color(at pixel.Vec) pixel.RGBA {
	return c.gf.Color(at)
}

// Texture returns the underlying OpenGL Texture of this Canvas.
//
// Implements GLPicture interface.
func (c *Canvas) Texture() *glhf.Texture {
	return c.gf.Texture()
}

type canvasTriangles struct {
	*GLTriangles
	dst *Canvas
}

func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
	ct.dst.gf.Dirty()

	// save the current state vars to avoid race condition
	mat := ct.dst.mat
	col := ct.dst.col

	mainthread.CallNonBlock(func() {
		ct.dst.setGlhfBounds()
		ct.dst.setBlendFunc()

		frame := ct.dst.gf.Frame()
		shader := ct.dst.shader

		frame.Begin()
		shader.Begin()

		dstBounds := ct.dst.Bounds()
		shader.SetUniformAttr(canvasBounds, mgl32.Vec4{
			float32(dstBounds.Min.X()),
			float32(dstBounds.Min.Y()),
			float32(dstBounds.W()),
			float32(dstBounds.H()),
		})
		shader.SetUniformAttr(canvasTransform, mat)
		shader.SetUniformAttr(canvasColorMask, col)

		if tex == nil {
			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()
		} else {
			tex.Begin()

			bx, by, bw, bh := intBounds(bounds)
			shader.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
				float32(bx),
				float32(by),
				float32(bw),
				float32(bh),
			})

			if tex.Smooth() != ct.dst.smooth {
				tex.SetSmooth(ct.dst.smooth)
			}

			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()

			tex.End()
		}

		shader.End()
		frame.End()
	})
}

func (ct *canvasTriangles) Draw() {
	ct.draw(nil, pixel.Rect{})
}

type canvasPicture struct {
	GLPicture
	dst *Canvas
}

func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
	ct := t.(*canvasTriangles)
	if cp.dst != ct.dst {
		panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Canvas", cp))
	}
	ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds())
}

const (
	canvasPosition int = iota
	canvasColor
	canvasTexture
	canvasIntensity
)

var canvasVertexFormat = glhf.AttrFormat{
	canvasPosition:  {Name: "position", Type: glhf.Vec2},
	canvasColor:     {Name: "color", Type: glhf.Vec4},
	canvasTexture:   {Name: "texture", Type: glhf.Vec2},
	canvasIntensity: {Name: "intensity", Type: glhf.Float},
}

const (
	canvasTransform int = iota
	canvasColorMask
	canvasBounds
	canvasTexBounds
)

var canvasUniformFormat = glhf.AttrFormat{
	canvasTransform: {Name: "transform", Type: glhf.Mat3},
	canvasColorMask: {Name: "colorMask", Type: glhf.Vec4},
	canvasBounds:    {Name: "bounds", Type: glhf.Vec4},
	canvasTexBounds: {Name: "texBounds", Type: glhf.Vec4},
}

var canvasVertexShader = `
#version 330 core

in vec2 position;
in vec4 color;
in vec2 texture;
in float intensity;

out vec4 Color;
out vec2 Texture;
out float Intensity;

uniform mat3 transform;
uniform vec4 bounds;

void main() {
	vec2 transPos = (transform * vec3(position, 1.0)).xy;
	vec2 normPos = (transPos - bounds.xy) / (bounds.zw) * 2 - vec2(1, 1);
	gl_Position = vec4(normPos, 0.0, 1.0);
	Color = color;
	Texture = texture;
	Intensity = intensity;
}
`

var canvasFragmentShader = `
#version 330 core

in vec4 Color;
in vec2 Texture;
in float Intensity;

out vec4 color;

uniform vec4 colorMask;
uniform vec4 texBounds;
uniform sampler2D tex;

void main() {
	if (Intensity == 0) {
		color = colorMask * Color;
	} else {
		color = vec4(0, 0, 0, 0);
		color += (1 - Intensity) * Color;
		vec2 t = (Texture - texBounds.xy) / texBounds.zw;
		color += Intensity * Color * texture(tex, t);
		color *= colorMask;
	}
}
`
<|endoftext|>


<commit_before>package api

import (
	"log"
	"fmt"
	"net/url"
	"net/http"
	"encoding/json"
	"net/http/httputil"
)

const QUERY_STRING = "select temp_high, temp_low, temp_med, temp_coll from puffer where time > now() - 1h order desc limit 1"

type column string
type point int

type QueryResult struct {
	Name    string
	Columns []column
	Points  [][]point
}

// FetchPufferData is for getting the latest puffer data
func FetchPufferData(options *Options) (*Info, error) {

	baseUrl := options.Url
	if baseUrl == "" {
		return nil, fmt.Errorf("No influxdb URL provided")
	}
	url :=
		fmt.Sprintf(options.Url+"?u=%s&p=%s&q=%s",
			url.QueryEscape(options.User), url.QueryEscape(options.Password), url.QueryEscape(QUERY_STRING))
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	client := &http.Client{}

	data := make([]QueryResult, 0)

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	dump, _ := httputil.DumpResponse(resp, true)

	log.Print(string(dump[:]))
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return nil, err
	}

	result := data[0]

	fmt.Printf("%+v\n", result)
	var collector, high, med, low float32
	for i := 0; i < len(result.Columns); i++ {
		key := result.Columns[i]
		value := result.Points[0][i]
		if key == "temp_coll" {
			collector = float32(value / 10)
		} else if key == "temp_high" {
			high = float32(value / 10)
		} else if key == "temp_med" {
			med = float32(value / 10)
		} else if key == "temp_low" {
			low = float32(value / 10)
		}
	}

	log.Printf("High: %f -- Med: %f -- Low: %f -- Collector: %f", high, med, low, collector)

	return &Info{
		CollectorTemp: collector,
		HighTemp:      high,
		LowTemp:       low,
		MidTemp:       med,
	}, nil
}
<commit_msg>worked on<commit_after>package api

import (
	"log"
	"fmt"
	"net/url"
	"net/http"
	"encoding/json"
	"net/http/httputil"
)

const QUERY_STRING = "select temp_high, temp_low, temp_med, temp_coll from puffer where time > now() - 1h order desc limit 1"

type column string
type point int

type points [][]point
type QueryResult struct {
	Name    string
	Columns []column
	Points  points
}

// FetchPufferData is for getting the latest puffer data
func FetchPufferData(options *Options) (*Info, error) {

	baseUrl := options.Url
	if baseUrl == "" {
		return nil, fmt.Errorf("No influxdb URL provided")
	}
	url :=
		fmt.Sprintf(options.Url+"?u=%s&p=%s&q=%s",
			url.QueryEscape(options.User), url.QueryEscape(options.Password), url.QueryEscape(QUERY_STRING))
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	client := &http.Client{}

	data := make([]QueryResult, 0)

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	dump, _ := httputil.DumpResponse(resp, true)

	log.Print(string(dump[:]))
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return nil, err
	}

	result := data[0]

	fmt.Printf("%+v\n", result)
	var collector, high, med, low float32
	for i := 0; i < len(result.Columns); i++ {
		key := result.Columns[i]
		value := result.Points[0][i]
		if key == "temp_coll" {
			collector = float32(value / 10)
		} else if key == "temp_high" {
			high = float32(value / 10)
		} else if key == "temp_med" {
			med = float32(value / 10)
		} else if key == "temp_low" {
			low = float32(value / 10)
		}
	}

	log.Printf("High: %f -- Med: %f -- Low: %f -- Collector: %f", high, med, low, collector)

	return &Info{
		CollectorTemp: collector,
		HighTemp:      high,
		LowTemp:       low,
		MidTemp:       med,
	}, nil
}
<|endoftext|>


<commit_before>package v1

import (
	"net/http"

	"github.com/gitpods/gitpods/pkg/api/v1/models"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi/operations"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi/operations/repositories"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi/operations/users"
	"github.com/gitpods/gitpods/pkg/gitpods/repository"
	"github.com/gitpods/gitpods/pkg/gitpods/user"
	"github.com/gitpods/gitpods/pkg/session"
	"github.com/go-openapi/loads"
	"github.com/go-openapi/runtime/middleware"
	"github.com/go-openapi/strfmt"
)

// API has the http.Handler for the OpenAPI implementation
type API struct {
	Handler http.Handler
}

// New creates a new API that adds our own Handler implementations
func New(rs repository.Service, us user.Service) (*API, error) {
	swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
	if err != nil {
		return nil, err
	}

	gitpodsAPI := operations.NewGitpodsAPI(swaggerSpec)

	gitpodsAPI.RepositoriesCreateRepositoryHandler = CreateRepositoryHandler(rs)
	gitpodsAPI.RepositoriesGetOwnerRepositoriesHandler = GetOwnerRepositoriesHandler(rs)
	gitpodsAPI.RepositoriesGetRepositoryBranchesHandler = GetRepositoryBranchesHandler(rs)
	gitpodsAPI.RepositoriesGetRepositoryHandler = GetRepositoryHandler(rs)
	gitpodsAPI.UsersGetUserHandler = GetUserHandler(us)
	gitpodsAPI.UsersGetUserMeHandler = GetUserMeHandler(us)
	gitpodsAPI.UsersListUsersHandler = ListUsersHandler(us)
	gitpodsAPI.UsersUpdateUserHandler = UpdateUserHandler(us)

	return &API{
		Handler: gitpodsAPI.Serve(nil),
	}, nil
}

func convertRepository(r *repository.Repository) *models.Repository {
	return &models.Repository{
		ID:            strfmt.UUID(r.ID),
		Name:          &r.Name,
		Description:   r.Description,
		DefaultBranch: r.DefaultBranch,
		Website:       r.Website,
		CreatedAt:     strfmt.DateTime(r.Created),
		UpdatedAt:     strfmt.DateTime(r.Updated),

		//Owner: nil, // TODO: Include via query parameter if wanted
	}
}

//CreateRepositoryHandler creates a new repository from given input
func CreateRepositoryHandler(rs repository.Service) repositories.CreateRepositoryHandlerFunc {
	return func(params repositories.CreateRepositoryParams) middleware.Responder {
		ctx := params.HTTPRequest.Context()
		owner := session.GetSessionUser(ctx)

		r, err := rs.Create(ctx, owner.Username, &repository.Repository{
			Name:        *params.NewRepository.Name,
			Description: params.NewRepository.Description,
			Website:     params.NewRepository.Website,
		})
		if err != nil {
			if v, ok := err.(repository.ValidationErrors); ok {
				message := "The given repository input is invalid"
				payload := &models.ValidationError{
					Message: &message,
				}
				for _, verr := range v.Errors {
					payload.Errors = append(payload.Errors, &models.ValidationErrorErrorsItems0{
						Field:   verr.Field,
						Message: verr.Error.Error(),
					})
				}
				return repositories.NewCreateRepositoryUnprocessableEntity().WithPayload(payload)
			}

			return repositories.NewCreateRepositoryDefault(http.StatusInternalServerError)
		}

		return repositories.NewCreateRepositoryOK().WithPayload(convertRepository(r))
	}
}

//GetOwnerRepositoriesHandler gets a repository by the owner's username
func GetOwnerRepositoriesHandler(rs repository.Service) repositories.GetOwnerRepositoriesHandlerFunc {
	return func(params repositories.GetOwnerRepositoriesParams) middleware.Responder {
		list, _, err := rs.List(params.HTTPRequest.Context(), params.Owner)
		if err != nil {
			if err == repository.ErrOwnerNotFound {
				message := "owner not found"
				return repositories.NewGetOwnerRepositoriesNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return repositories.NewGetOwnerRepositoriesDefault(http.StatusInternalServerError)
		}

		var payload []*models.Repository
		for _, r := range list {
			payload = append(payload, convertRepository(r))
		}

		return repositories.NewGetOwnerRepositoriesOK().WithPayload(payload)
	}
}

//GetRepositoryBranchesHandler gets all branches of a repository
func GetRepositoryBranchesHandler(rs repository.Service) repositories.GetRepositoryBranchesHandlerFunc {
	return func(params repositories.GetRepositoryBranchesParams) middleware.Responder {
		branches, err := rs.Branches(params.HTTPRequest.Context(), params.Owner, params.Name)
		if err != nil {
			if err == repository.ErrRepositoryNotFound {
				message := "repository not found"
				return repositories.NewGetRepositoryBranchesNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}

			return repositories.NewGetRepositoryBranchesDefault(http.StatusInternalServerError)
		}

		var payload []*models.Branch

		for _, b := range branches {
			payload = append(payload, &models.Branch{
				Name: b.Name,
				Sha1: b.Sha1,
				Type: b.Type,
			})
		}

		return repositories.NewGetRepositoryBranchesOK().WithPayload(payload)
	}
}

//GetRepositoryHandler gets a repository by name and the owner's username
func GetRepositoryHandler(rs repository.Service) repositories.GetRepositoryHandlerFunc {
	return func(params repositories.GetRepositoryParams) middleware.Responder {
		r, _, err := rs.Find(params.HTTPRequest.Context(), params.Owner, params.Name)
		if err != nil {
			if err == repository.ErrRepositoryNotFound {
				message := "repository not found"
				return repositories.NewGetRepositoryNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return repositories.NewGetRepositoryDefault(http.StatusInternalServerError)
		}

		return repositories.NewGetRepositoryOK().WithPayload(convertRepository(r))
	}
}

func convertUser(u *user.User) *models.User {
	return &models.User{
		ID:        strfmt.UUID(u.ID),
		Email:     strfmt.Email(u.Email),
		Username:  &u.Username,
		Name:      u.Name,
		CreatedAt: strfmt.DateTime(u.Created),
		UpdatedAt: strfmt.DateTime(u.Updated),
	}
}

// ListUsersHandler gets a list of users from the user.Service and returns a API response
func ListUsersHandler(us user.Service) users.ListUsersHandlerFunc {
	return func(params users.ListUsersParams) middleware.Responder {
		list, err := us.FindAll(params.HTTPRequest.Context())
		if err != nil {
			return users.NewListUsersDefault(http.StatusInternalServerError)
		}

		var payload []*models.User

		for _, u := range list {
			payload = append(payload, convertUser(u))
		}

		return users.NewListUsersOK().WithPayload(payload)
	}
}

// GetUserMeHandler gets the currently authenticated user
func GetUserMeHandler(us user.Service) users.GetUserMeHandlerFunc {
	return func(params users.GetUserMeParams) middleware.Responder {
		sessUser := session.GetSessionUser(params.HTTPRequest.Context())

		u, err := us.FindByUsername(params.HTTPRequest.Context(), sessUser.Username)
		if err != nil {
			return users.NewGetUserMeDefault(http.StatusInternalServerError)
		}

		return users.NewGetUserMeOK().WithPayload(convertUser(u))
	}
}

// GetUserHandler gets a user from the user.Service and returns a API response
func GetUserHandler(us user.Service) users.GetUserHandlerFunc {
	return func(params users.GetUserParams) middleware.Responder {
		u, err := us.FindByUsername(params.HTTPRequest.Context(), params.Username)
		if err != nil {
			if err == user.ErrNotFound {
				message := "user not found"
				return users.NewGetUserNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return users.NewGetUserDefault(http.StatusInternalServerError)
		}

		return users.NewGetUserOK().WithPayload(convertUser(u))
	}
}

// UpdateUserHandler receives a updated user and returns a API response after updating
func UpdateUserHandler(us user.Service) users.UpdateUserHandlerFunc {
	return func(params users.UpdateUserParams) middleware.Responder {
		old, err := us.FindByUsername(params.HTTPRequest.Context(), params.Username)
		if err != nil {
			if err == user.ErrNotFound {
				message := "user not found"
				return users.NewUpdateUserNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return users.NewUpdateUserDefault(http.StatusInternalServerError)
		}

		old.Name = *params.UpdatedUser.Name

		updated, err := us.Update(params.HTTPRequest.Context(), old)
		if err != nil {
			message := "updated user is invalid"
			return users.NewUpdateUserUnprocessableEntity().WithPayload(&models.ValidationError{
				Message: &message,
			})
		}

		return users.NewUpdateUserOK().WithPayload(convertUser(updated))
	}
}
<commit_msg>Disable redoc UI by disabling swagger middleware<commit_after>package v1

import (
	"net/http"

	"github.com/gitpods/gitpods/pkg/api/v1/models"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi/operations"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi/operations/repositories"
	"github.com/gitpods/gitpods/pkg/api/v1/restapi/operations/users"
	"github.com/gitpods/gitpods/pkg/gitpods/repository"
	"github.com/gitpods/gitpods/pkg/gitpods/user"
	"github.com/gitpods/gitpods/pkg/session"
	"github.com/go-openapi/loads"
	"github.com/go-openapi/runtime/middleware"
	"github.com/go-openapi/strfmt"
)

// API has the http.Handler for the OpenAPI implementation
type API struct {
	Handler http.Handler
}

// New creates a new API that adds our own Handler implementations
func New(rs repository.Service, us user.Service) (*API, error) {
	swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
	if err != nil {
		return nil, err
	}

	gitpodsAPI := operations.NewGitpodsAPI(swaggerSpec)

	gitpodsAPI.Middleware = func(b middleware.Builder) http.Handler {
		return middleware.Spec("", nil, gitpodsAPI.Context().RoutesHandler(b))
	}

	gitpodsAPI.RepositoriesCreateRepositoryHandler = CreateRepositoryHandler(rs)
	gitpodsAPI.RepositoriesGetOwnerRepositoriesHandler = GetOwnerRepositoriesHandler(rs)
	gitpodsAPI.RepositoriesGetRepositoryBranchesHandler = GetRepositoryBranchesHandler(rs)
	gitpodsAPI.RepositoriesGetRepositoryHandler = GetRepositoryHandler(rs)
	gitpodsAPI.UsersGetUserHandler = GetUserHandler(us)
	gitpodsAPI.UsersGetUserMeHandler = GetUserMeHandler(us)
	gitpodsAPI.UsersListUsersHandler = ListUsersHandler(us)
	gitpodsAPI.UsersUpdateUserHandler = UpdateUserHandler(us)

	return &API{
		Handler: gitpodsAPI.Serve(nil),
	}, nil
}

func convertRepository(r *repository.Repository) *models.Repository {
	return &models.Repository{
		ID:            strfmt.UUID(r.ID),
		Name:          &r.Name,
		Description:   r.Description,
		DefaultBranch: r.DefaultBranch,
		Website:       r.Website,
		CreatedAt:     strfmt.DateTime(r.Created),
		UpdatedAt:     strfmt.DateTime(r.Updated),

		//Owner: nil, // TODO: Include via query parameter if wanted
	}
}

//CreateRepositoryHandler creates a new repository from given input
func CreateRepositoryHandler(rs repository.Service) repositories.CreateRepositoryHandlerFunc {
	return func(params repositories.CreateRepositoryParams) middleware.Responder {
		ctx := params.HTTPRequest.Context()
		owner := session.GetSessionUser(ctx)

		r, err := rs.Create(ctx, owner.Username, &repository.Repository{
			Name:        *params.NewRepository.Name,
			Description: params.NewRepository.Description,
			Website:     params.NewRepository.Website,
		})
		if err != nil {
			if v, ok := err.(repository.ValidationErrors); ok {
				message := "The given repository input is invalid"
				payload := &models.ValidationError{
					Message: &message,
				}
				for _, verr := range v.Errors {
					payload.Errors = append(payload.Errors, &models.ValidationErrorErrorsItems0{
						Field:   verr.Field,
						Message: verr.Error.Error(),
					})
				}
				return repositories.NewCreateRepositoryUnprocessableEntity().WithPayload(payload)
			}

			return repositories.NewCreateRepositoryDefault(http.StatusInternalServerError)
		}

		return repositories.NewCreateRepositoryOK().WithPayload(convertRepository(r))
	}
}

//GetOwnerRepositoriesHandler gets a repository by the owner's username
func GetOwnerRepositoriesHandler(rs repository.Service) repositories.GetOwnerRepositoriesHandlerFunc {
	return func(params repositories.GetOwnerRepositoriesParams) middleware.Responder {
		list, _, err := rs.List(params.HTTPRequest.Context(), params.Owner)
		if err != nil {
			if err == repository.ErrOwnerNotFound {
				message := "owner not found"
				return repositories.NewGetOwnerRepositoriesNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return repositories.NewGetOwnerRepositoriesDefault(http.StatusInternalServerError)
		}

		var payload []*models.Repository
		for _, r := range list {
			payload = append(payload, convertRepository(r))
		}

		return repositories.NewGetOwnerRepositoriesOK().WithPayload(payload)
	}
}

//GetRepositoryBranchesHandler gets all branches of a repository
func GetRepositoryBranchesHandler(rs repository.Service) repositories.GetRepositoryBranchesHandlerFunc {
	return func(params repositories.GetRepositoryBranchesParams) middleware.Responder {
		branches, err := rs.Branches(params.HTTPRequest.Context(), params.Owner, params.Name)
		if err != nil {
			if err == repository.ErrRepositoryNotFound {
				message := "repository not found"
				return repositories.NewGetRepositoryBranchesNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}

			return repositories.NewGetRepositoryBranchesDefault(http.StatusInternalServerError)
		}

		var payload []*models.Branch

		for _, b := range branches {
			payload = append(payload, &models.Branch{
				Name: b.Name,
				Sha1: b.Sha1,
				Type: b.Type,
			})
		}

		return repositories.NewGetRepositoryBranchesOK().WithPayload(payload)
	}
}

//GetRepositoryHandler gets a repository by name and the owner's username
func GetRepositoryHandler(rs repository.Service) repositories.GetRepositoryHandlerFunc {
	return func(params repositories.GetRepositoryParams) middleware.Responder {
		r, _, err := rs.Find(params.HTTPRequest.Context(), params.Owner, params.Name)
		if err != nil {
			if err == repository.ErrRepositoryNotFound {
				message := "repository not found"
				return repositories.NewGetRepositoryNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return repositories.NewGetRepositoryDefault(http.StatusInternalServerError)
		}

		return repositories.NewGetRepositoryOK().WithPayload(convertRepository(r))
	}
}

func convertUser(u *user.User) *models.User {
	return &models.User{
		ID:        strfmt.UUID(u.ID),
		Email:     strfmt.Email(u.Email),
		Username:  &u.Username,
		Name:      u.Name,
		CreatedAt: strfmt.DateTime(u.Created),
		UpdatedAt: strfmt.DateTime(u.Updated),
	}
}

// ListUsersHandler gets a list of users from the user.Service and returns a API response
func ListUsersHandler(us user.Service) users.ListUsersHandlerFunc {
	return func(params users.ListUsersParams) middleware.Responder {
		list, err := us.FindAll(params.HTTPRequest.Context())
		if err != nil {
			return users.NewListUsersDefault(http.StatusInternalServerError)
		}

		var payload []*models.User

		for _, u := range list {
			payload = append(payload, convertUser(u))
		}

		return users.NewListUsersOK().WithPayload(payload)
	}
}

// GetUserMeHandler gets the currently authenticated user
func GetUserMeHandler(us user.Service) users.GetUserMeHandlerFunc {
	return func(params users.GetUserMeParams) middleware.Responder {
		sessUser := session.GetSessionUser(params.HTTPRequest.Context())

		u, err := us.FindByUsername(params.HTTPRequest.Context(), sessUser.Username)
		if err != nil {
			return users.NewGetUserMeDefault(http.StatusInternalServerError)
		}

		return users.NewGetUserMeOK().WithPayload(convertUser(u))
	}
}

// GetUserHandler gets a user from the user.Service and returns a API response
func GetUserHandler(us user.Service) users.GetUserHandlerFunc {
	return func(params users.GetUserParams) middleware.Responder {
		u, err := us.FindByUsername(params.HTTPRequest.Context(), params.Username)
		if err != nil {
			if err == user.ErrNotFound {
				message := "user not found"
				return users.NewGetUserNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return users.NewGetUserDefault(http.StatusInternalServerError)
		}

		return users.NewGetUserOK().WithPayload(convertUser(u))
	}
}

// UpdateUserHandler receives a updated user and returns a API response after updating
func UpdateUserHandler(us user.Service) users.UpdateUserHandlerFunc {
	return func(params users.UpdateUserParams) middleware.Responder {
		old, err := us.FindByUsername(params.HTTPRequest.Context(), params.Username)
		if err != nil {
			if err == user.ErrNotFound {
				message := "user not found"
				return users.NewUpdateUserNotFound().WithPayload(&models.Error{
					Message: &message,
				})
			}
			return users.NewUpdateUserDefault(http.StatusInternalServerError)
		}

		old.Name = *params.UpdatedUser.Name

		updated, err := us.Update(params.HTTPRequest.Context(), old)
		if err != nil {
			message := "updated user is invalid"
			return users.NewUpdateUserUnprocessableEntity().WithPayload(&models.ValidationError{
				Message: &message,
			})
		}

		return users.NewUpdateUserOK().WithPayload(convertUser(updated))
	}
}
<|endoftext|>