<commit_before>package main

import (
	"net/http"

	"github.com/labstack/echo"
	"fmt"
	"os"
	"bufio"
	"io"
	"strings"
	"time"
	"github.com/labstack/echo/middleware"
)

func main() {
	// Echo instance
	e := echo.New()

	// Middleware
	e.Use(middleware.Recover())

	// Route => handler
	e.GET("/", handleGet)

	e.POST("/", handlePostPayload)

	// Start server
	e.Logger.Fatal(e.Start(":1323"))
}

func handlePostPayload(c echo.Context) error {
	t := time.Now()
	dir := c.QueryParam("dir")
	if dir != "" {
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	} else {
		dir = t.Format("2006-01-02")
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	}

	fo, err := os.Create("./" + dir + "/" + t.Format("15.04.05.0000"))
	if err != nil {
		panic(err)
	}
	// close fo on exit and check for its returned error
	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	w := bufio.NewWriter(fo)
	defer w.Flush()

	for k, v := range c.Request().Header {
		fmt.Fprintln(w, k + ":", strings.Join(v, ","))
	}

	fmt.Fprintln(w)
	io.Copy(w, c.Request().Body)

	return c.String(http.StatusOK, t.Format("2006-01-02 15:04:05"))
}

func handleGet(c echo.Context) error {
	return c.String(http.StatusOK, "Hello, World!\n")
}<commit_msg>Added rudimentary support for getting your files. Definitely will need some sort of secuirty added because right now this will give access to everything in your filesystem.<commit_after>package main

import (
	"net/http"

	"github.com/labstack/echo"
	"fmt"
	"os"
	"bufio"
	"io"
	"strings"
	"time"
	"github.com/labstack/echo/middleware"
	"html/template"
	"io/ioutil"
)

func main() {
	// Echo instance
	e := echo.New()

	t := &Template{
		templates: template.Must(template.New("index").Parse(`{{define "index"}}
		{{range .Files}}
		{{.Name}}
		{{end}}
		{{end}}`)),
	}
	e.Renderer = t

	// Middleware
	e.Use(middleware.Recover())

	// Route => handler
	e.GET("/*", handleGet)

	e.POST("/", handlePostPayload)

	// Start server
	e.Logger.Fatal(e.Start(":1323"))
}

func handlePostPayload(c echo.Context) error {
	t := time.Now()
	dir := c.QueryParam("dir")
	if dir != "" {
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	} else {
		dir = t.Format("2006-01-02")
		err := os.MkdirAll(dir, 0644)
		if err != nil {
			panic("unable to create dir")
		}
	}

	fo, err := os.Create("./" + dir + "/" + t.Format("15.04.05.0000"))
	if err != nil {
		panic(err)
	}
	// close fo on exit and check for its returned error
	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	w := bufio.NewWriter(fo)
	defer w.Flush()

	for k, v := range c.Request().Header {
		fmt.Fprintln(w, k + ":", strings.Join(v, ","))
	}

	fmt.Fprintln(w)
	io.Copy(w, c.Request().Body)

	return c.String(http.StatusOK, t.Format("2006-01-02 15:04:05"))
}

type Template struct {
	templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

func handleGet(c echo.Context) error {
	path := c.Param("*")

	if info, err := os.Stat("./" + path); err == nil {
		if info.IsDir() {
			files, err := ioutil.ReadDir("./" + path)
			if err != nil {
				panic("Unable to read directory")
			}

			templData := struct {
				Path string
				Files []os.FileInfo
			}{
				info.Name(),
				files,
			}

			return c.Render(http.StatusOK, "index", templData)
		} else {
			return c.File(path)
		}
	}

	return c.NoContent(http.StatusNotFound)
}<|endoftext|>


<commit_before>package gf

const VERSION = "v1.16.5"
const AUTHORS = "john<john@goframe.org>"
<commit_msg>version updates<commit_after>package gf

const VERSION = "v1.17.0"
const AUTHORS = "john<john@goframe.org>"
<|endoftext|>


<commit_before>package godong

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strings"
)

const (
	UrlModeDashed      int    = 0
	UrlModeCapitalized int    = 1
	actionSlash        string = "/"
	actionMapSeparator string = "."
)

var (
	Debug         bool   = false
	Prefix        string = "Action"
	Separator     string = "_"
	DefaultAction string = ""
	UrlMode       int    = UrlModeDashed
)

func Route(o interface{}) {
	var reflectType = reflect.TypeOf(o)
	var reflectValue = reflect.ValueOf(o)

	for i := 0; i < reflectType.NumMethod(); i++ {
		handleRoute(reflectType, reflectValue, i)
	}
}

func getRoutePath(method reflect.Method, controllerName string) string {
	validMethodName := (func() string {
		result := method.Name

		result = strings.Replace(result, Prefix, "", -1)
		result = strings.Replace(result, Separator, actionSlash, -1)

		return result
	}

	routePath := actionSlash + controllerName + validMethodName()

	if UrlMode == UrlModeDashed {
		reg, err := regexp.Compile("([a-z])([A-Z])")
		if err != nil {
			return routePath
		}

		routePath = strings.ToLower(reg.ReplaceAllString(routePath, "$1-$2"))
	}

	return routePath
}

func handleRoute(reflectType reflect.Type, reflectValue reflect.Value, i int) {
	controllerName := reflect.Indirect(reflectValue).Type().Name()
	method := reflectType.Method(i)
	methodBody := reflectValue.MethodByName(method.Name)
	routePath := getRoutePath(method, controllerName)
	actionMap := fmt.Sprintf("%s%s%s", controllerName, actionMapSeparator, method.Name)

	if Debug {
		fmt.Println("route", routePath)
	}

	checkError := (func() error {
		var errorInvalidActionSchema error = errors.New(fmt.Sprintf("Invalid action parameter.\n      Action %s should be written in:\n      func (d *%s) %s (w http.ResponseWriter, r *http.Request)", actionMap, controllerName, method.Name))

		if methodBody.Type().NumIn() != 2 {
			return errorInvalidActionSchema
		} else if methodBody.Type().In(0).String() != "http.ResponseWriter" {
			return errorInvalidActionSchema
		} else if methodBody.Type().In(1).String() != "*http.Request" {
			return errorInvalidActionSchema
		}

		return nil
	})

	if err := checkError(); err != nil {
		fmt.Println("error", err.Error())
		os.Exit(0)
	}

	methodHandler := methodBody.Interface().(func(w http.ResponseWriter, r *http.Request))
	http.HandleFunc(routePath, methodHandler)

	if Debug {
		fmt.Println("   ->", actionMap)
	}

	if actionMap == DefaultAction {
		http.HandleFunc(actionSlash, methodHandler)

		if Debug {
			fmt.Println("route", actionSlash)
			fmt.Println("   ->", actionMap)
		}
	}
}
<commit_msg>adding missing bracked<commit_after>package godong

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strings"
)

const (
	UrlModeDashed      int    = 0
	UrlModeCapitalized int    = 1
	actionSlash        string = "/"
	actionMapSeparator string = "."
)

var (
	Debug         bool   = false
	Prefix        string = "Action"
	Separator     string = "_"
	DefaultAction string = ""
	UrlMode       int    = UrlModeDashed
)

func Route(o interface{}) {
	var reflectType = reflect.TypeOf(o)
	var reflectValue = reflect.ValueOf(o)

	for i := 0; i < reflectType.NumMethod(); i++ {
		handleRoute(reflectType, reflectValue, i)
	}
}

func getRoutePath(method reflect.Method, controllerName string) string {
	validMethodName := (func() string {
		result := method.Name

		result = strings.Replace(result, Prefix, "", -1)
		result = strings.Replace(result, Separator, actionSlash, -1)

		return result
	})

	routePath := actionSlash + controllerName + validMethodName()

	if UrlMode == UrlModeDashed {
		reg, err := regexp.Compile("([a-z])([A-Z])")
		if err != nil {
			return routePath
		}

		routePath = strings.ToLower(reg.ReplaceAllString(routePath, "$1-$2"))
	}

	return routePath
}

func handleRoute(reflectType reflect.Type, reflectValue reflect.Value, i int) {
	controllerName := reflect.Indirect(reflectValue).Type().Name()
	method := reflectType.Method(i)
	methodBody := reflectValue.MethodByName(method.Name)
	routePath := getRoutePath(method, controllerName)
	actionMap := fmt.Sprintf("%s%s%s", controllerName, actionMapSeparator, method.Name)

	if Debug {
		fmt.Println("route", routePath)
	}

	checkError := (func() error {
		var errorInvalidActionSchema error = errors.New(fmt.Sprintf("Invalid action parameter.\n      Action %s should be written in:\n      func (d *%s) %s (w http.ResponseWriter, r *http.Request)", actionMap, controllerName, method.Name))

		if methodBody.Type().NumIn() != 2 {
			return errorInvalidActionSchema
		} else if methodBody.Type().In(0).String() != "http.ResponseWriter" {
			return errorInvalidActionSchema
		} else if methodBody.Type().In(1).String() != "*http.Request" {
			return errorInvalidActionSchema
		}

		return nil
	})

	if err := checkError(); err != nil {
		fmt.Println("error", err.Error())
		os.Exit(0)
	}

	methodHandler := methodBody.Interface().(func(w http.ResponseWriter, r *http.Request))
	http.HandleFunc(routePath, methodHandler)

	if Debug {
		fmt.Println("   ->", actionMap)
	}

	if actionMap == DefaultAction {
		http.HandleFunc(actionSlash, methodHandler)

		if Debug {
			fmt.Println("route", actionSlash)
			fmt.Println("   ->", actionMap)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"

	"github.com/gophergala/goffee/probe"
	"github.com/gophergala/goffee/queue"
	"github.com/gophergala/goffee/scheduler"
	"github.com/gophergala/goffee/web"
	"github.com/gophergala/goffee/writer"
)

var webMode bool
var torFetch bool
var schedulerMode bool
var writerMode bool
var redisAddress string

func init() {
	flag.BoolVar(&webMode, "webmode", false, "Run goffee in webmode")
	flag.BoolVar(&torFetch, "torfetch", false, "Fetch something via Tor")
	flag.BoolVar(&schedulerMode, "scheduler", false, "Run goffee scheduler")
	flag.BoolVar(&writerMode, "writer", false, "Run goffee writer")
	flag.StringVar(&redisAddress, "redisaddress", "", "Address of redis including port")
	flag.Parse()
}

func main() {
	if webMode {
		web.StartServer()
	}

	if torFetch || schedulerMode || writerMode {
		queue.RedisAddressWithPort = redisAddress
	}

	if torFetch {
		probe.Run()
	}
	if schedulerMode {
		scheduler.Run()
	}
	if writerMode {
		writer.Run()
	}

	if webMode {
		web.Wait()
	}
	if writerMode {
		writer.Wait()
	}
	if schedulerMode {
		scheduler.Wait()
	}
	if torFetch {
		probe.Wait()
	}
}
<commit_msg>Rename torFetch to probeMode for consistency<commit_after>package main

import (
	"flag"

	"github.com/gophergala/goffee/probe"
	"github.com/gophergala/goffee/queue"
	"github.com/gophergala/goffee/scheduler"
	"github.com/gophergala/goffee/web"
	"github.com/gophergala/goffee/writer"
)

var webMode bool
var probeMode bool
var schedulerMode bool
var writerMode bool
var redisAddress string

func init() {
	flag.BoolVar(&webMode, "webmode", false, "Run goffee in webmode")
	flag.BoolVar(&probeMode, "torfetch", false, "Fetch something via Tor")
	flag.BoolVar(&schedulerMode, "scheduler", false, "Run goffee scheduler")
	flag.BoolVar(&writerMode, "writer", false, "Run goffee writer")
	flag.StringVar(&redisAddress, "redisaddress", "", "Address of redis including port")
	flag.Parse()
}

func main() {
	if webMode {
		web.StartServer()
	}

	if probeMode || schedulerMode || writerMode {
		queue.RedisAddressWithPort = redisAddress
	}

	if probeMode {
		probe.Run()
	}
	if schedulerMode {
		scheduler.Run()
	}
	if writerMode {
		writer.Run()
	}

	if webMode {
		web.Wait()
	}
	if writerMode {
		writer.Wait()
	}
	if schedulerMode {
		scheduler.Wait()
	}
	if probeMode {
		probe.Wait()
	}
}
<|endoftext|>


<commit_before>// Copyright 2016-2020 The Libsacloud Authors
//
// 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 libsacloud

// Version バージョン
const Version = "2.0.0-rc3"
<commit_msg>Bump to v2.0.0-rc4<commit_after>// Copyright 2016-2020 The Libsacloud Authors
//
// 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 libsacloud

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


<commit_before>package semver

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

// The compiled version of the regex created at init() is cached here so it
// only needs to be created once.
var versionRegex *regexp.Regexp
var validPrereleaseRegex *regexp.Regexp

var (
	// ErrInvalidSemVer is returned a version is found to be invalid when
	// being parsed.
	ErrInvalidSemVer = errors.New("Invalid Semantic Version")

	// ErrInvalidMetadata is returned when the metadata is an invalid format
	ErrInvalidMetadata = errors.New("Invalid Metadata string")

	// ErrInvalidPrerelease is returned when the pre-release is an invalid format
	ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
)

// SemVerRegex is the regular expression used to parse a semantic version.
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
	`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
	`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`

// ValidPrerelease is the regular expression which validates
// both prerelease and metadata values.
const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`

// Version represents a single semantic version.
type Version struct {
	major, minor, patch int64
	pre                 string
	metadata            string
	original            string
}

func init() {
	versionRegex = regexp.MustCompile("^" + SemVerRegex + "$")
	validPrereleaseRegex = regexp.MustCompile(ValidPrerelease)
}

// NewVersion parses a given version and returns an instance of Version or
// an error if unable to parse the version.
func NewVersion(v string) (*Version, error) {
	m := versionRegex.FindStringSubmatch(v)
	if m == nil {
		return nil, ErrInvalidSemVer
	}

	sv := &Version{
		metadata: m[8],
		pre:      m[5],
		original: v,
	}

	var temp int64
	temp, err := strconv.ParseInt(m[1], 10, 64)
	if err != nil {
		return nil, fmt.Errorf("Error parsing version segment: %s", err)
	}
	sv.major = temp

	if m[2] != "" {
		temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 64)
		if err != nil {
			return nil, fmt.Errorf("Error parsing version segment: %s", err)
		}
		sv.minor = temp
	} else {
		sv.minor = 0
	}

	if m[3] != "" {
		temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 64)
		if err != nil {
			return nil, fmt.Errorf("Error parsing version segment: %s", err)
		}
		sv.patch = temp
	} else {
		sv.patch = 0
	}

	return sv, nil
}

