<commit_before>package contour

// E versions, these return the error. Non-e versions are just wrapped calls to
// these functions with the error dropped.

// Config Get Methods

// E versions, these return the error. Non-e versions are just wrapped calls to
// these functions with the error dropped.

// GetE returns the setting Value as an interface{}. If its not a valid
// setting, an error is returned.
func (c *Cfg) GetE(k string) (interface{}, error) {
	_, ok := c.Settings[k]
	if !ok {
		return nil, notFoundErr(k)
	}

	return c.Settings[k].Value, nil
}

// GetBoolE returns the setting Value as a bool.
func (c *Cfg) GetBoolE(k string) (bool, error) {
	_, ok := c.Settings[k]
	if !ok {
		return false, notFoundErr(k)
	}

	switch c.Settings[k].Value.(type) {
	case bool:
		return c.Settings[k].Value.(bool), nil
	case *bool:
		return *c.Settings[k].Value.(*bool), nil
	}

	// Should never happen, but since we know the setting is there and we
	// expect it to be bool, given this method was called, we assume any
	// non-bool/*bool type == false.
	return false, nil
}

// GetIntE returns the setting Value as an int.
func (c *Cfg) GetIntE(k string) (int, error) {
	_, ok := c.Settings[k]
	if !ok {
		return 0, notFoundErr(k)
	}

	switch c.Settings[k].Value.(type) {
	case int:
		return c.Settings.k.Value.(int), nil
	case *int:
		return c.Settings[k].Value.(*int), nil
	}

	return 0, nil
}

// GetStringE returns the setting Value as a string.
func (c *Cfg) GetStringE(k string) (string, error) {
	_, ok := c.Settings[k]
	if !ok {
		return "", notFoundErr(k)
	}

	switch c.Settings[k].Value.(type) {
	case string:
		return c.Settings[k].Value.(string), nil
	case *string:
		return c.Settings[k].Value.(*string), nil
	}

	return "", nil
}

// GetInterfaceE is a convenience wrapper function to Get
func (c *Cfg) GetInterfaceE(k string) (interface{}, error) {
	return c.GetE(k)
}

func (c *Cfg) Get(k string) interface{} {
	s, _ := c.GetE(k)
	return s
}

// GetBool returns the setting Value as a bool.
func (c *Cfg) GetBool(k string) bool {
	s, _ := c.GetBoolE(k)
	return s
}

// GetInt returns the setting Value as an int.
func (c *Cfg) GetInt(k string) int {
	s, _ := c.GetIntE(k)
	return s
}

// GetString returns the setting Value as a string.
func (c *Cfg) GetString(k string) string {
	s, _ := c.GetStringE(k)
	return s
}

// GetInterfac returns the setting Value as an interface
func (c *Cfg) GetInterface(k string) interface{} {
	return c.Get(k)
}

// Filter Methods obtain a list of flags of the filter type, e.g. boolFilter
// for bool flags, and returns them.
// GetBoolFilterNames returns a list of filter names (flags).
func (c *Cfg) GetBoolFilterNames() []string {
	var names []string

	for k, setting := range c.Settings {
		if setting.IsFlag && setting.Type == "bool" {
			names = append(names, k)
		}
	}

	return names
}

// GetIntFilterNames returns a list of filter names (flags).
func (c *Cfg) GetIntFilterNames() []string {
	var names []string

	for k, setting := range c.Settings {
		if setting.IsFlag && setting.Type == "int" {
			names = append(names, k)
		}
	}

	return names
}

// GetStringFilterNames returns a list of filter names (flags).
func (c *Cfg) GetStringFilterNames() []string {
	var names []string

	for k, setting := range c.Settings {
		if setting.IsFlag && setting.Type == "string" {
			names = append(names, k)
		}
	}

	return names
}

// Convenience functions for configs[app]
// Get returns the setting Value as an interface{}.
// GetE returns the setting Value as an interface{}.
func GetE(k string) (interface{}, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return nil, notFoundErr(k)
	}

	return configs[app].Settings[k].Value, nil
}

// GetBoolE returns the setting Value as a bool.
func GetBoolE(k string) (bool, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return false, notFoundErr(k)
	}

	return *configs[app].Settings[k].Value.(*bool), nil
}

// GetIntE returns the setting Value as an int.
func GetIntE(k string) (int, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return 0, notFoundErr(k)
	}

	return *configs[app].Settings[k].Value.(*int), nil
}

// GetStringE returns the setting Value as a string.
func GetStringE(k string) (string, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return "", notFoundErr(k)
	}

	return configs[app].Settings[k].Value.(string), nil
}

// GetInterfaceE is a convenience wrapper function to Get
func GetInterfaceE(k string) (interface{}, error) {
	return configs[app].GetE(k)
}

func Get(k string) interface{} {
	s, _ := configs[app].GetE(k)
	return s
}

// GetBool returns the setting Value as a bool.
func GetBool(k string) bool {
	s, _ := configs[app].GetBoolE(k)
	return s
}

// GetInt returns the setting Value as an int.
func GetInt(k string) int {
	s, _ := configs[app].GetIntE(k)
	return s
}

// GetString returns the setting Value as a string.
func GetString(k string) string {
	s, _ := configs[app].GetStringE(k)
	return s
}

// GetInterface is a convenience wrapper function to Get
func GetInterface(k string) interface{} {
	return configs[app].Get(k)
}

// GetBoolFilterNames returns a list of filter names (flags).
func GetBoolFilterNames() []string {
	var names []string

	for k, setting := range configs[app].Settings {
		if setting.IsFlag && setting.Type == "bool" {
			names = append(names, k)
		}
	}

	return names
}

// GetIntFilterNames returns a list of filter names (flags).
func GetIntFilterNames() []string {
	var names []string

	for k, setting := range configs[app].Settings {
		if setting.IsFlag && setting.Type == "int" {
			names = append(names, k)
		}
	}

	return names
}

// GetStringFilterNames returns a list of filter names (flags).
func GetStringFilterNames() []string {
	var names []string

	for k, setting := range configs[app].Settings {
		if setting.IsFlag && setting.Type == "string" {
			names = append(names, k)
		}
	}

	return names
}
<commit_msg>fix errors in pointer fixes<commit_after>package contour

// E versions, these return the error. Non-e versions are just wrapped calls to
// these functions with the error dropped.

// Config Get Methods

// E versions, these return the error. Non-e versions are just wrapped calls to
// these functions with the error dropped.

// GetE returns the setting Value as an interface{}. If its not a valid
// setting, an error is returned.
func (c *Cfg) GetE(k string) (interface{}, error) {
	_, ok := c.Settings[k]
	if !ok {
		return nil, notFoundErr(k)
	}

	return c.Settings[k].Value, nil
}

// GetBoolE returns the setting Value as a bool.
func (c *Cfg) GetBoolE(k string) (bool, error) {
	_, ok := c.Settings[k]
	if !ok {
		return false, notFoundErr(k)
	}

	switch c.Settings[k].Value.(type) {
	case bool:
		return c.Settings[k].Value.(bool), nil
	case *bool:
		return *c.Settings[k].Value.(*bool), nil
	}

	// Should never happen, but since we know the setting is there and we
	// expect it to be bool, given this method was called, we assume any
	// non-bool/*bool type == false.
	return false, nil
}

// GetIntE returns the setting Value as an int.
func (c *Cfg) GetIntE(k string) (int, error) {
	_, ok := c.Settings[k]
	if !ok {
		return 0, notFoundErr(k)
	}

	switch c.Settings[k].Value.(type) {
	case int:
		return c.Settings[k].Value.(int), nil
	case *int:
		return *c.Settings[k].Value.(*int), nil
	}

	return 0, nil
}

// GetStringE returns the setting Value as a string.
func (c *Cfg) GetStringE(k string) (string, error) {
	_, ok := c.Settings[k]
	if !ok {
		return "", notFoundErr(k)
	}

	switch c.Settings[k].Value.(type) {
	case string:
		return c.Settings[k].Value.(string), nil
	case *string:
		return *c.Settings[k].Value.(*string), nil
	}

	return "", nil
}

// GetInterfaceE is a convenience wrapper function to Get
func (c *Cfg) GetInterfaceE(k string) (interface{}, error) {
	return c.GetE(k)
}

func (c *Cfg) Get(k string) interface{} {
	s, _ := c.GetE(k)
	return s
}

// GetBool returns the setting Value as a bool.
func (c *Cfg) GetBool(k string) bool {
	s, _ := c.GetBoolE(k)
	return s
}

// GetInt returns the setting Value as an int.
func (c *Cfg) GetInt(k string) int {
	s, _ := c.GetIntE(k)
	return s
}

// GetString returns the setting Value as a string.
func (c *Cfg) GetString(k string) string {
	s, _ := c.GetStringE(k)
	return s
}

// GetInterfac returns the setting Value as an interface
func (c *Cfg) GetInterface(k string) interface{} {
	return c.Get(k)
}

// Filter Methods obtain a list of flags of the filter type, e.g. boolFilter
// for bool flags, and returns them.
// GetBoolFilterNames returns a list of filter names (flags).
func (c *Cfg) GetBoolFilterNames() []string {
	var names []string

	for k, setting := range c.Settings {
		if setting.IsFlag && setting.Type == "bool" {
			names = append(names, k)
		}
	}

	return names
}

// GetIntFilterNames returns a list of filter names (flags).
func (c *Cfg) GetIntFilterNames() []string {
	var names []string

	for k, setting := range c.Settings {
		if setting.IsFlag && setting.Type == "int" {
			names = append(names, k)
		}
	}

	return names
}

// GetStringFilterNames returns a list of filter names (flags).
func (c *Cfg) GetStringFilterNames() []string {
	var names []string

	for k, setting := range c.Settings {
		if setting.IsFlag && setting.Type == "string" {
			names = append(names, k)
		}
	}

	return names
}

// Convenience functions for configs[app]
// Get returns the setting Value as an interface{}.
// GetE returns the setting Value as an interface{}.
func GetE(k string) (interface{}, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return nil, notFoundErr(k)
	}

	return configs[app].Settings[k].Value, nil
}

// GetBoolE returns the setting Value as a bool.
func GetBoolE(k string) (bool, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return false, notFoundErr(k)
	}

	return *configs[app].Settings[k].Value.(*bool), nil
}

// GetIntE returns the setting Value as an int.
func GetIntE(k string) (int, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return 0, notFoundErr(k)
	}

	return *configs[app].Settings[k].Value.(*int), nil
}

// GetStringE returns the setting Value as a string.
func GetStringE(k string) (string, error) {
	_, ok := configs[app].Settings[k]
	if !ok {
		return "", notFoundErr(k)
	}

	return configs[app].Settings[k].Value.(string), nil
}

