<commit_before>package analyticsbadge

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"appengine/urlfetch"
	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/google-api-go-client/analytics/v3"
	"encoding/json"
	"html/template"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)

type Account struct {
	Username     string
	AccessToken  string
	RefreshToken string
	Expiry       time.Time
}

func (a *Account) GetToken() *oauth.Token {
	if a.AccessToken == "" {
		return nil
	}
	return &oauth.Token{
		AccessToken:  a.AccessToken,
		RefreshToken: a.RefreshToken,
		Expiry:       a.Expiry,
	}
}

func (a *Account) SetToken(t *oauth.Token) {
	a.AccessToken = t.AccessToken
	a.RefreshToken = t.RefreshToken
	a.Expiry = t.Expiry
}

type Session struct {
	Id      string
	Account Account
	Loaded  Account
}

func (s *Session) Key(c appengine.Context) *datastore.Key {
	if s.Account.Username == "" {
		return datastore.NewIncompleteKey(c, "Account", nil)
	}
	return datastore.NewKey(c, "account", s.Account.Username, 0, nil)
}

type Property struct {
	Account *datastore.Key
	Id      string
	Profile string
}

type Wrapper func(http.ResponseWriter, *http.Request, *Session) error

func (fn Wrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	s := &Session{}
	cookie, err := r.Cookie("session")
	if err == nil {
		s.Id = cookie.Value
		item, err := memcache.Get(c, "s:"+s.Id)
		if err == nil {
			s.Account = Account{
				Username: string(item.Value),
			}
			if err := datastore.Get(c, s.Key(c), &s.Account); err != nil {
				c.Errorf("datastore.Get error: %#v", err)
				http.Redirect(w, r, "/", http.StatusFound)
				return
			}
			s.Loaded = s.Account
		}
	} else {
		s.Id = strconv.FormatInt(rand.Int63(), 36)
		cookie := &http.Cookie{
			Name:   "session",
			Value:  s.Id,
			MaxAge: 3600,
		}
		http.SetCookie(w, cookie)
	}
	if err := fn(w, r, s); err != nil {
		c.Errorf("Handler error: %#v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	if s.Loaded != s.Account {
		item := &memcache.Item{
			Key:        "s:" + s.Id,
			Value:      []byte(s.Account.Username),
			Expiration: time.Hour,
		}
		if err := memcache.Set(c, item); err != nil {
			c.Errorf("Memcache write error: %#v", err)
		}
		_, err = datastore.Put(c, s.Key(c), &s.Account)
		if err != nil {
			c.Errorf("datastore.Put write error: %#v", err)
		}
	}
}

type Config struct {
	Web struct {
		AuthUri      string   `json:"auth_uri"`
		ClientId     string   `json:"client_id"`
		ClientSecret string   `json:"client_secret"`
		RedirectURIs []string `json:"redirect_uris"`
		TokenURI     string   `json:"token_uri"`
	}
}

var (
	config    oauth.Config
	templates = template.Must(template.ParseGlob("templates/[^.]*"))
)

func init() {
	rand.Seed(time.Now().UnixNano())
	// Retrieved from https://console.developers.google.com/project after enabling the analytics API.
	file, _ := ioutil.ReadFile("client_secrets.json")
	var parsed Config
	json.Unmarshal(file, &parsed)
	config = oauth.Config{
		AccessType:   "offline",
		Scope:        "https://www.googleapis.com/auth/analytics.readonly",
		AuthURL:      parsed.Web.AuthUri,
		ClientId:     parsed.Web.ClientId,
		ClientSecret: parsed.Web.ClientSecret,
		RedirectURL:  parsed.Web.RedirectURIs[0],
		TokenURL:     parsed.Web.TokenURI,
	}
	http.HandleFunc("/", index)
	http.HandleFunc("/badge/", badge)
	http.Handle("/manage", Wrapper(manage))
	http.Handle("/oauth", Wrapper(auth))
}

func manage(w http.ResponseWriter, r *http.Request, s *Session) error {
	c := appengine.NewContext(r)
	t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}}
	t.Token = s.Account.GetToken()
	if t.Token == nil {
		http.Redirect(w, r, "/", http.StatusFound)
		return nil
	}
	a, err := analytics.New(t.Client())
	if err != nil {
		return err
	}
	accounts, err := a.Management.AccountSummaries.List().Do()
	if err != nil {
		return err
	}
	loaded := make(map[string]bool)
	for _, account := range accounts.Items {
		for _, property := range account.WebProperties {
			loaded[property.Id] = true
		}
	}
	s.Account.SetToken(t.Token)
	if r.Method == "POST" {
		w.Header().Set("Content-Type", "text/html")
		r.ParseForm()
		var keys []*datastore.Key
		var properties []*Property
		var cache []string
		for id := range r.Form {
			if !loaded[id] {
				continue
			}
			profile := r.FormValue(id)
			p := &Property{
				Account: s.Key(c),
				Id:      id,
				Profile: profile,
			}
			c.Errorf("key: %#v", p.Account)
			keys = append(keys, datastore.NewKey(c, "Property", p.Id, 0, nil))
			properties = append(properties, p)
			cache = append(cache, "b:"+p.Id)
		}
		_, err := datastore.PutMulti(c, keys, properties)
		if err != nil {
			c.Errorf("datastore.PutMulti error: %#v", err)
		}
		err = memcache.DeleteMulti(c, cache)
		if err != nil {
			c.Errorf("memcache.DeleteMulti error: %#v", err)
		}
		http.Redirect(w, r, "/manage", http.StatusFound)
		return nil
	}
	w.Header().Set("Content-Type", "text/html")
	params := &struct {
		Accounts *analytics.AccountSummaries
		Profiles map[string]string
	}{
		accounts,
		make(map[string]string),
	}
	var properties []Property
	q := datastore.NewQuery("Property").Filter("Account =", s.Key(c))
	q.GetAll(c, &properties)
	for _, p := range properties {
		params.Profiles[p.Id] = p.Profile
	}
	templates.ExecuteTemplate(w, "manage.html", params)
	return nil
}

func auth(w http.ResponseWriter, r *http.Request, s *Session) error {
	c := appengine.NewContext(r)
	t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}}
	token := s.Account.GetToken()
	if token != nil {
		t.Token = token
	}
	t.Exchange(r.FormValue("code"))
	a, err := analytics.New(t.Client())
	if err != nil {
		return err
	}
	accounts, err := a.Management.AccountSummaries.List().Do()
	if err != nil {
		return err
	}
	// Error out if no associated properties?
	s.Account.Username = accounts.Username
	s.Account.SetToken(t.Token)
	http.Redirect(w, r, "/manage", http.StatusFound)
	return nil
}

func index(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	templates.ExecuteTemplate(w, "index.html", config.AuthCodeURL(""))
}

func metric(i int) (string, string) {
	if i > 1000000 {
		return strconv.Itoa(i/1000000) + "M", "#4c1"
	}
	if i > 1000 {
		return strconv.Itoa(i/1000) + "k", "#a4a61d"
	}
	return strconv.Itoa(i), "#e05d44"
}

func size(s string) int {
	r := 10
	// Values from single letter SVG font rendering width, Chrome.
	for _, c := range s {
		switch c {
		case 'i':
			r += 2
		case ';', 'I', '\\', 'f', 'j', 'l', 'r', 't':
			r += 4
		case '1', '3', '5', '7', '9', ':', '?', 'E', 'F', 'J', 'P', 'T', 'Z', '[', ']', '`', 'b', 'c', 'd', 'g', 'k', 'o', 'p', 's', 'v', 'y':
			r += 6
		case 'K', 'L':
			r += 7
		case '<', '>', '@', 'G', 'O', 'W', 'm':
			r += 10
		default:
			r += 8
		}
	}
	return r
}

func badge(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	path := r.URL.Path[7 : len(r.URL.Path)-4]
	total := 0
	item, err := memcache.Get(c, "b:"+path)
	if err == nil {
		total, err = strconv.Atoi(string(item.Value))
		if err != nil {
			c.Errorf("badge(Memcache read) error: %#v", err)
			return
		}
	} else {
		k := datastore.NewKey(c, "Property", path, 0, nil)
		var p Property
		if err := datastore.Get(c, k, &p); err != nil {
			c.Errorf("badge(Property) error: %#v", err)
			return
		}
		var a Account
		if err := datastore.Get(c, p.Account, &a); err != nil {
			c.Errorf("badge(Account) error: %#v", err)
			return
		}
		loaded := a
		t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}}
		t.Token = a.GetToken()
		analytics, err := analytics.New(t.Client())
		if err != nil {
			c.Errorf("badge error: %#v", err)
			return
		}
		result, err := analytics.Data.Ga.Get("ga:"+p.Profile, "7daysAgo", "yesterday", "ga:users").Do()
		if err != nil {
			c.Errorf("badge(Data) error: %#v", err)
			return
		}
		total, err = strconv.Atoi(result.TotalsForAllResults["ga:users"])
		if err != nil {
			c.Errorf("badge(Total) error: %#v", err)
			return
		}
		item := &memcache.Item{
			Key:        "b:" + path,
			Value:      []byte(strconv.Itoa(total)),
			Expiration: time.Hour * 12,
		}
		if err := memcache.Set(c, item); err != nil {
			c.Errorf("badge(Memcache) error: %#v", err)
		}
		a.SetToken(t.Token)
		if a != loaded {
			_, err = datastore.Put(c, p.Account, &a)
		}
	}
	number, color := metric(total)
	params := &struct {
		Color       string
		Left        string
		Right       string
		LeftWidth   int
		RightWidth  int
		LeftCenter  int
		RightCenter int
		Total       int
	}{
		Left:  "users",
		Right: number + "/week",
		Color: color,
	}
	params.LeftWidth = size(params.Left)
	params.RightWidth = size(params.Right)
	params.Total = params.LeftWidth + params.RightWidth
	params.LeftCenter = params.LeftWidth/2 + 1
	params.RightCenter = params.LeftWidth + params.RightWidth/2 - 1
	w.Header().Set("Content-Type", "image/svg+xml")
	w.Header().Set("Cache-Control", "public, max-age=3600")
	templates.ExecuteTemplate(w, "badge.svg", params)
}
<commit_msg>Fix key name<commit_after>package analyticsbadge

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"appengine/urlfetch"
	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/google-api-go-client/analytics/v3"
	"encoding/json"
	"html/template"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)

type Account struct {
	Username     string
	AccessToken  string
	RefreshToken string
	Expiry       time.Time
}

func (a *Account) GetToken() *oauth.Token {
	if a.AccessToken == "" {
		return nil
	}
	return &oauth.Token{
		AccessToken:  a.AccessToken,
		RefreshToken: a.RefreshToken,
		Expiry:       a.Expiry,
	}
}

func (a *Account) SetToken(t *oauth.Token) {
	a.AccessToken = t.AccessToken
	a.RefreshToken = t.RefreshToken
	a.Expiry = t.Expiry
}

type Session struct {
	Id      string
	Account Account
	Loaded  Account
}

func (s *Session) Key(c appengine.Context) *datastore.Key {
	if s.Account.Username == "" {
		return datastore.NewIncompleteKey(c, "Account", nil)
	}
	return datastore.NewKey(c, "Account", s.Account.Username, 0, nil)
}

type Property struct {
	Account *datastore.Key
	Id      string
	Profile string
}

type Wrapper func(http.ResponseWriter, *http.Request, *Session) error