// MustParse parses a given version and panics on error.
func MustParse(v string) *Version {
	sv, err := NewVersion(v)
	if err != nil {
		panic(err)
	}
	return sv
}

// String converts a Version object to a string.
// Note, if the original version contained a leading v this version will not.
// See the Original() method to retrieve the original value. Semantic Versions
// don't contain a leading v per the spec. Instead it's optional on
// impelementation.
func (v *Version) String() string {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
	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 value passed in to be parsed.
func (v *Version) Original() string {
	return v.original
}

// Major returns the major version.
func (v *Version) Major() int64 {
	return v.major
}

// Minor returns the minor version.
func (v *Version) Minor() int64 {
	return v.minor
}

// Patch returns the patch version.
func (v *Version) Patch() int64 {
	return v.patch
}

// Prerelease returns the pre-release version.
func (v *Version) Prerelease() string {
	return v.pre
}

// Metadata returns the metadata on the version.
func (v *Version) Metadata() string {
	return v.metadata
}

// originalVPrefix returns the original 'v' prefix if any.
func (v *Version) originalVPrefix() string {

	// Note, only lowercase v is supported as a prefix by the parser.
	if v.original != "" && v.original[:1] == "v" {
		return v.original[:1]
	}
	return ""
}

// IncPatch produces the next patch version.
// If the current version does not have prerelease/metadata information,
// it unsets metadata and prerelease values, increments patch number.
// If the current version has any of prerelease or metadata information,
// it unsets both values and keeps curent patch value
func (v Version) IncPatch() Version {
	vNext := v
	// according to http://semver.org/#spec-item-9
	// Pre-release versions have a lower precedence than the associated normal version.
	// according to http://semver.org/#spec-item-10
	// Build metadata SHOULD be ignored when determining version precedence.
	if v.pre != "" {
		vNext.metadata = ""
		vNext.pre = ""
	} else {
		vNext.metadata = ""
		vNext.pre = ""
		vNext.patch = v.patch + 1
	}
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext
}

// IncMinor produces the next minor version.
// Sets patch to 0.
// Increments minor number.
// Unsets metadata.
// Unsets prerelease status.
func (v Version) IncMinor() Version {
	vNext := v
	vNext.metadata = ""
	vNext.pre = ""
	vNext.patch = 0
	vNext.minor = v.minor + 1
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext
}

// IncMajor produces the next major version.
// Sets patch to 0.
// Sets minor to 0.
// Increments major number.
// Unsets metadata.
// Unsets prerelease status.
func (v Version) IncMajor() Version {
	vNext := v
	vNext.metadata = ""
	vNext.pre = ""
	vNext.patch = 0
	vNext.minor = 0
	vNext.major = v.major + 1
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext
}

// SetPrerelease defines the prerelease value.
// Value must not include the required 'hypen' prefix.
func (v Version) SetPrerelease(prerelease string) (Version, error) {
	vNext := v
	if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) {
		return vNext, ErrInvalidPrerelease
	}
	vNext.pre = prerelease
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext, nil
}

// SetMetadata defines metadata value.
// Value must not include the required 'plus' prefix.
func (v Version) SetMetadata(metadata string) (Version, error) {
	vNext := v
	if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) {
		return vNext, ErrInvalidMetadata
	}
	vNext.metadata = metadata
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext, nil
}

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

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

// Equal tests if two versions are equal to each other.
// Note, versions can be equal with different metadata since metadata
// is not considered part of the comparable version.
func (v *Version) Equal(o *Version) bool {
	return v.Compare(o) == 0
}

// Compare compares this version to another one. It returns -1, 0, or 1 if
// the version smaller, equal, or larger than the other version.
//
// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
// lower than the version without a prerelease.
func (v *Version) Compare(o *Version) int {
	// Compare the major, minor, and patch version for differences. If a
	// difference is found return the comparison.
	if d := compareSegment(v.Major(), o.Major()); d != 0 {
		return d
	}
	if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
		return d
	}
	if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
		return d
	}

	// At this point the major, minor, and patch versions are the same.
	ps := v.pre
	po := o.Prerelease()

	if ps == "" && po == "" {
		return 0
	}
	if ps == "" {
		return 1
	}
	if po == "" {
		return -1
	}

	return comparePrerelease(ps, po)
}

// 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.major = temp.major
	v.minor = temp.minor
	v.patch = temp.patch
	v.pre = temp.pre
	v.metadata = temp.metadata
	v.original = temp.original
	temp = nil
	return nil
}

// MarshalJSON implements JSON.Marshaler interface.
func (v *Version) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}

func compareSegment(v, o int64) int {
	if v < o {
		return -1
	}
	if v > o {
		return 1
	}

	return 0
}

func comparePrerelease(v, o string) int {

	// split the prelease versions by their part. The separator, per the spec,
	// is a .
	sparts := strings.Split(v, ".")
	oparts := strings.Split(o, ".")

	// Find the longer length of the parts to know how many loop iterations to
	// go through.
	slen := len(sparts)
	olen := len(oparts)

	l := slen
	if olen > slen {
		l = olen
	}

	// Iterate over each part of the prereleases to compare the differences.
	for i := 0; i < l; i++ {
		// Since the lentgh of the parts can be different we need to create
		// a placeholder. This is to avoid out of bounds issues.
		stemp := ""
		if i < slen {
			stemp = sparts[i]
		}

		otemp := ""
		if i < olen {
			otemp = oparts[i]
		}

		d := comparePrePart(stemp, otemp)
		if d != 0 {
			return d
		}
	}

	// Reaching here means two versions are of equal value but have different
	// metadata (the part following a +). They are not identical in string form
	// but the version comparison finds them to be equal.
	return 0
}

func comparePrePart(s, o string) int {
	// Fastpath if they are equal
	if s == o {
		return 0
	}

	// When s or o are empty we can use the other in an attempt to determine
	// the response.
	if s == "" {
		if o != "" {
			return -1
		}
		return 1
	}

	if o == "" {
		if s != "" {
			return 1
		}
		return -1
	}

	// When comparing strings "99" is greater than "103". To handle
	// cases like this we need to detect numbers and compare them.

	oi, n1 := strconv.ParseInt(o, 10, 64)
	si, n2 := strconv.ParseInt(s, 10, 64)

	// The case where both are strings compare the strings
	if n1 != nil && n2 != nil {
		if s > o {
			return 1
		}
		return -1
	} else if n1 != nil {
		// o is a string and s is a number
		return -1
	} else if n2 != nil {
		// s is a string and o is a number
		return 1
	}
	// Both are numbers
	if si > oi {
		return 1
	}
	return -1

}
<commit_msg>Fix typo<commit_after>package semver

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

// The compiled version of the regex created at init() is cached here so it
// only needs to be created once.
var versionRegex *regexp.Regexp
var validPrereleaseRegex *regexp.Regexp

var (
	// ErrInvalidSemVer is returned a version is found to be invalid when
	// being parsed.
	ErrInvalidSemVer = errors.New("Invalid Semantic Version")

	// ErrInvalidMetadata is returned when the metadata is an invalid format
	ErrInvalidMetadata = errors.New("Invalid Metadata string")

	// ErrInvalidPrerelease is returned when the pre-release is an invalid format
	ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
)

// SemVerRegex is the regular expression used to parse a semantic version.
const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
	`(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
	`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`

// ValidPrerelease is the regular expression which validates
// both prerelease and metadata values.
const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`

// Version represents a single semantic version.
type Version struct {
	major, minor, patch int64
	pre                 string
	metadata            string
	original            string
}

func init() {
	versionRegex = regexp.MustCompile("^" + SemVerRegex + "$")
	validPrereleaseRegex = regexp.MustCompile(ValidPrerelease)
}

// NewVersion parses a given version and returns an instance of Version or
// an error if unable to parse the version.
func NewVersion(v string) (*Version, error) {
	m := versionRegex.FindStringSubmatch(v)
	if m == nil {
		return nil, ErrInvalidSemVer
	}

	sv := &Version{
		metadata: m[8],
		pre:      m[5],
		original: v,
	}

	var temp int64
	temp, err := strconv.ParseInt(m[1], 10, 64)
	if err != nil {
		return nil, fmt.Errorf("Error parsing version segment: %s", err)
	}
	sv.major = temp

	if m[2] != "" {
		temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 64)
		if err != nil {
			return nil, fmt.Errorf("Error parsing version segment: %s", err)
		}
		sv.minor = temp
	} else {
		sv.minor = 0
	}

	if m[3] != "" {
		temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 64)
		if err != nil {
			return nil, fmt.Errorf("Error parsing version segment: %s", err)
		}
		sv.patch = temp
	} else {
		sv.patch = 0
	}

	return sv, nil
}

// MustParse parses a given version and panics on error.
func MustParse(v string) *Version {
	sv, err := NewVersion(v)
	if err != nil {
		panic(err)
	}
	return sv
}

// String converts a Version object to a string.
// Note, if the original version contained a leading v this version will not.
// See the Original() method to retrieve the original value. Semantic Versions
// don't contain a leading v per the spec. Instead it's optional on
// implementation.
func (v *Version) String() string {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
	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 value passed in to be parsed.
func (v *Version) Original() string {
	return v.original
}

// Major returns the major version.
func (v *Version) Major() int64 {
	return v.major
}

// Minor returns the minor version.
func (v *Version) Minor() int64 {
	return v.minor
}

// Patch returns the patch version.
func (v *Version) Patch() int64 {
	return v.patch
}

// Prerelease returns the pre-release version.
func (v *Version) Prerelease() string {
	return v.pre
}

// Metadata returns the metadata on the version.
func (v *Version) Metadata() string {
	return v.metadata
}

// originalVPrefix returns the original 'v' prefix if any.
func (v *Version) originalVPrefix() string {

	// Note, only lowercase v is supported as a prefix by the parser.
	if v.original != "" && v.original[:1] == "v" {
		return v.original[:1]
	}
	return ""
}

// IncPatch produces the next patch version.
// If the current version does not have prerelease/metadata information,
// it unsets metadata and prerelease values, increments patch number.
// If the current version has any of prerelease or metadata information,
// it unsets both values and keeps curent patch value
func (v Version) IncPatch() Version {
	vNext := v
	// according to http://semver.org/#spec-item-9
	// Pre-release versions have a lower precedence than the associated normal version.
	// according to http://semver.org/#spec-item-10
	// Build metadata SHOULD be ignored when determining version precedence.
	if v.pre != "" {
		vNext.metadata = ""
		vNext.pre = ""
	} else {
		vNext.metadata = ""
		vNext.pre = ""
		vNext.patch = v.patch + 1
	}
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext
}

// IncMinor produces the next minor version.
// Sets patch to 0.
// Increments minor number.
// Unsets metadata.
// Unsets prerelease status.
func (v Version) IncMinor() Version {
	vNext := v
	vNext.metadata = ""
	vNext.pre = ""
	vNext.patch = 0
	vNext.minor = v.minor + 1
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext
}

// IncMajor produces the next major version.
// Sets patch to 0.
// Sets minor to 0.
// Increments major number.
// Unsets metadata.
// Unsets prerelease status.
func (v Version) IncMajor() Version {
	vNext := v
	vNext.metadata = ""
	vNext.pre = ""
	vNext.patch = 0
	vNext.minor = 0
	vNext.major = v.major + 1
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext
}

// SetPrerelease defines the prerelease value.
// Value must not include the required 'hypen' prefix.
func (v Version) SetPrerelease(prerelease string) (Version, error) {
	vNext := v
	if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) {
		return vNext, ErrInvalidPrerelease
	}
	vNext.pre = prerelease
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext, nil
}