// GetInterfaceE is a convenience wrapper function to Get
func GetInterfaceE(k string) (interface{}, error) {
	return configs[app].GetE(k)
}

func Get(k string) interface{} {
	s, _ := configs[app].GetE(k)
	return s
}

// GetBool returns the setting Value as a bool.
func GetBool(k string) bool {
	s, _ := configs[app].GetBoolE(k)
	return s
}

// GetInt returns the setting Value as an int.
func GetInt(k string) int {
	s, _ := configs[app].GetIntE(k)
	return s
}

// GetString returns the setting Value as a string.
func GetString(k string) string {
	s, _ := configs[app].GetStringE(k)
	return s
}

// GetInterface is a convenience wrapper function to Get
func GetInterface(k string) interface{} {
	return configs[app].Get(k)
}

// GetBoolFilterNames returns a list of filter names (flags).
func GetBoolFilterNames() []string {
	var names []string

	for k, setting := range configs[app].Settings {
		if setting.IsFlag && setting.Type == "bool" {
			names = append(names, k)
		}
	}

	return names
}

// GetIntFilterNames returns a list of filter names (flags).
func GetIntFilterNames() []string {
	var names []string

	for k, setting := range configs[app].Settings {
		if setting.IsFlag && setting.Type == "int" {
			names = append(names, k)
		}
	}

	return names
}

// GetStringFilterNames returns a list of filter names (flags).
func GetStringFilterNames() []string {
	var names []string

	for k, setting := range configs[app].Settings {
		if setting.IsFlag && setting.Type == "string" {
			names = append(names, k)
		}
	}

	return names
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"strings"

	"github.com/BurntSushi/toml"
	"hawx.me/code/ggg/repos"
	"hawx.me/code/ggg/web/assets"
	"hawx.me/code/ggg/web/filters"
	"hawx.me/code/ggg/web/handlers"
	"hawx.me/code/mux"
	"hawx.me/code/route"
	"hawx.me/code/serve"
	"hawx.me/code/uberich"
)

type Conf struct {
	Title  string
	URL    string
	Secret string
	GitDir string
	DbPath string

	Uberich struct {
		AppName    string
		AppURL     string
		UberichURL string
		Secret     string
	}
}

func main() {
	var (
		settingsPath = flag.String("settings", "./settings.toml", "Path to 'settings.toml'")
		port         = flag.String("port", "8080", "Port to run on")
		socket       = flag.String("socket", "", "")
	)
	flag.Parse()

	var conf *Conf
	if _, err := toml.DecodeFile(*settingsPath, &conf); err != nil {
		log.Fatal("toml: ", err)
	}

	db := repos.Open(conf.DbPath, conf.GitDir)
	defer db.Close()

	store := uberich.NewStore(conf.Secret)
	uberich := uberich.NewClient(conf.Uberich.AppName, conf.Uberich.AppURL, conf.Uberich.UberichURL, conf.Uberich.Secret, store)

	shield := func(h http.Handler) http.Handler {
		return uberich.Protect(h, http.NotFoundHandler())
	}

	list := handlers.List(db, conf.Title, conf.URL)
	repo := handlers.Repo(db, conf.Title, conf.URL, uberich.Protect)

	route.Handle("/", mux.Method{"GET": uberich.Protect(list.All, list.Public)})

	route.HandleFunc("/:name/*path", func(w http.ResponseWriter, r *http.Request) {
		vars := route.Vars(r)

		if strings.HasSuffix(vars["name"], ".git") {
			repo.Git.ServeHTTP(w, r)
			return
		}

		repo.Html.ServeHTTP(w, r)
	})

	route.Handle("/:name/edit", shield(handlers.Edit(db, conf.Title)))
	route.Handle("/:name/delete", shield(handlers.Delete(db)))

	route.Handle("/-/create", shield(handlers.Create(db, conf.Title)))
	route.Handle("/-/sign-in", uberich.SignIn("/"))
	route.Handle("/-/sign-out", uberich.SignOut("/"))

	route.Handle("/assets/styles.css", mux.Method{"GET": assets.Styles})
	route.Handle("/assets/highlight.js", mux.Method{"GET": assets.Highlight})
	route.Handle("/assets/filter.js", mux.Method{"GET": assets.Filter})

	serve.Serve(*port, *socket, filters.Log(route.Default))
}
<commit_msg>Use indieauth instead of uberich for authentication<commit_after>package main

import (
	"crypto/rand"
	"encoding/base64"
	"flag"
	"io"
	"log"
	"net/http"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/gorilla/sessions"
	"hawx.me/code/ggg/repos"
	"hawx.me/code/ggg/web/assets"
	"hawx.me/code/ggg/web/filters"
	"hawx.me/code/ggg/web/handlers"
	"hawx.me/code/indieauth"
	"hawx.me/code/mux"
	"hawx.me/code/route"
	"hawx.me/code/serve"
)

type Conf struct {
	Title  string
	URL    string
	Me     string
	Secret string
	GitDir string
	DbPath string
}

func main() {
	var (
		settingsPath = flag.String("settings", "./settings.toml", "Path to 'settings.toml'")
		port         = flag.String("port", "8080", "Port to run on")
		socket       = flag.String("socket", "", "")
	)
	flag.Parse()

	var conf *Conf
	if _, err := toml.DecodeFile(*settingsPath, &conf); err != nil {
		log.Fatal("toml: ", err)
	}

	db := repos.Open(conf.DbPath, conf.GitDir)
	defer db.Close()

	auth, err := indieauth.Authentication(conf.URL, conf.URL+"/-/callback")
	if err != nil {
		log.Fatal(err)
	}

	endpoints, err := indieauth.FindEndpoints(conf.Me)
	if err != nil {
		log.Fatal(err)
	}

	store := NewStore(conf.Secret)

	protect := func(good, bad http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if addr := store.Get(r); addr == conf.Me {
				good.ServeHTTP(w, r)
			} else {
				bad.ServeHTTP(w, r)
			}
		})
	}

	shield := func(h http.Handler) http.Handler {
		return protect(h, http.NotFoundHandler())
	}

	list := handlers.List(db, conf.Title, conf.URL)
	repo := handlers.Repo(db, conf.Title, conf.URL, protect)

	route.Handle("/", mux.Method{"GET": protect(list.All, list.Public)})

	route.HandleFunc("/:name/*path", func(w http.ResponseWriter, r *http.Request) {
		vars := route.Vars(r)

		if strings.HasSuffix(vars["name"], ".git") {
			repo.Git.ServeHTTP(w, r)
			return
		}

		repo.Html.ServeHTTP(w, r)
	})

	route.Handle("/:name/edit", shield(handlers.Edit(db, conf.Title)))
	route.Handle("/:name/delete", shield(handlers.Delete(db)))

	route.Handle("/-/create", shield(handlers.Create(db, conf.Title)))

	route.HandleFunc("/-/sign-in", func(w http.ResponseWriter, r *http.Request) {
		state, err := store.SetState(w, r)
		if err != nil {
			http.Error(w, "could not start auth", http.StatusInternalServerError)
			return
		}

		redirectURL := auth.RedirectURL(endpoints, conf.Me, state)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		http.Redirect(w, r, redirectURL, http.StatusFound)
	})

	route.HandleFunc("/-/callback", func(w http.ResponseWriter, r *http.Request) {
		state := store.GetState(r)

		if r.FormValue("state") != state {
			http.Error(w, "state is bad", http.StatusBadRequest)
			return
		}

		me, err := auth.Exchange(endpoints, r.FormValue("code"))
		if err != nil || me != conf.Me {
			http.Error(w, "nope", http.StatusForbidden)
			return
		}

		store.Set(w, r, me)
		http.Redirect(w, r, "/", http.StatusFound)
	})

	route.HandleFunc("/-/sign-out", func(w http.ResponseWriter, r *http.Request) {
		store.Set(w, r, "")
		http.Redirect(w, r, "/", http.StatusFound)
	})

	route.Handle("/assets/styles.css", mux.Method{"GET": assets.Styles})
	route.Handle("/assets/highlight.js", mux.Method{"GET": assets.Highlight})
	route.Handle("/assets/filter.js", mux.Method{"GET": assets.Filter})

	serve.Serve(*port, *socket, filters.Log(route.Default))
}

type meStore struct {
	store sessions.Store
}

func NewStore(secret string) *meStore {
	return &meStore{sessions.NewCookieStore([]byte(secret))}
}

func (s meStore) Get(r *http.Request) string {
	session, _ := s.store.Get(r, "session")

	if v, ok := session.Values["me"].(string); ok {
		return v
	}

	return ""
}

func (s meStore) Set(w http.ResponseWriter, r *http.Request, me string) {
	session, _ := s.store.Get(r, "session")
	session.Values["me"] = me
	session.Save(r, w)
}

func (s meStore) SetState(w http.ResponseWriter, r *http.Request) (string, error) {
	bytes := make([]byte, 32)

	if _, err := io.ReadFull(rand.Reader, bytes); err != nil {
		return "", err
	}

	state := base64.StdEncoding.EncodeToString(bytes)

	session, _ := s.store.Get(r, "session")
	session.Values["state"] = state
	return state, session.Save(r, w)
}

func (s meStore) GetState(r *http.Request) string {
	session, _ := s.store.Get(r, "session")

	if v, ok := session.Values["state"].(string); ok {
		return v
	}

	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"io"
	"path/filepath"
	"time"

	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"
)

type GHR struct {
	GitHub GitHub

	outStream io.Writer
}

