<commit_before>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

func byteSliceRemove(bytes []byte, from int, to int) []byte {
	copy(bytes[from:], bytes[to:])
	return bytes[:len(bytes)+from-to]
}

func byteSliceInsert(dst []byte, src []byte, pos int) []byte {
	length := len(dst) + len(src)
	if cap(dst) < length {
		s := make([]byte, len(dst), length)
		copy(s, dst)
		dst = s
	}
	dst = dst[:length]
	copy(dst[pos+len(src):], dst[pos:])
	copy(dst[pos:], src)
	return dst

}

func centeringStr(str string, width int) string {
	sub := width - len(str)
	if sub <= 0 {
		return str
	}
	val := ""
	if sub%2 == 0 {
		for i := 0; i < (sub / 2); i++ {
			val += " "
		}
	} else {
		for i := 0; i < (sub/2)+1; i++ {
			val += " "
		}
	}
	val += str

	for i := 0; i < (sub / 2); i++ {
		val += " "
	}
	return val
}

func drawText(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	i := 0
	for _, c := range str {
		termbox.SetCell(x+i, y, c, fg, bg)
		i += runewidth.RuneWidth(c)
	}
}

func drawTextWithAutoNotice(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	pos := 0
	foreColor := fg
	backColor := bg
	fgChanging := false
	bgChanging := false
	t := []byte(str)
	for {
		if len(t) == 0 {
			break
		}
		c, s := utf8.DecodeRune(t)
		if !(bgChanging || fgChanging) && len(t) > s {
			if c == '@' {
				tc, _ := utf8.DecodeRune(t[s:])
				if isScreenNameUsable(tc) {
					backColor = ColorLowlight
					bgChanging = true
				}
			} else {
				found := false
				s2 := 0
				if c == ' ' {
					var tc rune
					tc, s2 = utf8.DecodeRune(t[s:])
					if tc == '#' {
						found = true
					}
				} else if c == '#' && pos == 0 {
					found = true
				}
				if found {
					tc, _ := utf8.DecodeRune(t[s+s2:])
					if tc != ' ' {
						foreColor = ColorBlue
						fgChanging = true
					}
				}
			}
		} else {
			if bgChanging && !isScreenNameUsable(c) {
				backColor = bg
				bgChanging = false
			} else if fgChanging && c == ' ' {
				tc, _ := utf8.DecodeRune(t[s:])
				if tc != '#' {
					foreColor = fg
					fgChanging = false
				}
			}
		}

		termbox.SetCell(x+pos, y, c, foreColor, backColor)
		pos += runewidth.RuneWidth(c)
		t = t[s:]
	}
}

func isScreenNameUsable(r rune) bool {
	if r >= 'a' && r <= 'z' {
		return true
	} else if r >= 'A' && r <= 'Z' {
		return true
	} else if r >= '0' && r <= '9' {
		return true
	} else if r == '_' {
		return true
	}
	return false
}

func fillLine(offset int, y int, bg termbox.Attribute) {
	width, _ := getTermSize()
	x := offset
	for {
		if x >= width {
			break
		}
		termbox.SetCell(x, y, ' ', ColorBackground, bg)
		x++
	}
}

func generateLabelColorByUserID(id int64) termbox.Attribute {
	if val, ok := LabelColorMap[id]; ok {
		return LabelColors[val]
	}

	rand.Seed(id)
	val := rand.Intn(len(LabelColors))
	LabelColorMap[id] = val
	return LabelColors[val]
}

var (
	replacer = strings.NewReplacer(
		"&", "&",
		"<", "<",
		">", ">")
)

func wrapTweets(tweets []anaconda.Tweet) []tweetstatus {
	result := make([]tweetstatus, len(tweets))
	for i := 0; i < len(tweets); i++ {
		tweet := &tweets[i]
		for {
			if tweet.RetweetedStatus != nil {
				tweet = tweet.RetweetedStatus
			} else {
				break
			}
		}
		tweet.Text = replacer.Replace(tweet.Text)
		for _, url := range tweet.Entities.Urls {
			tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
		}
		for _, media := range tweet.ExtendedEntities.Media {
			tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
		}
		result[i] = tweetstatus{Content: &tweets[i]}
	}
	return result
}

func wrapTweet(t *anaconda.Tweet) tweetstatus {
	tweet := t
	for {
		if tweet.RetweetedStatus != nil {
			tweet = tweet.RetweetedStatus
		} else {
			break
		}
	}
	tweet.Text = replacer.Replace(tweet.Text)
	for _, url := range tweet.Entities.Urls {
		tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
	}
	for _, media := range tweet.ExtendedEntities.Media {
		tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
	}
	return tweetstatus{Content: t}
}

func sumTweetLines(tweetsStatusSlice []tweetstatus) int {
	sum := 0
	tweets := tweetsStatusSlice
	for _, t := range tweets {
		sum += t.countLines()
	}
	return sum
}

func openCommand(path string) {
	var commandName string
	switch runtime.GOOS {
	case "linux":
		commandName = "xdg-open"
	case "darwin":
		commandName = "open"
	default:
		return

	}
	exec.Command(commandName, path).Run()
}

const (
	tempDir = "ringot"
)