// SetMetadata defines metadata value.
// Value must not include the required 'plus' prefix.
func (v Version) SetMetadata(metadata string) (Version, error) {
	vNext := v
	if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) {
		return vNext, ErrInvalidMetadata
	}
	vNext.metadata = metadata
	vNext.original = v.originalVPrefix() + "" + vNext.String()
	return vNext, nil
}

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

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

// Equal tests if two versions are equal to each other.
// Note, versions can be equal with different metadata since metadata
// is not considered part of the comparable version.
func (v *Version) Equal(o *Version) bool {
	return v.Compare(o) == 0
}

// Compare compares this version to another one. It returns -1, 0, or 1 if
// the version smaller, equal, or larger than the other version.
//
// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
// lower than the version without a prerelease.
func (v *Version) Compare(o *Version) int {
	// Compare the major, minor, and patch version for differences. If a
	// difference is found return the comparison.
	if d := compareSegment(v.Major(), o.Major()); d != 0 {
		return d
	}
	if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
		return d
	}
	if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
		return d
	}

	// At this point the major, minor, and patch versions are the same.
	ps := v.pre
	po := o.Prerelease()

	if ps == "" && po == "" {
		return 0
	}
	if ps == "" {
		return 1
	}
	if po == "" {
		return -1
	}

	return comparePrerelease(ps, po)
}

// 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.major = temp.major
	v.minor = temp.minor
	v.patch = temp.patch
	v.pre = temp.pre
	v.metadata = temp.metadata
	v.original = temp.original
	temp = nil
	return nil
}

// MarshalJSON implements JSON.Marshaler interface.
func (v *Version) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}

func compareSegment(v, o int64) int {
	if v < o {
		return -1
	}
	if v > o {
		return 1
	}

	return 0
}

func comparePrerelease(v, o string) int {

	// split the prelease versions by their part. The separator, per the spec,
	// is a .
	sparts := strings.Split(v, ".")
	oparts := strings.Split(o, ".")

	// Find the longer length of the parts to know how many loop iterations to
	// go through.
	slen := len(sparts)
	olen := len(oparts)

	l := slen
	if olen > slen {
		l = olen
	}

	// Iterate over each part of the prereleases to compare the differences.
	for i := 0; i < l; i++ {
		// Since the lentgh of the parts can be different we need to create
		// a placeholder. This is to avoid out of bounds issues.
		stemp := ""
		if i < slen {
			stemp = sparts[i]
		}

		otemp := ""
		if i < olen {
			otemp = oparts[i]
		}

		d := comparePrePart(stemp, otemp)
		if d != 0 {
			return d
		}
	}

	// Reaching here means two versions are of equal value but have different
	// metadata (the part following a +). They are not identical in string form
	// but the version comparison finds them to be equal.
	return 0
}

func comparePrePart(s, o string) int {
	// Fastpath if they are equal
	if s == o {
		return 0
	}

	// When s or o are empty we can use the other in an attempt to determine
	// the response.
	if s == "" {
		if o != "" {
			return -1
		}
		return 1
	}

	if o == "" {
		if s != "" {
			return 1
		}
		return -1
	}

	// When comparing strings "99" is greater than "103". To handle
	// cases like this we need to detect numbers and compare them.

	oi, n1 := strconv.ParseInt(o, 10, 64)
	si, n2 := strconv.ParseInt(s, 10, 64)

	// The case where both are strings compare the strings
	if n1 != nil && n2 != nil {
		if s > o {
			return 1
		}
		return -1
	} else if n1 != nil {
		// o is a string and s is a number
		return -1
	} else if n2 != nil {
		// s is a string and o is a number
		return 1
	}
	// Both are numbers
	if si > oi {
		return 1
	}
	return -1

}
<|endoftext|>


<commit_before>package txtdirect

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strings"

	"github.com/gomods/athens/pkg/download"
	"github.com/gomods/athens/pkg/download/addons"
	"github.com/gomods/athens/pkg/module"
	"github.com/gomods/athens/pkg/stash"
	"github.com/gomods/athens/pkg/storage"
	"github.com/gomods/athens/pkg/storage/fs"
	"github.com/spf13/afero"
)

type Gomods struct {
	Enable   bool
	GoBinary string
	Workers  int
	Cache    struct {
		Type string
		Path string
	}
}

type Module struct {
	Name    string
	Version string
}

type ModuleHandler interface {
	fetch(r *http.Request, c Config) (*storage.Version, error)
	storage(c Config) (storage.Backend, error)
	dp(fetcher module.Fetcher, s storage.Backend, fs afero.Fs) download.Protocol
}

var gomodsRegex = regexp.MustCompile("(list|info|mod|zip)")
var modVersionRegex = regexp.MustCompile("@v\\/(v\\d+\\.\\d+\\.\\d+?|v\\d+\\.\\d+|latest|master)")

func gomods(w http.ResponseWriter, r *http.Request, path string, c Config) error {
	moduleName, version, ext := moduleNameAndVersion(path)
	if moduleName == "" {
		return fmt.Errorf("module url is empty")
	}
	m := Module{
		Name:    moduleName,
		Version: version,
	}
	dp, err := m.fetch(r, c)
	if err != nil {
		return err
	}
	switch ext {
	case "list":
		list, err := dp.List(r.Context(), m.Name)
		if err != nil {
			return err
		}
		_, err = w.Write([]byte(strings.Join(list, "\n")))
		if err != nil {
			return err
		}
		return nil
	case "info":
		info, err := dp.Info(r.Context(), m.Name, m.Version)
		if err != nil {
			return err
		}
		_, err = w.Write(info)
		if err != nil {
			return err
		}
		return nil
	case "mod":
		mod, err := dp.GoMod(r.Context(), m.Name, m.Version)
		if err != nil {
			return err
		}
		_, err = w.Write(mod)
		if err != nil {
			return err
		}
		return nil
	case "zip":
		zip, err := dp.Zip(r.Context(), m.Name, m.Version)
		if err != nil {
			return err
		}
		defer zip.Close()
		w.Write([]byte{})
		_, err = io.Copy(w, zip)
		if err != nil {
			return err
		}
		return nil
	case "latest":
		info, err := dp.Latest(r.Context(), m.Name)
		if err != nil {
			return err
		}
		json, err := json.Marshal(info)
		if err != nil {
			return err
		}
		_, err = w.Write(json)
		if err != nil {
			return err
		}
		return nil
	default:
		return fmt.Errorf("the requested file's extension is not supported")
	}

	return nil
}

func (m Module) fetch(r *http.Request, c Config) (download.Protocol, error) {
	fs := afero.NewOsFs()
	fetcher, err := module.NewGoGetFetcher("/usr/local/go/bin/go", fs)
	if err != nil {
		return nil, err
	}
	s, err := m.storage(c)
	if err != nil {
		return nil, err
	}
	dp := m.dp(fetcher, s, fs, c)
	return dp, nil
}

func (m Module) storage(c Config) (storage.Backend, error) {
	switch c.Gomods.Cache.Type {
	case "local":
		s, err := fs.NewStorage(c.Gomods.Cache.Path, afero.NewOsFs())
		if err != nil {
			return nil, fmt.Errorf("could not create new storage from os fs (%s)", err)
		}
		return s, nil
	}
	return nil, fmt.Errorf("Invalid storage config for gomods")
}

func (m Module) dp(fetcher module.Fetcher, s storage.Backend, fs afero.Fs, c Config) download.Protocol {
	lister := download.NewVCSLister(c.Gomods.GoBinary, fs)
	st := stash.New(fetcher, s, stash.WithPool(c.Gomods.Workers), stash.WithSingleflight)
	dpOpts := &download.Opts{
		Storage: s,
		Stasher: st,
		Lister:  lister,
	}
	dp := download.New(dpOpts, addons.WithPool(c.Gomods.Workers))
	return dp
}

func moduleNameAndVersion(path string) (string, string, string) {
	pathSlice := strings.Split(path, "/")[1:] // [1:] ignores the empty slice item
	var ext, version string
	for k, v := range pathSlice {
		if v == "@v" {
			ext = gomodsRegex.FindAllStringSubmatch(pathSlice[k+1], -1)[0][0]
			break
		}
	}
	moduleName := strings.Join(pathSlice[0:3], "/")
	if strings.Contains(path, "@latest") {
		return strings.Join(pathSlice[0:3], "/"), "", "latest"
	}
	if !strings.Contains(path, "list") {
		version = modVersionRegex.FindAllStringSubmatch(path, -1)[0][1]
	}
	return moduleName, version, ext
}
<commit_msg>(gomods): Fix mod version regex<commit_after>package txtdirect

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"regexp"
	"strings"

	"github.com/gomods/athens/pkg/download"
	"github.com/gomods/athens/pkg/download/addons"
	"github.com/gomods/athens/pkg/module"
	"github.com/gomods/athens/pkg/stash"
	"github.com/gomods/athens/pkg/storage"
	"github.com/gomods/athens/pkg/storage/fs"
	"github.com/spf13/afero"
)

type Gomods struct {
	Enable   bool
	GoBinary string
	Workers  int
	Cache    struct {
		Type string
		Path string
	}
}

type Module struct {
	Name    string
	Version string
}

type ModuleHandler interface {
	fetch(r *http.Request, c Config) (*storage.Version, error)
	storage(c Config) (storage.Backend, error)
	dp(fetcher module.Fetcher, s storage.Backend, fs afero.Fs) download.Protocol
}

var gomodsRegex = regexp.MustCompile("(list|info|mod|zip)")
var modVersionRegex = regexp.MustCompile("@v\\/(v\\d+\\.\\d+\\.\\d+\\-\\d+\\-[\\w\\d]+|v\\d+\\.\\d+\\.\\d+|v\\d+\\.\\d+|latest|master)")

func gomods(w http.ResponseWriter, r *http.Request, path string, c Config) error {
	moduleName, version, ext := moduleNameAndVersion(path)
	if moduleName == "" {
		return fmt.Errorf("module url is empty")
	}
	m := Module{
		Name:    moduleName,
		Version: version,
	}
	dp, err := m.fetch(r, c)
	if err != nil {
		return err
	}
	switch ext {
	case "list":
		list, err := dp.List(r.Context(), m.Name)
		if err != nil {
			return err
		}
		_, err = w.Write([]byte(strings.Join(list, "\n")))
		if err != nil {
			return err
		}
		return nil
	case "info":
		info, err := dp.Info(r.Context(), m.Name, m.Version)
		if err != nil {
			return err
		}
		_, err = w.Write(info)
		if err != nil {
			return err
		}
		return nil
	case "mod":
		mod, err := dp.GoMod(r.Context(), m.Name, m.Version)
		if err != nil {
			return err
		}
		_, err = w.Write(mod)
		if err != nil {
			return err
		}
		return nil
	case "zip":
		zip, err := dp.Zip(r.Context(), m.Name, m.Version)
		if err != nil {
			return err
		}
		defer zip.Close()
		w.Write([]byte{})
		_, err = io.Copy(w, zip)
		if err != nil {
			return err
		}
		return nil
	case "latest":
		info, err := dp.Latest(r.Context(), m.Name)
		if err != nil {
			return err
		}
		json, err := json.Marshal(info)
		if err != nil {
			return err
		}
		_, err = w.Write(json)
		if err != nil {
			return err
		}
		return nil
	default:
		return fmt.Errorf("the requested file's extension is not supported")
	}
}