func (g *GHR) CreateRelease(ctx context.Context, req *github.RepositoryRelease, recreate bool) (*github.RepositoryRelease, error) {

	// When draft release creation is requested,
	// create it witout any check (it can).
	if *req.Draft {
		fmt.Fprintln(g.outStream, "==> Create a draft release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// Check release is exist or not.
	// If release is not found, then create a new release.
	release, err := g.GitHub.GetRelease(ctx, *req.TagName)
	if err != nil {
		if err != RelaseNotFound {
			return nil, errors.Wrap(err, "failed to get release")
		}
		Debugf("Release (with tag %s) is not found: create a new one",
			*req.TagName)

		if recreate {
			fmt.Fprintf(g.outStream,
				"WARNING: '-recreate' is specified but release (%s) is not found",
				*req.TagName)
		}

		fmt.Fprintln(g.outStream, "==> Create a new release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// recreae is not true. Then use that exiting release.
	if !recreate {
		Debugf("Release (with tag %s) exists: use exsiting one",
			*req.TagName)

		fmt.Fprintf(g.outStream, "WARNING: found release (%s). Use existing one.",
			*req.TagName)
		return release, nil
	}

	// When recreate is requested, delete exsiting release
	// and create a new release.
	fmt.Fprintln(g.outStream, "==> Recreate a release")
	if err := g.DeleteRelease(ctx, *release.ID, *req.TagName); err != nil {
		return nil, err
	}

	return g.GitHub.CreateRelease(ctx, req)
}

func (g *GHR) DeleteRelease(ctx context.Context, ID int, tag string) error {

	err := g.GitHub.DeleteRelease(ctx, ID)
	if err != nil {
		return err
	}

	err = g.GitHub.DeleteTag(ctx, tag)
	if err != nil {
		return err
	}

	// This is because sometimes process of creating release on GitHub is more
	// fast than deleting tag.
	time.Sleep(5 * time.Second)

	return nil
}

func (g *GHR) UploadAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("UploadAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)
	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		localAsset := localAsset
		eg.Go(func() error {
			semaphore <- struct{}{}
			defer func() {
				<-semaphore
			}()

			fmt.Fprintf(g.outStream, "--> Uploading: %15s\n", filepath.Base(localAsset))
			_, err := g.GitHub.UploadAsset(ctx, releaseID, localAsset)
			if err != nil {
				return errors.Wrapf(err,
					"failed to upload asset: %s", localAsset)
			}
			return nil
		})
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}

func (g *GHR) DeleteAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("DeleteAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)

	assets, err := g.GitHub.ListAssets(ctx, releaseID)
	if err != nil {
		return errors.Wrap(err, "failed to list assets")
	}

	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		for _, asset := range assets {
			// https://golang.org/doc/faq#closures_and_goroutines
			localAsset, asset := localAsset, asset

			// Uploaded asset name is same as basename of local file
			if *asset.Name == filepath.Base(localAsset) {
				eg.Go(func() error {
					semaphore <- struct{}{}
					defer func() {
						<-semaphore
					}()

					fmt.Fprintf(g.outStream, "--> Deleting: %15s\n", *asset.Name)
					if err := g.GitHub.DeleteAsset(ctx, *asset.ID); err != nil {
						return errors.Wrapf(err,
							"failed to delete asset: %s", *asset.Name)
					}
					return nil
				})
			}
		}
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}
<commit_msg>chore(ghr): fix typo<commit_after>package main

import (
	"context"
	"fmt"
	"io"
	"path/filepath"
	"time"

	"github.com/google/go-github/github"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"
)

type GHR struct {
	GitHub GitHub

	outStream io.Writer
}

func (g *GHR) CreateRelease(ctx context.Context, req *github.RepositoryRelease, recreate bool) (*github.RepositoryRelease, error) {

	// When draft release creation is requested,
	// create it witout any check (it can).
	if *req.Draft {
		fmt.Fprintln(g.outStream, "==> Create a draft release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// Check release is exist or not.
	// If release is not found, then create a new release.
	release, err := g.GitHub.GetRelease(ctx, *req.TagName)
	if err != nil {
		if err != RelaseNotFound {
			return nil, errors.Wrap(err, "failed to get release")
		}
		Debugf("Release (with tag %s) is not found: create a new one",
			*req.TagName)

		if recreate {
			fmt.Fprintf(g.outStream,
				"WARNING: '-recreate' is specified but release (%s) is not found",
				*req.TagName)
		}

		fmt.Fprintln(g.outStream, "==> Create a new release")
		return g.GitHub.CreateRelease(ctx, req)
	}

	// recreate is not true. Then use that exiting release.
	if !recreate {
		Debugf("Release (with tag %s) exists: use exsiting one",
			*req.TagName)

		fmt.Fprintf(g.outStream, "WARNING: found release (%s). Use existing one.",
			*req.TagName)
		return release, nil
	}

	// When recreate is requested, delete exsiting release
	// and create a new release.
	fmt.Fprintln(g.outStream, "==> Recreate a release")
	if err := g.DeleteRelease(ctx, *release.ID, *req.TagName); err != nil {
		return nil, err
	}

	return g.GitHub.CreateRelease(ctx, req)
}

func (g *GHR) DeleteRelease(ctx context.Context, ID int, tag string) error {

	err := g.GitHub.DeleteRelease(ctx, ID)
	if err != nil {
		return err
	}

	err = g.GitHub.DeleteTag(ctx, tag)
	if err != nil {
		return err
	}

	// This is because sometimes process of creating release on GitHub is more
	// fast than deleting tag.
	time.Sleep(5 * time.Second)

	return nil
}

func (g *GHR) UploadAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("UploadAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)
	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		localAsset := localAsset
		eg.Go(func() error {
			semaphore <- struct{}{}
			defer func() {
				<-semaphore
			}()

			fmt.Fprintf(g.outStream, "--> Uploading: %15s\n", filepath.Base(localAsset))
			_, err := g.GitHub.UploadAsset(ctx, releaseID, localAsset)
			if err != nil {
				return errors.Wrapf(err,
					"failed to upload asset: %s", localAsset)
			}
			return nil
		})
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}

func (g *GHR) DeleteAssets(ctx context.Context, releaseID int, localAssets []string, parallel int) error {
	start := time.Now()
	defer func() {
		Debugf("DeleteAssets: time: %d ms", int(time.Since(start).Seconds()*1000))
	}()

	eg, ctx := errgroup.WithContext(ctx)

	assets, err := g.GitHub.ListAssets(ctx, releaseID)
	if err != nil {
		return errors.Wrap(err, "failed to list assets")
	}

	semaphore := make(chan struct{}, parallel)
	for _, localAsset := range localAssets {
		for _, asset := range assets {
			// https://golang.org/doc/faq#closures_and_goroutines
			localAsset, asset := localAsset, asset

			// Uploaded asset name is same as basename of local file
			if *asset.Name == filepath.Base(localAsset) {
				eg.Go(func() error {
					semaphore <- struct{}{}
					defer func() {
						<-semaphore
					}()

					fmt.Fprintf(g.outStream, "--> Deleting: %15s\n", *asset.Name)
					if err := g.GitHub.DeleteAsset(ctx, *asset.ID); err != nil {
						return errors.Wrapf(err,
							"failed to delete asset: %s", *asset.Name)
					}
					return nil
				})
			}
		}
	}

	if err := eg.Wait(); err != nil {
		return errors.Wrap(err, "one of goroutines is failed")
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/url"
	"os"
	"strings"

	"github.com/libgit2/git2go"
)

// the git segment provides useful information about a git repository such as the domain of the "origin" remote (with an icon), the current branch, and whether the HEAD is dirty
func gitSegment(segment *segment) {
	dir, err := os.Getwd()
	check(err)
	repo, err := git.OpenRepositoryExtended(dir, 0, "/")
	if err != nil {
		return
	}

	var domain string
	remote, err := repo.Remotes.Lookup("origin")
	if err == nil {
		uri, err := url.Parse(remote.Url())
		check(err)
		domain = uri.Hostname()
		remote.Free()
	}

	var stashes int
	repo.Stashes.Foreach(func(int, string, *git.Oid) error {
		stashes++
		return nil
	})

	var commitsAhead int
	var branch string
	var dirty, modified, staged bool

	var segments []string
	switch domain {
	case "github.com":
		segments = append(segments, iconGithub)
	case "gitlab.com":
		segments = append(segments, iconGitlab)
	case "bitbucket.com":
		segments = append(segments, iconBitbucket)
	default:
		segments = append(segments, iconGit)
	}
	if stashes != 0 || commitsAhead != 0 {
		segments = append(segments, strings.Repeat(iconStash, stashes)+strings.Repeat(iconAhead, commitsAhead))
	}
	if branch != "" {
		segments = append(segments, branch)
	}
	if dirty {
		segment.background = "yellow"

		var icons string
		if modified {
			icons += iconCircle
		}
		if staged {
			icons += iconPlus
		}
		if icons != "" {
			segments = append(segments, icons)
		}
	}
	segment.visible = true
	segment.value = strings.Join(segments, " ")
}
<commit_msg>check whether the repo is dirty<commit_after>package main

import (
	"net/url"
	"os"
	"strings"

	"github.com/libgit2/git2go"
)

// the git segment provides useful information about a git repository such as the domain of the "origin" remote (with an icon), the current branch, and whether the HEAD is dirty
func gitSegment(segment *segment) {
	dir, err := os.Getwd()
	check(err)
	repo, err := git.OpenRepositoryExtended(dir, 0, "/")
	if err != nil {
		return
	}

	var domain string
	remote, err := repo.Remotes.Lookup("origin")
	if err == nil {
		uri, err := url.Parse(remote.Url())
		check(err)
		domain = uri.Hostname()
		remote.Free()
	}

	var stashes int
	repo.Stashes.Foreach(func(int, string, *git.Oid) error {
		stashes++
		return nil
	})

	var commitsAhead int
	var branch string

	var dirty, modified, staged bool
	status, err := repo.StatusList(&git.StatusOptions{
		Flags: git.StatusOptIncludeUntracked,
	})
	check(err)
	count, err := status.EntryCount()
	check(err)
	if count != 0 {
		dirty = true
	}
	for i := 0; i < count; i++ {
		entry, err := status.ByIndex(i)
		check(err)
		if entry.Status&git.StatusWtNew != 0 || entry.Status&git.StatusWtModified != 0 || entry.Status&git.StatusWtDeleted != 0 || entry.Status&git.StatusWtTypeChange != 0 || entry.Status&git.StatusWtRenamed != 0 {
			modified = true
		}
		if entry.Status&git.StatusIndexNew != 0 || entry.Status&git.StatusIndexModified != 0 || entry.Status&git.StatusIndexDeleted != 0 || entry.Status&git.StatusIndexRenamed != 0 || entry.Status&git.StatusIndexTypeChange != 0 {
			staged = true
		}
	}
	status.Free()

	var segments []string
	switch domain {
	case "github.com":
		segments = append(segments, iconGithub)
	case "gitlab.com":
		segments = append(segments, iconGitlab)
	case "bitbucket.com":
		segments = append(segments, iconBitbucket)
	default:
		segments = append(segments, iconGit)
	}
	if stashes != 0 || commitsAhead != 0 {
		segments = append(segments, strings.Repeat(iconStash, stashes)+strings.Repeat(iconAhead, commitsAhead))
	}
	if branch != "" {
		segments = append(segments, branch)
	}
	if dirty {
		segment.background = "yellow"

		var icons string
		if modified {
			icons += iconCircle
		}
		if staged {
			icons += iconPlus
		}
		if icons != "" {
			segments = append(segments, icons)
		}
	}
	segment.visible = true
	segment.value = strings.Join(segments, " ")
}
<|endoftext|>


<commit_before>package main

// gitVersion returns the tag of the HEAD, if one exists,
// or else the commit hash.
func gitVersion() string {
	tag := cmd("git", "tag", "--contains", "HEAD").OutputLine()

	if tag != "" {
		return tag
	}

	return cmd("git", "rev-parse", "--short", "HEAD").OutputLine()
}
<commit_msg>Check that Git is in the PATH<commit_after>package main

import "os/exec"

// gitVersion returns one of the following:
// - Git tag of the HEAD if one exists, or
// - Commit hash of the HEAD, or
// - Empty string if Git is not in the PATH.
func gitVersion() string {
	cmdName := "git"

	if _, err := exec.LookPath(cmdName); err != nil {
		return ""
	}

	tag := cmd(cmdName, "tag", "--contains", "HEAD").OutputLine()
	if tag != "" {
		return tag
	}

	return cmd(cmdName, "rev-parse", "--short", "HEAD").OutputLine()
}
<|endoftext|>


<commit_before>// Copyright 2016 Marin Procureur. All rights reserved.
// Use of gjp source code is governed by a MIT license
// license that can be found in the LICENSE file.

/*
Package gjp stands for Go JobPool, and is willing to be a simple jobpool manager. It maintains
a number of queues determined at the init. No priority whatsoever, just every queues are
processing one job at a time.
*/

package gjp

import (
	"container/list"
	"fmt"
	"time"
	"strings"
)

/*
   TYPES
*/

type (
	// JobPool principal s²tructure maintaining queues of jobs
	// from a priority range
	JobPool struct {
		poolRange       int
		queue           []*JobQueue //Containing a "poolRange" number of queues
		shutdownChannel chan string //NYI
		working         bool
	}

	// JobQueue is structure to control jobs queues
	JobQueue struct {
		jobs               *list.List //list of waiting jobs
		executionChannel   chan *Job  //Channel to contain current job to execute in queue
		reportChannel      chan *Job  //Channel taking job back when its execution has finished
		working            bool       //Indicate whether or not the queue is working
		jobsRemaining      int        //Remaining jobs in the queue
		totalExecutionTime time.Duration
	}

	// Job
	Job struct {
		JobRunner
		name          string //Public property retrievable
		status        int    //Status of the current job
		error         *JobError
		executionTime time.Duration
	}

	//Error handling structure
	JobError struct {
		JobName     string //job name
		ErrorString string //error as a string
	}
)

/*
  SHUTDOWN INSTRUCTIONS
*/
const (
	abord   string = "abort"   //stop immediatly cuting jobs immediatly
	classic string = "classic" //stop by non authorizing new jobs in the pool and shutting down after
	long    string = "long"    //stop when there is no more job to process
)

/*
   JOB STATUS
*/
const (
	failed  int = 0
	success int = 1
	waiting int = 2
)

/*
   INTERFACES
*/

type JobRunner interface {
	ExecuteJob() (*JobError)
}

/*
   PUBLIC FUNCTIONS
*/

//Initialization function
func New(poolRange int) (jp *JobPool) {
	jp = &JobPool{
		poolRange: poolRange,
		working:   false,
	}
	jp.queue = make([]*JobQueue, jp.poolRange)
	for i := 0; i < len(jp.queue); i++ {
		jp.queue[i] = &JobQueue{
			jobs:             list.New(),
			executionChannel: make(chan *Job, 2),
			reportChannel:    make(chan *Job, 2),
			working:          false,
		}
	}

	//launch the loop
	go jp.ProcessJobs()
	go jp.StopProcessingJobs()

	return
}

//List current waiting jobs in each queues
func (jp *JobPool) ListWaitingJobs() {
	for i, _ := range jp.queue {
		if jp.queue[i] != nil {
			fmt.Println("in place", i, "there is", jp.queue[i].jobs.Len(), "job waiting")
		}
	}
}

//Queue new job to currentJobPool taking on
func (jp *JobPool) QueueJob(jobName string, jobRunner JobRunner, poolNumber int) (job *Job) {
	defer catchPanic(jobName, "QueueJob")

	job = &Job{
		JobRunner: jobRunner,
		name:      jobName,
		status:    waiting,
	}
	//Add new job to the queue
	jp.queue[poolNumber].jobsRemaining += 1
	jp.queue[poolNumber].jobs.PushBack(job)

	return
}

//Loop for processing jobs
//Started at the creation of the pool
func (jp *JobPool) ProcessJobs() {
	defer catchPanic("ProcessJobs")

	jp.working = true

	//While loop
	for jp.working == true {

		//iterate through each queue containing jobs
		for i := 0; i < len(jp.queue); i++ {
			if jp.queue[i].jobsRemaining > 0 &&
				jp.queue[i].working == false {

				//lock queue to avoid double processing
				jp.queue[i].lockQueue()

				//Launch the queue execution in a thread
				go jp.queue[i].executeJobQueue()
			}
		}
	}
	return
}

//Stop the jobPool and release all memory allowed
//NYI
func (jp *JobPool) StopProcessingJobs() {
	jp.working = false
}

/*
   PRIVATE FUNCTIONS
*/

//Handle error
func catchPanic(v ...string) {
	if r := recover(); r != nil {
		fmt.Println("Recover", r)
		fmt.Println("Details :", strings.Join(v, " "))
	}
}

//lock queue while executing
func (jq *JobQueue) lockQueue() {
	jq.working = true
}

//unlock queue when jobs are done
func (jq *JobQueue) unlockQueue() {
	jq.working = false
}

//Remove job from currentQueue
func (jq *JobQueue) dequeueJob(e *list.Element) {
	jq.jobs.Remove(e)
}

//execute current joblist
func (jq *JobQueue) executeJobQueue() {
	defer catchPanic("executeJobQueue")
	for jq.jobsRemaining > 0 {
		//Always take the first job in queue
		j := jq.jobs.Front().Value.(*Job)

		//Since job is retrieved remove it from the waiting queue
		jq.dequeueJob(jq.jobs.Front())

		//start job execution
		go jq.launchJobExecution()

		//put jo in the executionChannel
		jq.executionChannel <- j

		//Retrieve the job report from the reportChannel
		//Waiting until job is finished
		jobReport := <-jq.reportChannel

		//Checking status on report
		switch jobReport.status {
		//Through an error if failed
		case failed:
			if jobReport.error != nil {
				fmt.Println(jobReport.error.fmtError())
			} else {
				fmt.Println(jobReport.name, "panicked after an execution of", jobReport.executionTime)
			}
			break
		case success:
			fmt.Println("Job",
				jobReport.name,
				"executed in",
				jobReport.executionTime)
			break
		}
		jq.jobsRemaining -= 1
		//Go to the next job
	}
	//unlock queue to allow new jobs to be push to it
	jq.unlockQueue()
	return
}

//Launch the JobExecution
func (jq *JobQueue) launchJobExecution() {
	defer catchPanic("launchJobExecution")

	//Retrieve job from execution channel of the queue
	j := <-jq.executionChannel

	//execute the job synchronously with time starter
	j.status = j.executeJob(time.Now())
	//add this time to the queue execution time
	jq.totalExecutionTime += j.executionTime

	//Send job to the report channel
	jq.reportChannel <- j
}

//execute the job safely and set the status back for the reportChannel
func (j *Job) executeJob(start time.Time) (jobStatus int) {
	defer catchPanic("Job", j.name, "failed in executeJob")
	//Set the execution time for this job
	defer func() {
		j.executionTime = time.Since(start)
	}()

	j.error = j.ExecuteJob()
	//Set the status required for the job
	switch j.error {
	case nil:
		jobStatus = success
		break
	default:
		jobStatus = failed
		break
	}
	return
}

//create an error well formated
func (je *JobError) fmtError() (errorString string) {
	errorString = fmt.Sprintln("Job",
		je.JobName,
		"has failed with a error :",
		je.ErrorString)
	return
}

/*
Implementation example :

package main

import (
	"fmt"
	"github.com/FaXaq/gjp"
	"time"
)

type (
	MyJob struct {
		name string
	}
)

func (myjob *MyJob) ExecuteJob() (err *gjp.JobError) {
	if myjob.name == "YES" {
		defer panic("plz send haelp")
		err = &gjp.JobError{
			myjob.name,
			"nooooooooo",
		}
		return
	}
	for i := 0; i < 1; i++ {
		fmt.Println(myjob.name)
	}
	return
}

func main(){
	jobPool := gjp.New(2)
	newJob := &MyJob{
		name: "YES",
	}
	newJob2 := &MyJob{
		name: "THAT",
	}
	newJob3 := &MyJob{
		name: "ROCKS",
	}
	jobPool.QueueJob(newJob.name, newJob, 0)
	jobPool.QueueJob(newJob2.name, newJob2, 1)
	jobPool.QueueJob(newJob3.name, newJob3, 1)
	time.Sleep(time.Millisecond * 30)
}

The execution should retrieve something like :

Recover plz send haelp
Details : Job YES failed in executeJob
YES panicked after an execution of 14.046µs
THAT
Job THAT executed in 24.399µs
ROCKS
Job ROCKS executed in 21.57µs

*/
<commit_msg>Make use of the JobPool shutdown channel<commit_after>// Copyright 2016 Marin Procureur. All rights reserved.
// Use of gjp source code is governed by a MIT license
// license that can be found in the LICENSE file.

/*
Package gjp stands for Go JobPool, and is willing to be a simple jobpool manager. It maintains
a number of queues determined at the init. No priority whatsoever, just every queues are
processing one job at a time.
*/

package gjp

import (
	"container/list"
	"fmt"
	"time"
	"strings"
)

/*
   TYPES
*/

type (
	// JobPool principal s²tructure maintaining queues of jobs
	// from a priority range
	JobPool struct {
		poolRange       int
		queue           []*JobQueue //Containing a "poolRange" number of queues
		shutdownChannel chan string //NYI
		working         bool
	}

	// JobQueue is structure to control jobs queues
	JobQueue struct {
		jobs               *list.List //list of waiting jobs
		executionChannel   chan *Job  //Channel to contain current job to execute in queue
		reportChannel      chan *Job  //Channel taking job back when its execution has finished
		working            bool       //Indicate whether or not the queue is working
		jobsRemaining      int        //Remaining jobs in the queue
		totalExecutionTime time.Duration
	}

	// Job
	Job struct {
		JobRunner
		name          string //Public property retrievable
		status        int    //Status of the current job
		error         *JobError
		executionTime time.Duration
	}

	//Error handling structure
	JobError struct {
		JobName     string //job name
		ErrorString string //error as a string
	}
)

/*
  SHUTDOWN INSTRUCTIONS
*/
const (
	abort   string = "abort"   //stop immediatly cuting jobs immediatly
	classic string = "classic" //stop by non authorizing new jobs in the pool and shutting down after
	long    string = "long"    //stop when there is no more job to process
)

/*
   JOB STATUS
*/
const (
	failed  int = 0
	success int = 1
	waiting int = 2
)

/*
   INTERFACES
*/

type JobRunner interface {
	ExecuteJob() (*JobError)
}

/*
   PUBLIC FUNCTIONS
*/

//Initialization function
func New(poolRange int) (jp *JobPool) {
	//Create the jobPool
	jp = &JobPool{
		poolRange: poolRange,
		working:   false,
		shutdownChannel:  make(chan string),
	}

	//create the queuer ranges
	jp.queue = make([]*JobQueue, jp.poolRange)

	for i := 0; i < len(jp.queue); i++ {
		jp.queue[i] = &JobQueue{
			jobs:             list.New(),
			executionChannel: make(chan *Job, 2),
			reportChannel:    make(chan *Job, 2),
			working:          false,
		}
	}

	//launch the loop
	go jp.ProcessJobs()
	go jp.ListenForShutdown()

	return
}

//List current waiting jobs in each queues
func (jp *JobPool) ListWaitingJobs() {
	for i, _ := range jp.queue {
		if jp.queue[i] != nil {
			fmt.Println("in place", i, "there is", jp.queue[i].jobs.Len(), "job waiting")
		}
	}
}

//Queue new job to currentJobPool taking on
func (jp *JobPool) QueueJob(jobName string, jobRunner JobRunner, poolNumber int) (job *Job) {
	defer catchPanic(jobName, "QueueJob")

	job = &Job{
		JobRunner: jobRunner,
		name:      jobName,
		status:    waiting,
	}
	//Add new job to the queue
	jp.queue[poolNumber].jobsRemaining += 1
	jp.queue[poolNumber].jobs.PushBack(job)

	return
}

//Loop for processing jobs
//Started at the creation of the pool
func (jp *JobPool) ProcessJobs() {
	defer catchPanic("ProcessJobs")

	jp.working = true

	//While loop
	for jp.working == true {

		//iterate through each queue containing jobs
		for i := 0; i < len(jp.queue); i++ {
			if jp.queue[i].jobsRemaining > 0 &&
				jp.queue[i].working == false {

				//lock queue to avoid double processing
				jp.queue[i].lockQueue()

				//Launch the queue execution in a thread
				go jp.queue[i].executeJobQueue()
			}
		}
	}
	return
}

//Stop the jobPool and release all memory allowed
//NYI
func (jp *JobPool) ListenForShutdown() {
	fmt.Println("Waiting for shutdown")
	<- jp.shutdownChannel
	jp.working = false
}

func (jp *JobPool) ShutdownWorkPool() {
	jp.shutdownChannel <- abort
}

/*
   PRIVATE FUNCTIONS
*/

//Handle error
func catchPanic(v ...string) {
	if r := recover(); r != nil {
		fmt.Println("Recover", r)
		fmt.Println("Details :", strings.Join(v, " "))
	}
}

//lock queue while executing
func (jq *JobQueue) lockQueue() {
	jq.working = true
}

//unlock queue when jobs are done
func (jq *JobQueue) unlockQueue() {
	jq.working = false
}

//Remove job from currentQueue
func (jq *JobQueue) dequeueJob(e *list.Element) {
	jq.jobs.Remove(e)
}

//execute current joblist
func (jq *JobQueue) executeJobQueue() {
	defer catchPanic("executeJobQueue")
	for jq.jobsRemaining > 0 {
		//Always take the first job in queue
		j := jq.jobs.Front().Value.(*Job)

		//Since job is retrieved remove it from the waiting queue
		jq.dequeueJob(jq.jobs.Front())

		//start job execution
		go jq.launchJobExecution()

		//put jo in the executionChannel
		jq.executionChannel <- j

		//Retrieve the job report from the reportChannel
		//Waiting until job is finished
		jobReport := <-jq.reportChannel

		//Checking status on report
		switch jobReport.status {
		//Through an error if failed
		case failed:
			if jobReport.error != nil {
				fmt.Println(jobReport.error.fmtError())
			} else {
				fmt.Println(jobReport.name, "panicked after an execution of", jobReport.executionTime)
			}
			break
		case success:
			fmt.Println("Job",
				jobReport.name,
				"executed in",
				jobReport.executionTime)
			break
		}
		jq.jobsRemaining -= 1
		//Go to the next job
	}
	//unlock queue to allow new jobs to be push to it
	jq.unlockQueue()
	return
}

//Launch the JobExecution
func (jq *JobQueue) launchJobExecution() {
	defer catchPanic("launchJobExecution")

	//Retrieve job from execution channel of the queue
	j := <-jq.executionChannel

	//execute the job synchronously with time starter
	j.status = j.executeJob(time.Now())
	//add this time to the queue execution time
	jq.totalExecutionTime += j.executionTime

	//Send job to the report channel
	jq.reportChannel <- j
}

//execute the job safely and set the status back for the reportChannel
func (j *Job) executeJob(start time.Time) (jobStatus int) {
	defer catchPanic("Job", j.name, "failed in executeJob")
	//Set the execution time for this job
	defer func() {
		j.executionTime = time.Since(start)
	}()

	j.error = j.ExecuteJob()
	//Set the status required for the job
	switch j.error {
	case nil:
		jobStatus = success
		break
	default:
		jobStatus = failed
		break
	}
	return
}

//create an error well formated
func (je *JobError) fmtError() (errorString string) {
	errorString = fmt.Sprintln("Job",
		je.JobName,
		"has failed with a error :",
		je.ErrorString)
	return
}

/*
Implementation example :

package main

import (
	"fmt"
	"github.com/FaXaq/gjp"
	"time"
)

type (
	MyJob struct {
		name string
	}
)

func (myjob *MyJob) ExecuteJob() (err *gjp.JobError) {
	if myjob.name == "YES" {
		defer panic("plz send haelp")
		err = &gjp.JobError{
			myjob.name,
			"nooooooooo",
		}
		return
	}
	for i := 0; i < 1; i++ {
		fmt.Println(myjob.name)
	}
	return
}

func main(){
	jobPool := gjp.New(2)
	newJob := &MyJob{
		name: "YES",
	}
	newJob2 := &MyJob{
		name: "THAT",
	}
	newJob3 := &MyJob{
		name: "ROCKS",
	}
	jobPool.QueueJob(newJob.name, newJob, 0)
	jobPool.QueueJob(newJob2.name, newJob2, 1)
	jobPool.QueueJob(newJob3.name, newJob3, 1)
	time.Sleep(time.Millisecond * 30)
}

The execution should retrieve something like :

Recover plz send haelp
Details : Job YES failed in executeJob
YES panicked after an execution of 14.046µs
THAT
Job THAT executed in 24.399µs
ROCKS
Job ROCKS executed in 21.57µs

*/
<|endoftext|>


<commit_before>package gntagger

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

var (
	names = &Names{}
	text  = &Text{}
	a     = Annotation{}
)

func InitGUI(t *Text, n *Names) {
	text = t
	names = n
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Cursor = true

	g.SetManagerFunc(Layout)

	if err := Keybindings(g); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func Keybindings(g *gocui.Gui) error {
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone,
		quit); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyCtrlS, gocui.ModNone,
		save); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone,
		listBack); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone,
		listForward); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeySpace, gocui.ModNone,
		noName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'y', gocui.ModNone,
		yesName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 's', gocui.ModNone,
		speciesName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'g', gocui.ModNone,
		genusName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'u', gocui.ModNone,
		uninomialName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'd', gocui.ModNone,
		doubtfulName); err != nil {
		return err
	}

	return nil
}

func Layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()

	err := viewNames(g, maxX, maxY)
	if err != nil {
		return err
	}

	err = viewText(g, maxX, maxY)
	if err != nil {
		return err
	}

	err = viewHelp(g, maxX, maxY)
	if err != nil {
		return err
	}

	return nil
}

func viewNames(g *gocui.Gui, maxX, maxY int) error {
	if v, err := g.SetView("names", -1, 3, 35, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "Names"
		err := v.SetOrigin(0, 5)
		if err != nil {
			log.Panicln(err)
		}
		for i := 0; i <= maxY/2+1; i++ {
			fmt.Fprintln(v)
		}
		fmt.Fprintln(v, names.String())
		ox, oy := v.Origin()
		err = v.SetOrigin(ox, oy+(4*names.Data.Meta.CurrentName))
		if err != nil {
			log.Panicln(err)
		}
	}
	return nil
}

func viewText(g *gocui.Gui, maxX, maxY int) error {
	if v, err := g.SetView("text", 35, 3, maxX, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "Text"
		for i := 0; i <= maxY/2+2; i++ {
			fmt.Fprintln(v)
		}
		fmt.Fprintf(v, "%s", text.Markup(names))

		fmt.Fprintln(v, text.Markup(names))
		err := v.SetOrigin(0, text.OffsetY+3)
		if err != gocui.ErrUnknownView {
			return err
		}
	}
	return nil
}

func viewHelp(g *gocui.Gui, maxX, maxY int) error {
	if v, err := g.SetView("help", -1, maxY-2, maxX, maxY); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Frame = false
		v.BgColor = gocui.ColorWhite
		v.FgColor = gocui.ColorBlack
		fmt.Fprintln(v,
			"→ (yes*) next, ← back, Space no, y yes, s species, g genus, u uninomial, d doubt, ^S save, ^C exit")
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	save(g, v)
	return gocui.ErrQuit
}

func save(g *gocui.Gui, v *gocui.View) error {
	err := names.Save()
	return err
}

func speciesName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Species())
	return err
}