func (fn Wrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	s := &Session{}
	cookie, err := r.Cookie("session")
	if err == nil {
		s.Id = cookie.Value
		item, err := memcache.Get(c, "s:"+s.Id)
		if err == nil {
			s.Account = Account{
				Username: string(item.Value),
			}
			if err := datastore.Get(c, s.Key(c), &s.Account); err != nil {
				c.Errorf("datastore.Get error: %#v", err)
				http.Redirect(w, r, "/", http.StatusFound)
				return
			}
			s.Loaded = s.Account
		}
	} else {
		s.Id = strconv.FormatInt(rand.Int63(), 36)
		cookie := &http.Cookie{
			Name:   "session",
			Value:  s.Id,
			MaxAge: 3600,
		}
		http.SetCookie(w, cookie)
	}
	if err := fn(w, r, s); err != nil {
		c.Errorf("Handler error: %#v", err)
		http.Error(w, err.Error(), 500)
		return
	}
	if s.Loaded != s.Account {
		item := &memcache.Item{
			Key:        "s:" + s.Id,
			Value:      []byte(s.Account.Username),
			Expiration: time.Hour,
		}
		if err := memcache.Set(c, item); err != nil {
			c.Errorf("Memcache write error: %#v", err)
		}
		_, err = datastore.Put(c, s.Key(c), &s.Account)
		if err != nil {
			c.Errorf("datastore.Put write error: %#v", err)
		}
	}
}

type Config struct {
	Web struct {
		AuthUri      string   `json:"auth_uri"`
		ClientId     string   `json:"client_id"`
		ClientSecret string   `json:"client_secret"`
		RedirectURIs []string `json:"redirect_uris"`
		TokenURI     string   `json:"token_uri"`
	}
}

var (
	config    oauth.Config
	templates = template.Must(template.ParseGlob("templates/[^.]*"))
)

func init() {
	rand.Seed(time.Now().UnixNano())
	// Retrieved from https://console.developers.google.com/project after enabling the analytics API.
	file, _ := ioutil.ReadFile("client_secrets.json")
	var parsed Config
	json.Unmarshal(file, &parsed)
	config = oauth.Config{
		AccessType:   "offline",
		Scope:        "https://www.googleapis.com/auth/analytics.readonly",
		AuthURL:      parsed.Web.AuthUri,
		ClientId:     parsed.Web.ClientId,
		ClientSecret: parsed.Web.ClientSecret,
		RedirectURL:  parsed.Web.RedirectURIs[0],
		TokenURL:     parsed.Web.TokenURI,
	}
	http.HandleFunc("/", index)
	http.HandleFunc("/badge/", badge)
	http.Handle("/manage", Wrapper(manage))
	http.Handle("/oauth", Wrapper(auth))
}

func manage(w http.ResponseWriter, r *http.Request, s *Session) error {
	c := appengine.NewContext(r)
	t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}}
	t.Token = s.Account.GetToken()
	if t.Token == nil {
		http.Redirect(w, r, "/", http.StatusFound)
		return nil
	}
	a, err := analytics.New(t.Client())
	if err != nil {
		return err
	}
	accounts, err := a.Management.AccountSummaries.List().Do()
	if err != nil {
		return err
	}
	loaded := make(map[string]bool)
	for _, account := range accounts.Items {
		for _, property := range account.WebProperties {
			loaded[property.Id] = true
		}
	}
	s.Account.SetToken(t.Token)
	if r.Method == "POST" {
		w.Header().Set("Content-Type", "text/html")
		r.ParseForm()
		var keys []*datastore.Key
		var properties []*Property
		var cache []string
		for id := range r.Form {
			if !loaded[id] {
				continue
			}
			profile := r.FormValue(id)
			p := &Property{
				Account: s.Key(c),
				Id:      id,
				Profile: profile,
			}
			c.Errorf("key: %#v", p.Account)
			keys = append(keys, datastore.NewKey(c, "Property", p.Id, 0, nil))
			properties = append(properties, p)
			cache = append(cache, "b:"+p.Id)
		}
		_, err := datastore.PutMulti(c, keys, properties)
		if err != nil {
			c.Errorf("datastore.PutMulti error: %#v", err)
		}
		err = memcache.DeleteMulti(c, cache)
		if err != nil {
			c.Errorf("memcache.DeleteMulti error: %#v", err)
		}
		http.Redirect(w, r, "/manage", http.StatusFound)
		return nil
	}
	w.Header().Set("Content-Type", "text/html")
	params := &struct {
		Accounts *analytics.AccountSummaries
		Profiles map[string]string
	}{
		accounts,
		make(map[string]string),
	}
	var properties []Property
	q := datastore.NewQuery("Property").Filter("Account =", s.Key(c))
	q.GetAll(c, &properties)
	for _, p := range properties {
		params.Profiles[p.Id] = p.Profile
	}
	templates.ExecuteTemplate(w, "manage.html", params)
	return nil
}

func auth(w http.ResponseWriter, r *http.Request, s *Session) error {
	c := appengine.NewContext(r)
	t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}}
	token := s.Account.GetToken()
	if token != nil {
		t.Token = token
	}
	t.Exchange(r.FormValue("code"))
	a, err := analytics.New(t.Client())
	if err != nil {
		return err
	}
	accounts, err := a.Management.AccountSummaries.List().Do()
	if err != nil {
		return err
	}
	// Error out if no associated properties?
	s.Account.Username = accounts.Username
	s.Account.SetToken(t.Token)
	http.Redirect(w, r, "/manage", http.StatusFound)
	return nil
}

func index(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	templates.ExecuteTemplate(w, "index.html", config.AuthCodeURL(""))
}

func metric(i int) (string, string) {
	if i > 1000000 {
		return strconv.Itoa(i/1000000) + "M", "#4c1"
	}
	if i > 1000 {
		return strconv.Itoa(i/1000) + "k", "#a4a61d"
	}
	return strconv.Itoa(i), "#e05d44"
}

func size(s string) int {
	r := 10
	// Values from single letter SVG font rendering width, Chrome.
	for _, c := range s {
		switch c {
		case 'i':
			r += 2
		case ';', 'I', '\\', 'f', 'j', 'l', 'r', 't':
			r += 4
		case '1', '3', '5', '7', '9', ':', '?', 'E', 'F', 'J', 'P', 'T', 'Z', '[', ']', '`', 'b', 'c', 'd', 'g', 'k', 'o', 'p', 's', 'v', 'y':
			r += 6
		case 'K', 'L':
			r += 7
		case '<', '>', '@', 'G', 'O', 'W', 'm':
			r += 10
		default:
			r += 8
		}
	}
	return r
}

func badge(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	path := r.URL.Path[7 : len(r.URL.Path)-4]
	total := 0
	item, err := memcache.Get(c, "b:"+path)
	if err == nil {
		total, err = strconv.Atoi(string(item.Value))
		if err != nil {
			c.Errorf("badge(Memcache read) error: %#v", err)
			return
		}
	} else {
		k := datastore.NewKey(c, "Property", path, 0, nil)
		var p Property
		if err := datastore.Get(c, k, &p); err != nil {
			c.Errorf("badge(Property) error: %#v", err)
			return
		}
		var a Account
		if err := datastore.Get(c, p.Account, &a); err != nil {
			c.Errorf("badge(Account) error: %#v", err)
			return
		}
		loaded := a
		t := &oauth.Transport{Config: &config, Transport: &urlfetch.Transport{Context: c}}
		t.Token = a.GetToken()
		analytics, err := analytics.New(t.Client())
		if err != nil {
			c.Errorf("badge error: %#v", err)
			return
		}
		result, err := analytics.Data.Ga.Get("ga:"+p.Profile, "7daysAgo", "yesterday", "ga:users").Do()
		if err != nil {
			c.Errorf("badge(Data) error: %#v", err)
			return
		}
		total, err = strconv.Atoi(result.TotalsForAllResults["ga:users"])
		if err != nil {
			c.Errorf("badge(Total) error: %#v", err)
			return
		}
		item := &memcache.Item{
			Key:        "b:" + path,
			Value:      []byte(strconv.Itoa(total)),
			Expiration: time.Hour * 12,
		}
		if err := memcache.Set(c, item); err != nil {
			c.Errorf("badge(Memcache) error: %#v", err)
		}
		a.SetToken(t.Token)
		if a != loaded {
			_, err = datastore.Put(c, p.Account, &a)
		}
	}
	number, color := metric(total)
	params := &struct {
		Color       string
		Left        string
		Right       string
		LeftWidth   int
		RightWidth  int
		LeftCenter  int
		RightCenter int
		Total       int
	}{
		Left:  "users",
		Right: number + "/week",
		Color: color,
	}
	params.LeftWidth = size(params.Left)
	params.RightWidth = size(params.Right)
	params.Total = params.LeftWidth + params.RightWidth
	params.LeftCenter = params.LeftWidth/2 + 1
	params.RightCenter = params.LeftWidth + params.RightWidth/2 - 1
	w.Header().Set("Content-Type", "image/svg+xml")
	w.Header().Set("Cache-Control", "public, max-age=3600")
	templates.ExecuteTemplate(w, "badge.svg", params)
}
<|endoftext|>


<commit_before>package keypaircommands

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/jrperritt/gophercloud/rackspace/compute/v2/keypairs"
	"github.com/jrperritt/rack/auth"
	"github.com/jrperritt/rack/util"
)

var get = cli.Command{
	Name:        "get",
	Usage:       fmt.Sprintf("%s %s get <keypairName> [flags]", util.Name, commandPrefix),
	Description: "Retreives a keypair",
	Action:      commandGet,
	Flags:       util.CommandFlags(flagsGet),
	BashComplete: func(c *cli.Context) {
		util.CompleteFlags(util.CommandFlags(flagsGet))
	},
}

func flagsGet() []cli.Flag {
	return []cli.Flag{}
}

func commandGet(c *cli.Context) {
	util.CheckArgNum(c, 1)
	flavorID := c.Args()[0]
	client := auth.NewClient("compute")
	o, err := keypairs.Get(client, flavorID).Extract()
	if err != nil {
		fmt.Printf("Error retreiving image [%s]: %s\n", flavorID, err)
		os.Exit(1)
	}

	fmt.Fprintf(c.App.Writer, "%s", o.PublicKey)
}
<commit_msg>Add a comment.<commit_after>package keypaircommands

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
	"github.com/jrperritt/gophercloud/rackspace/compute/v2/keypairs"
	"github.com/jrperritt/rack/auth"
	"github.com/jrperritt/rack/util"
)

var get = cli.Command{
	Name:        "get",
	Usage:       fmt.Sprintf("%s %s get <keypairName> [flags]", util.Name, commandPrefix),
	Description: "Retreives a keypair",
	Action:      commandGet,
	Flags:       util.CommandFlags(flagsGet),
	BashComplete: func(c *cli.Context) {
		util.CompleteFlags(util.CommandFlags(flagsGet))
	},
}

func flagsGet() []cli.Flag {
	return []cli.Flag{}
}

func commandGet(c *cli.Context) {
	util.CheckArgNum(c, 1)
	flavorID := c.Args()[0]
	client := auth.NewClient("compute")
	o, err := keypairs.Get(client, flavorID).Extract()
	if err != nil {
		fmt.Printf("Error retreiving image [%s]: %s\n", flavorID, err)
		os.Exit(1)
	}

	// Assume they want the key directly
	fmt.Fprintf(c.App.Writer, "%s", o.PublicKey)
}
<|endoftext|>


<commit_before>package version

const Version = "1.2.0"
<commit_msg>chore(version): 1.3.0<commit_after>package version

const Version = "1.3.0"
<|endoftext|>


<commit_before>// Copyright 2017 The etcd-operator 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 version