func (m Module) fetch(r *http.Request, c Config) (download.Protocol, error) {
	fs := afero.NewOsFs()
	fetcher, err := module.NewGoGetFetcher(c.Gomods.GoBinary, fs)
	if err != nil {
		return nil, err
	}
	s, err := m.storage(c)
	if err != nil {
		return nil, err
	}
	dp := m.dp(fetcher, s, fs, c)
	return dp, nil
}

func (m Module) storage(c Config) (storage.Backend, error) {
	switch c.Gomods.Cache.Type {
	case "local":
		s, err := fs.NewStorage(c.Gomods.Cache.Path, afero.NewOsFs())
		if err != nil {
			return nil, fmt.Errorf("could not create new storage from os fs (%s)", err)
		}
		return s, nil
	}
	return nil, fmt.Errorf("Invalid storage config for gomods")
}

func (m Module) dp(fetcher module.Fetcher, s storage.Backend, fs afero.Fs, c Config) download.Protocol {
	lister := download.NewVCSLister(c.Gomods.GoBinary, fs)
	st := stash.New(fetcher, s, stash.WithPool(c.Gomods.Workers), stash.WithSingleflight)
	dpOpts := &download.Opts{
		Storage: s,
		Stasher: st,
		Lister:  lister,
	}
	dp := download.New(dpOpts, addons.WithPool(c.Gomods.Workers))
	return dp
}

func moduleNameAndVersion(path string) (string, string, string) {
	pathSlice := strings.Split(path, "/")[1:] // [1:] ignores the empty slice item
	var ext, version string
	for k, v := range pathSlice {
		if v == "@v" {
			ext = gomodsRegex.FindAllStringSubmatch(pathSlice[k+1], -1)[0][0]
			break
		}
	}
	moduleName := strings.Join(pathSlice[0:3], "/")
	if strings.Contains(path, "@latest") {
		return strings.Join(pathSlice[0:3], "/"), "", "latest"
	}
	if !strings.Contains(path, "list") {
		version = modVersionRegex.FindAllStringSubmatch(path, -1)[0][1]
	}
	return moduleName, version, ext
}
<|endoftext|>


<commit_before>package main

// AppVersion is application version
const AppVersion = "0.1.0"
<commit_msg>Bump version 0.1.0 -> 0.2.0<commit_after>package main

// AppVersion is application version
const AppVersion = "0.2.0"
<|endoftext|>


<commit_before>package transloadit

// Version specifies the version of the Go SDK.
var Version = "v1.0.0"
<commit_msg>Bump version to v1.1.0<commit_after>package transloadit

// Version specifies the version of the Go SDK.
var Version = "v1.1.0"
<|endoftext|>


<commit_before>package test161

import (
	"fmt"
)

type ProgramVersion struct {
	Major    uint `yaml:"major"`
	Minor    uint `yaml:"minor"`
	Revision uint `yaml:"revision"`
}

var Version = ProgramVersion{
	Major:    1,
	Minor:    2,
	Revision: 5,
}

func (v ProgramVersion) String() string {
	return fmt.Sprintf("%v.%v.%v", v.Major, v.Minor, v.Revision)
}

// Returns 1 if this > other, 0 if this == other, and -1 if this < other
func (this ProgramVersion) CompareTo(other ProgramVersion) int {

	if this.Major > other.Major {
		return 1
	} else if this.Major < other.Major {
		return -1
	} else if this.Minor > other.Minor {
		return 1
	} else if this.Minor < other.Minor {
		return -1
	} else if this.Revision > other.Revision {
		return 1
	} else if this.Revision < other.Revision {
		return -1
	} else {
		return 0
	}

}
<commit_msg>Updating version to 1.3.0<commit_after>package test161

import (
	"fmt"
)

type ProgramVersion struct {
	Major    uint `yaml:"major"`
	Minor    uint `yaml:"minor"`
	Revision uint `yaml:"revision"`
}

var Version = ProgramVersion{
	Major:    1,
	Minor:    3,
	Revision: 0,
}

func (v ProgramVersion) String() string {
	return fmt.Sprintf("%v.%v.%v", v.Major, v.Minor, v.Revision)
}

// Returns 1 if this > other, 0 if this == other, and -1 if this < other
func (this ProgramVersion) CompareTo(other ProgramVersion) int {

	if this.Major > other.Major {
		return 1
	} else if this.Major < other.Major {
		return -1
	} else if this.Minor > other.Minor {
		return 1
	} else if this.Minor < other.Minor {
		return -1
	} else if this.Revision > other.Revision {
		return 1
	} else if this.Revision < other.Revision {
		return -1
	} else {
		return 0
	}

}
<|endoftext|>


<commit_before>package main

var VersionInfo = struct {
	Version     string
	FullVersion string
	Hash        string
	ShortHash   string
	Date        string
}{
  "1.0.0",
  "1.0.0-5-g7d7e9a9",
  "7d7e9a9080527fe5e7da0cdfa2c1a46653aee6ae",
  "7d7e9a9",
  "2017-03-30-1626 UTC",
}

<commit_msg>Bump version to 1.0.1<commit_after>package main

var VersionInfo = struct {
	Version     string
	FullVersion string
	Hash        string
	ShortHash   string
	Date        string
}{
  "1.0.1",
  "1.0.1",
  "496d9e17a5851b3dda46d2c773c68c5709809b42",
  "496d9e1",
  "2017-03-30-1628 UTC",
}

<|endoftext|>


<commit_before>package main

const Version = "0.3.0"
<commit_msg>Bump version after release<commit_after>package main

const Version = "0.3.1"
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Snowflake Computing Inc. All right reserved.

package gosnowflake

// SnowflakeGoDriverVersion is the version of Go Snowflake Driver.
const SnowflakeGoDriverVersion = "1.3.9"
<commit_msg>Version Bump Go Connector to 1.3.10<commit_after>// Copyright (c) 2017-2019 Snowflake Computing Inc. All right reserved.

package gosnowflake

// SnowflakeGoDriverVersion is the version of Go Snowflake Driver.
const SnowflakeGoDriverVersion = "1.3.10"
<|endoftext|>


<commit_before>//
// store.go
//

package srnd

import (

  "github.com/majestrate/srndv2/src/nacl"
  "github.com/gographics/imagick/imagick"

  "bytes"
  "crypto/sha512"
  "encoding/base32"
  "encoding/base64"
  "errors"
  "fmt"
  "io"
  //"io/ioutil"
  "log"
  "mime"
  "mime/multipart"
  "net/mail"
  "net/textproto"
  "os"
  "path/filepath"
  "strings"
)

type ArticleStore interface {
  MessageReader
  MessageWriter
  MessageVerifier
  AttachmentReader

  // get the filepath for an attachment
  AttachmentFilepath(fname string) string
  // get the filepath for an attachment's thumbnail
  ThumbnailFilepath(fname string) string
  // do we have this article?
  HasArticle(msgid string) bool
  // create a file for a message
  CreateFile(msgid string) io.WriteCloser
  // create a file for a temp message
  CreateTempFile(msgid string) io.WriteCloser
  // get the filename of a message
  GetFilename(msgid string) string
  // get the filename of a temp message
  GetTempFilename(msgid string) string
  // Get a message given its messageid
  GetMessage(msgid string) NNTPMessage
  // get a temp message given its messageid
  // temp message is deleted once read
  ReadTempMessage(msgid string) NNTPMessage
  // store a post
  StorePost(nntp NNTPMessage) error
  // get article headers only
  GetHeaders(msgid string) ArticleHeaders

  // get our temp directory for articles
  TempDir() string
}
type articleStore struct {
  directory string
  temp string
  attachments string
  thumbs string
  database Database
}

func createArticleStore(config map[string]string, database Database) ArticleStore {
  store := articleStore{
    directory: config["store_dir"],
    temp: config["incoming_dir"],
    attachments: config["attachments_dir"],
    thumbs: config["thumbs_dir"],
    database: database,
  }
  store.Init()
  return store
}

func (self articleStore) TempDir() string {
  return self.temp
}

// initialize article store
func (self articleStore) Init() {
  EnsureDir(self.directory)
  EnsureDir(self.temp)
  EnsureDir(self.attachments)
  EnsureDir(self.thumbs)
}

func (self articleStore) GenerateThumbnail(infname string) (err error) {
  wand := imagick.NewMagickWand()
  defer wand.Destroy()
  // read image source
  err = wand.ReadImage(self.AttachmentFilepath(infname))
  if err == nil {
    // get size
    h := wand.GetImageHeight()
    w := wand.GetImageWidth()

    // calculate scale parameters
    var scale, th, tw float64
    scale = 180
    modifier := scale / float64(w)
    th = modifier * float64(h)
    tw = modifier * float64(w)
    // scale it
    err = wand.ScaleImage(uint(tw), uint(th))
    if err == nil {
      err = wand.WriteImage(self.ThumbnailFilepath(infname))
    }
  }
  return
}

func (self articleStore) StorePost(nntp NNTPMessage) (err error) {
  f := self.CreateFile(nntp.MessageID())
  if f != nil {
    err = self.WriteMessage(nntp, f)
    f.Close()
  }
  for _, att := range nntp.Attachments() {
    fpath := att.Filepath()

    upload := self.AttachmentFilepath(fpath)

    // save attachment
    log.Println("save attachment", att.Filename(), "to", upload)
    f, err = os.Create(upload)
    if err == nil {
      err = att.WriteTo(f)
      f.Close()
    }
    if err != nil {
      return
    }

    // generate thumbanils
    if att.NeedsThumbnail() {
      err = self.GenerateThumbnail(fpath)
      if err != nil {
        log.Println("failed to generate thumbnail", err)
        return
      }
    }
  }
  return
}

func (self articleStore) ReadMessage(r io.Reader) (NNTPMessage, error) {

  msg, err := mail.ReadMessage(r)
  nntp := nntpArticle{}

  if err == nil {
    nntp.headers = ArticleHeaders(msg.Header)
    content_type := msg.Header.Get("Content-Type")
    media_type, params, err := mime.ParseMediaType(content_type)
    if err != nil {
      log.Println("failed to parse media type", err)
      return nil, err
    }
    boundary, ok := params["boundary"]
    if ok {
      partReader := multipart.NewReader(msg.Body, boundary)
      for {
        part, err := partReader.NextPart()
        if err == io.EOF {
          return nntp, nil
        } else if err == nil {
          hdr := part.Header
          // get content type of part
          part_type := hdr.Get("Content-Type")
          log.Println("part has content type", part_type)
          // parse content type
          media_type, _, err = mime.ParseMediaType(part_type)
          if err == nil {
            if media_type == "text/plain" {
              att := self.ReadAttachmentFromMimePart(part, true)
              if att != nil {
                att.WriteTo(&nntp.message.body)
              }
              if nntp.message.header == nil {
                nntp.message.header = make(textproto.MIMEHeader)
              }
              nntp.message.header.Set("Content-Type", part_type)

            } else {
              // non plaintext gets added to attachments
              att := self.ReadAttachmentFromMimePart(part, true)
              if att != nil {
                nntp = nntp.Attach(att).(nntpArticle)
              }
            }
          } else {
            log.Println("part has no content type", err)
          }
          part.Close()
        } else {
          log.Println("failed to load part! ", err)
          return nntp, err
        }
      }

    } else if media_type == "message/rfc822" {
      // tripcoded message
      sig := nntp.headers.Get("X-Signature-Ed25519-Sha512", "")
      pk := nntp.headers.Get("X-Pubkey-Ed25519", "")
      if pk == "" || sig == "" {
        log.Println("invalid sig or pubkey", sig, pk)
        return nil, errors.New("invalid headers")
      }
      log.Printf("got signed message from %s", pk)
      var smsg bytes.Buffer
      _, err = io.Copy(&smsg, msg.Body)
      if err == nil {
        pk_bytes := unhex(pk)
        sig_bytes := unhex(sig)
        body_bytes := sha512.Sum512(smsg.Bytes())
        if nacl.CryptoVerifyFucky(body_bytes[:], sig_bytes, pk_bytes) {
          log.Println("signature is valid :^)")
        } else {
          log.Println("!!!signature is invalid!!!")
        }
      }
    } else {
      _, err = nntp.message.body.ReadFrom(msg.Body)
    }
  } else {
    log.Println("failed to read message", err)
  }
  return nntp, err
}

func (self articleStore) WriteMessage(nntp NNTPMessage, wr io.Writer) (err error) {
  // write headers
  for hdr, hdr_vals := range(nntp.Headers()) {
    for _ , hdr_val := range hdr_vals {
      _, err = io.WriteString(wr, fmt.Sprintf("%s: %s\n", hdr, hdr_val))
      if err != nil {
        return
      }
    }
  }
  // done headers
  _, err = io.WriteString(wr, "\n")
  if err != nil {
    return
  }
  // write body
  err = nntp.WriteBody(wr)
  return
}