func genusName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Genus())
	return err
}

func uninomialName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Uninomial())
	return err
}

func doubtfulName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Doubtful())
	return err
}

func yesName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Accepted())
	return err
}

func noName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.NotName())
	return err
}

func setKey(g *gocui.Gui, v *gocui.View, annot string) error {
	for _, view := range g.Views() {
		if view.Name() == "names" {
			v = view
			break
		}
	}
	err := updateNamesView(g, v, 0, annot)
	return err
}

func listForward(g *gocui.Gui, viewNames *gocui.View) error {
	var viewText *gocui.View
	if names.Data.Meta.CurrentName == len(names.Data.Names) {
		names.Data.Meta.CurrentName--
		return nil
	}
	for _, v := range g.Views() {
		if v.Name() == "names" {
			viewNames = v
		} else if v.Name() == "text" {
			viewText = v
		}
	}
	err := updateNamesView(g, viewNames, 1, a.Accepted())
	if err != nil {
		return err
	}
	err = updateText(g, viewText)
	return err
}

func listBack(g *gocui.Gui, viewNames *gocui.View) error {
	var viewText *gocui.View
	if names.Data.Meta.CurrentName == 0 {
		return nil
	}
	for _, v := range g.Views() {
		if v.Name() == "names" {
			viewNames = v
		} else if v.Name() == "text" {
			viewText = v
		}
	}
	err := updateNamesView(g, viewNames, -1, "")
	if err != nil {
		return err
	}
	err = updateText(g, viewText)
	return err
}