var (
	Version = "0.1.4+git"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<commit_msg>version: release 0.1.5<commit_after>// Copyright 2017 The etcd-operator 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 version

var (
	Version = "0.1.5"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<|endoftext|>


<commit_before>package version

import (
	"bytes"
	"fmt"
)

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

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

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

	// VersionMetadata is metadata further describing the build type.
	VersionMetadata = ""
)

// VersionInfo
type VersionInfo struct {
	Revision          string
	Version           string
	VersionPrerelease string
	VersionMetadata   string
}

func GetVersion() *VersionInfo {
	ver := Version
	rel := VersionPrerelease
	md := VersionMetadata
	if GitDescribe != "" {
		ver = GitDescribe
	}
	if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
		rel = "dev"
	}

	return &VersionInfo{
		Revision:          GitCommit,
		Version:           ver,
		VersionPrerelease: rel,
		VersionMetadata:   md,
	}
}

func (c *VersionInfo) VersionNumber() string {
	version := fmt.Sprintf("%s", c.Version)

	if c.VersionPrerelease != "" {
		version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
	}

	return version
}

func (c *VersionInfo) FullVersionNumber(rev bool) string {
	var versionString bytes.Buffer

	fmt.Fprintf(&versionString, "Nomad v%s", c.Version)
	if c.VersionPrerelease != "" {
		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
	}

	if rev && c.Revision != "" {
		fmt.Fprintf(&versionString, " (%s)", c.Revision)
	}

	return versionString.String()
}
<commit_msg>version to 1.0.0-dev (!!!!)<commit_after>package version

import (
	"bytes"
	"fmt"
)

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

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

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

	// VersionMetadata is metadata further describing the build type.
	VersionMetadata = ""
)

// VersionInfo
type VersionInfo struct {
	Revision          string
	Version           string
	VersionPrerelease string
	VersionMetadata   string
}

func GetVersion() *VersionInfo {
	ver := Version
	rel := VersionPrerelease
	md := VersionMetadata
	if GitDescribe != "" {
		ver = GitDescribe
	}
	if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
		rel = "dev"
	}

	return &VersionInfo{
		Revision:          GitCommit,
		Version:           ver,
		VersionPrerelease: rel,
		VersionMetadata:   md,
	}
}

func (c *VersionInfo) VersionNumber() string {
	version := fmt.Sprintf("%s", c.Version)

	if c.VersionPrerelease != "" {
		version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
	}

	return version
}

func (c *VersionInfo) FullVersionNumber(rev bool) string {
	var versionString bytes.Buffer

	fmt.Fprintf(&versionString, "Nomad v%s", c.Version)
	if c.VersionPrerelease != "" {
		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
	}

	if rev && c.Revision != "" {
		fmt.Fprintf(&versionString, " (%s)", c.Revision)
	}

	return versionString.String()
}
<|endoftext|>


<commit_before>package version

const (
	Version = "0.1.3+git"
)
<commit_msg>bump(version): v0.1.4<commit_after>package version

const (
	Version = "0.1.4"
)
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package version

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

// semverAlphabet is an alphabet of all characters allowed in semver prerelease
// or build metadata identifiers, and the . separator.
const semverAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."

// Constants defining the application version number.
const (
	Major = 1
	Minor = 5
	Patch = 0
)

// Integer is an integer encoding of the major.minor.patch version.
const Integer = 1000000*Major + 10000*Minor + 100*Patch

// PreRelease contains the prerelease name of the application.  It is a variable
// so it can be modified at link time (e.g.
// `-ldflags "-X github.com/decred/dcrwallet/version.PreRelease=rc1"`).
// It must only contain characters from the semantic version alphabet.
var PreRelease = "pre"

// BuildMetadata defines additional build metadata.  It is modified at link time
// for official releases.  It must only contain characters from the semantic
// version alphabet.
var BuildMetadata = "dev"

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

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

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

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	var buf bytes.Buffer
	for _, r := range str {
		if strings.ContainsRune(semverAlphabet, r) {
			_, err := buf.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return buf.String()
}
<commit_msg>Bump version constants for 1.5.1.<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package version

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

// semverAlphabet is an alphabet of all characters allowed in semver prerelease
// or build metadata identifiers, and the . separator.
const semverAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."

// Constants defining the application version number.
const (
	Major = 1
	Minor = 5
	Patch = 1
)

// Integer is an integer encoding of the major.minor.patch version.
const Integer = 1000000*Major + 10000*Minor + 100*Patch

// PreRelease contains the prerelease name of the application.  It is a variable
// so it can be modified at link time (e.g.
// `-ldflags "-X github.com/decred/dcrwallet/version.PreRelease=rc1"`).
// It must only contain characters from the semantic version alphabet.
var PreRelease = "pre"

// BuildMetadata defines additional build metadata.  It is modified at link time
// for official releases.  It must only contain characters from the semantic
// version alphabet.
var BuildMetadata = "dev"

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

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

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

	return version
}

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


<commit_before>// Copyright The OpenTelemetry 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 version

import "runtime/debug"

var version = func() string {
	bi, ok := debug.ReadBuildInfo()
	if !ok {
		return "unknown"
	}

	for _, mod := range bi.Deps {
		if mod.Path == "github.com/open-telemetry/opentelemetry-log-collection" {
			return mod.Version
		}
	}
	return "unknown"
}()