func (self articleStore) VerifyMessage(nntp NNTPMessage) (NNTPMessage, error) {
  // TODO: implement
  return nntp, nil
}

// get the filepath for an attachment
func (self articleStore) AttachmentFilepath(fname string) string {
  return filepath.Join(self.attachments, fname)
}

// get the filepath for a thumbanil
func (self articleStore) ThumbnailFilepath(fname string) string {
  return filepath.Join(self.thumbs, fname)
}

// create a file for this article
func (self articleStore) CreateFile(messageID string) io.WriteCloser {
  fname := self.GetFilename(messageID)
  file, err := os.Create(fname)
  if err != nil {
    log.Println("cannot open file", fname)
    return nil
  }
  return file
}

// create a temp file for inboud articles
func (self articleStore) CreateTempFile(messageID string) io.WriteCloser {
  fname := self.GetTempFilename(messageID)
  file, err := os.Create(fname)
  if err != nil {
    log.Println("cannot open file", fname)
    return nil
  }
  return file
}

// return true if we have an article
func (self articleStore) HasArticle(messageID string) bool {
  return self.database.HasArticle(messageID)
}

// get the filename for this article
func (self articleStore) GetFilename(messageID string) string {
  return filepath.Join(self.directory, messageID)
}

// get the filename for this article
func (self articleStore) GetTempFilename(messageID string) string {
  return filepath.Join(self.temp, messageID)
}

// loads temp message and deletes old article
func (self articleStore) ReadTempMessage(messageID string) NNTPMessage {
  fname := self.GetTempFilename(messageID)
  nntp := self.readfile(fname)
  DelFile(fname)
  return nntp
}

// read a file give filepath
func (self articleStore) readfile(fname string) NNTPMessage {

  file, err := os.Open(fname)
  if err != nil {
    log.Println("store cannot open file",fname)
    return nil
  }
  message, err := self.ReadMessage(file)
  file.Close()
  if err == nil {
    return message
  }

  log.Println("failed to load file", fname)
  return nil
}

// get the replies for a thread
func (self articleStore) GetThreadReplies(messageID string, last int) []NNTPMessage {
  var repls []NNTPMessage
  if self.database.ThreadHasReplies(messageID) {
    rpls := self.database.GetThreadReplies(messageID, last)
    if rpls == nil {
      return repls
    }
    for _, rpl := range rpls {
      msg := self.GetMessage(rpl)
      if msg == nil {
        log.Println("cannot get message", rpl)
      } else {
        repls = append(repls, msg)
      }
    }
  }
  return repls
}

// load an article
// return nil on failure
func (self articleStore) GetMessage(messageID string) NNTPMessage {
  return self.readfile(self.GetFilename(messageID))
}

// get article with headers only
func (self articleStore) GetHeaders(messageID string) ArticleHeaders {
  // TODO: don't load the entire body
  nntp := self.readfile(self.GetFilename(messageID))
  if nntp == nil {
    return nil
  }
  return nntp.Headers()
}

func (self articleStore) ReadAttachmentFromMimePart(part *multipart.Part, decode bool) NNTPAttachment {
  var buff bytes.Buffer
  content_type := part.Header.Get("Content-Type")
  media_type, _ , err := mime.ParseMediaType(content_type)

  fname := part.FileName()
  idx := strings.LastIndex(fname, ".")
  ext := ".txt"
  if idx > 0 {
    ext = fname[idx:]
  }

  transfer_encoding := part.Header.Get("Content-Transfer-Encoding")

  if transfer_encoding == "base64" {
    reader := base64.NewDecoder(base64.StdEncoding, part)
    _, err = io.Copy(&buff, reader)
  } else {
    _, err = io.Copy(&buff, part)
  }
  if err != nil {
    log.Println("failed to read attachment from mimepart", err)
    return nil
  }
  sha := sha512.Sum512(buff.Bytes())
  hashstr := base32.StdEncoding.EncodeToString(sha[:])
  fpath := hashstr+ext
  hdr := part.Header
  return nntpAttachment{
    header: hdr,
    body: buff,
    mime: media_type,
    filename: fname,
    filepath: fpath,
    ext: ext,
    hash: sha[:],
  }
}
<commit_msg>log sha512 for debugging<commit_after>//
// store.go
//

package srnd

import (

  "github.com/majestrate/srndv2/src/nacl"
  "github.com/gographics/imagick/imagick"

  "bytes"
  "crypto/sha512"
  "encoding/base32"
  "encoding/base64"
  "encoding/hex"
  "errors"
  "fmt"
  "io"
  //"io/ioutil"
  "log"
  "mime"
  "mime/multipart"
  "net/mail"
  "net/textproto"
  "os"
  "path/filepath"
  "strings"
)

type ArticleStore interface {
  MessageReader
  MessageWriter
  MessageVerifier
  AttachmentReader

  // get the filepath for an attachment
  AttachmentFilepath(fname string) string
  // get the filepath for an attachment's thumbnail
  ThumbnailFilepath(fname string) string
  // do we have this article?
  HasArticle(msgid string) bool
  // create a file for a message
  CreateFile(msgid string) io.WriteCloser
  // create a file for a temp message
  CreateTempFile(msgid string) io.WriteCloser
  // get the filename of a message
  GetFilename(msgid string) string
  // get the filename of a temp message
  GetTempFilename(msgid string) string
  // Get a message given its messageid
  GetMessage(msgid string) NNTPMessage
  // get a temp message given its messageid
  // temp message is deleted once read
  ReadTempMessage(msgid string) NNTPMessage
  // store a post
  StorePost(nntp NNTPMessage) error
  // get article headers only
  GetHeaders(msgid string) ArticleHeaders

  // get our temp directory for articles
  TempDir() string
}
type articleStore struct {
  directory string
  temp string
  attachments string
  thumbs string
  database Database
}

func createArticleStore(config map[string]string, database Database) ArticleStore {
  store := articleStore{
    directory: config["store_dir"],
    temp: config["incoming_dir"],
    attachments: config["attachments_dir"],
    thumbs: config["thumbs_dir"],
    database: database,
  }
  store.Init()
  return store
}

func (self articleStore) TempDir() string {
  return self.temp
}

// initialize article store
func (self articleStore) Init() {
  EnsureDir(self.directory)
  EnsureDir(self.temp)
  EnsureDir(self.attachments)
  EnsureDir(self.thumbs)
}

func (self articleStore) GenerateThumbnail(infname string) (err error) {
  wand := imagick.NewMagickWand()
  defer wand.Destroy()
  // read image source
  err = wand.ReadImage(self.AttachmentFilepath(infname))
  if err == nil {
    // get size
    h := wand.GetImageHeight()
    w := wand.GetImageWidth()

    // calculate scale parameters
    var scale, th, tw float64
    scale = 180
    modifier := scale / float64(w)
    th = modifier * float64(h)
    tw = modifier * float64(w)
    // scale it
    err = wand.ScaleImage(uint(tw), uint(th))
    if err == nil {
      err = wand.WriteImage(self.ThumbnailFilepath(infname))
    }
  }
  return
}

func (self articleStore) StorePost(nntp NNTPMessage) (err error) {
  f := self.CreateFile(nntp.MessageID())
  if f != nil {
    err = self.WriteMessage(nntp, f)
    f.Close()
  }
  for _, att := range nntp.Attachments() {
    fpath := att.Filepath()

    upload := self.AttachmentFilepath(fpath)

    // save attachment
    log.Println("save attachment", att.Filename(), "to", upload)
    f, err = os.Create(upload)
    if err == nil {
      err = att.WriteTo(f)
      f.Close()
    }
    if err != nil {
      return
    }

    // generate thumbanils
    if att.NeedsThumbnail() {
      err = self.GenerateThumbnail(fpath)
      if err != nil {
        log.Println("failed to generate thumbnail", err)
        return
      }
    }
  }
  return
}

func (self articleStore) ReadMessage(r io.Reader) (NNTPMessage, error) {

  msg, err := mail.ReadMessage(r)
  nntp := nntpArticle{}

  if err == nil {
    nntp.headers = ArticleHeaders(msg.Header)
    content_type := msg.Header.Get("Content-Type")
    media_type, params, err := mime.ParseMediaType(content_type)
    if err != nil {
      log.Println("failed to parse media type", err)
      return nil, err
    }
    boundary, ok := params["boundary"]
    if ok {
      partReader := multipart.NewReader(msg.Body, boundary)
      for {
        part, err := partReader.NextPart()
        if err == io.EOF {
          return nntp, nil
        } else if err == nil {
          hdr := part.Header
          // get content type of part
          part_type := hdr.Get("Content-Type")
          log.Println("part has content type", part_type)
          // parse content type
          media_type, _, err = mime.ParseMediaType(part_type)
          if err == nil {
            if media_type == "text/plain" {
              att := self.ReadAttachmentFromMimePart(part, true)
              if att != nil {
                att.WriteTo(&nntp.message.body)
              }
              if nntp.message.header == nil {
                nntp.message.header = make(textproto.MIMEHeader)
              }
              nntp.message.header.Set("Content-Type", part_type)

            } else {
              // non plaintext gets added to attachments
              att := self.ReadAttachmentFromMimePart(part, true)
              if att != nil {
                nntp = nntp.Attach(att).(nntpArticle)
              }
            }
          } else {
            log.Println("part has no content type", err)
          }
          part.Close()
        } else {
          log.Println("failed to load part! ", err)
          return nntp, err
        }
      }

    } else if media_type == "message/rfc822" {
      // tripcoded message
      sig := nntp.headers.Get("X-Signature-Ed25519-Sha512", "")
      pk := nntp.headers.Get("X-Pubkey-Ed25519", "")
      if pk == "" || sig == "" {
        log.Println("invalid sig or pubkey", sig, pk)
        return nil, errors.New("invalid headers")
      }
      log.Printf("got signed message from %s", pk)
      var smsg bytes.Buffer
      _, err = io.Copy(&smsg, msg.Body)
      if err == nil {
        pk_bytes := unhex(pk)
        sig_bytes := unhex(sig)
        body_bytes := sha512.Sum512(smsg.Bytes())
        log.Printf("body sum=%s", hex.EncodeToString(body_bytes[:]))
        if nacl.CryptoVerifyFucky(body_bytes[:], sig_bytes, pk_bytes) {
          log.Println("signature is valid :^)")
        } else {
          log.Println("!!!signature is invalid!!!")
        }
      }
    } else {
      _, err = nntp.message.body.ReadFrom(msg.Body)
    }
  } else {
    log.Println("failed to read message", err)
  }
  return nntp, err
}

func (self articleStore) WriteMessage(nntp NNTPMessage, wr io.Writer) (err error) {
  // write headers
  for hdr, hdr_vals := range(nntp.Headers()) {
    for _ , hdr_val := range hdr_vals {
      _, err = io.WriteString(wr, fmt.Sprintf("%s: %s\n", hdr, hdr_val))
      if err != nil {
        return
      }
    }
  }
  // done headers
  _, err = io.WriteString(wr, "\n")
  if err != nil {
    return
  }
  // write body
  err = nntp.WriteBody(wr)
  return
}

func (self articleStore) VerifyMessage(nntp NNTPMessage) (NNTPMessage, error) {
  // TODO: implement
  return nntp, nil
}

// get the filepath for an attachment
func (self articleStore) AttachmentFilepath(fname string) string {
  return filepath.Join(self.attachments, fname)
}

// get the filepath for a thumbanil
func (self articleStore) ThumbnailFilepath(fname string) string {
  return filepath.Join(self.thumbs, fname)
}

// create a file for this article
func (self articleStore) CreateFile(messageID string) io.WriteCloser {
  fname := self.GetFilename(messageID)
  file, err := os.Create(fname)
  if err != nil {
    log.Println("cannot open file", fname)
    return nil
  }
  return file
}

// create a temp file for inboud articles
func (self articleStore) CreateTempFile(messageID string) io.WriteCloser {
  fname := self.GetTempFilename(messageID)
  file, err := os.Create(fname)
  if err != nil {
    log.Println("cannot open file", fname)
    return nil
  }
  return file
}

// return true if we have an article
func (self articleStore) HasArticle(messageID string) bool {
  return self.database.HasArticle(messageID)
}

// get the filename for this article
func (self articleStore) GetFilename(messageID string) string {
  return filepath.Join(self.directory, messageID)
}