func updateText(g *gocui.Gui, v *gocui.View) error {
	_, maxY := g.Size()
	v.Clear()
	for i := 0; i <= maxY/2+2; i++ {
		fmt.Fprintln(v)
	}
	fmt.Fprintln(v, text.Markup(names))
	err := v.SetOrigin(0, text.OffsetY+3)
	return err
}

func updateNamesView(g *gocui.Gui, v *gocui.View,
	increment int, annot string) error {
	_, maxY := g.Size()
	name := &names.Data.Names[names.Data.Meta.CurrentName]
	if annot == a.Accepted() {
		if increment == 1 && name.Annotation == "" {
			name.Annotation = annot
		} else if increment == 0 {
			name.Annotation = annot
		}
	} else if annot != "" {
		name.Annotation = annot
	}
	names.Data.Meta.CurrentName += increment
	v.Clear()
	for i := 0; i <= maxY/2+1; i++ {
		fmt.Fprintln(v)
	}
	fmt.Fprintln(v, names.String())
	ox, oy := v.Origin()
	err := v.SetOrigin(ox, oy+(4*increment))
	return err
}
<commit_msg>Fix #14 autosave every 30 edits<commit_after>package gntagger

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

var (
	names     = &Names{}
	text      = &Text{}
	a         = Annotation{}
	saveCount = 0
)