func downloadMedia(url string) (fullpath string, err error) {
	_, filename := path.Split(url)
	fullpath = filepath.Join(os.TempDir(), tempDir, filename)
	if _, err := os.Stat(fullpath); err == nil {
		return "", os.ErrExist
	}

	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if res.StatusCode != 200 {
		errors.New(res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tempdir := filepath.Join(os.TempDir(), tempDir)
	if _, err := os.Stat(tempdir); err != nil {
		err := os.Mkdir(tempdir, 0775)
		if err != nil {
			return "", err
		}
	}
	file, err := os.OpenFile(fullpath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0664)
	if err != nil {
		return "", err
	}
	defer file.Close()
	file.Write(body)
	return fullpath, nil
}

func openMedia(url string) {
	fullpath, err := downloadMedia(url)
	if err != nil && err != os.ErrExist {
		panic(err)
		return
	}
	openCommand(fullpath)
}

func favoriteTweet(id int64) {
	_, err := api.Favorite(id)
	if err != nil {
		changeBufferState("Err:Favorite")
		return
	}
}

func unfavoriteTweet(id int64) {
	_, err := api.Unfavorite(id)
	if err != nil {
		changeBufferState("Err:Unfavorite")
		return
	}
}

func retweet(id int64) {
	_, err := api.Retweet(id, false)
	if err != nil {
		changeBufferState("Err:Retweet")
		return
	}
}

func changeBufferState(state string) {
	go func() { stateCh <- state }()
}

func getTermSize() (int, int) {
	return termWidth, termHeight
}

func setTermSize(w, h int) {
	termWidth, termHeight = w, h
}

type lock struct {
	mutex   sync.Mutex
	locking uint32
}

// Errors
var (
	ErrAlreayLocking = errors.New("already locking")
)

func (l *lock) lock() error {
	if atomic.LoadUint32(&l.locking) == 1 {
		return ErrAlreayLocking
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 0 {
		atomic.StoreUint32(&l.locking, 1)
	}
	return nil
}

func (l *lock) unlock() {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 1 {
		atomic.StoreUint32(&l.locking, 0)
	}
}

func (l *lock) isLocking() bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	return atomic.LoadUint32(&l.locking) == 1
}
<commit_msg>Fix wrong codes that are warned by go vet<commit_after>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

func byteSliceRemove(bytes []byte, from int, to int) []byte {
	copy(bytes[from:], bytes[to:])
	return bytes[:len(bytes)+from-to]
}

func byteSliceInsert(dst []byte, src []byte, pos int) []byte {
	length := len(dst) + len(src)
	if cap(dst) < length {
		s := make([]byte, len(dst), length)
		copy(s, dst)
		dst = s
	}
	dst = dst[:length]
	copy(dst[pos+len(src):], dst[pos:])
	copy(dst[pos:], src)
	return dst

}

func centeringStr(str string, width int) string {
	sub := width - len(str)
	if sub <= 0 {
		return str
	}
	val := ""
	if sub%2 == 0 {
		for i := 0; i < (sub / 2); i++ {
			val += " "
		}
	} else {
		for i := 0; i < (sub/2)+1; i++ {
			val += " "
		}
	}
	val += str

	for i := 0; i < (sub / 2); i++ {
		val += " "
	}
	return val
}

func drawText(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	i := 0
	for _, c := range str {
		termbox.SetCell(x+i, y, c, fg, bg)
		i += runewidth.RuneWidth(c)
	}
}

func drawTextWithAutoNotice(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	pos := 0
	foreColor := fg
	backColor := bg
	fgChanging := false
	bgChanging := false
	t := []byte(str)
	for {
		if len(t) == 0 {
			break
		}
		c, s := utf8.DecodeRune(t)
		if !(bgChanging || fgChanging) && len(t) > s {
			if c == '@' {
				tc, _ := utf8.DecodeRune(t[s:])
				if isScreenNameUsable(tc) {
					backColor = ColorLowlight
					bgChanging = true
				}
			} else {
				found := false
				s2 := 0
				if c == ' ' {
					var tc rune
					tc, s2 = utf8.DecodeRune(t[s:])
					if tc == '#' {
						found = true
					}
				} else if c == '#' && pos == 0 {
					found = true
				}
				if found {
					tc, _ := utf8.DecodeRune(t[s+s2:])
					if tc != ' ' {
						foreColor = ColorBlue
						fgChanging = true
					}
				}
			}
		} else {
			if bgChanging && !isScreenNameUsable(c) {
				backColor = bg
				bgChanging = false
			} else if fgChanging && c == ' ' {
				tc, _ := utf8.DecodeRune(t[s:])
				if tc != '#' {
					foreColor = fg
					fgChanging = false
				}
			}
		}

		termbox.SetCell(x+pos, y, c, foreColor, backColor)
		pos += runewidth.RuneWidth(c)
		t = t[s:]
	}
}

func isScreenNameUsable(r rune) bool {
	if r >= 'a' && r <= 'z' {
		return true
	} else if r >= 'A' && r <= 'Z' {
		return true
	} else if r >= '0' && r <= '9' {
		return true
	} else if r == '_' {
		return true
	}
	return false
}

func fillLine(offset int, y int, bg termbox.Attribute) {
	width, _ := getTermSize()
	x := offset
	for {
		if x >= width {
			break
		}
		termbox.SetCell(x, y, ' ', ColorBackground, bg)
		x++
	}
}

func generateLabelColorByUserID(id int64) termbox.Attribute {
	if val, ok := LabelColorMap[id]; ok {
		return LabelColors[val]
	}

	rand.Seed(id)
	val := rand.Intn(len(LabelColors))
	LabelColorMap[id] = val
	return LabelColors[val]
}

var (
	replacer = strings.NewReplacer(
		"&", "&",
		"<", "<",
		">", ">")
)

func wrapTweets(tweets []anaconda.Tweet) []tweetstatus {
	result := make([]tweetstatus, len(tweets))
	for i := 0; i < len(tweets); i++ {
		tweet := &tweets[i]
		for {
			if tweet.RetweetedStatus != nil {
				tweet = tweet.RetweetedStatus
			} else {
				break
			}
		}
		tweet.Text = replacer.Replace(tweet.Text)
		for _, url := range tweet.Entities.Urls {
			tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
		}
		for _, media := range tweet.ExtendedEntities.Media {
			tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
		}
		result[i] = tweetstatus{Content: &tweets[i]}
	}
	return result
}

func wrapTweet(t *anaconda.Tweet) tweetstatus {
	tweet := t
	for {
		if tweet.RetweetedStatus != nil {
			tweet = tweet.RetweetedStatus
		} else {
			break
		}
	}
	tweet.Text = replacer.Replace(tweet.Text)
	for _, url := range tweet.Entities.Urls {
		tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
	}
	for _, media := range tweet.ExtendedEntities.Media {
		tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
	}
	return tweetstatus{Content: t}
}

func sumTweetLines(tweetsStatusSlice []tweetstatus) int {
	sum := 0
	tweets := tweetsStatusSlice
	for _, t := range tweets {
		sum += t.countLines()
	}
	return sum
}

func openCommand(path string) {
	var commandName string
	switch runtime.GOOS {
	case "linux":
		commandName = "xdg-open"
	case "darwin":
		commandName = "open"
	default:
		return

	}
	exec.Command(commandName, path).Run()
}

const (
	tempDir = "ringot"
)

func downloadMedia(url string) (fullpath string, err error) {
	_, filename := path.Split(url)
	fullpath = filepath.Join(os.TempDir(), tempDir, filename)
	if _, err := os.Stat(fullpath); err == nil {
		return "", os.ErrExist
	}

	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if res.StatusCode != 200 {
		return "", errors.New(res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tempdir := filepath.Join(os.TempDir(), tempDir)
	if _, err := os.Stat(tempdir); err != nil {
		err := os.Mkdir(tempdir, 0775)
		if err != nil {
			return "", err
		}
	}
	file, err := os.OpenFile(fullpath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0664)
	if err != nil {
		return "", err
	}
	defer file.Close()
	file.Write(body)
	return fullpath, nil
}

func openMedia(url string) {
	fullpath, err := downloadMedia(url)
	if err != nil && err != os.ErrExist {
		panic(err)
	}
	openCommand(fullpath)
}

func favoriteTweet(id int64) {
	_, err := api.Favorite(id)
	if err != nil {
		changeBufferState("Err:Favorite")
		return
	}
}

func unfavoriteTweet(id int64) {
	_, err := api.Unfavorite(id)
	if err != nil {
		changeBufferState("Err:Unfavorite")
		return
	}
}

func retweet(id int64) {
	_, err := api.Retweet(id, false)
	if err != nil {
		changeBufferState("Err:Retweet")
		return
	}
}

func changeBufferState(state string) {
	go func() { stateCh <- state }()
}

func getTermSize() (int, int) {
	return termWidth, termHeight
}

func setTermSize(w, h int) {
	termWidth, termHeight = w, h
}

type lock struct {
	mutex   sync.Mutex
	locking uint32
}

// Errors
var (
	ErrAlreayLocking = errors.New("already locking")
)

func (l *lock) lock() error {
	if atomic.LoadUint32(&l.locking) == 1 {
		return ErrAlreayLocking
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 0 {
		atomic.StoreUint32(&l.locking, 1)
	}
	return nil
}

func (l *lock) unlock() {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 1 {
		atomic.StoreUint32(&l.locking, 0)
	}
}

func (l *lock) isLocking() bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	return atomic.LoadUint32(&l.locking) == 1
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"os/exec"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"github.com/prometheus/client_golang/prometheus"
)

var (
	DescCache = &descCache{
		descs: make(map[string]*prometheus.Desc),
	}
)

type descCache struct {
	sync.RWMutex

	descs map[string]*prometheus.Desc
}

func (dc *descCache) Desc(key string) *prometheus.Desc {
	dc.RLock()
	desc := dc.descs[key]
	dc.RUnlock()
	return desc
}

func (dc *descCache) Set(key string, desc *prometheus.Desc) *prometheus.Desc {
	dc.Lock()
	dc.descs[key] = desc
	dc.Unlock()
	return desc
}

func ScrapeVarnish(ch chan<- prometheus.Metric) ([]byte, error) {
	params := []string{"-j"}
	if VarnishVersion.EqualsOrGreater(4, 1) {
		// 4.1 started to support timeout to exit immediately on connection errors.
		// Before that varnishstat exits immediately on faulty params or connection errors.
		params = append(params, "-t", "0")
	}
	if !StartParams.Params.isEmpty() {
		params = append(params, StartParams.Params.make()...)
	}
	buf, errExec := executeVarnishstat(StartParams.VarnishstatExe, params...)
	if errExec != nil {
		return buf.Bytes(), fmt.Errorf("%s scrape failed: %s", StartParams.VarnishstatExe, errExec)
	}
	return ScrapeVarnishFrom(buf.Bytes(), ch)
}

func ScrapeVarnishFrom(buf []byte, ch chan<- prometheus.Metric) ([]byte, error) {
	// The output JSON annoyingly is not structured so that we could make a nice map[string]struct for it.
	metricsJSON := make(map[string]interface{})
	dec := json.NewDecoder(bytes.NewBuffer(buf))
	dec.UseNumber()
	if err := dec.Decode(&metricsJSON); err != nil {
		return buf, err
	}

	for vName, raw := range metricsJSON {
		if vName == "timestamp" {
			continue
		}
		if dt := reflect.TypeOf(raw); dt.Kind() != reflect.Map {
			if StartParams.Verbose {
				logWarn("Found unexpected data from json: %s: %#v", vName, raw)
			}
			continue
		}
		data, ok := raw.(map[string]interface{})
		if !ok {
			if StartParams.Verbose {
				logWarn("Failed to cast to map[string]interface{}: %s: %#v", vName, raw)
			}
			continue
		}
		var (
			vGroup       = prometheusGroup(vName)
			vDescription string
			vIdentifier  string
			vValue       float64
			iValue       uint64
			vErr         error
		)
		flag, _ := stringProperty(data, "flag")

		if value, ok := data["description"]; ok && vErr == nil {
			if vDescription, ok = value.(string); !ok {
				vErr = fmt.Errorf("%s description it not a string", vName)
			}
		}
		if value, ok := data["ident"]; ok && vErr == nil {
			if vIdentifier, ok = value.(string); !ok {
				vErr = fmt.Errorf("%s ident it not a string", vName)
			}
		}
		if value, ok := data["value"]; ok && vErr == nil {
			if number, ok := value.(json.Number); ok {
				if vValue, vErr = number.Float64(); vErr != nil {
					vErr = fmt.Errorf("%s value float64 error: %s", vName, vErr)
				}
				if flag == "b" {
					if iValue, vErr = strconv.ParseUint(number.String(), 10, 64); vErr != nil {
						vErr = fmt.Errorf("%s value uint64 error: %s", vName, vErr)
					}
				}
			} else {
				vErr = fmt.Errorf("%s value it not a float64", vName)
			}
		}
		if vErr != nil {
			if StartParams.Verbose {
				logWarn(vErr.Error())
			}
			continue
		}

		pName, pDescription, pLabelKeys, pLabelValues := computePrometheusInfo(vName, vGroup, vIdentifier, vDescription)

		descKey := pName + "_" + strings.Join(pLabelKeys, "_")
		pDesc := DescCache.Desc(descKey)
		if pDesc == nil {
			pDesc = DescCache.Set(descKey, prometheus.NewDesc(
				pName,
				pDescription,
				pLabelKeys,
				nil,
			))
		}

		var metricType prometheus.ValueType
		switch flag {
		case "c", "a":
			metricType = prometheus.CounterValue
		case "g":
			metricType = prometheus.GaugeValue
		default:
			metricType = prometheus.GaugeValue
		}

		ch <- prometheus.MustNewConstMetric(pDesc, metricType, vValue, pLabelValues...)

		// augment varnish_backend_up from _happy varnish bitmap value
		// we are only interested in the latest happy value (up or down) on each scrape
		// see draw_line_bitmap function from https://github.com/varnishcache/varnish-cache/blob/master/bin/varnishstat/varnishstat_curses.c
		if pName == "varnish_backend_happy" {
			upName := "varnish_backend_up"
			upDesc := "Backend up as per the latest health probe"
			upValue := 0.0
			if iValue > 0 && (iValue&uint64(1)) > 0 {
				upValue = 1.0
			}

			descKey = upName + "_" + strings.Join(pLabelKeys, "_")
			pDesc = DescCache.Desc(descKey)
			if pDesc == nil {
				pDesc = DescCache.Set(descKey, prometheus.NewDesc(
					upName,
					upDesc,
					pLabelKeys,
					nil,
				))
			}
			ch <- prometheus.MustNewConstMetric(pDesc, prometheus.GaugeValue, upValue, pLabelValues...)
		}
	}
	return buf, nil
}

// Returns the result of 'varnishtat' with optional command line params.
func executeVarnishstat(varnishstatExe string, params ...string) (*bytes.Buffer, error) {
	buf := &bytes.Buffer{}
	var cmd *exec.Cmd
	if len(StartParams.VarnishDockerContainer) == 0 {
		cmd = exec.Command(varnishstatExe, params...)
	} else {
		cmd = exec.Command("docker", append([]string{"exec", "-t", StartParams.VarnishDockerContainer, varnishstatExe}, params...)...)
	}
	cmd.Stdout = buf
	cmd.Stderr = buf
	return buf, cmd.Run()
}

// varnishVersion

type varnishVersion struct {
	Major    int
	Minor    int
	Patch    int
	Revision string
}

func NewVarnishVersion() *varnishVersion {
	return &varnishVersion{
		Major: -1, Minor: -1, Patch: -1,
	}
}

func (v *varnishVersion) EqualsOrGreater(major, minor int) bool {
	if v.Major > major {
		return true
	} else if v.Major == major && v.Minor >= minor {
		return true
	}
	return false
}

func (v *varnishVersion) Valid() bool {
	return v.Major != -1
}

func (v *varnishVersion) Initialize() error {
	return v.queryVersion()
}

func (v *varnishVersion) queryVersion() error {
	buf, err := executeVarnishstat(StartParams.VarnishstatExe, "-V")
	if err != nil {
		return err
	}
	if scanner := bufio.NewScanner(buf); scanner.Scan() {
		return v.parseVersion(scanner.Text())
	}
	return fmt.Errorf("Failed to get varnishstat -V output")
}

func (v *varnishVersion) parseVersion(version string) error {
	r := regexp.MustCompile(`(?P<major>\d+)(\.(?P<minor>\d+))?(\.(?P<patch>\d+))?(.*revision\s(?P<revision>[0-9a-f]*)\))?`)
	match := r.FindStringSubmatch(version)

	parts := make(map[string]string)
	for i, name := range r.SubexpNames() {
		if i != 0 && name != "" {
			parts[name] = match[i]
		}
	}

	if len(parts) > 1 {
		if err := v.set(parts); err != nil {
			return err
		}
	}
	if !v.Valid() {
		return fmt.Errorf("Failed to resolve version from %q", version)
	}
	return nil
}

func (v *varnishVersion) Labels() map[string]string {
	labels := make(map[string]string)
	if v.Major != -1 {
		labels["major"] = strconv.Itoa(v.Major)
	}
	if v.Minor != -1 {
		labels["minor"] = strconv.Itoa(v.Minor)
	}
	if v.Patch != -1 {
		labels["patch"] = strconv.Itoa(v.Patch)
	}
	if v.Revision != "" {
		labels["revision"] = v.Revision
	}
	labels["version"] = v.VersionString()
	return labels
}

func (v *varnishVersion) set(parts map[string]string) error {
	for name, value := range parts {
		// skip empty value
		if len(value) == 0 {
			continue
		}

		// save revision as-is (string)
		if name == "revision" {
			v.Revision = value
			continue
		}

		// convert semver parts to integer and save it
		num, err := strconv.Atoi(value)
		if err != nil {
			return err
		}
		switch name {
		case "major":
			v.Major = num
		case "minor":
			v.Minor = num
		case "patch":
			v.Patch = num
		}
	}
	return nil
}

// Version string with numbers only, no revision.
func (v *varnishVersion) VersionString() string {
	parts := []string{}
	for _, num := range []int{v.Major, v.Minor, v.Patch} {
		if num != -1 {
			parts = append(parts, strconv.Itoa(num))
		}
	}
	return strings.Join(parts, ".")
}

// Full version string, including revision.
func (v *varnishVersion) String() string {
	version := v.VersionString()
	if v.Revision != "" {
		version += " " + v.Revision
	}
	return version
}
<commit_msg>Non-working fix for newer varnishstat JSON with metrics in the "counters" object ``` {   "version": 1,   "timestamp": "2020-09-22T11:55:40",   "counters": {     "MGT.uptime": {       "description": "Management process uptime",       "flag": "c",       "format": "d",       "value": 4725     },     ... ```<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"os/exec"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"github.com/prometheus/client_golang/prometheus"
)

var (
	DescCache = &descCache{
		descs: make(map[string]*prometheus.Desc),
	}
)

type descCache struct {
	sync.RWMutex

	descs map[string]*prometheus.Desc
}

func (dc *descCache) Desc(key string) *prometheus.Desc {
	dc.RLock()
	desc := dc.descs[key]
	dc.RUnlock()
	return desc
}

func (dc *descCache) Set(key string, desc *prometheus.Desc) *prometheus.Desc {
	dc.Lock()
	dc.descs[key] = desc
	dc.Unlock()
	return desc
}

func ScrapeVarnish(ch chan<- prometheus.Metric) ([]byte, error) {
	params := []string{"-j"}
	if VarnishVersion.EqualsOrGreater(4, 1) {
		// 4.1 started to support timeout to exit immediately on connection errors.
		// Before that varnishstat exits immediately on faulty params or connection errors.
		params = append(params, "-t", "0")
	}
	if !StartParams.Params.isEmpty() {
		params = append(params, StartParams.Params.make()...)
	}
	buf, errExec := executeVarnishstat(StartParams.VarnishstatExe, params...)
	if errExec != nil {
		return buf.Bytes(), fmt.Errorf("%s scrape failed: %s", StartParams.VarnishstatExe, errExec)
	}
	return ScrapeVarnishFrom(buf.Bytes(), ch)
}

func ScrapeVarnishFrom(buf []byte, ch chan<- prometheus.Metric) ([]byte, error) {
	// The output JSON annoyingly is not structured so that we could make a nice map[string]struct for it.
	metricsJSON := make(map[string]interface{})
	dec := json.NewDecoder(bytes.NewBuffer(buf))
	dec.UseNumber()
	if err := dec.Decode(&metricsJSON); err != nil {
		return buf, err
	}

	countersJSON := make(map[string]interface{})
	if metricsJSON["version"] == 1 {
		countersJSON = metricsJSON["counters"]
	} else {
		countersJSON = metricsJSON
	}

	for vName, raw := range countersJSON {
		if vName == "version" || vName == "timestamp" {
			continue
		}
		if dt := reflect.TypeOf(raw); dt.Kind() != reflect.Map {
			if StartParams.Verbose {
				logWarn("Found unexpected data from json: %s: %#v", vName, raw)
			}
			continue
		}
		data, ok := raw.(map[string]interface{})
		if !ok {
			if StartParams.Verbose {
				logWarn("Failed to cast to map[string]interface{}: %s: %#v", vName, raw)
			}
			continue
		}
		var (
			vGroup       = prometheusGroup(vName)
			vDescription string
			vIdentifier  string
			vValue       float64
			iValue       uint64
			vErr         error
		)
		flag, _ := stringProperty(data, "flag")

		if value, ok := data["description"]; ok && vErr == nil {
			if vDescription, ok = value.(string); !ok {
				vErr = fmt.Errorf("%s description it not a string", vName)
			}
		}
		if value, ok := data["ident"]; ok && vErr == nil {
			if vIdentifier, ok = value.(string); !ok {
				vErr = fmt.Errorf("%s ident it not a string", vName)
			}
		}
		if value, ok := data["value"]; ok && vErr == nil {
			if number, ok := value.(json.Number); ok {
				if vValue, vErr = number.Float64(); vErr != nil {
					vErr = fmt.Errorf("%s value float64 error: %s", vName, vErr)
				}
				if flag == "b" {
					if iValue, vErr = strconv.ParseUint(number.String(), 10, 64); vErr != nil {
						vErr = fmt.Errorf("%s value uint64 error: %s", vName, vErr)
					}
				}
			} else {
				vErr = fmt.Errorf("%s value it not a float64", vName)
			}
		}
		if vErr != nil {
			if StartParams.Verbose {
				logWarn(vErr.Error())
			}
			continue
		}

		pName, pDescription, pLabelKeys, pLabelValues := computePrometheusInfo(vName, vGroup, vIdentifier, vDescription)

		descKey := pName + "_" + strings.Join(pLabelKeys, "_")
		pDesc := DescCache.Desc(descKey)
		if pDesc == nil {
			pDesc = DescCache.Set(descKey, prometheus.NewDesc(
				pName,
				pDescription,
				pLabelKeys,
				nil,
			))
		}

		var metricType prometheus.ValueType
		switch flag {
		case "c", "a":
			metricType = prometheus.CounterValue
		case "g":
			metricType = prometheus.GaugeValue
		default:
			metricType = prometheus.GaugeValue
		}

		ch <- prometheus.MustNewConstMetric(pDesc, metricType, vValue, pLabelValues...)

		// augment varnish_backend_up from _happy varnish bitmap value
		// we are only interested in the latest happy value (up or down) on each scrape
		// see draw_line_bitmap function from https://github.com/varnishcache/varnish-cache/blob/master/bin/varnishstat/varnishstat_curses.c
		if pName == "varnish_backend_happy" {
			upName := "varnish_backend_up"
			upDesc := "Backend up as per the latest health probe"
			upValue := 0.0
			if iValue > 0 && (iValue&uint64(1)) > 0 {
				upValue = 1.0
			}

			descKey = upName + "_" + strings.Join(pLabelKeys, "_")
			pDesc = DescCache.Desc(descKey)
			if pDesc == nil {
				pDesc = DescCache.Set(descKey, prometheus.NewDesc(
					upName,
					upDesc,
					pLabelKeys,
					nil,
				))
			}
			ch <- prometheus.MustNewConstMetric(pDesc, prometheus.GaugeValue, upValue, pLabelValues...)
		}
	}
	return buf, nil
}

// Returns the result of 'varnishtat' with optional command line params.
func executeVarnishstat(varnishstatExe string, params ...string) (*bytes.Buffer, error) {
	buf := &bytes.Buffer{}
	var cmd *exec.Cmd
	if len(StartParams.VarnishDockerContainer) == 0 {
		cmd = exec.Command(varnishstatExe, params...)
	} else {
		cmd = exec.Command("docker", append([]string{"exec", "-t", StartParams.VarnishDockerContainer, varnishstatExe}, params...)...)
	}
	cmd.Stdout = buf
	cmd.Stderr = buf
	return buf, cmd.Run()
}

// varnishVersion

type varnishVersion struct {
	Major    int
	Minor    int
	Patch    int
	Revision string
}

func NewVarnishVersion() *varnishVersion {
	return &varnishVersion{
		Major: -1, Minor: -1, Patch: -1,
	}
}

func (v *varnishVersion) EqualsOrGreater(major, minor int) bool {
	if v.Major > major {
		return true
	} else if v.Major == major && v.Minor >= minor {
		return true
	}
	return false
}

func (v *varnishVersion) Valid() bool {
	return v.Major != -1
}

func (v *varnishVersion) Initialize() error {
	return v.queryVersion()
}

func (v *varnishVersion) queryVersion() error {
	buf, err := executeVarnishstat(StartParams.VarnishstatExe, "-V")
	if err != nil {
		return err
	}
	if scanner := bufio.NewScanner(buf); scanner.Scan() {
		return v.parseVersion(scanner.Text())
	}
	return fmt.Errorf("Failed to get varnishstat -V output")
}

func (v *varnishVersion) parseVersion(version string) error {
	r := regexp.MustCompile(`(?P<major>\d+)(\.(?P<minor>\d+))?(\.(?P<patch>\d+))?(.*revision\s(?P<revision>[0-9a-f]*)\))?`)
	match := r.FindStringSubmatch(version)

	parts := make(map[string]string)
	for i, name := range r.SubexpNames() {
		if i != 0 && name != "" {
			parts[name] = match[i]
		}
	}

	if len(parts) > 1 {
		if err := v.set(parts); err != nil {
			return err
		}
	}
	if !v.Valid() {
		return fmt.Errorf("Failed to resolve version from %q", version)
	}
	return nil
}

func (v *varnishVersion) Labels() map[string]string {
	labels := make(map[string]string)
	if v.Major != -1 {
		labels["major"] = strconv.Itoa(v.Major)
	}
	if v.Minor != -1 {
		labels["minor"] = strconv.Itoa(v.Minor)
	}
	if v.Patch != -1 {
		labels["patch"] = strconv.Itoa(v.Patch)
	}
	if v.Revision != "" {
		labels["revision"] = v.Revision
	}
	labels["version"] = v.VersionString()
	return labels
}

func (v *varnishVersion) set(parts map[string]string) error {
	for name, value := range parts {
		// skip empty value
		if len(value) == 0 {
			continue
		}

		// save revision as-is (string)
		if name == "revision" {
			v.Revision = value
			continue
		}

		// convert semver parts to integer and save it
		num, err := strconv.Atoi(value)
		if err != nil {
			return err
		}
		switch name {
		case "major":
			v.Major = num
		case "minor":
			v.Minor = num
		case "patch":
			v.Patch = num
		}
	}
	return nil
}

// Version string with numbers only, no revision.
func (v *varnishVersion) VersionString() string {
	parts := []string{}
	for _, num := range []int{v.Major, v.Minor, v.Patch} {
		if num != -1 {
			parts = append(parts, strconv.Itoa(num))
		}
	}
	return strings.Join(parts, ".")
}

// Full version string, including revision.
func (v *varnishVersion) String() string {
	version := v.VersionString()
	if v.Revision != "" {
		version += " " + v.Revision
	}
	return version
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, 2014 The btcsuite developers
 * Copyright (c) 2015 The Decred developers
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

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

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 0
	appPatch uint = 1

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "alpha"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<commit_msg>Catch up dcrwallet version.<commit_after>/*
 * Copyright (c) 2013, 2014 The btcsuite developers
 * Copyright (c) 2015 The Decred developers
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

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

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 0
	appPatch uint = 4

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "alpha"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.1.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<commit_msg>Update version for dev<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.1.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"
<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string
var GitDescribe string

// The main version number that is being run at the moment.
const Version = "0.5.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<commit_msg>version bump<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string
var GitDescribe string

// The main version number that is being run at the moment.
const Version = "0.5.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"
<|endoftext|>


<commit_before>package main

const Version = "0.1.20141210"

// EOF
<commit_msg>version: 0.1.20141215<commit_after>package main

const Version = "0.1.20141215"

// EOF
<|endoftext|>


<commit_before>package mailfull

// Version is a version number.
const Version = "v0.0.4"
<commit_msg>Bump version to v0.0.5<commit_after>package mailfull

// Version is a version number.
const Version = "v0.0.5"
<|endoftext|>


<commit_before>package atlas

const ourVersion = "0.5.0"
<commit_msg>Add APIVersion().<commit_after>package atlas

const ourVersion = "0.5.0"

// APIVersion is the official API (not CLI) version.
func APIVersion() string {
	return ourVersion
}
<|endoftext|>


<commit_before>package libsacloud

// Version バージョン
const Version = "2.0.0-beta4"
<commit_msg>Bump to v2.0.0-beta5<commit_after>package libsacloud

// Version バージョン
const Version = "2.0.0-beta5"
<|endoftext|>


<commit_before>package gps

import "github.com/Masterminds/semver"

// Version represents one of the different types of versions used by gps.
//
// Version composes Constraint, because all versions can be used as a constraint
// (where they allow one, and only one, version - themselves), but constraints
// are not necessarily discrete versions.
//
// Version is an interface, but it contains private methods, which restricts it
// to gps's own internal implementations. We do this for the confluence of
// two reasons: the implementation of Versions is complete (there is no case in
// which we'd need other types), and the implementation relies on type magic
// under the hood, which would be unsafe to do if other dynamic types could be
// hiding behind the interface.
type Version interface {
	Constraint
	// Indicates the type of version - Revision, Branch, Version, or Semver
	Type() string
}

// PairedVersion represents a normal Version, but paired with its corresponding,
// underlying Revision.
type PairedVersion interface {
	Version
	// Underlying returns the immutable Revision that identifies this Version.
	Underlying() Revision
	// Ensures it is impossible to be both a PairedVersion and an
	// UnpairedVersion
	_pair(int)
}

// UnpairedVersion represents a normal Version, with a method for creating a
// VersionPair by indicating the version's corresponding, underlying Revision.
type UnpairedVersion interface {
	Version
	// Is takes the underlying Revision that this UnpairedVersion corresponds
	// to and unites them into a PairedVersion.
	Is(Revision) PairedVersion
	// Ensures it is impossible to be both a PairedVersion and an
	// UnpairedVersion
	_pair(bool)
}

// types are weird
func (branchVersion) _private()  {}
func (branchVersion) _pair(bool) {}
func (plainVersion) _private()   {}
func (plainVersion) _pair(bool)  {}
func (semVersion) _private()     {}
func (semVersion) _pair(bool)    {}
func (versionPair) _private()    {}
func (versionPair) _pair(int)    {}
func (Revision) _private()       {}

// NewBranch creates a new Version to represent a floating version (in
// general, a branch).
func NewBranch(body string) UnpairedVersion {
	return branchVersion(body)
}

// NewVersion creates a Semver-typed Version if the provided version string is
// valid semver, and a plain/non-semver version if not.
func NewVersion(body string) UnpairedVersion {
	sv, err := semver.NewVersion(body)

	if err != nil {
		return plainVersion(body)
	}
	return semVersion{sv: sv}
}

// A Revision represents an immutable versioning identifier.
type Revision string

// String converts the Revision back into a string.
func (r Revision) String() string {
	return string(r)
}

func (r Revision) Type() string {
	return "rev"
}

// Matches is the Revision acting as a constraint; it checks to see if the provided
// version is the same Revision as itself.
func (r Revision) Matches(v Version) bool {
	switch tv := v.(type) {
	case versionTypeUnion:
		return tv.Matches(r)
	case Revision:
		return r == tv
	case versionPair:
		return r == tv.r
	}

	return false
}

// MatchesAny is the Revision acting as a constraint; it checks to see if the provided
// version is the same Revision as itself.
func (r Revision) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(r)
	case Revision:
		return r == tc
	case versionPair:
		return r == tc.r
	}

	return false
}

func (r Revision) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return r
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(r)
	case Revision:
		if r == tc {
			return r
		}
	case versionPair:
		if r == tc.r {
			return r
		}
	}

	return none
}

type branchVersion string

func (v branchVersion) String() string {
	return string(v)
}

func (r branchVersion) Type() string {
	return "branch"
}

func (v branchVersion) Matches(v2 Version) bool {
	switch tv := v2.(type) {
	case versionTypeUnion:
		return tv.Matches(v)
	case branchVersion:
		return v == tv
	case versionPair:
		if tv2, ok := tv.v.(branchVersion); ok {
			return tv2 == v
		}
	}
	return false
}

func (v branchVersion) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(v)
	case branchVersion:
		return v == tc
	case versionPair:
		if tc2, ok := tc.v.(branchVersion); ok {
			return tc2 == v
		}
	}

	return false
}

func (v branchVersion) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case branchVersion:
		if v == tc {
			return v
		}
	case versionPair:
		if tc2, ok := tc.v.(branchVersion); ok {
			if v == tc2 {
				return v
			}
		}
	}

	return none
}

func (v branchVersion) Is(r Revision) PairedVersion {
	return versionPair{
		v: v,
		r: r,
	}
}

type plainVersion string

func (v plainVersion) String() string {
	return string(v)
}

func (r plainVersion) Type() string {
	return "version"
}

func (v plainVersion) Matches(v2 Version) bool {
	switch tv := v2.(type) {
	case versionTypeUnion:
		return tv.Matches(v)
	case plainVersion:
		return v == tv
	case versionPair:
		if tv2, ok := tv.v.(plainVersion); ok {
			return tv2 == v
		}
	}
	return false
}

func (v plainVersion) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(v)
	case plainVersion:
		return v == tc
	case versionPair:
		if tc2, ok := tc.v.(plainVersion); ok {
			return tc2 == v
		}
	}

	return false
}

func (v plainVersion) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case plainVersion:
		if v == tc {
			return v
		}
	case versionPair:
		if tc2, ok := tc.v.(plainVersion); ok {
			if v == tc2 {
				return v
			}
		}
	}

	return none
}

func (v plainVersion) Is(r Revision) PairedVersion {
	return versionPair{
		v: v,
		r: r,
	}
}

type semVersion struct {
	sv *semver.Version
}

func (v semVersion) String() string {
	return v.sv.Original()
}

func (r semVersion) Type() string {
	return "semver"
}

func (v semVersion) Matches(v2 Version) bool {
	switch tv := v2.(type) {
	case versionTypeUnion:
		return tv.Matches(v)
	case semVersion:
		return v.sv.Equal(tv.sv)
	case versionPair:
		if tv2, ok := tv.v.(semVersion); ok {
			return tv2.sv.Equal(v.sv)
		}
	}
	return false
}

func (v semVersion) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(v)
	case semVersion:
		return v.sv.Equal(tc.sv)
	case semverConstraint:
		return tc.Intersect(v) != none
	case versionPair:
		if tc2, ok := tc.v.(semVersion); ok {
			return tc2.sv.Equal(v.sv)
		}
	}

	return false
}

func (v semVersion) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case semVersion:
		if v.sv.Equal(tc.sv) {
			return v
		}
	case semverConstraint:
		return tc.Intersect(v)
	case versionPair:
		if tc2, ok := tc.v.(semVersion); ok {
			if v.sv.Equal(tc2.sv) {
				return v
			}
		}
	}

	return none
}

func (v semVersion) Is(r Revision) PairedVersion {
	return versionPair{
		v: v,
		r: r,
	}
}

type versionPair struct {
	v UnpairedVersion
	r Revision
}

func (v versionPair) String() string {
	return v.v.String()
}

func (v versionPair) Type() string {
	return v.v.Type()
}

func (v versionPair) Underlying() Revision {
	return v.r
}

func (v versionPair) Matches(v2 Version) bool {
	switch tv2 := v2.(type) {
	case versionTypeUnion:
		return tv2.Matches(v)
	case versionPair:
		return v.r == tv2.r
	case Revision:
		return v.r == tv2
	}

	switch tv := v.v.(type) {
	case plainVersion:
		if tv.Matches(v2) {
			return true
		}
	case branchVersion:
		if tv.Matches(v2) {
			return true
		}
	case semVersion:
		if tv2, ok := v2.(semVersion); ok {
			if tv.sv.Equal(tv2.sv) {
				return true
			}
		}
	}

	return false
}

func (v versionPair) MatchesAny(c2 Constraint) bool {
	return c2.Matches(v)
}

func (v versionPair) Intersect(c2 Constraint) Constraint {
	switch tc := c2.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case versionPair:
		if v.r == tc.r {
			return v.r
		}
	case Revision:
		if v.r == tc {
			return v.r
		}
	case semverConstraint:
		if tv, ok := v.v.(semVersion); ok {
			if tc.Intersect(tv) == v.v {
				return v
			}
		}
		// If the semver intersection failed, we know nothing could work
		return none
	}

	switch tv := v.v.(type) {
	case plainVersion, branchVersion:
		if c2.Matches(v) {
			return v
		}
	case semVersion:
		if tv2, ok := c2.(semVersion); ok {
			if tv.sv.Equal(tv2.sv) {
				return v
			}
		}
	}

	return none
}

// compareVersionType is a sort func helper that makes a coarse-grained sorting
// decision based on version type.
//
// Make sure that l and r have already been converted from versionPair (if
// applicable).
func compareVersionType(l, r Version) int {
	// Big fugly double type switch. No reflect, because this can be smack in a hot loop
	switch l.(type) {
	case Revision:
		switch r.(type) {
		case Revision:
			return 0
		case branchVersion, plainVersion, semVersion:
			return 1
		default:
			panic("unknown version type")
		}
	case branchVersion:
		switch r.(type) {
		case Revision:
			return -1
		case branchVersion:
			return 0
		case plainVersion, semVersion:
			return 1
		default:
			panic("unknown version type")
		}

	case plainVersion:
		switch r.(type) {
		case Revision, branchVersion:
			return -1
		case plainVersion:
			return 0
		case semVersion:
			return 1
		default:
			panic("unknown version type")
		}

	case semVersion:
		switch r.(type) {
		case Revision, branchVersion, plainVersion:
			return -1
		case semVersion:
			return 0
		default:
			panic("unknown version type")
		}
	default:
		panic("unknown version type")
	}
}
<commit_msg>One panic can rule them all<commit_after>package gps

import "github.com/Masterminds/semver"

// Version represents one of the different types of versions used by gps.
//
// Version composes Constraint, because all versions can be used as a constraint
// (where they allow one, and only one, version - themselves), but constraints
// are not necessarily discrete versions.
//
// Version is an interface, but it contains private methods, which restricts it
// to gps's own internal implementations. We do this for the confluence of
// two reasons: the implementation of Versions is complete (there is no case in
// which we'd need other types), and the implementation relies on type magic
// under the hood, which would be unsafe to do if other dynamic types could be
// hiding behind the interface.
type Version interface {
	Constraint
	// Indicates the type of version - Revision, Branch, Version, or Semver
	Type() string
}

// PairedVersion represents a normal Version, but paired with its corresponding,
// underlying Revision.
type PairedVersion interface {
	Version
	// Underlying returns the immutable Revision that identifies this Version.
	Underlying() Revision
	// Ensures it is impossible to be both a PairedVersion and an
	// UnpairedVersion
	_pair(int)
}

// UnpairedVersion represents a normal Version, with a method for creating a
// VersionPair by indicating the version's corresponding, underlying Revision.
type UnpairedVersion interface {
	Version
	// Is takes the underlying Revision that this UnpairedVersion corresponds
	// to and unites them into a PairedVersion.
	Is(Revision) PairedVersion
	// Ensures it is impossible to be both a PairedVersion and an
	// UnpairedVersion
	_pair(bool)
}

// types are weird
func (branchVersion) _private()  {}
func (branchVersion) _pair(bool) {}
func (plainVersion) _private()   {}
func (plainVersion) _pair(bool)  {}
func (semVersion) _private()     {}
func (semVersion) _pair(bool)    {}
func (versionPair) _private()    {}
func (versionPair) _pair(int)    {}
func (Revision) _private()       {}

// NewBranch creates a new Version to represent a floating version (in
// general, a branch).
func NewBranch(body string) UnpairedVersion {
	return branchVersion(body)
}

// NewVersion creates a Semver-typed Version if the provided version string is
// valid semver, and a plain/non-semver version if not.
func NewVersion(body string) UnpairedVersion {
	sv, err := semver.NewVersion(body)

	if err != nil {
		return plainVersion(body)
	}
	return semVersion{sv: sv}
}

// A Revision represents an immutable versioning identifier.
type Revision string

// String converts the Revision back into a string.
func (r Revision) String() string {
	return string(r)
}

func (r Revision) Type() string {
	return "rev"
}

// Matches is the Revision acting as a constraint; it checks to see if the provided
// version is the same Revision as itself.
func (r Revision) Matches(v Version) bool {
	switch tv := v.(type) {
	case versionTypeUnion:
		return tv.Matches(r)
	case Revision:
		return r == tv
	case versionPair:
		return r == tv.r
	}

	return false
}

// MatchesAny is the Revision acting as a constraint; it checks to see if the provided
// version is the same Revision as itself.
func (r Revision) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(r)
	case Revision:
		return r == tc
	case versionPair:
		return r == tc.r
	}

	return false
}

func (r Revision) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return r
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(r)
	case Revision:
		if r == tc {
			return r
		}
	case versionPair:
		if r == tc.r {
			return r
		}
	}

	return none
}

type branchVersion string

func (v branchVersion) String() string {
	return string(v)
}

func (r branchVersion) Type() string {
	return "branch"
}

func (v branchVersion) Matches(v2 Version) bool {
	switch tv := v2.(type) {
	case versionTypeUnion:
		return tv.Matches(v)
	case branchVersion:
		return v == tv
	case versionPair:
		if tv2, ok := tv.v.(branchVersion); ok {
			return tv2 == v
		}
	}
	return false
}

func (v branchVersion) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(v)
	case branchVersion:
		return v == tc
	case versionPair:
		if tc2, ok := tc.v.(branchVersion); ok {
			return tc2 == v
		}
	}

	return false
}

func (v branchVersion) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case branchVersion:
		if v == tc {
			return v
		}
	case versionPair:
		if tc2, ok := tc.v.(branchVersion); ok {
			if v == tc2 {
				return v
			}
		}
	}

	return none
}

func (v branchVersion) Is(r Revision) PairedVersion {
	return versionPair{
		v: v,
		r: r,
	}
}

type plainVersion string

func (v plainVersion) String() string {
	return string(v)
}

func (r plainVersion) Type() string {
	return "version"
}

func (v plainVersion) Matches(v2 Version) bool {
	switch tv := v2.(type) {
	case versionTypeUnion:
		return tv.Matches(v)
	case plainVersion:
		return v == tv
	case versionPair:
		if tv2, ok := tv.v.(plainVersion); ok {
			return tv2 == v
		}
	}
	return false
}

func (v plainVersion) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(v)
	case plainVersion:
		return v == tc
	case versionPair:
		if tc2, ok := tc.v.(plainVersion); ok {
			return tc2 == v
		}
	}

	return false
}

func (v plainVersion) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case plainVersion:
		if v == tc {
			return v
		}
	case versionPair:
		if tc2, ok := tc.v.(plainVersion); ok {
			if v == tc2 {
				return v
			}
		}
	}

	return none
}

func (v plainVersion) Is(r Revision) PairedVersion {
	return versionPair{
		v: v,
		r: r,
	}
}

type semVersion struct {
	sv *semver.Version
}

func (v semVersion) String() string {
	return v.sv.Original()
}

func (r semVersion) Type() string {
	return "semver"
}

func (v semVersion) Matches(v2 Version) bool {
	switch tv := v2.(type) {
	case versionTypeUnion:
		return tv.Matches(v)
	case semVersion:
		return v.sv.Equal(tv.sv)
	case versionPair:
		if tv2, ok := tv.v.(semVersion); ok {
			return tv2.sv.Equal(v.sv)
		}
	}
	return false
}

func (v semVersion) MatchesAny(c Constraint) bool {
	switch tc := c.(type) {
	case anyConstraint:
		return true
	case noneConstraint:
		return false
	case versionTypeUnion:
		return tc.MatchesAny(v)
	case semVersion:
		return v.sv.Equal(tc.sv)
	case semverConstraint:
		return tc.Intersect(v) != none
	case versionPair:
		if tc2, ok := tc.v.(semVersion); ok {
			return tc2.sv.Equal(v.sv)
		}
	}

	return false
}

func (v semVersion) Intersect(c Constraint) Constraint {
	switch tc := c.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case semVersion:
		if v.sv.Equal(tc.sv) {
			return v
		}
	case semverConstraint:
		return tc.Intersect(v)
	case versionPair:
		if tc2, ok := tc.v.(semVersion); ok {
			if v.sv.Equal(tc2.sv) {
				return v
			}
		}
	}

	return none
}

func (v semVersion) Is(r Revision) PairedVersion {
	return versionPair{
		v: v,
		r: r,
	}
}

type versionPair struct {
	v UnpairedVersion
	r Revision
}

func (v versionPair) String() string {
	return v.v.String()
}

func (v versionPair) Type() string {
	return v.v.Type()
}

func (v versionPair) Underlying() Revision {
	return v.r
}

func (v versionPair) Matches(v2 Version) bool {
	switch tv2 := v2.(type) {
	case versionTypeUnion:
		return tv2.Matches(v)
	case versionPair:
		return v.r == tv2.r
	case Revision:
		return v.r == tv2
	}

	switch tv := v.v.(type) {
	case plainVersion:
		if tv.Matches(v2) {
			return true
		}
	case branchVersion:
		if tv.Matches(v2) {
			return true
		}
	case semVersion:
		if tv2, ok := v2.(semVersion); ok {
			if tv.sv.Equal(tv2.sv) {
				return true
			}
		}
	}

	return false
}

func (v versionPair) MatchesAny(c2 Constraint) bool {
	return c2.Matches(v)
}

func (v versionPair) Intersect(c2 Constraint) Constraint {
	switch tc := c2.(type) {
	case anyConstraint:
		return v
	case noneConstraint:
		return none
	case versionTypeUnion:
		return tc.Intersect(v)
	case versionPair:
		if v.r == tc.r {
			return v.r
		}
	case Revision:
		if v.r == tc {
			return v.r
		}
	case semverConstraint:
		if tv, ok := v.v.(semVersion); ok {
			if tc.Intersect(tv) == v.v {
				return v
			}
		}
		// If the semver intersection failed, we know nothing could work
		return none
	}

	switch tv := v.v.(type) {
	case plainVersion, branchVersion:
		if c2.Matches(v) {
			return v
		}
	case semVersion:
		if tv2, ok := c2.(semVersion); ok {
			if tv.sv.Equal(tv2.sv) {
				return v
			}
		}
	}

	return none
}

// compareVersionType is a sort func helper that makes a coarse-grained sorting
// decision based on version type.
//
// Make sure that l and r have already been converted from versionPair (if
// applicable).
func compareVersionType(l, r Version) int {
	// Big fugly double type switch. No reflect, because this can be smack in a hot loop
	switch l.(type) {
	case Revision:
		switch r.(type) {
		case Revision:
			return 0
		case branchVersion, plainVersion, semVersion:
			return 1
		}
	case branchVersion:
		switch r.(type) {
		case Revision:
			return -1
		case branchVersion:
			return 0
		case plainVersion, semVersion:
			return 1
		}

	case plainVersion:
		switch r.(type) {
		case Revision, branchVersion:
			return -1
		case plainVersion:
			return 0
		case semVersion:
			return 1
		}

	case semVersion:
		switch r.(type) {
		case Revision, branchVersion, plainVersion:
			return -1
		case semVersion:
			return 0
		}
	}
	panic("unknown version type")
}
<|endoftext|>


<commit_before>package types

import (
	"context"
	"errors"
	"fmt"
	"time"
)

// Backend allows the server to retrieve single files based on snowflake
// and also load and store the index data.
type Backend interface {
	// Name returns an identifier for the backend type
	// This does not need to be equivalent to the driver name.
	Name() string

	// Upload creates a file. If the file already exist, it must abort
	// with an error
	// Upload needs to ensure that no two files with the same name are
	// uploaded, ie operate atomically.
	Upload(name string, file *File, ctx context.Context) error
	// Exists returns nil if the name exists.
	// If the name does not exists, returns ErrorFileNotExist,
	// if an actual error occurs, returns an error instance that is not
	// equal to ErrorFileNotExist
	Exists(name string, ctx context.Context) error
	// Get returns the file associated with the flake in name
	Get(name string, ctx context.Context) (*File, error)
	// Delete Removes a file from the backend
	// This is required to happen atomically and if the file
	// cannot be delete now but only later, it *must* still return an error
	Delete(name string, ctx context.Context) error

	// ListGlob returns a list of all files with the given prefix
	// The returned file structs need to contain the name but need not
	// contain the file data
	ListGlob(ctx context.Context, glob string) (files []*File, err error)

	// RunGC will clean up expired files from the storage backend.
	// On automatically expiring backends, this returns an empty array
	// and a nil error.
	// Otherwise it will return an array of all deleted files minus their
	// content.
	// If Deleting a file fails, the function returns with an error
	// and a full list of files that were about to be deleted.
	RunGC(ctx context.Context) ([]File, error)
}

// File contains the data of a file, if it's public and when it was created.
type File struct {
	// CreatedAt is the creation time of the file
	CreatedAt *DateOnlyTime `json:"created_at"`
	// Public marks if the file is public or not
	Public bool `json:"public,omitempty"`
	// Data is the raw binary data of the file
	Data []byte `json:"data,omitempty"`
	// DeleteAt  is the expiry date of a file
	DeleteAt *DateOnlyTime `json:"delete_at"`
	// Flake is a unique identifier for the file
	Flake string `json:"name"`
	// Content Type sets the Mime Header
	ContentType string `json:"mime"`
	// If this is not empty, use this extension for downloads.
	FileExtension string `json:"ext,omitempty"`
	// Username of who uploaded the file
	User string `json:"usr,omitempty"`
}

// DefaultTTL is the default Time-to-Live of new Objects
const DefaultTTL = time.Hour * 24 * 7

// MaxTTL is the maximum Lifetime of an Object
const MaxTTL = time.Hour * 24 * 30

// MinTTL is the minimum Lifetime of an Object
const MinTTL = time.Hour * 1

// MaxDataSize is the maximum size of a file
const MaxDataSize = 25 * 1024 * 1024

// SkipSize marks how many characters should be grouped when
// splitting filenames. If filenames aren't split, this can be
// ignored.
const SkipSize = 2

// ErrorFileNotExist is returned when a requested file does not
// exist. Non-fatal when returned from backend.Exists().
type ErrorFileNotExist struct {
	Object     string
	InnerError error
}

// Error returns a nested Error Message regarding a missing file
func (e ErrorFileNotExist) Error() string {
	return "ErrFileNotExist(" + e.Object + "): " + e.InnerError.Error()
}

// NewErrorFileNotExists returns a ErrFileNotExist typed error.
func NewErrorFileNotExists(name string, err error) error {
	if err == nil {
		err = errors.New("generic file not exist")
	}
	return ErrorFileNotExist{
		Object:     name,
		InnerError: err,
	}
}

var (
	// ErrorNotImplemented is returned if the underlying interface has
	// not implemented a function. The presence of ErrorNotImplemented is
	// not acceptable for any production-ready backend.
	ErrorNotImplemented = errors.New("Request without Implementation")
	// ErrorExpired is returned when the file that was requested has been
	// found but was deleted because it expired
	ErrorExpired = errors.New("The requested file has expired")
	// ErrorQuotaExceeded is returned when the request issued exceeded a
	// quota in the backend, for example if a file is too large or a publish
	// contains too many flakes.
	ErrorQuotaExceeded = errors.New("Backend aborted because a quota was exceeded")
	// ErrorIncompleteWrite is returned when the underlying data was not
	// written to the backend entirely and may be in an inconsistent state.
	ErrorIncompleteWrite = errors.New("Backend could not complete write")
	// ErrorIndexNoSerialize is returned by index.Serialize() or index.Unserialize() when they
	// are not to be stored in the backend
	ErrorIndexNoSerialize = errors.New("Do not serialize this index")
)

type DateOnlyTime struct {
	time.Time
}

func (dot *DateOnlyTime) UnmarshalJSON(b []byte) (err error) {
	s := string(b)
	if len(s) == 2 {
		return errors.New("Cannot parse empty date")
	}
	s = s[1 : len(s)-1]

	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		return err
	}
	dot.Time = t
	return nil
}

func (dot *DateOnlyTime) MarshalJSON() ([]byte, error) {
	s := dot.Format("2006-01-02")
	s = fmt.Sprintf("\"%s\"", s)
	return []byte(s), nil
}

func FromTime(t time.Time) *DateOnlyTime {
	return &DateOnlyTime{
		Time: t,
	}
}

func FromString(s string) (*DateOnlyTime, error) {
	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		return nil, err
	}
	return FromTime(t), nil
}
<commit_msg>Added TTL to DOT-Time<commit_after>package types

import (
	"context"
	"errors"
	"fmt"
	"time"
)

// Backend allows the server to retrieve single files based on snowflake
// and also load and store the index data.
type Backend interface {
	// Name returns an identifier for the backend type
	// This does not need to be equivalent to the driver name.
	Name() string

	// Upload creates a file. If the file already exist, it must abort
	// with an error
	// Upload needs to ensure that no two files with the same name are
	// uploaded, ie operate atomically.
	Upload(name string, file *File, ctx context.Context) error
	// Exists returns nil if the name exists.
	// If the name does not exists, returns ErrorFileNotExist,
	// if an actual error occurs, returns an error instance that is not
	// equal to ErrorFileNotExist
	Exists(name string, ctx context.Context) error
	// Get returns the file associated with the flake in name
	Get(name string, ctx context.Context) (*File, error)
	// Delete Removes a file from the backend
	// This is required to happen atomically and if the file
	// cannot be delete now but only later, it *must* still return an error
	Delete(name string, ctx context.Context) error

	// ListGlob returns a list of all files with the given prefix
	// The returned file structs need to contain the name but need not
	// contain the file data
	ListGlob(ctx context.Context, glob string) (files []*File, err error)

	// RunGC will clean up expired files from the storage backend.
	// On automatically expiring backends, this returns an empty array
	// and a nil error.
	// Otherwise it will return an array of all deleted files minus their
	// content.
	// If Deleting a file fails, the function returns with an error
	// and a full list of files that were about to be deleted.
	RunGC(ctx context.Context) ([]File, error)
}

// File contains the data of a file, if it's public and when it was created.
type File struct {
	// CreatedAt is the creation time of the file
	CreatedAt *DateOnlyTime `json:"created_at"`
	// Public marks if the file is public or not
	Public bool `json:"public,omitempty"`
	// Data is the raw binary data of the file
	Data []byte `json:"data,omitempty"`
	// DeleteAt  is the expiry date of a file
	DeleteAt *DateOnlyTime `json:"delete_at"`
	// Flake is a unique identifier for the file
	Flake string `json:"name"`
	// Content Type sets the Mime Header
	ContentType string `json:"mime"`
	// If this is not empty, use this extension for downloads.
	FileExtension string `json:"ext,omitempty"`
	// Username of who uploaded the file
	User string `json:"usr,omitempty"`
}

// DefaultTTL is the default Time-to-Live of new Objects
const DefaultTTL = time.Hour * 24 * 7

// MaxTTL is the maximum Lifetime of an Object
const MaxTTL = time.Hour * 24 * 30

// MinTTL is the minimum Lifetime of an Object
const MinTTL = time.Hour * 1

// MaxDataSize is the maximum size of a file
const MaxDataSize = 25 * 1024 * 1024

// SkipSize marks how many characters should be grouped when
// splitting filenames. If filenames aren't split, this can be
// ignored.
const SkipSize = 2

// ErrorFileNotExist is returned when a requested file does not
// exist. Non-fatal when returned from backend.Exists().
type ErrorFileNotExist struct {
	Object     string
	InnerError error
}

// Error returns a nested Error Message regarding a missing file
func (e ErrorFileNotExist) Error() string {
	return "ErrFileNotExist(" + e.Object + "): " + e.InnerError.Error()
}

// NewErrorFileNotExists returns a ErrFileNotExist typed error.
func NewErrorFileNotExists(name string, err error) error {
	if err == nil {
		err = errors.New("generic file not exist")
	}
	return ErrorFileNotExist{
		Object:     name,
		InnerError: err,
	}
}

var (
	// ErrorNotImplemented is returned if the underlying interface has
	// not implemented a function. The presence of ErrorNotImplemented is
	// not acceptable for any production-ready backend.
	ErrorNotImplemented = errors.New("Request without Implementation")
	// ErrorExpired is returned when the file that was requested has been
	// found but was deleted because it expired
	ErrorExpired = errors.New("The requested file has expired")
	// ErrorQuotaExceeded is returned when the request issued exceeded a
	// quota in the backend, for example if a file is too large or a publish
	// contains too many flakes.
	ErrorQuotaExceeded = errors.New("Backend aborted because a quota was exceeded")
	// ErrorIncompleteWrite is returned when the underlying data was not
	// written to the backend entirely and may be in an inconsistent state.
	ErrorIncompleteWrite = errors.New("Backend could not complete write")
	// ErrorIndexNoSerialize is returned by index.Serialize() or index.Unserialize() when they
	// are not to be stored in the backend
	ErrorIndexNoSerialize = errors.New("Do not serialize this index")
)

type DateOnlyTime struct {
	time.Time
}

func (dot *DateOnlyTime) UnmarshalJSON(b []byte) (err error) {
	s := string(b)
	if len(s) == 2 {
		return errors.New("Cannot parse empty date")
	}
	s = s[1 : len(s)-1]

	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		return err
	}
	dot.Time = t
	return nil
}

func (dot *DateOnlyTime) MarshalJSON() ([]byte, error) {
	s := dot.Format("2006-01-02")
	s = fmt.Sprintf("\"%s\"", s)
	return []byte(s), nil
}

func (dot *DateOnlyTime) TTL() time.Duration {
	dead := dot.Unix()
	now := time.Now().UTC().Unix()
	if now >= dead {
		return 0 * time.Second
	}
	return time.Duration(dead-now) * time.Second
}

func FromTime(t time.Time) *DateOnlyTime {
	return &DateOnlyTime{
		Time: t,
	}
}

func FromString(s string) (*DateOnlyTime, error) {
	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		return nil, err
	}
	return FromTime(t), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

type Version struct {
	Major, Minor, Patch int
}

func (v Version) String() string {
	if v.Major < 0 {
		panic(fmt.Sprintf("cannot stringify invalid version (major is %d)", v.Major))
	}
	if v.Minor < 0 {
		return fmt.Sprintf("v%d", v.Major)
	}
	if v.Patch < 0 {
		return fmt.Sprintf("v%d.%d", v.Major, v.Minor)
	}
	return fmt.Sprintf("v%d.%d.%d", v.Major, v.Minor, v.Patch)
}

func (v Version) Less(other Version) bool {
	if v.Major != other.Major {
		return v.Major < other.Major
	}
	if v.Minor != other.Minor {
		return v.Minor < other.Minor
	}
	return v.Patch < other.Patch
}

func (v Version) Contains(other Version) bool {
	if v.Patch != -1 {
		return v == other
	}
	if v.Minor != -1 {
		return v.Major == other.Major && v.Minor == other.Minor
	}
	return v.Major == other.Major
}

func (v Version) IsValid() bool {
	return v == InvalidVersion
}

var InvalidVersion = Version{-1, -1, -1}

func parseVersion(s string) (Version, bool) {
	if len(s) < 2 {
		return InvalidVersion, false
	}
	if s[0] != 'v' {
		return InvalidVersion, false
	}
	v := Version{-1, -1, -1}
	i := 1
	v.Major, i = parseVersionPart(s, i)
	if i < 0 {
		return InvalidVersion, false
	}
	if i == len(s) {
		return v, true
	}
	v.Minor, i = parseVersionPart(s, i)
	if i < 0 {
		return InvalidVersion, false
	}
	if i == len(s) {
		return v, true
	}
	v.Patch, i = parseVersionPart(s, i)
	if i < 0 || i < len(s) {
		return InvalidVersion, false
	}
	return v, true
}

func parseVersionPart(s string, i int) (part int, newi int) {
	dot := i
	for dot < len(s) && s[dot] != '.' {
		dot++
	}
	if dot == i || dot-i > 1 && s[i] == '0' {
		return -1, -1
	}
	for i < len(s) {
		if s[i] < '0' || s[i] > '9' {
			return -1, -1
		}
		part *= 10
		part += int(s[i] - '0')
		if part < 0 {
			return -1, -1
		}
		i++
		if i+1 < len(s) && s[i] == '.' {
			return part, i + 1
		}
	}
	return part, i
}

// VersionList implements sort.Interface
type VersionList []Version

func (vl VersionList) Len() int {
	return len(vl)
}
func (vl VersionList) Less(i, j int) bool {
	return vl[i].Less(vl[j])
}

func (vl VersionList) Swap(i, j int) {
	vl[i], vl[j] = vl[j], vl[i]
}
<commit_msg>Use one-line formatting for VersionList sort.Interface implementations<commit_after>package main

import (
	"fmt"
)

type Version struct {
	Major, Minor, Patch int
}

func (v Version) String() string {
	if v.Major < 0 {
		panic(fmt.Sprintf("cannot stringify invalid version (major is %d)", v.Major))
	}
	if v.Minor < 0 {
		return fmt.Sprintf("v%d", v.Major)
	}
	if v.Patch < 0 {
		return fmt.Sprintf("v%d.%d", v.Major, v.Minor)
	}
	return fmt.Sprintf("v%d.%d.%d", v.Major, v.Minor, v.Patch)
}

func (v Version) Less(other Version) bool {
	if v.Major != other.Major {
		return v.Major < other.Major
	}
	if v.Minor != other.Minor {
		return v.Minor < other.Minor
	}
	return v.Patch < other.Patch
}

func (v Version) Contains(other Version) bool {
	if v.Patch != -1 {
		return v == other
	}
	if v.Minor != -1 {
		return v.Major == other.Major && v.Minor == other.Minor
	}
	return v.Major == other.Major
}

func (v Version) IsValid() bool {
	return v == InvalidVersion
}

var InvalidVersion = Version{-1, -1, -1}

func parseVersion(s string) (Version, bool) {
	if len(s) < 2 {
		return InvalidVersion, false
	}
	if s[0] != 'v' {
		return InvalidVersion, false
	}
	v := Version{-1, -1, -1}
	i := 1
	v.Major, i = parseVersionPart(s, i)
	if i < 0 {
		return InvalidVersion, false
	}
	if i == len(s) {
		return v, true
	}
	v.Minor, i = parseVersionPart(s, i)
	if i < 0 {
		return InvalidVersion, false
	}
	if i == len(s) {
		return v, true
	}
	v.Patch, i = parseVersionPart(s, i)
	if i < 0 || i < len(s) {
		return InvalidVersion, false
	}
	return v, true
}

func parseVersionPart(s string, i int) (part int, newi int) {
	dot := i
	for dot < len(s) && s[dot] != '.' {
		dot++
	}
	if dot == i || dot-i > 1 && s[i] == '0' {
		return -1, -1
	}
	for i < len(s) {
		if s[i] < '0' || s[i] > '9' {
			return -1, -1
		}
		part *= 10
		part += int(s[i] - '0')
		if part < 0 {
			return -1, -1
		}
		i++
		if i+1 < len(s) && s[i] == '.' {
			return part, i + 1
		}
	}
	return part, i
}

// VersionList implements sort.Interface
type VersionList []Version

func (vl VersionList) Len() int           { return len(vl) }
func (vl VersionList) Less(i, j int) bool { return vl[i].Less(vl[j]) }
func (vl VersionList) Swap(i, j int)      { vl[i], vl[j] = vl[j], vl[i] }
<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.1.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<commit_msg>Change the reported version to v0.2.0<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.2.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<|endoftext|>


<commit_before>package version

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// The compiled regular expression used to test the validity of a version.
var (
	versionRegexp *regexp.Regexp
	semverRegexp  *regexp.Regexp
)

// The raw regular expression string used for testing the validity
// of a version.
const (
	VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
		`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` +
		`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` +
		`?`

	// SemverRegexpRaw requires a separator between version and prerelease
	SemverRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
		`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` +
		`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` +
		`?`
)

// Version represents a single version.
type Version struct {
	metadata string
	pre      string
	segments []int64
	si       int
	original string
}

func init() {
	versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$")
	semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$")
}

// NewVersion parses the given version and returns a new
// Version.
func NewVersion(v string) (*Version, error) {
	return newVersion(v, versionRegexp)
}

// NewSemver parses the given version and returns a new
// Version that adheres strictly to SemVer specs
// https://semver.org/
func NewSemver(v string) (*Version, error) {
	return newVersion(v, semverRegexp)
}

func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
	matches := pattern.FindStringSubmatch(v)
	if matches == nil {
		return nil, fmt.Errorf("Malformed version: %s", v)
	}
	segmentsStr := strings.Split(matches[1], ".")
	segments := make([]int64, len(segmentsStr))
	for i, str := range segmentsStr {
		val, err := strconv.ParseInt(str, 10, 64)
		if err != nil {
			return nil, fmt.Errorf(
				"Error parsing version: %s", err)
		}

		segments[i] = val
	}

	// Even though we could support more than three segments, if we
	// got less than three, pad it with 0s. This is to cover the basic
	// default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum
	for i := len(segments); i < 3; i++ {
		segments = append(segments, 0)
	}

	pre := matches[7]
	if pre == "" {
		pre = matches[4]
	}

	return &Version{
		metadata: matches[10],
		pre:      pre,
		segments: segments,
		si:       len(segmentsStr),
		original: v,
	}, nil
}

// Must is a helper that wraps a call to a function returning (*Version, error)
// and panics if error is non-nil.
func Must(v *Version, err error) *Version {
	if err != nil {
		panic(err)
	}

	return v
}

// Compare compares this version to another version. This
// returns -1, 0, or 1 if this version is smaller, equal,
// or larger than the other version, respectively.
//
// If you want boolean results, use the LessThan, Equal,
// GreaterThan, GreaterThanOrEqual or LessThanOrEqual methods.
func (v *Version) Compare(other *Version) int {
	// A quick, efficient equality check
	if v.String() == other.String() {
		return 0
	}

	segmentsSelf := v.Segments64()
	segmentsOther := other.Segments64()

	// If the segments are the same, we must compare on prerelease info
	if reflect.DeepEqual(segmentsSelf, segmentsOther) {
		preSelf := v.Prerelease()
		preOther := other.Prerelease()
		if preSelf == "" && preOther == "" {
			return 0
		}
		if preSelf == "" {
			return 1
		}
		if preOther == "" {
			return -1
		}

		return comparePrereleases(preSelf, preOther)
	}

	// Get the highest specificity (hS), or if they're equal, just use segmentSelf length
	lenSelf := len(segmentsSelf)
	lenOther := len(segmentsOther)
	hS := lenSelf
	if lenSelf < lenOther {
		hS = lenOther
	}
	// Compare the segments
	// Because a constraint could have more/less specificity than the version it's
	// checking, we need to account for a lopsided or jagged comparison
	for i := 0; i < hS; i++ {
		if i > lenSelf-1 {
			// This means Self had the lower specificity
			// Check to see if the remaining segments in Other are all zeros
			if !allZero(segmentsOther[i:]) {
				// if not, it means that Other has to be greater than Self
				return -1
			}
			break
		} else if i > lenOther-1 {
			// this means Other had the lower specificity
			// Check to see if the remaining segments in Self are all zeros -
			if !allZero(segmentsSelf[i:]) {
				//if not, it means that Self has to be greater than Other
				return 1
			}
			break
		}
		lhs := segmentsSelf[i]
		rhs := segmentsOther[i]
		if lhs == rhs {
			continue
		} else if lhs < rhs {
			return -1
		}
		// Otherwis, rhs was > lhs, they're not equal
		return 1
	}

	// if we got this far, they're equal
	return 0
}

func allZero(segs []int64) bool {
	for _, s := range segs {
		if s != 0 {
			return false
		}
	}
	return true
}

func comparePart(preSelf string, preOther string) int {
	if preSelf == preOther {
		return 0
	}

	var selfInt int64
	selfNumeric := true
	selfInt, err := strconv.ParseInt(preSelf, 10, 64)
	if err != nil {
		selfNumeric = false
	}

	var otherInt int64
	otherNumeric := true
	otherInt, err = strconv.ParseInt(preOther, 10, 64)
	if err != nil {
		otherNumeric = false
	}

	// if a part is empty, we use the other to decide
	if preSelf == "" {
		if otherNumeric {
			return -1
		}
		return 1
	}

	if preOther == "" {
		if selfNumeric {
			return 1
		}
		return -1
	}

	if selfNumeric && !otherNumeric {
		return -1
	} else if !selfNumeric && otherNumeric {
		return 1
	} else if !selfNumeric && !otherNumeric && preSelf > preOther {
		return 1
	} else if selfInt > otherInt {
		return 1
	}

	return -1
}

func comparePrereleases(v string, other string) int {
	// the same pre release!
	if v == other {
		return 0
	}

	// split both pre releases for analyse their parts
	selfPreReleaseMeta := strings.Split(v, ".")
	otherPreReleaseMeta := strings.Split(other, ".")

	selfPreReleaseLen := len(selfPreReleaseMeta)
	otherPreReleaseLen := len(otherPreReleaseMeta)

	biggestLen := otherPreReleaseLen
	if selfPreReleaseLen > otherPreReleaseLen {
		biggestLen = selfPreReleaseLen
	}

	// loop for parts to find the first difference
	for i := 0; i < biggestLen; i = i + 1 {
		partSelfPre := ""
		if i < selfPreReleaseLen {
			partSelfPre = selfPreReleaseMeta[i]
		}

		partOtherPre := ""
		if i < otherPreReleaseLen {
			partOtherPre = otherPreReleaseMeta[i]
		}

		compare := comparePart(partSelfPre, partOtherPre)
		// if parts are equals, continue the loop
		if compare != 0 {
			return compare
		}
	}

	return 0
}

// Core returns a new version constructed from only the MAJOR.MINOR.PATCH
// segments of the version, without prerelease or metadata.
func (v *Version) Core() *Version {
	segments := v.Segments64()
	segmentsOnly := fmt.Sprintf("%d.%d.%d", segments[0], segments[1], segments[2])
	return Must(NewVersion(segmentsOnly))
}

// Equal tests if two versions are equal.
func (v *Version) Equal(o *Version) bool {
	if v == nil || o == nil {
		return v == o
	}

	return v.Compare(o) == 0
}

// GreaterThan tests if this version is greater than another version.
func (v *Version) GreaterThan(o *Version) bool {
	return v.Compare(o) > 0
}

// GreaterThanOrEqual tests if this version is greater than or equal to another version.
func (v *Version) GreaterThanOrEqual(o *Version) bool {
	return v.Compare(o) >= 0
}

// LessThan tests if this version is less than another version.
func (v *Version) LessThan(o *Version) bool {
	return v.Compare(o) < 0
}

// LessThanOrEqual tests if this version is less than or equal to another version.
func (v *Version) LessThanOrEqual(o *Version) bool {
	return v.Compare(o) <= 0
}

// Metadata returns any metadata that was part of the version
// string.
//
// Metadata is anything that comes after the "+" in the version.
// For example, with "1.2.3+beta", the metadata is "beta".
func (v *Version) Metadata() string {
	return v.metadata
}

// Prerelease returns any prerelease data that is part of the version,
// or blank if there is no prerelease data.
//
// Prerelease information is anything that comes after the "-" in the
// version (but before any metadata). For example, with "1.2.3-beta",
// the prerelease information is "beta".
func (v *Version) Prerelease() string {
	return v.pre
}

// Segments returns the numeric segments of the version as a slice of ints.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments() []int {
	segmentSlice := make([]int, len(v.segments))
	for i, v := range v.segments {
		segmentSlice[i] = int(v)
	}
	return segmentSlice
}

// Segments64 returns the numeric segments of the version as a slice of int64s.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments64() []int64 {
	result := make([]int64, len(v.segments))
	copy(result, v.segments)
	return result
}

// String returns the full version string included pre-release
// and metadata information.
//
// This value is rebuilt according to the parsed segments and other
// information. Therefore, ambiguities in the version string such as
// prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and
// missing parts (1.0 => 1.0.0) will be made into a canonicalized form
// as shown in the parenthesized examples.
func (v *Version) String() string {
	var buf bytes.Buffer
	fmtParts := make([]string, len(v.segments))
	for i, s := range v.segments {
		// We can ignore err here since we've pre-parsed the values in segments
		str := strconv.FormatInt(s, 10)
		fmtParts[i] = str
	}
	fmt.Fprintf(&buf, strings.Join(fmtParts, "."))
	if v.pre != "" {
		fmt.Fprintf(&buf, "-%s", v.pre)
	}
	if v.metadata != "" {
		fmt.Fprintf(&buf, "+%s", v.metadata)
	}

	return buf.String()
}

// Original returns the original parsed version as-is, including any
// potential whitespace, `v` prefix, etc.
func (v *Version) Original() string {
	return v.original
}

// UnmarshalJSON implements JSON.Unmarshaler interface.
func (v *Version) UnmarshalJSON(b []byte) error {
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	temp, err := NewVersion(s)
	if err != nil {
		return err
	}
	v.metadata = temp.metadata
	v.pre = temp.pre
	v.segments = temp.segments
	v.si = temp.si
	v.original = temp.original
	return nil
}

// MarshalJSON implements JSON.Marshaler interface.
func (v Version) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}
<commit_msg>Use encoding TextMarshaler & TextUnmarshaler instead json equivalents (#95)<commit_after>package version

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

// The compiled regular expression used to test the validity of a version.
var (
	versionRegexp *regexp.Regexp
	semverRegexp  *regexp.Regexp
)

// The raw regular expression string used for testing the validity
// of a version.
const (
	VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
		`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` +
		`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` +
		`?`

	// SemverRegexpRaw requires a separator between version and prerelease
	SemverRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
		`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` +
		`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` +
		`?`
)

// Version represents a single version.
type Version struct {
	metadata string
	pre      string
	segments []int64
	si       int
	original string
}

func init() {
	versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$")
	semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$")
}

// NewVersion parses the given version and returns a new
// Version.
func NewVersion(v string) (*Version, error) {
	return newVersion(v, versionRegexp)
}

// NewSemver parses the given version and returns a new
// Version that adheres strictly to SemVer specs
// https://semver.org/
func NewSemver(v string) (*Version, error) {
	return newVersion(v, semverRegexp)
}

func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
	matches := pattern.FindStringSubmatch(v)
	if matches == nil {
		return nil, fmt.Errorf("Malformed version: %s", v)
	}
	segmentsStr := strings.Split(matches[1], ".")
	segments := make([]int64, len(segmentsStr))
	for i, str := range segmentsStr {
		val, err := strconv.ParseInt(str, 10, 64)
		if err != nil {
			return nil, fmt.Errorf(
				"Error parsing version: %s", err)
		}

		segments[i] = val
	}

	// Even though we could support more than three segments, if we
	// got less than three, pad it with 0s. This is to cover the basic
	// default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum
	for i := len(segments); i < 3; i++ {
		segments = append(segments, 0)
	}

	pre := matches[7]
	if pre == "" {
		pre = matches[4]
	}

	return &Version{
		metadata: matches[10],
		pre:      pre,
		segments: segments,
		si:       len(segmentsStr),
		original: v,
	}, nil
}

// Must is a helper that wraps a call to a function returning (*Version, error)
// and panics if error is non-nil.
func Must(v *Version, err error) *Version {
	if err != nil {
		panic(err)
	}

	return v
}

// Compare compares this version to another version. This
// returns -1, 0, or 1 if this version is smaller, equal,
// or larger than the other version, respectively.
//
// If you want boolean results, use the LessThan, Equal,
// GreaterThan, GreaterThanOrEqual or LessThanOrEqual methods.
func (v *Version) Compare(other *Version) int {
	// A quick, efficient equality check
	if v.String() == other.String() {
		return 0
	}

	segmentsSelf := v.Segments64()
	segmentsOther := other.Segments64()

	// If the segments are the same, we must compare on prerelease info
	if reflect.DeepEqual(segmentsSelf, segmentsOther) {
		preSelf := v.Prerelease()
		preOther := other.Prerelease()
		if preSelf == "" && preOther == "" {
			return 0
		}
		if preSelf == "" {
			return 1
		}
		if preOther == "" {
			return -1
		}

		return comparePrereleases(preSelf, preOther)
	}

	// Get the highest specificity (hS), or if they're equal, just use segmentSelf length
	lenSelf := len(segmentsSelf)
	lenOther := len(segmentsOther)
	hS := lenSelf
	if lenSelf < lenOther {
		hS = lenOther
	}
	// Compare the segments
	// Because a constraint could have more/less specificity than the version it's
	// checking, we need to account for a lopsided or jagged comparison
	for i := 0; i < hS; i++ {
		if i > lenSelf-1 {
			// This means Self had the lower specificity
			// Check to see if the remaining segments in Other are all zeros
			if !allZero(segmentsOther[i:]) {
				// if not, it means that Other has to be greater than Self
				return -1
			}
			break
		} else if i > lenOther-1 {
			// this means Other had the lower specificity
			// Check to see if the remaining segments in Self are all zeros -
			if !allZero(segmentsSelf[i:]) {
				//if not, it means that Self has to be greater than Other
				return 1
			}
			break
		}
		lhs := segmentsSelf[i]
		rhs := segmentsOther[i]
		if lhs == rhs {
			continue
		} else if lhs < rhs {
			return -1
		}
		// Otherwis, rhs was > lhs, they're not equal
		return 1
	}

	// if we got this far, they're equal
	return 0
}

func allZero(segs []int64) bool {
	for _, s := range segs {
		if s != 0 {
			return false
		}
	}
	return true
}

func comparePart(preSelf string, preOther string) int {
	if preSelf == preOther {
		return 0
	}

	var selfInt int64
	selfNumeric := true
	selfInt, err := strconv.ParseInt(preSelf, 10, 64)
	if err != nil {
		selfNumeric = false
	}

	var otherInt int64
	otherNumeric := true
	otherInt, err = strconv.ParseInt(preOther, 10, 64)
	if err != nil {
		otherNumeric = false
	}

	// if a part is empty, we use the other to decide
	if preSelf == "" {
		if otherNumeric {
			return -1
		}
		return 1
	}

	if preOther == "" {
		if selfNumeric {
			return 1
		}
		return -1
	}

	if selfNumeric && !otherNumeric {
		return -1
	} else if !selfNumeric && otherNumeric {
		return 1
	} else if !selfNumeric && !otherNumeric && preSelf > preOther {
		return 1
	} else if selfInt > otherInt {
		return 1
	}

	return -1
}

func comparePrereleases(v string, other string) int {
	// the same pre release!
	if v == other {
		return 0
	}

	// split both pre releases for analyse their parts
	selfPreReleaseMeta := strings.Split(v, ".")
	otherPreReleaseMeta := strings.Split(other, ".")

	selfPreReleaseLen := len(selfPreReleaseMeta)
	otherPreReleaseLen := len(otherPreReleaseMeta)

	biggestLen := otherPreReleaseLen
	if selfPreReleaseLen > otherPreReleaseLen {
		biggestLen = selfPreReleaseLen
	}

	// loop for parts to find the first difference
	for i := 0; i < biggestLen; i = i + 1 {
		partSelfPre := ""
		if i < selfPreReleaseLen {
			partSelfPre = selfPreReleaseMeta[i]
		}

		partOtherPre := ""
		if i < otherPreReleaseLen {
			partOtherPre = otherPreReleaseMeta[i]
		}

		compare := comparePart(partSelfPre, partOtherPre)
		// if parts are equals, continue the loop
		if compare != 0 {
			return compare
		}
	}

	return 0
}

// Core returns a new version constructed from only the MAJOR.MINOR.PATCH
// segments of the version, without prerelease or metadata.
func (v *Version) Core() *Version {
	segments := v.Segments64()
	segmentsOnly := fmt.Sprintf("%d.%d.%d", segments[0], segments[1], segments[2])
	return Must(NewVersion(segmentsOnly))
}

// Equal tests if two versions are equal.
func (v *Version) Equal(o *Version) bool {
	if v == nil || o == nil {
		return v == o
	}

	return v.Compare(o) == 0
}

// GreaterThan tests if this version is greater than another version.
func (v *Version) GreaterThan(o *Version) bool {
	return v.Compare(o) > 0
}

// GreaterThanOrEqual tests if this version is greater than or equal to another version.
func (v *Version) GreaterThanOrEqual(o *Version) bool {
	return v.Compare(o) >= 0
}

// LessThan tests if this version is less than another version.
func (v *Version) LessThan(o *Version) bool {
	return v.Compare(o) < 0
}

// LessThanOrEqual tests if this version is less than or equal to another version.
func (v *Version) LessThanOrEqual(o *Version) bool {
	return v.Compare(o) <= 0
}

// Metadata returns any metadata that was part of the version
// string.
//
// Metadata is anything that comes after the "+" in the version.
// For example, with "1.2.3+beta", the metadata is "beta".
func (v *Version) Metadata() string {
	return v.metadata
}

// Prerelease returns any prerelease data that is part of the version,
// or blank if there is no prerelease data.
//
// Prerelease information is anything that comes after the "-" in the
// version (but before any metadata). For example, with "1.2.3-beta",
// the prerelease information is "beta".
func (v *Version) Prerelease() string {
	return v.pre
}

// Segments returns the numeric segments of the version as a slice of ints.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments() []int {
	segmentSlice := make([]int, len(v.segments))
	for i, v := range v.segments {
		segmentSlice[i] = int(v)
	}
	return segmentSlice
}

// Segments64 returns the numeric segments of the version as a slice of int64s.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments64() []int64 {
	result := make([]int64, len(v.segments))
	copy(result, v.segments)
	return result
}

// String returns the full version string included pre-release
// and metadata information.
//
// This value is rebuilt according to the parsed segments and other
// information. Therefore, ambiguities in the version string such as
// prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and
// missing parts (1.0 => 1.0.0) will be made into a canonicalized form
// as shown in the parenthesized examples.
func (v *Version) String() string {
	var buf bytes.Buffer
	fmtParts := make([]string, len(v.segments))
	for i, s := range v.segments {
		// We can ignore err here since we've pre-parsed the values in segments
		str := strconv.FormatInt(s, 10)
		fmtParts[i] = str
	}
	fmt.Fprintf(&buf, strings.Join(fmtParts, "."))
	if v.pre != "" {
		fmt.Fprintf(&buf, "-%s", v.pre)
	}
	if v.metadata != "" {
		fmt.Fprintf(&buf, "+%s", v.metadata)
	}

	return buf.String()
}

// Original returns the original parsed version as-is, including any
// potential whitespace, `v` prefix, etc.
func (v *Version) Original() string {
	return v.original
}

// UnmarshalText implements encoding.TextUnmarshaler interface.
func (v *Version) UnmarshalText(b []byte) error {
	temp, err := NewVersion(string(b))
	if err != nil {
		return err
	}

	*v = *temp

	return nil
}

// MarshalText implements encoding.TextMarshaler interface.
func (v *Version) MarshalText() ([]byte, error) {
	return []byte(v.String()), nil
}
<|endoftext|>


<commit_before>package main

import "fmt"

const version = "1.5"

func printVersion() {
	fmt.Println(version)
}
<commit_msg>update version<commit_after>package main

import "fmt"

const version = "1.5.1"

func printVersion() {
	fmt.Println(version)
}
<|endoftext|>


<commit_before>package nsq

const VERSION = "0.1.27"
<commit_msg>bump to 0.1.28<commit_after>package nsq

const VERSION = "0.1.28"
<|endoftext|>