// get the filename for this article
func (self articleStore) GetTempFilename(messageID string) string {
  return filepath.Join(self.temp, messageID)
}

// loads temp message and deletes old article
func (self articleStore) ReadTempMessage(messageID string) NNTPMessage {
  fname := self.GetTempFilename(messageID)
  nntp := self.readfile(fname)
  DelFile(fname)
  return nntp
}

// read a file give filepath
func (self articleStore) readfile(fname string) NNTPMessage {

  file, err := os.Open(fname)
  if err != nil {
    log.Println("store cannot open file",fname)
    return nil
  }
  message, err := self.ReadMessage(file)
  file.Close()
  if err == nil {
    return message
  }

  log.Println("failed to load file", fname)
  return nil
}

// get the replies for a thread
func (self articleStore) GetThreadReplies(messageID string, last int) []NNTPMessage {
  var repls []NNTPMessage
  if self.database.ThreadHasReplies(messageID) {
    rpls := self.database.GetThreadReplies(messageID, last)
    if rpls == nil {
      return repls
    }
    for _, rpl := range rpls {
      msg := self.GetMessage(rpl)
      if msg == nil {
        log.Println("cannot get message", rpl)
      } else {
        repls = append(repls, msg)
      }
    }
  }
  return repls
}

// load an article
// return nil on failure
func (self articleStore) GetMessage(messageID string) NNTPMessage {
  return self.readfile(self.GetFilename(messageID))
}

// get article with headers only
func (self articleStore) GetHeaders(messageID string) ArticleHeaders {
  // TODO: don't load the entire body
  nntp := self.readfile(self.GetFilename(messageID))
  if nntp == nil {
    return nil
  }
  return nntp.Headers()
}

func (self articleStore) ReadAttachmentFromMimePart(part *multipart.Part, decode bool) NNTPAttachment {
  var buff bytes.Buffer
  content_type := part.Header.Get("Content-Type")
  media_type, _ , err := mime.ParseMediaType(content_type)

  fname := part.FileName()
  idx := strings.LastIndex(fname, ".")
  ext := ".txt"
  if idx > 0 {
    ext = fname[idx:]
  }

  transfer_encoding := part.Header.Get("Content-Transfer-Encoding")

  if transfer_encoding == "base64" {
    reader := base64.NewDecoder(base64.StdEncoding, part)
    _, err = io.Copy(&buff, reader)
  } else {
    _, err = io.Copy(&buff, part)
  }
  if err != nil {
    log.Println("failed to read attachment from mimepart", err)
    return nil
  }
  sha := sha512.Sum512(buff.Bytes())
  hashstr := base32.StdEncoding.EncodeToString(sha[:])
  fpath := hashstr+ext
  hdr := part.Header
  return nntpAttachment{
    header: hdr,
    body: buff,
    mime: media_type,
    filename: fname,
    filepath: fpath,
    ext: ext,
    hash: sha[:],
  }
}
<|endoftext|>


<commit_before>package gopher

import (
	"github.com/gopherlabs/gopher-framework"
	"github.com/gopherlabs/gopher-services"
)

const (
	LOGGER   = framework.LOGGER
	ROUTER   = framework.ROUTER
	RENDERER = framework.RENDERER
	PARAMS   = framework.PARAMS
	SAMPLE   = framework.SAMPLE
)

func NewApp(config ...framework.Config) *framework.Container {
	appConf := framework.Config{}
	if len(config) > 0 {
		appConf = config[0]
	}
	container := framework.NewContainer(appConf)
	registerProviders(container)
	return container
}

func registerProviders(container *framework.Container) {
	container.RegisterProvider(new(services.LogProvider))
	container.RegisterProvider(new(services.RouteProvider))
	container.RegisterProvider(new(services.ParameterProvider))
	container.RegisterProvider(new(services.RenderProvider))
}
<commit_msg>Pulled LoggerMiddleware up to app container and moved to bootstrapper<commit_after>package gopher

import (
	"github.com/gopherlabs/gopher-framework"
	"github.com/gopherlabs/gopher-services"
)

const (
	LOGGER   = framework.LOGGER
	ROUTER   = framework.ROUTER
	RENDERER = framework.RENDERER
	PARAMS   = framework.PARAMS
	SAMPLE   = framework.SAMPLE
)

func NewApp(config ...framework.Config) *framework.Container {
	appConf := framework.Config{}
	if len(config) > 0 {
		appConf = config[0]
	}
	container := framework.NewContainer(appConf)
	registerProviders(container)
	container.Use(framework.LoggerMiddleware)
	return container
}

func registerProviders(container *framework.Container) {
	container.RegisterProvider(new(services.LogProvider))
	container.RegisterProvider(new(services.RouteProvider))
	container.RegisterProvider(new(services.ParameterProvider))
	container.RegisterProvider(new(services.RenderProvider))
}
<|endoftext|>


<commit_before>// Package gopush provides an implementation of Push 3.0, a stack-based
// programming language designed for genetic programming
package gopush

import (
	"errors"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
)

// Interpreter is a Push interpreter.
type Interpreter struct {
	Stacks  map[string]*Stack
	Options Options
	Rand    *rand.Rand

	Definitions       map[string]Code
	listOfDefinitions []string

	numEvalPush       int
	quoteNextName     bool
	numNamesGenerated uint
}

// NewInterpreter returns a new Push Interpreter, configured with the provided Options.
func NewInterpreter(options Options) *Interpreter {

	if options.RandomSeed == 0 {
		options.RandomSeed = rand.Int63()
	}

	interpreter := &Interpreter{
		Stacks:            make(map[string]*Stack),
		Options:           options,
		Rand:              rand.New(rand.NewSource(options.RandomSeed)),
		Definitions:       make(map[string]Code),
		listOfDefinitions: make([]string, 0),
		numEvalPush:       0,
		quoteNextName:     false,
		numNamesGenerated: 0,
	}

	// Setup stacks
	interpreter.Stacks["exec"] = newExecStack(interpreter)
	interpreter.Stacks["name"] = newNameStack(interpreter)

	if _, ok := options.AllowedTypes["boolean"]; ok {
		interpreter.Stacks["boolean"] = newBooleanStack(interpreter)

		// Prune disallowed instructions
		for fn := range interpreter.Stacks["boolean"].Functions {
			if _, ok := options.AllowedInstructions["boolean."+fn]; !ok {
				delete(interpreter.Stacks["boolean"].Functions, fn)
			}
		}
	}

	if _, ok := options.AllowedTypes["code"]; ok {
		interpreter.Stacks["code"] = newCodeStack(interpreter)

		// Prune disallowed instructions
		for fn := range interpreter.Stacks["code"].Functions {
			if _, ok := options.AllowedInstructions["code."+fn]; !ok {
				delete(interpreter.Stacks["code"].Functions, fn)
			}
		}
	}

	if _, ok := options.AllowedTypes["float"]; ok {
		interpreter.Stacks["float"] = newFloatStack(interpreter)

		// Prune disallowed instructions
		for fn := range interpreter.Stacks["float"].Functions {
			if _, ok := options.AllowedInstructions["float."+fn]; !ok {
				delete(interpreter.Stacks["float"].Functions, fn)
			}
		}
	}

	if _, ok := options.AllowedTypes["integer"]; ok {
		interpreter.Stacks["integer"] = newIntStack(interpreter)

		// Prune disallowed instructions
		for fn := range interpreter.Stacks["integer"].Functions {
			if _, ok := options.AllowedInstructions["integer."+fn]; !ok {
				delete(interpreter.Stacks["integer"].Functions, fn)
			}
		}
	}

	return interpreter
}

func (i *Interpreter) stackOK(name string, mindepth int64) bool {
	s, ok := i.Stacks[name]
	if !ok {
		return false
	}

	if s.Len() < mindepth {
		return false
	}

	return true
}

func (i *Interpreter) define(name string, code Code) {
	if _, ok := i.Definitions[name]; !ok {
		i.listOfDefinitions = append(i.listOfDefinitions, name)
	}

	i.Definitions[name] = code
}

func (i *Interpreter) printInterpreterState() {
	fmt.Println("Step", i.numEvalPush)
	for k, v := range i.Stacks {
		fmt.Printf("%s:\n", k)
		for i := len(v.Stack) - 1; i >= 0; i-- {
			fmt.Printf("- %v\n", v.Stack[i])
		}
	}
	fmt.Println()
	fmt.Println()
}

func (i *Interpreter) runCode(program Code) (err error) {

	// Recover from a panic that could occur while executing an instruction.
	// Because it is more convenient for functions to not return an error,
	// the functions that want to return an error panic instead.
	defer func() {
		if perr := recover(); perr != nil {
			err = perr.(error)
		}
	}()

	i.Stacks["exec"].Push(program)

	for i.Stacks["exec"].Len() > 0 && i.numEvalPush < i.Options.EvalPushLimit {

		if i.Options.Tracing {
			i.printInterpreterState()
		}

		item := i.Stacks["exec"].Pop().(Code)
		i.numEvalPush++

		// If the item on top of the exec stack is a list, push it in
		// reverse order
		if item.Literal == "" {
			for j := len(item.List) - 1; j >= 0; j-- {
				i.Stacks["exec"].Push(item.List[j])
			}
			continue
		}

		// Try to parse the item on top of the exec stack as a literal
		if intlit, err := strconv.ParseInt(item.Literal, 10, 64); err == nil {
			if !i.stackOK("integer", 0) {
				return fmt.Errorf("found integer literal %v, but the integer stack is disabled", intlit)
			}
			i.Stacks["integer"].Push(intlit)
			continue
		}

		if floatlit, err := strconv.ParseFloat(item.Literal, 64); err == nil {
			if !i.stackOK("float", 0) {
				return fmt.Errorf("found float literal %v, but the float stack is disabled", floatlit)
			}
			i.Stacks["float"].Push(floatlit)
			continue
		}

		if boollit, err := strconv.ParseBool(item.Literal); err == nil {
			if !i.stackOK("boolean", 0) {
				return fmt.Errorf("found boolean literal %v, but the boolean stack is disabled", boollit)
			}
			i.Stacks["boolean"].Push(boollit)
			continue
		}

		// Try to parse the item on top of the exec stack as instruction
		if strings.Contains(item.Literal, ".") {
			stack := strings.ToLower(item.Literal[:strings.Index(item.Literal, ".")])
			operation := strings.ToLower(item.Literal[strings.Index(item.Literal, ".")+1:])

			s, ok := i.Stacks[stack]
			if !ok {
				return fmt.Errorf("unknown or disabled stack: %v", stack)
			}

			f, ok := s.Functions[operation]
			if !ok {
				return fmt.Errorf("unknown or disabled instruction %v.%v", stack, operation)
			}

			f()
			continue
		}

		// If the item is not an instruction, it must be a name, either
		// bound or unbound. If the quoteNextName flag is false, we can
		// check if the name is already bound.
		if !i.quoteNextName {
			if d, ok := i.Definitions[strings.ToLower(item.Literal)]; ok {
				// Name is already bound, push its value onto the exec stack
				i.Stacks["exec"].Push(d)
				continue
			}
		}

		// The name is not bound yet, so push it onto the name stack
		i.Stacks["name"].Push(strings.ToLower(item.Literal))
		i.quoteNextName = false
	}

	if i.numEvalPush >= i.Options.EvalPushLimit {
		return errors.New("the EvalPushLimit was exceeded")
	}

	return nil
}

// Run runs the given program written in the Push programming language until the
// EvalPushLimit is reached
func (i *Interpreter) Run(program string) error {
	c, err := ParseCode(program)
	if err != nil {
		return err
	}

	if i.Options.TopLevelPushCode {
		if s, ok := i.Stacks["code"]; ok {
			s.Push(c)
		}
	}

	err = i.runCode(c)

	if i.Options.TopLevelPopCode {
		if s, ok := i.Stacks["code"]; ok {
			s.Pop()
		}
	}

	if i.Options.Tracing {
		i.printInterpreterState()
	}

	return err
}
<commit_msg>DRY up pruning of disallowed instructions<commit_after>// Package gopush provides an implementation of Push 3.0, a stack-based
// programming language designed for genetic programming
package gopush

import (
	"errors"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
)

// Interpreter is a Push interpreter.
type Interpreter struct {
	Stacks  map[string]*Stack
	Options Options
	Rand    *rand.Rand

	Definitions       map[string]Code
	listOfDefinitions []string

	numEvalPush       int
	quoteNextName     bool
	numNamesGenerated uint
}