func InitGUI(t *Text, n *Names) {
	text = t
	names = n
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Cursor = true

	g.SetManagerFunc(Layout)

	if err := Keybindings(g); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func Keybindings(g *gocui.Gui) error {
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone,
		quit); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyCtrlS, gocui.ModNone,
		save); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone,
		listBack); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone,
		listForward); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeySpace, gocui.ModNone,
		noName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'y', gocui.ModNone,
		yesName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 's', gocui.ModNone,
		speciesName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'g', gocui.ModNone,
		genusName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'u', gocui.ModNone,
		uninomialName); err != nil {
		return err
	}

	if err := g.SetKeybinding("", 'd', gocui.ModNone,
		doubtfulName); err != nil {
		return err
	}

	return nil
}

func Layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()

	err := viewNames(g, maxX, maxY)
	if err != nil {
		return err
	}

	err = viewText(g, maxX, maxY)
	if err != nil {
		return err
	}

	err = viewHelp(g, maxX, maxY)
	if err != nil {
		return err
	}

	return nil
}

func viewNames(g *gocui.Gui, maxX, maxY int) error {
	if v, err := g.SetView("names", -1, 3, 35, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "Names"
		err := v.SetOrigin(0, 5)
		if err != nil {
			log.Panicln(err)
		}
		for i := 0; i <= maxY/2+1; i++ {
			fmt.Fprintln(v)
		}
		fmt.Fprintln(v, names.String())
		ox, oy := v.Origin()
		err = v.SetOrigin(ox, oy+(4*names.Data.Meta.CurrentName))
		if err != nil {
			log.Panicln(err)
		}
	}
	return nil
}

func viewText(g *gocui.Gui, maxX, maxY int) error {
	if v, err := g.SetView("text", 35, 3, maxX, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "Text"
		for i := 0; i <= maxY/2+2; i++ {
			fmt.Fprintln(v)
		}
		fmt.Fprintf(v, "%s", text.Markup(names))

		fmt.Fprintln(v, text.Markup(names))
		err := v.SetOrigin(0, text.OffsetY+3)
		if err != gocui.ErrUnknownView {
			return err
		}
	}
	return nil
}

func viewHelp(g *gocui.Gui, maxX, maxY int) error {
	if v, err := g.SetView("help", -1, maxY-2, maxX, maxY); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Frame = false
		v.BgColor = gocui.ColorWhite
		v.FgColor = gocui.ColorBlack
		fmt.Fprintln(v,
			"→ (yes*) next, ← back, Space no, y yes, s species, g genus, u uninomial, d doubt, ^S save, ^C exit")
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	save(g, v)
	return gocui.ErrQuit
}

func save(g *gocui.Gui, v *gocui.View) error {
	err := names.Save()
	return err
}

func speciesName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Species())
	return err
}

func genusName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Genus())
	return err
}

func uninomialName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Uninomial())
	return err
}

func doubtfulName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Doubtful())
	return err
}

func yesName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.Accepted())
	return err
}

func noName(g *gocui.Gui, v *gocui.View) error {
	err := setKey(g, v, a.NotName())
	return err
}

func setKey(g *gocui.Gui, v *gocui.View, annot string) error {
	for _, view := range g.Views() {
		if view.Name() == "names" {
			v = view
			break
		}
	}
	err := updateNamesView(g, v, 0, annot)
	return err
}

func listForward(g *gocui.Gui, viewNames *gocui.View) error {
	var viewText *gocui.View
	if names.Data.Meta.CurrentName == len(names.Data.Names) {
		names.Data.Meta.CurrentName--
		return nil
	}
	for _, v := range g.Views() {
		if v.Name() == "names" {
			viewNames = v
		} else if v.Name() == "text" {
			viewText = v
		}
	}
	err := updateNamesView(g, viewNames, 1, a.Accepted())
	if err != nil {
		return err
	}
	err = updateText(g, viewText)
	return err
}

func listBack(g *gocui.Gui, viewNames *gocui.View) error {
	var viewText *gocui.View
	if names.Data.Meta.CurrentName == 0 {
		return nil
	}
	for _, v := range g.Views() {
		if v.Name() == "names" {
			viewNames = v
		} else if v.Name() == "text" {
			viewText = v
		}
	}
	err := updateNamesView(g, viewNames, -1, "")
	if err != nil {
		return err
	}
	err = updateText(g, viewText)
	return err
}

func updateText(g *gocui.Gui, v *gocui.View) error {
	_, maxY := g.Size()
	v.Clear()
	for i := 0; i <= maxY/2+2; i++ {
		fmt.Fprintln(v)
	}
	fmt.Fprintln(v, text.Markup(names))
	err := v.SetOrigin(0, text.OffsetY+3)
	return err
}

func updateNamesView(g *gocui.Gui, v *gocui.View,
	increment int, annot string) error {
	saveCount++
	if saveCount == 30 {
		save(g, v)
		saveCount = 0
	}
	_, maxY := g.Size()
	name := &names.Data.Names[names.Data.Meta.CurrentName]
	if annot == a.Accepted() {
		if increment == 1 && name.Annotation == "" {
			name.Annotation = annot
		} else if increment == 0 {
			name.Annotation = annot
		}
	} else if annot != "" {
		name.Annotation = annot
	}
	names.Data.Meta.CurrentName += increment
	v.Clear()
	for i := 0; i <= maxY/2+1; i++ {
		fmt.Fprintln(v)
	}
	fmt.Fprintln(v, names.String())
	ox, oy := v.Origin()
	err := v.SetOrigin(ox, oy+(4*increment))
	return err
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/polydawn/gosh"

	"polydawn.net/repeatr/def"
	"polydawn.net/repeatr/io"
	"polydawn.net/repeatr/io/placer"
	"polydawn.net/repeatr/io/transmat/cachedir"
	"polydawn.net/repeatr/io/transmat/dir"
	"polydawn.net/repeatr/io/transmat/git"
	"polydawn.net/repeatr/io/transmat/s3"
	"polydawn.net/repeatr/io/transmat/tar"
	"polydawn.net/repeatr/io/transmat/tarexec"
)

/*
	The default, "universal", dispatching Transmat.
	You should be able to throw pretty much any type of input spec at it.

	If you're building your own transports and data warehousing integrations,
	you'll need to assemble your own Transmat instead of this one --
	`integrity.DispatchingTransmat` is good for composing them so you can still
	use one interface to get any kind of data you want.
*/
func DefaultTransmat() integrity.Transmat {
	workDir := filepath.Join(def.Base(), "io")
	dirCacher := cachedir.New(filepath.Join(workDir, "dircacher"), map[integrity.TransmatKind]integrity.TransmatFactory{
		integrity.TransmatKind("dir"): dir.New,
		integrity.TransmatKind("tar"): tar.New,
		integrity.TransmatKind("s3"):  s3.New,
	})
	universalTransmat := integrity.NewDispatchingTransmat(map[integrity.TransmatKind]integrity.Transmat{
		integrity.TransmatKind("dir"):      dirCacher,
		integrity.TransmatKind("tar"):      dirCacher,
		integrity.TransmatKind("exec-tar"): tarexec.New(filepath.Join(workDir, "tarexec")),
		integrity.TransmatKind("s3"):       dirCacher,
		integrity.TransmatKind("git"):      git.New(filepath.Join(workDir, "git")),
	})
	return universalTransmat
}

func BestAssembler() integrity.Assembler {
	if bestAssembler == nil {
		bestAssembler = determineBestAssembler()
	}
	return bestAssembler
}

var bestAssembler integrity.Assembler

func determineBestAssembler() integrity.Assembler {
	if os.Getuid() != 0 {
		// Can't mount without root.
		fmt.Fprintf(os.Stderr, "WARN: using slow fs assembly system: need root privs to use faster systems.\n")
		return placer.NewAssembler(placer.CopyingPlacer)
	}
	if os.Getenv("TRAVIS") != "" {
		// Travis's own virtualization denies mounting.  whee.
		fmt.Fprintf(os.Stderr, "WARN: using slow fs assembly system: travis' environment blocks faster systems.\n")
		return placer.NewAssembler(placer.CopyingPlacer)
	}
	// If we *can* mount...
	if isAUFSAvailable() {
		// if AUFS is installed, AUFS+Bind is The Winner.
		return placer.NewAssembler(placer.NewAufsPlacer(filepath.Join(def.Base(), "aufs")))
	}
	// last fallback... :( copy it is
	fmt.Fprintf(os.Stderr, "WARN: using slow fs assembly system: install AUFS to use faster systems.\n")
	return placer.NewAssembler(placer.CopyingPlacer)
	// TODO we should be able to use copy for fallback RW isolator but still bind for RO.  write a new placer for that.  or really, maybe bind should chain.
}