// GetVersion returns the version of the stanza library
func GetVersion() string {
	return version
}
<commit_msg>Remove version package (#382)<commit_after><|endoftext|>


<commit_before>package version

const Version = "1.4.0"
<commit_msg>version: bump to v1.4.0+git<commit_after>package version

const Version = "1.4.0+git"
<|endoftext|>


<commit_before>package version

const (
	// Version is the current File Browser version.
	Version = "(untracked)"
)
<commit_msg>chore: version v2.0.0<commit_after>package version

const (
	// Version is the current File Browser version.
	Version = "v2.0.0"
)
<|endoftext|>


<commit_before>/*
   Copyright 2014 CoreOS, 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,
   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 version

const (
	Version = "0.2.1+git"
)
<commit_msg>version: bump to 0.2.2<commit_after>/*
   Copyright 2014 CoreOS, 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,
   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 version

const (
	Version = "0.2.2"
)
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package version

// ensure that git has a tag: "vX.Y" corresponding to major and minor
const (
	Major   = "2"
	Minor   = "10"
	Version = Major + "." + Minor
)
<commit_msg>[version] update version<commit_after>// Copyright (c) 2014-2016 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package version

// ensure that git has a tag: "vX.Y" corresponding to major and minor
const (
	Major   = "2"
	Minor   = "11"
	Version = Major + "." + Minor
)
<|endoftext|>


<commit_before>package browspr

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"testing"

	"veyron.io/veyron/veyron/profiles"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
	mounttable "veyron.io/veyron/veyron/services/mounttable/lib"
	"veyron.io/veyron/veyron2/ipc"
	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/options"
	"veyron.io/veyron/veyron2/rt"
	"veyron.io/veyron/veyron2/vdl/vdlutil"
	"veyron.io/veyron/veyron2/vom2"
	"veyron.io/veyron/veyron2/wiretype"
	"veyron.io/wspr/veyron/services/wsprd/app"
	"veyron.io/wspr/veyron/services/wsprd/lib"
)

var (
	r = rt.Init()
)

func startProxy() (*proxy.Proxy, error) {
	rid, err := naming.NewRoutingID()
	if err != nil {
		return nil, err
	}
	return proxy.New(rid, nil, "tcp", "127.0.0.1:0", "")
}

func startMounttable() (ipc.Server, naming.Endpoint, error) {
	mt, err := mounttable.NewMountTable("")
	if err != nil {
		return nil, nil, err
	}

	s, err := r.NewServer(options.ServesMountTable(true))
	if err != nil {
		return nil, nil, err
	}

	endpoint, err := s.Listen(profiles.LocalListenSpec)
	if err != nil {
		return nil, nil, err
	}

	if err := s.ServeDispatcher("", mt); err != nil {
		return nil, nil, err
	}

	return s, endpoint, nil
}

type mockServer struct{}

func (s mockServer) BasicCall(_ ipc.ServerCall, txt string) (string, error) {
	return "[" + txt + "]", nil
}

func (s mockServer) Signature(call ipc.ServerCall) (ipc.ServiceSignature, error) {
	result := ipc.ServiceSignature{Methods: make(map[string]ipc.MethodSignature)}
	result.Methods["BasicCall"] = ipc.MethodSignature{
		InArgs: []ipc.MethodArgument{
			{Name: "Txt", Type: 3},
		},
		OutArgs: []ipc.MethodArgument{
			{Name: "Value", Type: 3},
			{Name: "Err", Type: 65},
		},
	}
	result.TypeDefs = []vdlutil.Any{
		wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}

	return result, nil
}

func startMockServer(desiredName string) (ipc.Server, naming.Endpoint, error) {
	// Create a new server instance.
	s, err := r.NewServer()
	if err != nil {
		return nil, nil, err
	}

	endpoint, err := s.Listen(profiles.LocalListenSpec)
	if err != nil {
		return nil, nil, err
	}

	if err := s.ServeDispatcher(desiredName, ipc.LeafDispatcher(mockServer{}, nil)); err != nil {
		return nil, nil, err
	}

	return s, endpoint, nil
}

type veyronTempRPC struct {
	Name        string
	Method      string
	InArgs      []json.RawMessage
	NumOutArgs  int32
	IsStreaming bool
	Timeout     int64
}

func TestBrowspr(t *testing.T) {
	proxy, err := startProxy()
	if err != nil {
		t.Fatalf("Failed to start proxy: %v", err)
	}
	defer proxy.Shutdown()

	mtServer, mtEndpoint, err := startMounttable()
	if err != nil {
		t.Fatalf("Failed to start mounttable server: %v", err)
	}
	defer mtServer.Stop()
	if err := r.Namespace().SetRoots("/" + mtEndpoint.String()); err != nil {
		t.Fatalf("Failed to set namespace roots: %v", err)
	}

	mockServerName := "mock/server"
	mockServer, mockServerEndpoint, err := startMockServer(mockServerName)
	if err != nil {
		t.Fatalf("Failed to start mock server: %v", err)
	}
	defer mockServer.Stop()

	names, err := mockServer.Published()
	if err != nil {
		t.Fatalf("Error fetching published names: %v", err)
	}
	if len(names) != 1 || names[0] != "/"+mtEndpoint.String()+"/"+mockServerName {
		t.Fatalf("Incorrectly mounted server. Names: %v", names)
	}
	mountEntry, err := r.Namespace().ResolveX(nil, mockServerName)
	if err != nil {
		t.Fatalf("Error fetching published names from mounttable: %v", err)
	}
	if len(mountEntry.Servers) != 1 || mountEntry.Servers[0].Server != "/"+mockServerEndpoint.String() {
		t.Fatalf("Incorrect names retrieved from mounttable: %v", mountEntry)
	}

	spec := profiles.LocalListenSpec
	spec.Proxy = proxy.Endpoint().String()

	receivedResponse := make(chan bool, 1)
	var receivedInstanceId int32
	var receivedType string
	var receivedMsg string

	var postMessageHandler = func(instanceId int32, ty, msg string) {
		receivedInstanceId = instanceId
		receivedType = ty
		receivedMsg = msg
		receivedResponse <- true
	}

	browspr := NewBrowspr(postMessageHandler, spec, "/mock/identd", []string{"/" + mtEndpoint.String()}, options.RuntimePrincipal{r.Principal()})

	principal := browspr.rt.Principal()
	browspr.accountManager.SetMockBlesser(newMockBlesserService(principal))

	msgInstanceId := int32(11)

	rpcMessage := veyronTempRPC{
		Name:   mockServerName,
		Method: "BasicCall",
		InArgs: []json.RawMessage{
			json.RawMessage([]byte("\"InputValue\"")),
		},
		NumOutArgs:  2,
		IsStreaming: false,
		Timeout:     (1 << 31) - 1,
	}

	jsonRpcMessage, err := json.Marshal(rpcMessage)
	if err != nil {
		t.Fatalf("Failed to marshall rpc message to json: %v", err)
	}

	msg, err := json.Marshal(app.Message{
		Id:   1,
		Data: string(jsonRpcMessage),
		Type: app.VeyronRequestMessage,
	})
	if err != nil {
		t.Fatalf("Failed to marshall app message to json: %v", err)
	}

	err = browspr.HandleMessage(msgInstanceId, string(msg))
	if err != nil {
		t.Fatalf("Error while handling message: %v", err)
	}

	<-receivedResponse

	if receivedInstanceId != msgInstanceId {
		t.Errorf("Received unexpected instance id: %d. Expected: %d", receivedInstanceId, msgInstanceId)
	}
	if receivedType != "msg" {
		t.Errorf("Received unexpected response type. Expected: %q, but got %q", "msg", receivedType)
	}

	var outMsg app.Message
	if err := json.Unmarshal([]byte(receivedMsg), &outMsg); err != nil {
		t.Fatalf("Failed to unmarshall outgoing message: %v", err)
	}
	if outMsg.Id != int64(1) {
		t.Errorf("Id was %v, expected %v", outMsg.Id, int64(1))
	}
	if outMsg.Type != app.VeyronRequestMessage {
		t.Errorf("Message type was %v, expected %v", outMsg.Type, app.MessageType(0))
	}

	var responseMsg app.Response
	if err := json.Unmarshal([]byte(outMsg.Data), &responseMsg); err != nil {
		t.Fatalf("Failed to unmarshall outgoing response: %v", err)
	}
	if responseMsg.Type != lib.ResponseFinal {
		t.Errorf("Data was %q, expected %q", outMsg.Data, `["[InputValue]"]`)
	}
	var outArg string
	var ok bool
	if outArg, ok = responseMsg.Message.(string); !ok {
		t.Errorf("Got unexpected response message body of type %T, expected type string", responseMsg.Message)
	}
	var result []string
	arg, err := hex.DecodeString(outArg)
	if err != nil {
		t.Errorf("failed to hex decode string: %v", err)
	}
	decoder, err := vom2.NewDecoder(bytes.NewBuffer(arg))
	if err != nil {
		t.Fatalf("failed to construct new decoder: %v", err)
	}
	if err := decoder.Decode(&result); err != nil || result[0] != "[InputValue]" {
		t.Errorf("got %s with err: %v, expected %s", result[0], err, "[InputValue]")
	}
}
<commit_msg>Fix the browsper tests so it handles the fact that a server listens on both tcp and ws.<commit_after>package browspr

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"strings"
	"testing"

	"veyron.io/veyron/veyron/profiles"
	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
	mounttable "veyron.io/veyron/veyron/services/mounttable/lib"
	"veyron.io/veyron/veyron2/ipc"
	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/options"
	"veyron.io/veyron/veyron2/rt"
	"veyron.io/veyron/veyron2/vdl/vdlutil"
	"veyron.io/veyron/veyron2/vom2"
	"veyron.io/veyron/veyron2/wiretype"
	"veyron.io/wspr/veyron/services/wsprd/app"
	"veyron.io/wspr/veyron/services/wsprd/lib"
)

var (
	r = rt.Init()
)

func startProxy() (*proxy.Proxy, error) {
	rid, err := naming.NewRoutingID()
	if err != nil {
		return nil, err
	}
	return proxy.New(rid, nil, "tcp", "127.0.0.1:0", "")
}

func startMounttable() (ipc.Server, naming.Endpoint, error) {
	mt, err := mounttable.NewMountTable("")
	if err != nil {
		return nil, nil, err
	}

	s, err := r.NewServer(options.ServesMountTable(true))
	if err != nil {
		return nil, nil, err
	}

	endpoint, err := s.Listen(profiles.LocalListenSpec)
	if err != nil {
		return nil, nil, err
	}

	if err := s.ServeDispatcher("", mt); err != nil {
		return nil, nil, err
	}

	return s, endpoint, nil
}

type mockServer struct{}

func (s mockServer) BasicCall(_ ipc.ServerCall, txt string) (string, error) {
	return "[" + txt + "]", nil
}

func (s mockServer) Signature(call ipc.ServerCall) (ipc.ServiceSignature, error) {
	result := ipc.ServiceSignature{Methods: make(map[string]ipc.MethodSignature)}
	result.Methods["BasicCall"] = ipc.MethodSignature{
		InArgs: []ipc.MethodArgument{
			{Name: "Txt", Type: 3},
		},
		OutArgs: []ipc.MethodArgument{
			{Name: "Value", Type: 3},
			{Name: "Err", Type: 65},
		},
	}
	result.TypeDefs = []vdlutil.Any{
		wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}

	return result, nil
}

func startMockServer(desiredName string) (ipc.Server, naming.Endpoint, error) {
	// Create a new server instance.
	s, err := r.NewServer()
	if err != nil {
		return nil, nil, err
	}

	endpoint, err := s.Listen(profiles.LocalListenSpec)
	if err != nil {
		return nil, nil, err
	}

	if err := s.ServeDispatcher(desiredName, ipc.LeafDispatcher(mockServer{}, nil)); err != nil {
		return nil, nil, err
	}

	return s, endpoint, nil
}

type veyronTempRPC struct {
	Name        string
	Method      string
	InArgs      []json.RawMessage
	NumOutArgs  int32
	IsStreaming bool
	Timeout     int64
}

func TestBrowspr(t *testing.T) {
	proxy, err := startProxy()
	if err != nil {
		t.Fatalf("Failed to start proxy: %v", err)
	}
	defer proxy.Shutdown()

	mtServer, mtEndpoint, err := startMounttable()
	if err != nil {
		t.Fatalf("Failed to start mounttable server: %v", err)
	}
	defer mtServer.Stop()
	if err := r.Namespace().SetRoots("/" + mtEndpoint.String()); err != nil {
		t.Fatalf("Failed to set namespace roots: %v", err)
	}

	mockServerName := "mock/server"
	mockServer, mockServerEndpoint, err := startMockServer(mockServerName)
	if err != nil {
		t.Fatalf("Failed to start mock server: %v", err)
	}
	defer mockServer.Stop()

	names, err := mockServer.Published()
	if err != nil {
		t.Fatalf("Error fetching published names: %v", err)
	}
	if len(names) != 1 || names[0] != "/"+mtEndpoint.String()+"/"+mockServerName {
		t.Fatalf("Incorrectly mounted server. Names: %v", names)
	}
	mountEntry, err := r.Namespace().ResolveX(nil, mockServerName)
	if err != nil {
		t.Fatalf("Error fetching published names from mounttable: %v", err)
	}

	servers := []string{}
	for _, s := range mountEntry.Servers {
		if strings.Index(s.Server, "@tcp") != -1 {
			servers = append(servers, s.Server)
		}
	}
	if len(servers) != 1 || servers[0] != "/"+mockServerEndpoint.String() {
		t.Fatalf("Incorrect names retrieved from mounttable: %v", mountEntry)
	}

	spec := profiles.LocalListenSpec
	spec.Proxy = proxy.Endpoint().String()

	receivedResponse := make(chan bool, 1)
	var receivedInstanceId int32
	var receivedType string
	var receivedMsg string

	var postMessageHandler = func(instanceId int32, ty, msg string) {
		receivedInstanceId = instanceId
		receivedType = ty
		receivedMsg = msg
		receivedResponse <- true
	}

	browspr := NewBrowspr(postMessageHandler, spec, "/mock/identd", []string{"/" + mtEndpoint.String()}, options.RuntimePrincipal{r.Principal()})

	principal := browspr.rt.Principal()
	browspr.accountManager.SetMockBlesser(newMockBlesserService(principal))

	msgInstanceId := int32(11)

	rpcMessage := veyronTempRPC{
		Name:   mockServerName,
		Method: "BasicCall",
		InArgs: []json.RawMessage{
			json.RawMessage([]byte("\"InputValue\"")),
		},
		NumOutArgs:  2,
		IsStreaming: false,
		Timeout:     (1 << 31) - 1,
	}

	jsonRpcMessage, err := json.Marshal(rpcMessage)
	if err != nil {
		t.Fatalf("Failed to marshall rpc message to json: %v", err)
	}

	msg, err := json.Marshal(app.Message{
		Id:   1,
		Data: string(jsonRpcMessage),
		Type: app.VeyronRequestMessage,
	})
	if err != nil {
		t.Fatalf("Failed to marshall app message to json: %v", err)
	}

	err = browspr.HandleMessage(msgInstanceId, string(msg))
	if err != nil {
		t.Fatalf("Error while handling message: %v", err)
	}

	<-receivedResponse

	if receivedInstanceId != msgInstanceId {
		t.Errorf("Received unexpected instance id: %d. Expected: %d", receivedInstanceId, msgInstanceId)
	}
	if receivedType != "msg" {
		t.Errorf("Received unexpected response type. Expected: %q, but got %q", "msg", receivedType)
	}

	var outMsg app.Message
	if err := json.Unmarshal([]byte(receivedMsg), &outMsg); err != nil {
		t.Fatalf("Failed to unmarshall outgoing message: %v", err)
	}
	if outMsg.Id != int64(1) {
		t.Errorf("Id was %v, expected %v", outMsg.Id, int64(1))
	}
	if outMsg.Type != app.VeyronRequestMessage {
		t.Errorf("Message type was %v, expected %v", outMsg.Type, app.MessageType(0))
	}

	var responseMsg app.Response
	if err := json.Unmarshal([]byte(outMsg.Data), &responseMsg); err != nil {
		t.Fatalf("Failed to unmarshall outgoing response: %v", err)
	}
	if responseMsg.Type != lib.ResponseFinal {
		t.Errorf("Data was %q, expected %q", outMsg.Data, `["[InputValue]"]`)
	}
	var outArg string
	var ok bool
	if outArg, ok = responseMsg.Message.(string); !ok {
		t.Errorf("Got unexpected response message body of type %T, expected type string", responseMsg.Message)
	}
	var result []string
	arg, err := hex.DecodeString(outArg)
	if err != nil {
		t.Errorf("failed to hex decode string: %v", err)
	}
	decoder, err := vom2.NewDecoder(bytes.NewBuffer(arg))
	if err != nil {
		t.Fatalf("failed to construct new decoder: %v", err)
	}
	if err := decoder.Decode(&result); err != nil || result[0] != "[InputValue]" {
		t.Errorf("got %s with err: %v, expected %s", result[0], err, "[InputValue]")
	}
}
<|endoftext|>


<commit_before>package bf

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/crillab/gophersat/solver"
)

// A Formula is any kind of boolean formula, not necessarily in CNF form.
type Formula interface {
	nnf() Formula
	String() string
}

// Solve solves the given formula.
// f is first converted as a CNF formula. It is then given to gophersat.
// The function returns a boolean indicating if the formula was satisfiable.
// If it was, a model is then provided, associating each variable name with its binding.
func Solve(f Formula) (sat bool, model map[string]bool, err error) {
	return asCnf(f).solve()
}

// Dimacs writes the DIMACS CNF version of the formula on w.
// It is useful so as to feed it to any SAT solver.
func Dimacs(f Formula, w io.Writer) error {
	cnf := asCnf(f)
	nbVars := len(cnf.vars.all)
	nbClauses := len(cnf.clauses)
	prefix := fmt.Sprintf("p cnf %d %d\n", nbVars, nbClauses)
	if _, err := io.WriteString(w, prefix); err != nil {
		return fmt.Errorf("could not write DIMACS output: %v", err)
	}
	for _, clause := range cnf.clauses {
		strClause := make([]string, len(clause))
		for i, lit := range clause {
			strClause[i] = strconv.Itoa(lit)
		}
		line := fmt.Sprintf("%s 0\n", strings.Join(strClause, " "))
		if _, err := io.WriteString(w, line); err != nil {
			return fmt.Errorf("could not write DIMACS output: %v", err)
		}
	}
	return nil
}

// Var generates a named boolean variable in a formula.
func Var(name string) Formula {
	return variable(name)
}

type variable string

func (v variable) nnf() Formula {
	return lit{signed: false, v: v}
}

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

type lit struct {
	signed bool
	v      variable
}

func (l lit) nnf() Formula {
	return l
}

func (l lit) String() string {
	if l.signed {
		return "not(" + string(l.v) + ")"
	}
	return string(l.v)
}

// Not represents a negation. It negates the given subformula.
func Not(f Formula) Formula {
	return not{f}
}

type not [1]Formula

func (n not) nnf() Formula {
	switch f := n[0].(type) {
	case variable:
		l := f.nnf().(lit)
		l.signed = true
		return l
	case lit:
		f.signed = !f.signed
		return f
	case not:
		return f[0].nnf()
	case and:
		subs := make([]Formula, len(f))
		for i, sub := range f {
			subs[i] = not{sub}.nnf()
		}
		return or(subs).nnf()
	case or:
		subs := make([]Formula, len(f))
		for i, sub := range f {
			subs[i] = not{sub}.nnf()
		}
		return and(subs).nnf()
	default:
		panic("invalid formula type")
	}
}

func (n not) String() string {
	return "not(" + n[0].String() + ")"
}

// And generates a conjunction of subformulas.
func And(subs ...Formula) Formula {
	return and(subs)
}

type and []Formula

func (a and) nnf() Formula {
	var res and
	for _, s := range a {
		nnf := s.nnf()
		if a2, ok := nnf.(and); ok { // // Simplify: "and"s in the "and" get to the higher level
			for _, s2 := range a2 {
				res = append(res, s2)
			}
		} else {
			res = append(res, nnf)
		}
	}
	if len(res) == 1 {
		return res[0]
	}
	return res
}

func (a and) String() string {
	strs := make([]string, len(a))
	for i, f := range a {
		strs[i] = f.String()
	}
	return "and(" + strings.Join(strs, ", ") + ")"
}

// Or generates a disjunction of subformulas.
func Or(subs ...Formula) Formula {
	return or(subs)
}

type or []Formula

func (o or) nnf() Formula {
	var res or
	for _, s := range o {
		nnf := s.nnf()
		if o2, ok := nnf.(or); ok { // Simplify: "or"s in the "or" get to the higher level
			for _, s2 := range o2 {
				res = append(res, s2)
			}
		} else {
			res = append(res, nnf)
		}
	}
	if len(res) == 1 {
		return res[0]
	}
	return res
}

func (o or) String() string {
	strs := make([]string, len(o))
	for i, f := range o {
		strs[i] = f.String()
	}
	return "or(" + strings.Join(strs, ", ") + ")"
}

// Implies indicates a subformula implies another one.
func Implies(f1, f2 Formula) Formula {
	return or{not{f1}, f2}
}

// Eq indicates a subformula is equivalent to another one.
func Eq(f1, f2 Formula) Formula {
	return and{or{not{f1}, f2}, or{f1, not{f2}}}
}

// Xor indicates exactly one of the two given subformulas is true.
func Xor(f1, f2 Formula) Formula {
	return and{or{not{f1}, not{f2}}, or{f1, f2}}
}

// vars associate variable names with numeric indices.
type vars struct {
	all map[variable]int // all vars, including those created when converting the formula
	pb  map[variable]int // Only the vars that appeared orinigally in the problem
}

// litValue returns the int value associated with the given problem var.
// If the var was not referenced yet, it is created first.
func (vars *vars) litValue(l lit) int {
	val, ok := vars.all[l.v]
	if !ok {
		val = len(vars.all) + 1
		vars.all[l.v] = val
		vars.pb[l.v] = val
	}
	if l.signed {
		return -val
	}
	return val
}

// Dummy creates a dummy variable and returns its associated index.
func (vars *vars) dummy() int {
	val := len(vars.all) + 1
	vars.all[variable(fmt.Sprintf("dummy-%d", val))] = val
	return val
}

// A CNF is the representation of a boolean formula as a conjunction of disjunction.
// It can be solved by a SAT solver.
type cnf struct {
	vars    vars
	clauses [][]int
}

// solve solves the given formula.
// cnf is given to gophersat.
// The function returns a boolean indicating if the formula was satisfiable.
// If it was, a model is then provided, associating each variable name with its binding.
func (cnf *cnf) solve() (sat bool, vars map[string]bool, err error) {
	pb, err := solver.ParseSlice(cnf.clauses)
	if err != nil {
		return false, nil, fmt.Errorf("could not create problem from formula: %v", err)
	}
	s := solver.New(pb)
	if s.Solve() != solver.Sat {
		return false, nil, nil
	}
	m, err := s.Model()
	if err != nil {
		return false, nil, fmt.Errorf("could not retrieve model: %v", err)
	}
	vars = make(map[string]bool)
	for name, idx := range cnf.vars.pb {
		vars[string(name)] = m[idx-1]
	}
	return true, vars, nil
}

// asCnf returns a CNF representation of the given formula.
func asCnf(f Formula) *cnf {
	vars := vars{all: make(map[variable]int), pb: make(map[variable]int)}
	clauses := cnfRec(f.nnf(), &vars)
	return &cnf{vars: vars, clauses: clauses}
}

// transforms the f NNF formula into a CNF formula.
// nbDummies is the current number of dummy variables created.
// Note: code should be improved, there are a few useless allocs/deallocs
// here and there.
func cnfRec(f Formula, vars *vars) [][]int {
	switch f := f.(type) {
	case lit:
		return [][]int{[]int{vars.litValue(f)}}
	case and:
		var res [][]int
		for _, sub := range f {
			res = append(res, cnfRec(sub, vars)...)
		}
		return res
	case or:
		var res [][]int
		var lits []int
		for _, sub := range f {
			switch sub := sub.(type) {
			case lit:
				lits = append(lits, vars.litValue(sub))
			case and:
				d := vars.dummy()
				lits = append(lits, d)
				for _, sub2 := range sub {
					nnf := cnfRec(sub2, vars)[0]
					nnf = append(nnf, -d)
					res = append(res, nnf)
				}
			default:
				panic("unexpected or in or")
			}
		}
		res = append(res, lits)
		return res
	default:
		panic("invalid NNF formula")
	}
}
<commit_msg>simplified code<commit_after>package bf

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"github.com/crillab/gophersat/solver"
)

// A Formula is any kind of boolean formula, not necessarily in CNF form.
type Formula interface {
	nnf() Formula
	String() string
}

// Solve solves the given formula.
// f is first converted as a CNF formula. It is then given to gophersat.
// The function returns a boolean indicating if the formula was satisfiable.
// If it was, a model is then provided, associating each variable name with its binding.
func Solve(f Formula) (sat bool, model map[string]bool, err error) {
	return asCnf(f).solve()
}

// Dimacs writes the DIMACS CNF version of the formula on w.
// It is useful so as to feed it to any SAT solver.
func Dimacs(f Formula, w io.Writer) error {
	cnf := asCnf(f)
	nbVars := len(cnf.vars.all)
	nbClauses := len(cnf.clauses)
	prefix := fmt.Sprintf("p cnf %d %d\n", nbVars, nbClauses)
	if _, err := io.WriteString(w, prefix); err != nil {
		return fmt.Errorf("could not write DIMACS output: %v", err)
	}
	for _, clause := range cnf.clauses {
		strClause := make([]string, len(clause))
		for i, lit := range clause {
			strClause[i] = strconv.Itoa(lit)
		}
		line := fmt.Sprintf("%s 0\n", strings.Join(strClause, " "))
		if _, err := io.WriteString(w, line); err != nil {
			return fmt.Errorf("could not write DIMACS output: %v", err)
		}
	}
	return nil
}

// Var generates a named boolean variable in a formula.
func Var(name string) Formula {
	return variable(name)
}

type variable string

func (v variable) nnf() Formula {
	return lit{signed: false, v: v}
}

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

type lit struct {
	signed bool
	v      variable
}

func (l lit) nnf() Formula {
	return l
}

func (l lit) String() string {
	if l.signed {
		return "not(" + string(l.v) + ")"
	}
	return string(l.v)
}

// Not represents a negation. It negates the given subformula.
func Not(f Formula) Formula {
	return not{f}
}

type not [1]Formula

func (n not) nnf() Formula {
	switch f := n[0].(type) {
	case variable:
		l := f.nnf().(lit)
		l.signed = true
		return l
	case lit:
		f.signed = !f.signed
		return f
	case not:
		return f[0].nnf()
	case and:
		subs := make([]Formula, len(f))
		for i, sub := range f {
			subs[i] = not{sub}.nnf()
		}
		return or(subs).nnf()
	case or:
		subs := make([]Formula, len(f))
		for i, sub := range f {
			subs[i] = not{sub}.nnf()
		}
		return and(subs).nnf()
	default:
		panic("invalid formula type")
	}
}

func (n not) String() string {
	return "not(" + n[0].String() + ")"
}

// And generates a conjunction of subformulas.
func And(subs ...Formula) Formula {
	return and(subs)
}

type and []Formula

func (a and) nnf() Formula {
	var res and
	for _, s := range a {
		nnf := s.nnf()
		if a2, ok := nnf.(and); ok { // // Simplify: "and"s in the "and" get to the higher level
			for _, s2 := range a2 {
				res = append(res, s2)
			}
		} else {
			res = append(res, nnf)
		}
	}
	if len(res) == 1 {
		return res[0]
	}
	return res
}

func (a and) String() string {
	strs := make([]string, len(a))
	for i, f := range a {
		strs[i] = f.String()
	}
	return "and(" + strings.Join(strs, ", ") + ")"
}

// Or generates a disjunction of subformulas.
func Or(subs ...Formula) Formula {
	return or(subs)
}

type or []Formula

func (o or) nnf() Formula {
	var res or
	for _, s := range o {
		nnf := s.nnf()
		if o2, ok := nnf.(or); ok { // Simplify: "or"s in the "or" get to the higher level
			for _, s2 := range o2 {
				res = append(res, s2)
			}
		} else {
			res = append(res, nnf)
		}
	}
	if len(res) == 1 {
		return res[0]
	}
	return res
}

func (o or) String() string {
	strs := make([]string, len(o))
	for i, f := range o {
		strs[i] = f.String()
	}
	return "or(" + strings.Join(strs, ", ") + ")"
}

// Implies indicates a subformula implies another one.
func Implies(f1, f2 Formula) Formula {
	return or{not{f1}, f2}
}

// Eq indicates a subformula is equivalent to another one.
func Eq(f1, f2 Formula) Formula {
	return and{or{not{f1}, f2}, or{f1, not{f2}}}
}

// Xor indicates exactly one of the two given subformulas is true.
func Xor(f1, f2 Formula) Formula {
	return and{or{not{f1}, not{f2}}, or{f1, f2}}
}

// vars associate variable names with numeric indices.
type vars struct {
	all map[variable]int // all vars, including those created when converting the formula
	pb  map[variable]int // Only the vars that appeared orinigally in the problem
}

// litValue returns the int value associated with the given problem var.
// If the var was not referenced yet, it is created first.
func (vars *vars) litValue(l lit) int {
	val, ok := vars.all[l.v]
	if !ok {
		val = len(vars.all) + 1
		vars.all[l.v] = val
		vars.pb[l.v] = val
	}
	if l.signed {
		return -val
	}
	return val
}

// Dummy creates a dummy variable and returns its associated index.
func (vars *vars) dummy() int {
	val := len(vars.all) + 1
	vars.all[variable(fmt.Sprintf("dummy-%d", val))] = val
	return val
}

// A CNF is the representation of a boolean formula as a conjunction of disjunction.
// It can be solved by a SAT solver.
type cnf struct {
	vars    vars
	clauses [][]int
}

// solve solves the given formula.
// cnf is given to gophersat.
// The function returns a boolean indicating if the formula was satisfiable.
// If it was, a model is then provided, associating each variable name with its binding.
func (cnf *cnf) solve() (sat bool, vars map[string]bool, err error) {
	pb, err := solver.ParseSlice(cnf.clauses)
	if err != nil {
		return false, nil, fmt.Errorf("could not create problem from formula: %v", err)
	}
	s := solver.New(pb)
	if s.Solve() != solver.Sat {
		return false, nil, nil
	}
	m, err := s.Model()
	if err != nil {
		return false, nil, fmt.Errorf("could not retrieve model: %v", err)
	}
	vars = make(map[string]bool)
	for name, idx := range cnf.vars.pb {
		vars[string(name)] = m[idx-1]
	}
	return true, vars, nil
}

// asCnf returns a CNF representation of the given formula.
func asCnf(f Formula) *cnf {
	vars := vars{all: make(map[variable]int), pb: make(map[variable]int)}
	clauses := cnfRec(f.nnf(), &vars)
	return &cnf{vars: vars, clauses: clauses}
}

// transforms the f NNF formula into a CNF formula.
// nbDummies is the current number of dummy variables created.
// Note: code should be improved, there are a few useless allocs/deallocs
// here and there.
func cnfRec(f Formula, vars *vars) [][]int {
	switch f := f.(type) {
	case lit:
		return [][]int{{vars.litValue(f)}}
	case and:
		var res [][]int
		for _, sub := range f {
			res = append(res, cnfRec(sub, vars)...)
		}
		return res
	case or:
		var res [][]int
		var lits []int
		for _, sub := range f {
			switch sub := sub.(type) {
			case lit:
				lits = append(lits, vars.litValue(sub))
			case and:
				d := vars.dummy()
				lits = append(lits, d)
				for _, sub2 := range sub {
					nnf := cnfRec(sub2, vars)[0]
					nnf = append(nnf, -d)
					res = append(res, nnf)
				}
			default:
				panic("unexpected or in or")
			}
		}
		res = append(res, lits)
		return res
	default:
		panic("invalid NNF formula")
	}
}
<|endoftext|>


<commit_before>package storage

import (
	"fmt"
	"path"
	"strconv"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/storage/backend"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/storage/super_block"
	"github.com/chrislusf/seaweedfs/weed/storage/types"

	"github.com/chrislusf/seaweedfs/weed/glog"
)

type Volume struct {
	Id                 needle.VolumeId
	dir                string
	dirIdx             string
	Collection         string
	DataBackend        backend.BackendStorageFile
	nm                 NeedleMapper
	needleMapKind      NeedleMapKind
	noWriteOrDelete    bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	noWriteCanDelete   bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	noWriteLock        sync.RWMutex
	hasRemoteFile      bool // if the volume has a remote file
	MemoryMapMaxSizeMb uint32

	super_block.SuperBlock

	dataFileAccessLock    sync.RWMutex
	asyncRequestsChan     chan *needle.AsyncRequest
	lastModifiedTsSeconds uint64 // unix time in seconds
	lastAppendAtNs        uint64 // unix time in nanoseconds

	lastCompactIndexOffset uint64
	lastCompactRevision    uint16

	isCompacting bool

	volumeInfo *volume_server_pb.VolumeInfo
	location   *DiskLocation

	lastIoError error
}

func NewVolume(dirname string, dirIdx string, collection string, id needle.VolumeId, needleMapKind NeedleMapKind, replicaPlacement *super_block.ReplicaPlacement, ttl *needle.TTL, preallocate int64, memoryMapMaxSizeMb uint32) (v *Volume, e error) {
	// if replicaPlacement is nil, the superblock will be loaded from disk
	v = &Volume{dir: dirname, dirIdx: dirIdx, Collection: collection, Id: id, MemoryMapMaxSizeMb: memoryMapMaxSizeMb,
		asyncRequestsChan: make(chan *needle.AsyncRequest, 128)}
	v.SuperBlock = super_block.SuperBlock{ReplicaPlacement: replicaPlacement, Ttl: ttl}
	v.needleMapKind = needleMapKind
	e = v.load(true, true, needleMapKind, preallocate)
	v.startWorker()
	return
}

func (v *Volume) String() string {
	v.noWriteLock.RLock()
	defer v.noWriteLock.RUnlock()
	return fmt.Sprintf("Id:%v dir:%s dirIdx:%s Collection:%s dataFile:%v nm:%v noWrite:%v canDelete:%v", v.Id, v.dir, v.dirIdx, v.Collection, v.DataBackend, v.nm, v.noWriteOrDelete || v.noWriteCanDelete, v.noWriteCanDelete)
}

func VolumeFileName(dir string, collection string, id int) (fileName string) {
	idString := strconv.Itoa(id)
	if collection == "" {
		fileName = path.Join(dir, idString)
	} else {
		fileName = path.Join(dir, collection+"_"+idString)
	}
	return
}

func (v *Volume) DataFileName() (fileName string) {
	return VolumeFileName(v.dir, v.Collection, int(v.Id))
}

func (v *Volume) IndexFileName() (fileName string) {
	return VolumeFileName(v.dirIdx, v.Collection, int(v.Id))
}

func (v *Volume) FileName(ext string) (fileName string) {
	switch ext {
	case ".idx", ".cpx", ".ldb":
		return VolumeFileName(v.dirIdx, v.Collection, int(v.Id)) + ext
	}
	// .dat, .cpd, .vif
	return VolumeFileName(v.dir, v.Collection, int(v.Id)) + ext
}

func (v *Volume) Version() needle.Version {
	if v.volumeInfo.Version != 0 {
		v.SuperBlock.Version = needle.Version(v.volumeInfo.Version)
	}
	return v.SuperBlock.Version
}

func (v *Volume) FileStat() (datSize uint64, idxSize uint64, modTime time.Time) {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()

	if v.DataBackend == nil {
		return
	}

	datFileSize, modTime, e := v.DataBackend.GetStat()
	if e == nil {
		return uint64(datFileSize), v.nm.IndexFileSize(), modTime
	}
	glog.V(0).Infof("Failed to read file size %s %v", v.DataBackend.Name(), e)
	return // -1 causes integer overflow and the volume to become unwritable.
}

func (v *Volume) ContentSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.ContentSize()
}

func (v *Volume) DeletedSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.DeletedSize()
}

func (v *Volume) FileCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.FileCount())
}

func (v *Volume) DeletedCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.DeletedCount())
}

func (v *Volume) MaxFileKey() types.NeedleId {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.MaxFileKey()
}

func (v *Volume) IndexFileSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.IndexFileSize()
}

func (v *Volume) DiskType() types.DiskType {
	return v.location.DiskType
}

func (v *Volume) SetStopping() {
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.nm != nil {
		if err := v.nm.Sync(); err != nil {
			glog.Warningf("Volume SetStopping fail to sync volume idx %d", v.Id)
		}
	}
	if v.DataBackend != nil {
		if err := v.DataBackend.Sync(); err != nil {
			glog.Warningf("Volume SetStopping fail to sync volume %d", v.Id)
		}
	}
}

// Close cleanly shuts down this volume
func (v *Volume) Close() {
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.nm != nil {
		if err := v.nm.Sync(); err != nil {
			glog.Warningf("Volume Close fail to sync volume idx %d", v.Id)
		}
		v.nm.Close()
		v.nm = nil
	}
	if v.DataBackend != nil {
		if err := v.DataBackend.Sync(); err != nil {
			glog.Warningf("Volume Close fail to sync volume %d", v.Id)
		}
		_ = v.DataBackend.Close()
		v.DataBackend = nil
		stats.VolumeServerVolumeCounter.WithLabelValues(v.Collection, "volume").Dec()
	}
}

func (v *Volume) NeedToReplicate() bool {
	return v.ReplicaPlacement.GetCopyCount() > 1
}

// volume is expired if modified time + volume ttl < now
// except when volume is empty
// or when the volume does not have a ttl
// or when volumeSizeLimit is 0 when server just starts
func (v *Volume) expired(contentSize uint64, volumeSizeLimit uint64) bool {
	if volumeSizeLimit == 0 {
		// skip if we don't know size limit
		return false
	}
	if contentSize <= super_block.SuperBlockSize {
		return false
	}
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	glog.V(2).Infof("volume %d now:%v lastModified:%v", v.Id, time.Now().Unix(), v.lastModifiedTsSeconds)
	livedMinutes := (time.Now().Unix() - int64(v.lastModifiedTsSeconds)) / 60
	glog.V(2).Infof("volume %d ttl:%v lived:%v", v.Id, v.Ttl, livedMinutes)
	if int64(v.Ttl.Minutes()) < livedMinutes {
		return true
	}
	return false
}

// wait either maxDelayMinutes or 10% of ttl minutes
func (v *Volume) expiredLongEnough(maxDelayMinutes uint32) bool {
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	removalDelay := v.Ttl.Minutes() / 10
	if removalDelay > maxDelayMinutes {
		removalDelay = maxDelayMinutes
	}

	if uint64(v.Ttl.Minutes()+removalDelay)*60+v.lastModifiedTsSeconds < uint64(time.Now().Unix()) {
		return true
	}
	return false
}

func (v *Volume) collectStatus() (maxFileKey types.NeedleId, datFileSize int64, modTime time.Time, fileCount, deletedCount, deletedSize uint64, ok bool) {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	glog.V(3).Infof("collectStatus volume %d", v.Id)

	if v.nm == nil || v.DataBackend == nil {
		return
	}

	ok = true

	maxFileKey = v.nm.MaxFileKey()
	datFileSize, modTime, _ = v.DataBackend.GetStat()
	fileCount = uint64(v.nm.FileCount())
	deletedCount = uint64(v.nm.DeletedCount())
	deletedSize = v.nm.DeletedSize()
	fileCount = uint64(v.nm.FileCount())

	return
}

func (v *Volume) ToVolumeInformationMessage() (types.NeedleId, *master_pb.VolumeInformationMessage) {

	maxFileKey, volumeSize, modTime, fileCount, deletedCount, deletedSize, ok := v.collectStatus()

	if !ok {
		return 0, nil
	}

	volumeInfo := &master_pb.VolumeInformationMessage{
		Id:               uint32(v.Id),
		Size:             uint64(volumeSize),
		Collection:       v.Collection,
		FileCount:        fileCount,
		DeleteCount:      deletedCount,
		DeletedByteCount: deletedSize,
		ReadOnly:         v.IsReadOnly(),
		ReplicaPlacement: uint32(v.ReplicaPlacement.Byte()),
		Version:          uint32(v.Version()),
		Ttl:              v.Ttl.ToUint32(),
		CompactRevision:  uint32(v.SuperBlock.CompactionRevision),
		ModifiedAtSecond: modTime.Unix(),
		DiskType:         string(v.location.DiskType),
	}

	volumeInfo.RemoteStorageName, volumeInfo.RemoteStorageKey = v.RemoteStorageNameKey()

	return maxFileKey, volumeInfo
}

func (v *Volume) RemoteStorageNameKey() (storageName, storageKey string) {
	if v.volumeInfo == nil {
		return
	}
	if len(v.volumeInfo.GetFiles()) == 0 {
		return
	}
	return v.volumeInfo.GetFiles()[0].BackendName(), v.volumeInfo.GetFiles()[0].GetKey()
}

func (v *Volume) IsReadOnly() bool {
	v.noWriteLock.RLock()
	defer v.noWriteLock.RUnlock()
	return v.noWriteOrDelete || v.noWriteCanDelete || v.location.isDiskSpaceLow
}
<commit_msg>waite volume being closed during compression idx<commit_after>package storage

import (
	"fmt"
	"path"
	"strconv"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/storage/backend"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/storage/super_block"
	"github.com/chrislusf/seaweedfs/weed/storage/types"

	"github.com/chrislusf/seaweedfs/weed/glog"
)

type Volume struct {
	Id                 needle.VolumeId
	dir                string
	dirIdx             string
	Collection         string
	DataBackend        backend.BackendStorageFile
	nm                 NeedleMapper
	needleMapKind      NeedleMapKind
	noWriteOrDelete    bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	noWriteCanDelete   bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	noWriteLock        sync.RWMutex
	hasRemoteFile      bool // if the volume has a remote file
	MemoryMapMaxSizeMb uint32

	super_block.SuperBlock

	dataFileAccessLock    sync.RWMutex
	asyncRequestsChan     chan *needle.AsyncRequest
	lastModifiedTsSeconds uint64 // unix time in seconds
	lastAppendAtNs        uint64 // unix time in nanoseconds

	lastCompactIndexOffset uint64
	lastCompactRevision    uint16

	isCompacting bool

	volumeInfo *volume_server_pb.VolumeInfo
	location   *DiskLocation

	lastIoError error
}

func NewVolume(dirname string, dirIdx string, collection string, id needle.VolumeId, needleMapKind NeedleMapKind, replicaPlacement *super_block.ReplicaPlacement, ttl *needle.TTL, preallocate int64, memoryMapMaxSizeMb uint32) (v *Volume, e error) {
	// if replicaPlacement is nil, the superblock will be loaded from disk
	v = &Volume{dir: dirname, dirIdx: dirIdx, Collection: collection, Id: id, MemoryMapMaxSizeMb: memoryMapMaxSizeMb,
		asyncRequestsChan: make(chan *needle.AsyncRequest, 128)}
	v.SuperBlock = super_block.SuperBlock{ReplicaPlacement: replicaPlacement, Ttl: ttl}
	v.needleMapKind = needleMapKind
	e = v.load(true, true, needleMapKind, preallocate)
	v.startWorker()
	return
}

func (v *Volume) String() string {
	v.noWriteLock.RLock()
	defer v.noWriteLock.RUnlock()
	return fmt.Sprintf("Id:%v dir:%s dirIdx:%s Collection:%s dataFile:%v nm:%v noWrite:%v canDelete:%v", v.Id, v.dir, v.dirIdx, v.Collection, v.DataBackend, v.nm, v.noWriteOrDelete || v.noWriteCanDelete, v.noWriteCanDelete)
}

func VolumeFileName(dir string, collection string, id int) (fileName string) {
	idString := strconv.Itoa(id)
	if collection == "" {
		fileName = path.Join(dir, idString)
	} else {
		fileName = path.Join(dir, collection+"_"+idString)
	}
	return
}

func (v *Volume) DataFileName() (fileName string) {
	return VolumeFileName(v.dir, v.Collection, int(v.Id))
}

func (v *Volume) IndexFileName() (fileName string) {
	return VolumeFileName(v.dirIdx, v.Collection, int(v.Id))
}

func (v *Volume) FileName(ext string) (fileName string) {
	switch ext {
	case ".idx", ".cpx", ".ldb":
		return VolumeFileName(v.dirIdx, v.Collection, int(v.Id)) + ext
	}
	// .dat, .cpd, .vif
	return VolumeFileName(v.dir, v.Collection, int(v.Id)) + ext
}

func (v *Volume) Version() needle.Version {
	if v.volumeInfo.Version != 0 {
		v.SuperBlock.Version = needle.Version(v.volumeInfo.Version)
	}
	return v.SuperBlock.Version
}

func (v *Volume) FileStat() (datSize uint64, idxSize uint64, modTime time.Time) {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()

	if v.DataBackend == nil {
		return
	}

	datFileSize, modTime, e := v.DataBackend.GetStat()
	if e == nil {
		return uint64(datFileSize), v.nm.IndexFileSize(), modTime
	}
	glog.V(0).Infof("Failed to read file size %s %v", v.DataBackend.Name(), e)
	return // -1 causes integer overflow and the volume to become unwritable.
}

func (v *Volume) ContentSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.ContentSize()
}

func (v *Volume) DeletedSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.DeletedSize()
}

func (v *Volume) FileCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.FileCount())
}

func (v *Volume) DeletedCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.DeletedCount())
}

func (v *Volume) MaxFileKey() types.NeedleId {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.MaxFileKey()
}

func (v *Volume) IndexFileSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.IndexFileSize()
}

func (v *Volume) DiskType() types.DiskType {
	return v.location.DiskType
}

func (v *Volume) SetStopping() {
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.nm != nil {
		if err := v.nm.Sync(); err != nil {
			glog.Warningf("Volume SetStopping fail to sync volume idx %d", v.Id)
		}
	}
	if v.DataBackend != nil {
		if err := v.DataBackend.Sync(); err != nil {
			glog.Warningf("Volume SetStopping fail to sync volume %d", v.Id)
		}
	}
}

// Close cleanly shuts down this volume
func (v *Volume) Close() {
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.nm != nil {
		for v.isCompacting {
			glog.Warningf("Volume being closed during compression idx %d", v.Id)
			time.Sleep(time.Second)
		}
		if err := v.nm.Sync(); err != nil {
			glog.Warningf("Volume Close fail to sync volume idx %d", v.Id)
		}
		v.nm.Close()
		v.nm = nil
	}
	if v.DataBackend != nil {
		if err := v.DataBackend.Sync(); err != nil {
			glog.Warningf("Volume Close fail to sync volume %d", v.Id)
		}
		_ = v.DataBackend.Close()
		v.DataBackend = nil
		stats.VolumeServerVolumeCounter.WithLabelValues(v.Collection, "volume").Dec()
	}
}

func (v *Volume) NeedToReplicate() bool {
	return v.ReplicaPlacement.GetCopyCount() > 1
}

// volume is expired if modified time + volume ttl < now
// except when volume is empty
// or when the volume does not have a ttl
// or when volumeSizeLimit is 0 when server just starts
func (v *Volume) expired(contentSize uint64, volumeSizeLimit uint64) bool {
	if volumeSizeLimit == 0 {
		// skip if we don't know size limit
		return false
	}
	if contentSize <= super_block.SuperBlockSize {
		return false
	}
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	glog.V(2).Infof("volume %d now:%v lastModified:%v", v.Id, time.Now().Unix(), v.lastModifiedTsSeconds)
	livedMinutes := (time.Now().Unix() - int64(v.lastModifiedTsSeconds)) / 60
	glog.V(2).Infof("volume %d ttl:%v lived:%v", v.Id, v.Ttl, livedMinutes)
	if int64(v.Ttl.Minutes()) < livedMinutes {
		return true
	}
	return false
}

// wait either maxDelayMinutes or 10% of ttl minutes
func (v *Volume) expiredLongEnough(maxDelayMinutes uint32) bool {
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	removalDelay := v.Ttl.Minutes() / 10
	if removalDelay > maxDelayMinutes {
		removalDelay = maxDelayMinutes
	}

	if uint64(v.Ttl.Minutes()+removalDelay)*60+v.lastModifiedTsSeconds < uint64(time.Now().Unix()) {
		return true
	}
	return false
}

func (v *Volume) collectStatus() (maxFileKey types.NeedleId, datFileSize int64, modTime time.Time, fileCount, deletedCount, deletedSize uint64, ok bool) {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	glog.V(3).Infof("collectStatus volume %d", v.Id)

	if v.nm == nil || v.DataBackend == nil {
		return
	}

	ok = true

	maxFileKey = v.nm.MaxFileKey()
	datFileSize, modTime, _ = v.DataBackend.GetStat()
	fileCount = uint64(v.nm.FileCount())
	deletedCount = uint64(v.nm.DeletedCount())
	deletedSize = v.nm.DeletedSize()
	fileCount = uint64(v.nm.FileCount())

	return
}

func (v *Volume) ToVolumeInformationMessage() (types.NeedleId, *master_pb.VolumeInformationMessage) {

	maxFileKey, volumeSize, modTime, fileCount, deletedCount, deletedSize, ok := v.collectStatus()

	if !ok {
		return 0, nil
	}

	volumeInfo := &master_pb.VolumeInformationMessage{
		Id:               uint32(v.Id),
		Size:             uint64(volumeSize),
		Collection:       v.Collection,
		FileCount:        fileCount,
		DeleteCount:      deletedCount,
		DeletedByteCount: deletedSize,
		ReadOnly:         v.IsReadOnly(),
		ReplicaPlacement: uint32(v.ReplicaPlacement.Byte()),
		Version:          uint32(v.Version()),
		Ttl:              v.Ttl.ToUint32(),
		CompactRevision:  uint32(v.SuperBlock.CompactionRevision),
		ModifiedAtSecond: modTime.Unix(),
		DiskType:         string(v.location.DiskType),
	}

	volumeInfo.RemoteStorageName, volumeInfo.RemoteStorageKey = v.RemoteStorageNameKey()

	return maxFileKey, volumeInfo
}

func (v *Volume) RemoteStorageNameKey() (storageName, storageKey string) {
	if v.volumeInfo == nil {
		return
	}
	if len(v.volumeInfo.GetFiles()) == 0 {
		return
	}
	return v.volumeInfo.GetFiles()[0].BackendName(), v.volumeInfo.GetFiles()[0].GetKey()
}

func (v *Volume) IsReadOnly() bool {
	v.noWriteLock.RLock()
	defer v.noWriteLock.RUnlock()
	return v.noWriteOrDelete || v.noWriteCanDelete || v.location.isDiskSpaceLow
}
<|endoftext|>


<commit_before>package main

import (
_	"compress/gzip"
	"encoding/xml"
	"fmt"
	"os"
	"time"
)

// TODO:
// - format time as Zulu time
// Support for more than one trkseg? Mebbe. Mebbe not.

type GPX struct {
	XMLName   xml.Name  `xml:"gpx"`
	XMLNS     string    `xml:"xmlns,attr"`
	XMLNSxsi  string    `xml:"xmlns:xsi,attr"`
	XMLSchema string    `xml:"xsi:schemaLocation,attr"`
	Creator   string    `xml:"creator,attr"`
	Version   string    `xml:"version,attr"`
	Time      time.Time `xml:"metadata>time"`

	Name	string	`xml:"trk>name"`
	Points []Trkpt `xml:"trk>trkseg>trkpt"`
}

type Trkpt struct {
	Lat     float32   `xml:"lat,attr"`
	Lon     float32   `xml:"lon,attr"`
	Ele     float32   `xml:"ele"`
	Time    time.Time `xml:"time"`
	HR      int64     `xml:"extensions>heartrate,omitempty"`
	Cadence int64     `xml:"extensions>cadence,omitempty"`
}

var point = Trkpt{
	Lat:     60.1732920,
	Lon:     24.9311040,
	Ele:     14.5,
	Time:    time.Now(),
	HR:      90,
	Cadence: 0,
}

func NewGPX(name string, t time.Time, pts []Trkpt) GPX {
	return GPX{
		XMLNS: "http://www.topografix.com/GPX/1/1",
		XMLNSxsi: "http://www.w3.org/2001/XMLSchema-instance",
		XMLSchema: "http://www.topografix.com/GPX/1/1",

		Creator: "Holux GPSSport 260 Pro with barometer",
		Version: "1.1",
		Time: t,
		Name: name,
		Points: pts,
	}
}

func main() {
	doc := NewGPX("Joyride", time.Now(), []Trkpt{point})

	//dst := gzip.NewWriter(os.Stdout)
	dst := os.Stdout
	defer dst.Close()
	dst.Write([]byte(xml.Header))
	enc := xml.NewEncoder(dst)
	enc.Indent("", "    ")

	err := enc.Encode(doc)

	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
}
<commit_msg>Run go fmt on previous commit<commit_after>package main

import (
	_ "compress/gzip"
	"encoding/xml"
	"fmt"
	"os"
	"time"
)

// TODO:
// - format time as Zulu time
// Support for more than one trkseg? Mebbe. Mebbe not.

type GPX struct {
	XMLName   xml.Name  `xml:"gpx"`
	XMLNS     string    `xml:"xmlns,attr"`
	XMLNSxsi  string    `xml:"xmlns:xsi,attr"`
	XMLSchema string    `xml:"xsi:schemaLocation,attr"`
	Creator   string    `xml:"creator,attr"`
	Version   string    `xml:"version,attr"`
	Time      time.Time `xml:"metadata>time"`

	Name   string  `xml:"trk>name"`
	Points []Trkpt `xml:"trk>trkseg>trkpt"`
}

type Trkpt struct {
	Lat     float32   `xml:"lat,attr"`
	Lon     float32   `xml:"lon,attr"`
	Ele     float32   `xml:"ele"`
	Time    time.Time `xml:"time"`
	HR      int64     `xml:"extensions>heartrate,omitempty"`
	Cadence int64     `xml:"extensions>cadence,omitempty"`
}

var point = Trkpt{
	Lat:     60.1732920,
	Lon:     24.9311040,
	Ele:     14.5,
	Time:    time.Now(),
	HR:      90,
	Cadence: 0,
}

func NewGPX(name string, t time.Time, pts []Trkpt) GPX {
	return GPX{
		XMLNS:     "http://www.topografix.com/GPX/1/1",
		XMLNSxsi:  "http://www.w3.org/2001/XMLSchema-instance",
		XMLSchema: "http://www.topografix.com/GPX/1/1",

		Creator: "Holux GPSSport 260 Pro with barometer",
		Version: "1.1",
		Time:    t,
		Name:    name,
		Points:  pts,
	}
}

func main() {
	doc := NewGPX("Joyride", time.Now(), []Trkpt{point})

	//dst := gzip.NewWriter(os.Stdout)
	dst := os.Stdout
	defer dst.Close()
	dst.Write([]byte(xml.Header))
	enc := xml.NewEncoder(dst)
	enc.Indent("", "    ")

	err := enc.Encode(doc)

	if err != nil {
		fmt.Printf("error: %v\n", err)
	}
}
<|endoftext|>


<commit_before>package dsc

import (
	"fmt"
	"reflect"
	"sync"

	"github.com/viant/toolbox"
	"strings"
)

type commonTableDescriptorRegistry struct {
	sync.RWMutex
	manager  Manager
	registry map[string]*TableDescriptor
}

func (r *commonTableDescriptorRegistry) Has(table string) bool {
	r.RLock()
	defer r.RUnlock()
	_, found := r.registry[table]
	return found
}

func (r *commonTableDescriptorRegistry) getDescriptor(table string) *TableDescriptor {
	dbConfig := r.manager.Config()
	dialect := GetDatastoreDialect(dbConfig.DriverName)
	datastore, _ := dialect.GetCurrentDatastore(r.manager)
	key := dialect.GetKeyName(r.manager, datastore, table)
	isAutoincrement := dialect.IsAutoincrement(r.manager, datastore, table)
	descriptor := &TableDescriptor{
		Table:         table,
		Autoincrement: isAutoincrement,
		PkColumns:     []string{},
	}
	if key != "" {
		descriptor.PkColumns = strings.Split(key, ",")
	}
	return descriptor
}

func (r *commonTableDescriptorRegistry) Get(table string) *TableDescriptor {
	r.RLock()
	if descriptor, found := r.registry[table]; found {
		r.RUnlock()
		return descriptor
	}
	r.RUnlock()
	var result = r.getDescriptor(table)
	r.Register(result)
	return result
}

func (r *commonTableDescriptorRegistry) Register(descriptor *TableDescriptor) error {
	if descriptor.Table == "" {
		return fmt.Errorf("table name was not set %v", descriptor)
	}
	for i, column := range descriptor.Columns {
		if column == "" {
			return fmt.Errorf("columns[%d] was empty %v %v", i, descriptor.Table, descriptor.Columns)
		}
	}
	for i, column := range descriptor.PkColumns {
		if column == "" {
			return fmt.Errorf("pkColumns[%d] was empty %v %v", i, descriptor.Table, descriptor.Columns)
		}
	}
	r.RLock()
	defer r.RUnlock()
	r.registry[descriptor.Table] = descriptor
	return nil
}

func (r *commonTableDescriptorRegistry) Tables() []string {
	r.RLock()
	defer r.RUnlock()
	var result = make([]string, 0)
	for key := range r.registry {
		result = append(result, key)
	}
	return result
}

func newTableDescriptorRegistry() *commonTableDescriptorRegistry {
	return &commonTableDescriptorRegistry{registry: make(map[string]*TableDescriptor)}
}

//newTableDescriptorRegistry returns a new newTableDescriptorRegistry
func NewTableDescriptorRegistry() TableDescriptorRegistry {
	return newTableDescriptorRegistry()
}

//HasSchema check if table desciptor has defined schema.
func (d *TableDescriptor) HasSchema() bool {
	return len(d.SchemaURL) > 0 || d.Schema != nil
}

//NewTableDescriptor creates a new table descriptor for passed in instance, it can use the following tags:"column", "dateLayout","dateFormat", "autoincrement", "primaryKey", "sequence", "transient"
func NewTableDescriptor(table string, instance interface{}) (*TableDescriptor, error) {
	targetType := toolbox.DiscoverTypeByKind(instance, reflect.Struct)
	var autoincrement bool
	var pkColumns = make([]string, 0)
	var columns = make([]string, 0)
	columnToFieldMap := toolbox.NewFieldSettingByKey(targetType, "column")

	for key := range columnToFieldMap {
		mapping, _ := columnToFieldMap[key]
		column, ok := mapping["column"]
		if !ok {
			column = mapping["fieldName"]
		}
		if _, ok := mapping["autoincrement"]; ok {
			pkColumns = append(pkColumns, column)
			autoincrement = true
			continue
		}
	}

	for key := range columnToFieldMap {
		mapping, _ := columnToFieldMap[key]
		column, ok := mapping["column"]
		if !ok {
			column = mapping["fieldName"]
		}

		columns = append(columns, column)
		if _, ok := mapping["primaryKey"]; ok {
			if !toolbox.HasSliceAnyElements(pkColumns, column) {
				pkColumns = append(pkColumns, column)
			}
			continue
		}
		if key == "id" {
			if !toolbox.HasSliceAnyElements(pkColumns, column) {
				pkColumns = append(pkColumns, column)
			}
			continue
		}
	}
	if len(pkColumns) == 0 {
		return nil, fmt.Errorf("No primary key defined on table: %v, type: %v, consider adding 'primaryKey' tag to primary key column", table, targetType)
	}
	return &TableDescriptor{
		Table:         table,
		Autoincrement: autoincrement,
		Columns:       columns,
		PkColumns:     pkColumns,
	}, nil
}
<commit_msg>patched race condition<commit_after>package dsc

import (
	"fmt"
	"reflect"
	"sync"

	"github.com/viant/toolbox"
	"strings"
)

type commonTableDescriptorRegistry struct {
	sync.RWMutex
	manager  Manager
	registry map[string]*TableDescriptor
}

func (r *commonTableDescriptorRegistry) Has(table string) bool {
	r.RLock()
	defer r.RUnlock()
	_, found := r.registry[table]
	return found
}

func (r *commonTableDescriptorRegistry) getDescriptor(table string) *TableDescriptor {
	dbConfig := r.manager.Config()
	dialect := GetDatastoreDialect(dbConfig.DriverName)
	datastore, _ := dialect.GetCurrentDatastore(r.manager)
	key := dialect.GetKeyName(r.manager, datastore, table)
	isAutoincrement := dialect.IsAutoincrement(r.manager, datastore, table)
	descriptor := &TableDescriptor{
		Table:         table,
		Autoincrement: isAutoincrement,
		PkColumns:     []string{},
	}
	if key != "" {
		descriptor.PkColumns = strings.Split(key, ",")
	}
	return descriptor
}

func (r *commonTableDescriptorRegistry) Get(table string) *TableDescriptor {
	r.RLock()
	if descriptor, found := r.registry[table]; found {
		r.RUnlock()
		return descriptor
	}
	r.RUnlock()
	var result = r.getDescriptor(table)
	r.Register(result)
	return result
}

func (r *commonTableDescriptorRegistry) Register(descriptor *TableDescriptor) error {
	if descriptor.Table == "" {
		return fmt.Errorf("table name was not set %v", descriptor)
	}
	for i, column := range descriptor.Columns {
		if column == "" {
			return fmt.Errorf("columns[%d] was empty %v %v", i, descriptor.Table, descriptor.Columns)
		}
	}
	for i, column := range descriptor.PkColumns {
		if column == "" {
			return fmt.Errorf("pkColumns[%d] was empty %v %v", i, descriptor.Table, descriptor.Columns)
		}
	}
	r.Lock()
	defer r.Unlock()
	r.registry[descriptor.Table] = descriptor
	return nil
}

func (r *commonTableDescriptorRegistry) Tables() []string {
	r.RLock()
	defer r.RUnlock()
	var result = make([]string, 0)
	for key := range r.registry {
		result = append(result, key)
	}
	return result
}

func newTableDescriptorRegistry() *commonTableDescriptorRegistry {
	return &commonTableDescriptorRegistry{registry: make(map[string]*TableDescriptor)}
}

//newTableDescriptorRegistry returns a new newTableDescriptorRegistry
func NewTableDescriptorRegistry() TableDescriptorRegistry {
	return newTableDescriptorRegistry()
}

//HasSchema check if table desciptor has defined schema.
func (d *TableDescriptor) HasSchema() bool {
	return len(d.SchemaURL) > 0 || d.Schema != nil
}

//NewTableDescriptor creates a new table descriptor for passed in instance, it can use the following tags:"column", "dateLayout","dateFormat", "autoincrement", "primaryKey", "sequence", "transient"
func NewTableDescriptor(table string, instance interface{}) (*TableDescriptor, error) {
	targetType := toolbox.DiscoverTypeByKind(instance, reflect.Struct)
	var autoincrement bool
	var pkColumns = make([]string, 0)
	var columns = make([]string, 0)
	columnToFieldMap := toolbox.NewFieldSettingByKey(targetType, "column")

	for key := range columnToFieldMap {
		mapping, _ := columnToFieldMap[key]
		column, ok := mapping["column"]
		if !ok {
			column = mapping["fieldName"]
		}
		if _, ok := mapping["autoincrement"]; ok {
			pkColumns = append(pkColumns, column)
			autoincrement = true
			continue
		}
	}

	for key := range columnToFieldMap {
		mapping, _ := columnToFieldMap[key]
		column, ok := mapping["column"]
		if !ok {
			column = mapping["fieldName"]
		}

		columns = append(columns, column)
		if _, ok := mapping["primaryKey"]; ok {
			if !toolbox.HasSliceAnyElements(pkColumns, column) {
				pkColumns = append(pkColumns, column)
			}
			continue
		}
		if key == "id" {
			if !toolbox.HasSliceAnyElements(pkColumns, column) {
				pkColumns = append(pkColumns, column)
			}
			continue
		}
	}
	if len(pkColumns) == 0 {
		return nil, fmt.Errorf("No primary key defined on table: %v, type: %v, consider adding 'primaryKey' tag to primary key column", table, targetType)
	}
	return &TableDescriptor{
		Table:         table,
		Autoincrement: autoincrement,
		Columns:       columns,
		PkColumns:     pkColumns,
	}, nil
}
<|endoftext|>