// NewInterpreter returns a new Push Interpreter, configured with the provided Options.
func NewInterpreter(options Options) *Interpreter {

	if options.RandomSeed == 0 {
		options.RandomSeed = rand.Int63()
	}

	interpreter := &Interpreter{
		Stacks:            make(map[string]*Stack),
		Options:           options,
		Rand:              rand.New(rand.NewSource(options.RandomSeed)),
		Definitions:       make(map[string]Code),
		listOfDefinitions: make([]string, 0),
		numEvalPush:       0,
		quoteNextName:     false,
		numNamesGenerated: 0,
	}

	// Setup stacks
	interpreter.Stacks["exec"] = newExecStack(interpreter)
	interpreter.Stacks["name"] = newNameStack(interpreter)

	if _, ok := options.AllowedTypes["boolean"]; ok {
		interpreter.Stacks["boolean"] = newBooleanStack(interpreter)
	}

	if _, ok := options.AllowedTypes["code"]; ok {
		interpreter.Stacks["code"] = newCodeStack(interpreter)
	}

	if _, ok := options.AllowedTypes["float"]; ok {
		interpreter.Stacks["float"] = newFloatStack(interpreter)
	}

	if _, ok := options.AllowedTypes["integer"]; ok {
		interpreter.Stacks["integer"] = newIntStack(interpreter)
	}

	// Prune disallowed instructions
	for sn, stack := range interpreter.Stacks {
		for fn := range stack.Functions {
			if _, ok := options.AllowedInstructions[sn+"."+fn]; !ok {
				delete(stack.Functions, fn)
			}
		}
	}

	return interpreter
}

func (i *Interpreter) stackOK(name string, mindepth int64) bool {
	s, ok := i.Stacks[name]
	if !ok {
		return false
	}

	if s.Len() < mindepth {
		return false
	}

	return true
}

func (i *Interpreter) define(name string, code Code) {
	if _, ok := i.Definitions[name]; !ok {
		i.listOfDefinitions = append(i.listOfDefinitions, name)
	}

	i.Definitions[name] = code
}

func (i *Interpreter) printInterpreterState() {
	fmt.Println("Step", i.numEvalPush)
	for k, v := range i.Stacks {
		fmt.Printf("%s:\n", k)
		for i := len(v.Stack) - 1; i >= 0; i-- {
			fmt.Printf("- %v\n", v.Stack[i])
		}
	}
	fmt.Println()
	fmt.Println()
}

func (i *Interpreter) runCode(program Code) (err error) {

	// Recover from a panic that could occur while executing an instruction.
	// Because it is more convenient for functions to not return an error,
	// the functions that want to return an error panic instead.
	defer func() {
		if perr := recover(); perr != nil {
			err = perr.(error)
		}
	}()

	i.Stacks["exec"].Push(program)

	for i.Stacks["exec"].Len() > 0 && i.numEvalPush < i.Options.EvalPushLimit {

		if i.Options.Tracing {
			i.printInterpreterState()
		}

		item := i.Stacks["exec"].Pop().(Code)
		i.numEvalPush++

		// If the item on top of the exec stack is a list, push it in
		// reverse order
		if item.Literal == "" {
			for j := len(item.List) - 1; j >= 0; j-- {
				i.Stacks["exec"].Push(item.List[j])
			}
			continue
		}

		// Try to parse the item on top of the exec stack as a literal
		if intlit, err := strconv.ParseInt(item.Literal, 10, 64); err == nil {
			if !i.stackOK("integer", 0) {
				return fmt.Errorf("found integer literal %v, but the integer stack is disabled", intlit)
			}
			i.Stacks["integer"].Push(intlit)
			continue
		}

		if floatlit, err := strconv.ParseFloat(item.Literal, 64); err == nil {
			if !i.stackOK("float", 0) {
				return fmt.Errorf("found float literal %v, but the float stack is disabled", floatlit)
			}
			i.Stacks["float"].Push(floatlit)
			continue
		}

		if boollit, err := strconv.ParseBool(item.Literal); err == nil {
			if !i.stackOK("boolean", 0) {
				return fmt.Errorf("found boolean literal %v, but the boolean stack is disabled", boollit)
			}
			i.Stacks["boolean"].Push(boollit)
			continue
		}

		// Try to parse the item on top of the exec stack as instruction
		if strings.Contains(item.Literal, ".") {
			stack := strings.ToLower(item.Literal[:strings.Index(item.Literal, ".")])
			operation := strings.ToLower(item.Literal[strings.Index(item.Literal, ".")+1:])

			s, ok := i.Stacks[stack]
			if !ok {
				return fmt.Errorf("unknown or disabled stack: %v", stack)
			}

			f, ok := s.Functions[operation]
			if !ok {
				return fmt.Errorf("unknown or disabled instruction %v.%v", stack, operation)
			}

			f()
			continue
		}

		// If the item is not an instruction, it must be a name, either
		// bound or unbound. If the quoteNextName flag is false, we can
		// check if the name is already bound.
		if !i.quoteNextName {
			if d, ok := i.Definitions[strings.ToLower(item.Literal)]; ok {
				// Name is already bound, push its value onto the exec stack
				i.Stacks["exec"].Push(d)
				continue
			}
		}

		// The name is not bound yet, so push it onto the name stack
		i.Stacks["name"].Push(strings.ToLower(item.Literal))
		i.quoteNextName = false
	}

	if i.numEvalPush >= i.Options.EvalPushLimit {
		return errors.New("the EvalPushLimit was exceeded")
	}

	return nil
}

// Run runs the given program written in the Push programming language until the
// EvalPushLimit is reached
func (i *Interpreter) Run(program string) error {
	c, err := ParseCode(program)
	if err != nil {
		return err
	}

	if i.Options.TopLevelPushCode {
		if s, ok := i.Stacks["code"]; ok {
			s.Push(c)
		}
	}

	err = i.runCode(c)

	if i.Options.TopLevelPopCode {
		if s, ok := i.Stacks["code"]; ok {
			s.Pop()
		}
	}

	if i.Options.Tracing {
		i.printInterpreterState()
	}

	return err
}
<|endoftext|>


<commit_before>/*
The govers command searches all Go packages under the current
directory for imports with a prefix matching a particular pattern, and
changes them to another specified prefix. As with gofmt and gofix, there is
no backup - you are expected to be using a version control system.
It prints the names of any packages that are modified.

Usage:

	govers [-d] [-m regexp] [-n] new-package-path

It accepts the following flags:

	-d
		Suppress dependency checking
	-m regexp
		Search for and change imports which have the
		given pattern as a prefix (see below for the default).
	-n
		Don't make any changes; just perform checks.

If the pattern is not specified with the -m flag, it is derived from
new-package-path and matches any prefix that is the same in all but
version.  A version is defined to be an element within a package path
that matches the regular expression "(/|\.)v[0-9.]+".

The govers command will also check (unless the -d flag is given)
that no (recursive) dependencies would be changed if the same govers
command was run on them. If they would, govers will fail and do nothing.

For example, say a new version of the tomb package is released.
The old import path was gopkg.in/tomb.v2, and we want
to use the new verson, gopkg.in/tomb.v3. In the root of the
source tree we want to change, we run:

	govers gopkg.in/tomb.v3

This will change all gopkg.in/tomb.v2 imports to use v3.
It will also check that all external packages that we're
using are also using v3, making sure that our program
is consistently using the same version throughout.
*/
package main

import (
	"bufio"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

const help = `
The govers command searches all Go packages under the current
directory for imports with a prefix matching a particular pattern, and
changes them to another specified prefix. As with gofmt and gofix, there is
no backup - you are expected to be using a version control system.
It prints the names of any packages that are modified.

Usage:

	govers [-d] [-m regexp] [-n] new-package-path

It accepts the following flags:

	-d
		Suppress dependency checking
	-m regexp
		Search for and change imports which have the
		given pattern as a prefix (see below for the default).
	-n
		Don't make any changes; just perform checks.

If the pattern is not specified with the -m flag, it is derived from
new-package-path and matches any prefix that is the same in all but
version.  A version is defined to be an element within a package path
that matches the regular expression "(/|\.)v[0-9.]+(-unstable)?".

The govers command will also check (unless the -d flag is given)
that no (recursive) dependencies would be changed if the same govers
command was run on them. If they would, govers will fail and do nothing.

For example, say a new version of the tomb package is released.
The old import path was gopkg.in/tomb.v2, and we want
to use the new verson, gopkg.in/tomb.v3. In the root of the
source tree we want to change, we run:

	govers gopkg.in/tomb.v3

This will change all gopkg.in/tomb.v2 imports to use v3.
It will also check that all external packages that we're
using are also using v3, making sure that our program
is consistently using the same version throughout.
`

var (
	match          = flag.String("m", "", "change imports with a matching prefix")
	noEdit         = flag.Bool("n", false, "don't make any changes; perform checks only")
	noDependencies = flag.Bool("d", false, "suppress dependency checking")
)

func main() {
	flag.Usage = func() {
		fmt.Printf("%s", help[1:])
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
	}
	newPackage := flag.Arg(0)
	cwd, err := os.Getwd()
	if err != nil {
		fatalf("cannot get working directory: %v", err)
	}
	var oldPackagePat *regexp.Regexp
	if *match != "" {
		oldPackagePat, err = regexp.Compile("^(" + *match + ")")
		if err != nil {
			fatalf("invalid match pattern: %v", err)
		}
	} else {
		oldPackagePat = pathVersionPat(newPackage)
	}
	buildCtxt := build.Default
	// BUG we ignore files that are ignored by the current build context
	// if we don't set this flag, but if we do set it, the import fails.
	// The solution is to avoid using build.Import but it's convenient
	// at the moment.
	//	buildCtxt.UseAllFiles = true
	ctxt := &context{
		cwd:           cwd,
		newPackage:    newPackage,
		oldPackagePat: oldPackagePat,
		buildCtxt:     &buildCtxt,
		checked:       make(map[string]bool),
		editPkgs:      make(map[string]*editPkg),
	}
	ctxt.walkDir(cwd)
	for path := range ctxt.editPkgs {
		ctxt.checkPackage(path)
	}
	if ctxt.failed {
		os.Exit(1)
	}
	for path, ep := range ctxt.editPkgs {
		if !ep.needsEdit {
			continue
		}
		changed := false
		for _, file := range ep.goFiles {
			changed = ctxt.changeVersion(file) || changed
		}
		if changed {
			fmt.Printf("%s\n", path)
		}
	}
	if ctxt.failed {
		os.Exit(1)
	}
}

type editPkg struct {
	goFiles   []string
	needsEdit bool
}

type context struct {
	cwd           string
	failed        bool
	newPackage    string
	oldPackagePat *regexp.Regexp
	buildCtxt     *build.Context
	checked       map[string]bool
	editPkgs      map[string]*editPkg
}

// walkDir walks all directories below path and
// adds any packages to ctxt.editPkgs.
func (ctxt *context) walkDir(path string) {
	entries, err := ioutil.ReadDir(path)
	if err != nil {
		logf("cannot read directory %q: %v", path, err)
		return
	}
	var ep editPkg
	for _, entry := range entries {
		if entry.IsDir() {
			if !strings.HasPrefix(entry.Name(), ".") {
				ctxt.walkDir(filepath.Join(path, entry.Name()))
			}
		} else {
			if strings.HasSuffix(entry.Name(), ".go") {
				ep.goFiles = append(ep.goFiles, filepath.Join(path, entry.Name()))
			}
		}
	}
	pkg, err := ctxt.buildCtxt.Import(".", path, build.FindOnly)
	if err != nil {
		// ignore directories that don't correspond to packages.
		return
	}
	ctxt.editPkgs[pkg.ImportPath] = &ep
}

// checkPackage checks all go files in the given
// package, and all their dependencies.
func (ctxt *context) checkPackage(path string) {
	if path == "C" {
		return
	}
	if ctxt.checked[path] {
		// The package has already been, is or being, checked
		return
	}
	pkg, err := ctxt.buildCtxt.Import(path, ".", 0)
	ctxt.checked[pkg.ImportPath] = true
	if err != nil {
		if _, ok := err.(*build.NoGoError); !ok {
			logf("cannot import %q: %v", path, err)
		}
		return
	}
	ep := ctxt.editPkgs[path]
	// N.B. is it worth eliminating duplicates here?
	var allImports []string
	allImports = append(allImports, pkg.Imports...)
	if ctxt.editPkgs[path] != nil {
		// The package is in our set of root packages so
		// add testing imports too.
		allImports = append(allImports, pkg.TestImports...)
		allImports = append(allImports, pkg.XTestImports...)
	}
	for _, impPath := range allImports {
		if p := ctxt.fixPath(impPath); p != impPath {
			if ep == nil {
				logf("package %q is using inconsistent path %q", path, impPath)
				ctxt.failed = true
				continue
			}
			ep.needsEdit = true
			impPath = p
		}
		if !*noDependencies {
			ctxt.checkPackage(impPath)
		}
	}
}

var printConfig = printer.Config{
	Mode:     printer.TabIndent | printer.UseSpaces,
	Tabwidth: 8,
}

// changeVersion changes the named go file to
// import the new version.
func (ctxt *context) changeVersion(path string) bool {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
	if err != nil {
		logf("cannot parse %q: %v", path, err)
	}
	changed := false
	for _, ispec := range f.Imports {
		impPath, err := strconv.Unquote(ispec.Path.Value)
		if err != nil {
			panic(err)
		}
		if p := ctxt.fixPath(impPath); p != impPath {
			ispec.Path.Value = strconv.Quote(p)
			changed = true
		}
	}
	if !changed || *noEdit {
		return changed
	}
	out, err := os.Create(path)
	if err != nil {
		logf("cannot create file: %v", err)
	}
	defer out.Close()
	w := bufio.NewWriter(out)
	if err := printConfig.Fprint(w, fset, f); err != nil {
		logf("cannot write file: %v", err)
	}
	if err := w.Flush(); err != nil {
		logf("cannot write file: %v", err)
	}
	return true
}

func (ctxt *context) fixPath(p string) string {
	loc := ctxt.oldPackagePat.FindStringSubmatchIndex(p)
	if loc == nil {
		return p
	}
	i := loc[3]
	if p[0:i] != ctxt.newPackage {
		p = ctxt.newPackage + p[i:]
	}
	return p
}

const versPat = `[/|\.]v[0-9]+(-unstable)?`

// pathVersionPat returns a pattern that will match any
// package path that's the same except possibly
// the version number.
func pathVersionPat(p string) *regexp.Regexp {
	versRe := regexp.MustCompile(versPat + "(/|$)")
	if !versRe.MatchString(p) {
		fatalf("%q is not versioned", p)
	}
	// Use an intermediate step so that we can use QuoteMeta after
	// matching against versPat.  (versPat won't match quoted
	// metacharacters).
	// Note that  '#' is an invalid character in an import path
	p = versRe.ReplaceAllString(p, "#")
	p = regexp.QuoteMeta(p)
	// BUG doesn't match "foo/v0/v1/bar", but do we care?
	p = "^(" + strings.Replace(p, "#", versPat, -1) + ")(/|$)"
	return regexp.MustCompile(p)
}

func logf(f string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, "govers: %s\n", fmt.Sprintf(f, a...))
}