func isAUFSAvailable() bool {
	// the greatest thing to do would of course just be to issue the syscall once and see if it flies
	// but that's a distrubingly stateful and messy operation so we're gonna check a bunch
	// of next-best-things instead.

	// if we can't find it in /proc/filesystems, it's probably not installed
	if fs, err := ioutil.ReadFile("/proc/filesystems"); err == nil {
		found := false
		fsLines := strings.Split(string(fs), "\n")
		for _, line := range fsLines {
			parts := strings.Split(line, "\t")
			if len(parts) < 2 {
				continue
			}
			if parts[1] == "aufs" {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}

	// if we can't find it in modprobe, it's probably not installed
	modprobeCode := gosh.Sh(
		"modprobe", "aufs",
		gosh.NullIO,
		gosh.Opts{OkExit: gosh.AnyExit},
	).GetExitCodeSoon(100 * time.Millisecond)
	if modprobeCode != 0 {
		return false
	}

	return true
}
<commit_msg>Cache git checkouts.<commit_after>package util

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/polydawn/gosh"

	"polydawn.net/repeatr/def"
	"polydawn.net/repeatr/io"
	"polydawn.net/repeatr/io/placer"
	"polydawn.net/repeatr/io/transmat/cachedir"
	"polydawn.net/repeatr/io/transmat/dir"
	"polydawn.net/repeatr/io/transmat/git"
	"polydawn.net/repeatr/io/transmat/s3"
	"polydawn.net/repeatr/io/transmat/tar"
	"polydawn.net/repeatr/io/transmat/tarexec"
)

/*
	The default, "universal", dispatching Transmat.
	You should be able to throw pretty much any type of input spec at it.

	If you're building your own transports and data warehousing integrations,
	you'll need to assemble your own Transmat instead of this one --
	`integrity.DispatchingTransmat` is good for composing them so you can still
	use one interface to get any kind of data you want.
*/
func DefaultTransmat() integrity.Transmat {
	workDir := filepath.Join(def.Base(), "io")
	dirCacher := cachedir.New(filepath.Join(workDir, "dircacher"), map[integrity.TransmatKind]integrity.TransmatFactory{
		integrity.TransmatKind("dir"): dir.New,
		integrity.TransmatKind("tar"): tar.New,
		integrity.TransmatKind("s3"):  s3.New,
	})
	gitCacher := cachedir.New(filepath.Join(workDir, "dircacher-git"), map[integrity.TransmatKind]integrity.TransmatFactory{
		integrity.TransmatKind("git"): git.New,
	})
	universalTransmat := integrity.NewDispatchingTransmat(map[integrity.TransmatKind]integrity.Transmat{
		integrity.TransmatKind("dir"):      dirCacher,
		integrity.TransmatKind("tar"):      dirCacher,
		integrity.TransmatKind("exec-tar"): tarexec.New(filepath.Join(workDir, "tarexec")),
		integrity.TransmatKind("s3"):       dirCacher,
		integrity.TransmatKind("git"):      gitCacher,
	})
	return universalTransmat
}

func BestAssembler() integrity.Assembler {
	if bestAssembler == nil {
		bestAssembler = determineBestAssembler()
	}
	return bestAssembler
}

var bestAssembler integrity.Assembler

func determineBestAssembler() integrity.Assembler {
	if os.Getuid() != 0 {
		// Can't mount without root.
		fmt.Fprintf(os.Stderr, "WARN: using slow fs assembly system: need root privs to use faster systems.\n")
		return placer.NewAssembler(placer.CopyingPlacer)
	}
	if os.Getenv("TRAVIS") != "" {
		// Travis's own virtualization denies mounting.  whee.
		fmt.Fprintf(os.Stderr, "WARN: using slow fs assembly system: travis' environment blocks faster systems.\n")
		return placer.NewAssembler(placer.CopyingPlacer)
	}
	// If we *can* mount...
	if isAUFSAvailable() {
		// if AUFS is installed, AUFS+Bind is The Winner.
		return placer.NewAssembler(placer.NewAufsPlacer(filepath.Join(def.Base(), "aufs")))
	}
	// last fallback... :( copy it is
	fmt.Fprintf(os.Stderr, "WARN: using slow fs assembly system: install AUFS to use faster systems.\n")
	return placer.NewAssembler(placer.CopyingPlacer)
	// TODO we should be able to use copy for fallback RW isolator but still bind for RO.  write a new placer for that.  or really, maybe bind should chain.
}

func isAUFSAvailable() bool {
	// the greatest thing to do would of course just be to issue the syscall once and see if it flies
	// but that's a distrubingly stateful and messy operation so we're gonna check a bunch
	// of next-best-things instead.

	// if we can't find it in /proc/filesystems, it's probably not installed
	if fs, err := ioutil.ReadFile("/proc/filesystems"); err == nil {
		found := false
		fsLines := strings.Split(string(fs), "\n")
		for _, line := range fsLines {
			parts := strings.Split(line, "\t")
			if len(parts) < 2 {
				continue
			}
			if parts[1] == "aufs" {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}

	// if we can't find it in modprobe, it's probably not installed
	modprobeCode := gosh.Sh(
		"modprobe", "aufs",
		gosh.NullIO,
		gosh.Opts{OkExit: gosh.AnyExit},
	).GetExitCodeSoon(100 * time.Millisecond)
	if modprobeCode != 0 {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package expression

import (
	"time"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/ast"
	"github.com/pingcap/tidb/model"
	"github.com/pingcap/tidb/mysql"
	"github.com/pingcap/tidb/sessionctx/variable"
	"github.com/pingcap/tidb/util/codec"
	"github.com/pingcap/tidb/util/mock"
	"github.com/pingcap/tidb/util/types"
	"github.com/pingcap/tipb/go-tipb"
)

var distFuncs = map[tipb.ExprType]string{
	// compare op
	tipb.ExprType_LT:     ast.LT,
	tipb.ExprType_LE:     ast.LE,
	tipb.ExprType_GT:     ast.GT,
	tipb.ExprType_GE:     ast.GE,
	tipb.ExprType_EQ:     ast.EQ,
	tipb.ExprType_NE:     ast.NE,
	tipb.ExprType_NullEQ: ast.NullEQ,

	// bit op
	tipb.ExprType_BitAnd:    ast.And,
	tipb.ExprType_BitOr:     ast.Or,
	tipb.ExprType_BitXor:    ast.Xor,
	tipb.ExprType_RighShift: ast.RightShift,
	tipb.ExprType_LeftShift: ast.LeftShift,
	tipb.ExprType_BitNeg:    ast.BitNeg,

	// logical op
	tipb.ExprType_And: ast.LogicAnd,
	tipb.ExprType_Or:  ast.LogicOr,
	tipb.ExprType_Xor: ast.LogicXor,
	tipb.ExprType_Not: ast.UnaryNot,

	// arithmetic operator
	tipb.ExprType_Plus:   ast.Plus,
	tipb.ExprType_Minus:  ast.Minus,
	tipb.ExprType_Mul:    ast.Mul,
	tipb.ExprType_Div:    ast.Div,
	tipb.ExprType_IntDiv: ast.IntDiv,
	tipb.ExprType_Mod:    ast.Mod,

	// control operator
	tipb.ExprType_Case:   ast.Case,
	tipb.ExprType_If:     ast.If,
	tipb.ExprType_IfNull: ast.Ifnull,
	tipb.ExprType_NullIf: ast.Nullif,

	// other operator
	tipb.ExprType_Like:     ast.Like,
	tipb.ExprType_In:       ast.In,
	tipb.ExprType_IsNull:   ast.IsNull,
	tipb.ExprType_Coalesce: ast.Coalesce,

	// for json functions.
	tipb.ExprType_JsonType:    ast.JSONType,
	tipb.ExprType_JsonExtract: ast.JSONExtract,
	tipb.ExprType_JsonUnquote: ast.JSONUnquote,
	tipb.ExprType_JsonMerge:   ast.JSONMerge,
	tipb.ExprType_JsonSet:     ast.JSONSet,
	tipb.ExprType_JsonInsert:  ast.JSONInsert,
	tipb.ExprType_JsonReplace: ast.JSONReplace,
	tipb.ExprType_JsonRemove:  ast.JSONRemove,
	tipb.ExprType_JsonArray:   ast.JSONArray,
	tipb.ExprType_JsonObject:  ast.JSONObject,
}

// newDistSQLFunction only creates function for mock-tikv.
func newDistSQLFunction(sc *variable.StatementContext, exprType tipb.ExprType, args []Expression) (Expression, error) {
	name, ok := distFuncs[exprType]
	if !ok {
		return nil, errFunctionNotExists.GenByArgs(exprType)
	}
	// TODO: Too ugly...
	ctx := mock.NewContext()
	ctx.GetSessionVars().StmtCtx = sc
	tp, err := reinferFuncType(sc, name, args)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return NewFunction(ctx, name, tp, args...)
}

// reinferFuncType re-infer FieldType of ScalarFunction because FieldType information will be lost after ScalarFunction be converted to pb.
// reinferFuncType is only used by mock-tikv, the real TiKV do not need to re-infer field type.
// This is a temporary solution to make the new type inferer works normally, and will be replaced by passing function signature in the future.
func reinferFuncType(sc *variable.StatementContext, funcName string, args []Expression) (*types.FieldType, error) {
	newArgs := make([]ast.ExprNode, len(args))
	for i, arg := range args {
		switch x := arg.(type) {
		case *Constant:
			newArgs[i] = &ast.ValueExpr{}
			newArgs[i].SetValue(x.Value.GetValue())
		case *Column:
			newArgs[i] = &ast.ColumnNameExpr{
				Refer: &ast.ResultField{
					Column: &model.ColumnInfo{
						FieldType: *x.GetType(),
					},
				},
			}
		case *ScalarFunction:
			newArgs[i] = &ast.FuncCallExpr{FnName: x.FuncName}
			_, err := reinferFuncType(sc, x.FuncName.O, x.GetArgs())
			if err != nil {
				return nil, errors.Trace(err)
			}
		}
	}
	funcNode := &ast.FuncCallExpr{FnName: model.NewCIStr(funcName), Args: newArgs}
	err := InferType(sc, funcNode)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return funcNode.GetType(), nil
}

// PBToExpr converts pb structure to expression.
func PBToExpr(expr *tipb.Expr, tps []*types.FieldType, sc *variable.StatementContext) (Expression, error) {
	switch expr.Tp {
	case tipb.ExprType_ColumnRef:
		_, offset, err := codec.DecodeInt(expr.Val)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return &Column{Index: int(offset), RetType: tps[offset]}, nil
	case tipb.ExprType_Null:
		return &Constant{Value: types.Datum{}, RetType: types.NewFieldType(mysql.TypeNull)}, nil
	case tipb.ExprType_Int64:
		return convertInt(expr.Val)
	case tipb.ExprType_Uint64:
		return convertUint(expr.Val)
	case tipb.ExprType_String:
		return convertString(expr.Val)
	case tipb.ExprType_Bytes:
		return &Constant{Value: types.NewBytesDatum(expr.Val), RetType: types.NewFieldType(mysql.TypeString)}, nil
	case tipb.ExprType_Float32:
		return convertFloat(expr.Val, true)
	case tipb.ExprType_Float64:
		return convertFloat(expr.Val, false)
	case tipb.ExprType_MysqlDecimal:
		return convertDecimal(expr.Val)
	case tipb.ExprType_MysqlDuration:
		return convertDuration(expr.Val)
	}
	// Then it must be a scalar function.
	args := make([]Expression, 0, len(expr.Children))
	for _, child := range expr.Children {
		if child.Tp == tipb.ExprType_ValueList {
			results, err := decodeValueList(child.Val)
			if err != nil {
				return nil, errors.Trace(err)
			}
			if len(results) == 0 {
				return &Constant{Value: types.NewDatum(false), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil
			}
			args = append(args, results...)
			continue
		}
		arg, err := PBToExpr(child, tps, sc)
		if err != nil {
			return nil, errors.Trace(err)
		}
		args = append(args, arg)
	}
	return newDistSQLFunction(sc, expr.Tp, args)
}

func decodeValueList(data []byte) ([]Expression, error) {
	if len(data) == 0 {
		return nil, nil
	}
	list, err := codec.Decode(data, 1)
	if err != nil {
		return nil, errors.Trace(err)
	}
	result := make([]Expression, 0, len(list))
	for _, value := range list {
		result = append(result, &Constant{Value: value})
	}
	return result, nil
}

func convertInt(val []byte) (*Constant, error) {
	var d types.Datum
	_, i, err := codec.DecodeInt(val)
	if err != nil {
		return nil, errors.Errorf("invalid int % x", val)
	}
	d.SetInt64(i)
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeLonglong)}, nil
}

func convertUint(val []byte) (*Constant, error) {
	var d types.Datum
	_, u, err := codec.DecodeUint(val)
	if err != nil {
		return nil, errors.Errorf("invalid uint % x", val)
	}
	d.SetUint64(u)
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeLonglong)}, nil
}

func convertString(val []byte) (*Constant, error) {
	var d types.Datum
	d.SetBytesAsString(val)
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeVarString)}, nil
}