func fatalf(f string, a ...interface{}) {
	logf(f, a...)
	os.Exit(2)
}
<commit_msg>govers: work better with vendoring<commit_after>/*
The govers command searches all Go packages under the current
directory for imports with a prefix matching a particular pattern, and
changes them to another specified prefix. As with gofmt and gofix, there is
no backup - you are expected to be using a version control system.
It prints the names of any packages that are modified.

Usage:

	govers [-d] [-m regexp] [-n] new-package-path

It accepts the following flags:

	-d
		Suppress dependency checking
	-m regexp
		Search for and change imports which have the
		given pattern as a prefix (see below for the default).
	-n
		Don't make any changes; just perform checks.

If the pattern is not specified with the -m flag, it is derived from
new-package-path and matches any prefix that is the same in all but
version.  A version is defined to be an element within a package path
that matches the regular expression "(/|\.)v[0-9.]+".

The govers command will also check (unless the -d flag is given)
that no (recursive) dependencies would be changed if the same govers
command was run on them. If they would, govers will fail and do nothing.

For example, say a new version of the tomb package is released.
The old import path was gopkg.in/tomb.v2, and we want
to use the new verson, gopkg.in/tomb.v3. In the root of the
source tree we want to change, we run:

	govers gopkg.in/tomb.v3

This will change all gopkg.in/tomb.v2 imports to use v3.
It will also check that all external packages that we're
using are also using v3, making sure that our program
is consistently using the same version throughout.

BUG: Vendored imports are not dealt with correctly - they won't
be changed. It's not yet clear how this command should work then.
*/
package main

import (
	"bufio"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

const help = `
The govers command searches all Go packages under the current
directory for imports with a prefix matching a particular pattern, and
changes them to another specified prefix. As with gofmt and gofix, there is
no backup - you are expected to be using a version control system.
It prints the names of any packages that are modified.

Usage:

	govers [-d] [-m regexp] [-n] new-package-path

It accepts the following flags:

	-d
		Suppress dependency checking
	-m regexp
		Search for and change imports which have the
		given pattern as a prefix (see below for the default).
	-n
		Don't make any changes; just perform checks.

If the pattern is not specified with the -m flag, it is derived from
new-package-path and matches any prefix that is the same in all but
version.  A version is defined to be an element within a package path
that matches the regular expression "(/|\.)v[0-9.]+(-unstable)?".

The govers command will also check (unless the -d flag is given)
that no (recursive) dependencies would be changed if the same govers
command was run on them. If they would, govers will fail and do nothing.

For example, say a new version of the tomb package is released.
The old import path was gopkg.in/tomb.v2, and we want
to use the new verson, gopkg.in/tomb.v3. In the root of the
source tree we want to change, we run:

	govers gopkg.in/tomb.v3

This will change all gopkg.in/tomb.v2 imports to use v3.
It will also check that all external packages that we're
using are also using v3, making sure that our program
is consistently using the same version throughout.
`

var (
	match          = flag.String("m", "", "change imports with a matching prefix")
	noEdit         = flag.Bool("n", false, "don't make any changes; perform checks only")
	noDependencies = flag.Bool("d", false, "suppress dependency checking")
)

var cwd, _ = os.Getwd()

func main() {
	flag.Usage = func() {
		fmt.Printf("%s", help[1:])
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
	}
	newPackage := flag.Arg(0)
	cwd, err := os.Getwd()
	if err != nil {
		fatalf("cannot get working directory: %v", err)
	}
	var oldPackagePat *regexp.Regexp
	if *match != "" {
		oldPackagePat, err = regexp.Compile("^(" + *match + ")")
		if err != nil {
			fatalf("invalid match pattern: %v", err)
		}
	} else {
		oldPackagePat = pathVersionPat(newPackage)
	}
	buildCtxt := build.Default
	// BUG we ignore files that are ignored by the current build context
	// if we don't set this flag, but if we do set it, the import fails.
	// The solution is to avoid using build.Import but it's convenient
	// at the moment.
	//	buildCtxt.UseAllFiles = true
	ctxt := &context{
		cwd:           cwd,
		newPackage:    newPackage,
		oldPackagePat: oldPackagePat,
		buildCtxt:     &buildCtxt,
		checked:       make(map[string]bool),
		editPkgs:      make(map[string]*editPkg),
	}
	ctxt.walkDir(cwd)
	for path := range ctxt.editPkgs {
		ctxt.checkPackage(path, cwd)
	}
	if ctxt.failed {
		os.Exit(1)
	}
	for path, ep := range ctxt.editPkgs {
		if !ep.needsEdit {
			continue
		}
		changed := false
		for _, file := range ep.goFiles {
			changed = ctxt.changeVersion(file) || changed
		}
		if changed {
			fmt.Printf("%s\n", path)
		}
	}
	if ctxt.failed {
		os.Exit(1)
	}
}

type editPkg struct {
	goFiles   []string
	needsEdit bool
}

type context struct {
	cwd           string
	failed        bool
	newPackage    string
	oldPackagePat *regexp.Regexp
	buildCtxt     *build.Context
	checked       map[string]bool
	editPkgs      map[string]*editPkg
}

// walkDir walks all directories below path and
// adds any packages to ctxt.editPkgs.
func (ctxt *context) walkDir(path string) {
	entries, err := ioutil.ReadDir(path)
	if err != nil {
		logf("cannot read directory %q: %v", path, err)
		return
	}
	var ep editPkg
	for _, entry := range entries {
		if entry.IsDir() {
			if !strings.HasPrefix(entry.Name(), ".") {
				ctxt.walkDir(filepath.Join(path, entry.Name()))
			}
		} else {
			if strings.HasSuffix(entry.Name(), ".go") {
				ep.goFiles = append(ep.goFiles, filepath.Join(path, entry.Name()))
			}
		}
	}
	pkg, err := ctxt.buildCtxt.Import(".", path, build.FindOnly)
	if err != nil {
		// ignore directories that don't correspond to packages.
		return
	}
	ctxt.editPkgs[pkg.ImportPath] = &ep
}

// checkPackage checks all go files in the given
// package, and all their dependencies.
func (ctxt *context) checkPackage(path, fromDir string) {
	if path == "C" {
		return
	}
	if ctxt.checked[path] {
		// The package has already been, is or being, checked
		return
	}
	pkg, err := ctxt.buildCtxt.Import(path, fromDir, 0)
	ctxt.checked[pkg.ImportPath] = true
	if err != nil {
		if _, ok := err.(*build.NoGoError); !ok {
			logf("cannot import %q from %q: %v", path, fromDir, err)
		}
		return
	}
	ep := ctxt.editPkgs[path]
	// N.B. is it worth eliminating duplicates here?
	var allImports []string
	allImports = append(allImports, pkg.Imports...)
	if ctxt.editPkgs[path] != nil {
		// The package is in our set of root packages so
		// add testing imports too.
		allImports = append(allImports, pkg.TestImports...)
		allImports = append(allImports, pkg.XTestImports...)
	}
	for _, impPath := range allImports {
		// Import the package to find out its absolute path
		// including vendor directories before applying the
		// rewrite.
		impPkg, _ := ctxt.buildCtxt.Import(impPath, pkg.Dir, 0)
		if err != nil {
			continue
		}
		if p := ctxt.fixPath(impPkg.ImportPath); p != impPkg.ImportPath {
			if ep == nil {
				logf("package %q is using inconsistent path %q", pkg.ImportPath, impPkg.ImportPath)
				ctxt.failed = true
				continue
			}
			ep.needsEdit = true
			impPath = p
		}
		if !*noDependencies {
			ctxt.checkPackage(impPath, impPkg.Dir)
		}
	}
}

var printConfig = printer.Config{
	Mode:     printer.TabIndent | printer.UseSpaces,
	Tabwidth: 8,
}

// changeVersion changes the named go file to
// import the new version.
func (ctxt *context) changeVersion(path string) bool {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
	if err != nil {
		logf("cannot parse %q: %v", path, err)
	}
	changed := false
	for _, ispec := range f.Imports {
		impPath, err := strconv.Unquote(ispec.Path.Value)
		if err != nil {
			panic(err)
		}
		if p := ctxt.fixPath(impPath); p != impPath {
			ispec.Path.Value = strconv.Quote(p)
			changed = true
		}
	}
	if !changed || *noEdit {
		return changed
	}
	out, err := os.Create(path)
	if err != nil {
		logf("cannot create file: %v", err)
	}
	defer out.Close()
	w := bufio.NewWriter(out)
	if err := printConfig.Fprint(w, fset, f); err != nil {
		logf("cannot write file: %v", err)
	}
	if err := w.Flush(); err != nil {
		logf("cannot write file: %v", err)
	}
	return true
}

func (ctxt *context) fixPath(p string) string {
	loc := ctxt.oldPackagePat.FindStringSubmatchIndex(p)
	if loc == nil {
		return p
	}
	i := loc[3]
	if p[0:i] != ctxt.newPackage {
		p = ctxt.newPackage + p[i:]
	}
	return p
}

const versPat = `[/|\.]v[0-9]+(-unstable)?`

// pathVersionPat returns a pattern that will match any
// package path that's the same except possibly
// the version number.
func pathVersionPat(p string) *regexp.Regexp {
	versRe := regexp.MustCompile(versPat + "(/|$)")
	if !versRe.MatchString(p) {
		fatalf("%q is not versioned", p)
	}
	// Use an intermediate step so that we can use QuoteMeta after
	// matching against versPat.  (versPat won't match quoted
	// metacharacters).
	// Note that  '#' is an invalid character in an import path
	p = versRe.ReplaceAllString(p, "#")
	p = regexp.QuoteMeta(p)
	// BUG doesn't match "foo/v0/v1/bar", but do we care?
	p = "^(" + strings.Replace(p, "#", versPat, -1) + ")(/|$)"
	return regexp.MustCompile(p)
}

func logf(f string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, "govers: %s\n", fmt.Sprintf(f, a...))
}

func fatalf(f string, a ...interface{}) {
	logf(f, a...)
	os.Exit(2)
}
<|endoftext|>