func convertFloat(val []byte, f32 bool) (*Constant, error) {
	var d types.Datum
	_, f, err := codec.DecodeFloat(val)
	if err != nil {
		return nil, errors.Errorf("invalid float % x", val)
	}
	if f32 {
		d.SetFloat32(float32(f))
	} else {
		d.SetFloat64(f)
	}
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeDouble)}, nil
}

func convertDecimal(val []byte) (*Constant, error) {
	_, dec, err := codec.DecodeDecimal(val)
	if err != nil {
		return nil, errors.Errorf("invalid decimal % x", val)
	}
	return &Constant{Value: dec, RetType: types.NewFieldType(mysql.TypeNewDecimal)}, nil
}

func convertDuration(val []byte) (*Constant, error) {
	var d types.Datum
	_, i, err := codec.DecodeInt(val)
	if err != nil {
		return nil, errors.Errorf("invalid duration %d", i)
	}
	d.SetMysqlDuration(types.Duration{Duration: time.Duration(i), Fsp: types.MaxFsp})
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeDuration)}, nil
}
<commit_msg>expression: clean code. (#4223)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package expression

import (
	"time"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/ast"
	"github.com/pingcap/tidb/mysql"
	"github.com/pingcap/tidb/sessionctx/variable"
	"github.com/pingcap/tidb/util/codec"
	"github.com/pingcap/tidb/util/mock"
	"github.com/pingcap/tidb/util/types"
	"github.com/pingcap/tipb/go-tipb"
)

var distFuncs = map[tipb.ExprType]string{
	// compare op
	tipb.ExprType_LT:     ast.LT,
	tipb.ExprType_LE:     ast.LE,
	tipb.ExprType_GT:     ast.GT,
	tipb.ExprType_GE:     ast.GE,
	tipb.ExprType_EQ:     ast.EQ,
	tipb.ExprType_NE:     ast.NE,
	tipb.ExprType_NullEQ: ast.NullEQ,

	// bit op
	tipb.ExprType_BitAnd:    ast.And,
	tipb.ExprType_BitOr:     ast.Or,
	tipb.ExprType_BitXor:    ast.Xor,
	tipb.ExprType_RighShift: ast.RightShift,
	tipb.ExprType_LeftShift: ast.LeftShift,
	tipb.ExprType_BitNeg:    ast.BitNeg,

	// logical op
	tipb.ExprType_And: ast.LogicAnd,
	tipb.ExprType_Or:  ast.LogicOr,
	tipb.ExprType_Xor: ast.LogicXor,
	tipb.ExprType_Not: ast.UnaryNot,

	// arithmetic operator
	tipb.ExprType_Plus:   ast.Plus,
	tipb.ExprType_Minus:  ast.Minus,
	tipb.ExprType_Mul:    ast.Mul,
	tipb.ExprType_Div:    ast.Div,
	tipb.ExprType_IntDiv: ast.IntDiv,
	tipb.ExprType_Mod:    ast.Mod,

	// control operator
	tipb.ExprType_Case:   ast.Case,
	tipb.ExprType_If:     ast.If,
	tipb.ExprType_IfNull: ast.Ifnull,
	tipb.ExprType_NullIf: ast.Nullif,

	// other operator
	tipb.ExprType_Like:     ast.Like,
	tipb.ExprType_In:       ast.In,
	tipb.ExprType_IsNull:   ast.IsNull,
	tipb.ExprType_Coalesce: ast.Coalesce,

	// for json functions.
	tipb.ExprType_JsonType:    ast.JSONType,
	tipb.ExprType_JsonExtract: ast.JSONExtract,
	tipb.ExprType_JsonUnquote: ast.JSONUnquote,
	tipb.ExprType_JsonMerge:   ast.JSONMerge,
	tipb.ExprType_JsonSet:     ast.JSONSet,
	tipb.ExprType_JsonInsert:  ast.JSONInsert,
	tipb.ExprType_JsonReplace: ast.JSONReplace,
	tipb.ExprType_JsonRemove:  ast.JSONRemove,
	tipb.ExprType_JsonArray:   ast.JSONArray,
	tipb.ExprType_JsonObject:  ast.JSONObject,
}

// newDistSQLFunction only creates function for mock-tikv.
func newDistSQLFunction(sc *variable.StatementContext, exprType tipb.ExprType, args []Expression) (Expression, error) {
	name, ok := distFuncs[exprType]
	if !ok {
		return nil, errFunctionNotExists.GenByArgs(exprType)
	}
	// TODO: Too ugly...
	ctx := mock.NewContext()
	ctx.GetSessionVars().StmtCtx = sc
	return NewFunction(ctx, name, types.NewFieldType(mysql.TypeUnspecified), args...)
}

// PBToExpr converts pb structure to expression.
func PBToExpr(expr *tipb.Expr, tps []*types.FieldType, sc *variable.StatementContext) (Expression, error) {
	switch expr.Tp {
	case tipb.ExprType_ColumnRef:
		_, offset, err := codec.DecodeInt(expr.Val)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return &Column{Index: int(offset), RetType: tps[offset]}, nil
	case tipb.ExprType_Null:
		return &Constant{Value: types.Datum{}, RetType: types.NewFieldType(mysql.TypeNull)}, nil
	case tipb.ExprType_Int64:
		return convertInt(expr.Val)
	case tipb.ExprType_Uint64:
		return convertUint(expr.Val)
	case tipb.ExprType_String:
		return convertString(expr.Val)
	case tipb.ExprType_Bytes:
		return &Constant{Value: types.NewBytesDatum(expr.Val), RetType: types.NewFieldType(mysql.TypeString)}, nil
	case tipb.ExprType_Float32:
		return convertFloat(expr.Val, true)
	case tipb.ExprType_Float64:
		return convertFloat(expr.Val, false)
	case tipb.ExprType_MysqlDecimal:
		return convertDecimal(expr.Val)
	case tipb.ExprType_MysqlDuration:
		return convertDuration(expr.Val)
	}
	// Then it must be a scalar function.
	args := make([]Expression, 0, len(expr.Children))
	for _, child := range expr.Children {
		if child.Tp == tipb.ExprType_ValueList {
			results, err := decodeValueList(child.Val)
			if err != nil {
				return nil, errors.Trace(err)
			}
			if len(results) == 0 {
				return &Constant{Value: types.NewDatum(false), RetType: types.NewFieldType(mysql.TypeLonglong)}, nil
			}
			args = append(args, results...)
			continue
		}
		arg, err := PBToExpr(child, tps, sc)
		if err != nil {
			return nil, errors.Trace(err)
		}
		args = append(args, arg)
	}
	return newDistSQLFunction(sc, expr.Tp, args)
}

func decodeValueList(data []byte) ([]Expression, error) {
	if len(data) == 0 {
		return nil, nil
	}
	list, err := codec.Decode(data, 1)
	if err != nil {
		return nil, errors.Trace(err)
	}
	result := make([]Expression, 0, len(list))
	for _, value := range list {
		result = append(result, &Constant{Value: value})
	}
	return result, nil
}

func convertInt(val []byte) (*Constant, error) {
	var d types.Datum
	_, i, err := codec.DecodeInt(val)
	if err != nil {
		return nil, errors.Errorf("invalid int % x", val)
	}
	d.SetInt64(i)
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeLonglong)}, nil
}

func convertUint(val []byte) (*Constant, error) {
	var d types.Datum
	_, u, err := codec.DecodeUint(val)
	if err != nil {
		return nil, errors.Errorf("invalid uint % x", val)
	}
	d.SetUint64(u)
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeLonglong)}, nil
}

func convertString(val []byte) (*Constant, error) {
	var d types.Datum
	d.SetBytesAsString(val)
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeVarString)}, nil
}

func convertFloat(val []byte, f32 bool) (*Constant, error) {
	var d types.Datum
	_, f, err := codec.DecodeFloat(val)
	if err != nil {
		return nil, errors.Errorf("invalid float % x", val)
	}
	if f32 {
		d.SetFloat32(float32(f))
	} else {
		d.SetFloat64(f)
	}
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeDouble)}, nil
}

func convertDecimal(val []byte) (*Constant, error) {
	_, dec, err := codec.DecodeDecimal(val)
	if err != nil {
		return nil, errors.Errorf("invalid decimal % x", val)
	}
	return &Constant{Value: dec, RetType: types.NewFieldType(mysql.TypeNewDecimal)}, nil
}

func convertDuration(val []byte) (*Constant, error) {
	var d types.Datum
	_, i, err := codec.DecodeInt(val)
	if err != nil {
		return nil, errors.Errorf("invalid duration %d", i)
	}
	d.SetMysqlDuration(types.Duration{Duration: time.Duration(i), Fsp: types.MaxFsp})
	return &Constant{Value: d, RetType: types.NewFieldType(mysql.TypeDuration)}, nil
}
<|endoftext|>