<commit_before>package config

type Config struct {
	Project struct {
		Name        string `yaml:"name"`
		Description string `yaml:"description"`
		State       string `yaml:"state,omitempty"`
		OneLiner    string `yaml:"oneLiner,omitempty"`
		Image       string `yaml:"image,omitempty"`
		Website     string `yaml:"website,omitempty"`
		Version     string `yaml:"version,omitempty"`
		MainLicense string `yaml:"mainLicense,omitempty"`
		DocsLicense string `yaml:"docsLicense,omitempty"`
	} `yaml:"project"`
	Vision struct {
		Type     string   `yaml:"type"`
		Items    []string `yaml:"items"`
		Concept  string   `yaml:"concept"`
		Overview string   `yaml:"overview"`
		Aim      string   `yaml:"aim"`
	} `yaml:"vision"`
	Repo struct {
		Type string `yaml:"type"`
		Link string `yaml:"link"`
	} `yaml:"repo"`
	Copyright struct {
		Owner string `yaml:"owner"`
		Year  string `yaml:"year"`
	} `yaml:"copyright"`
	Cla struct {
		CopyrightHolder string `yaml:"copyrightHolder"`
	} `yaml:"cla"`
	Maintainers []struct {
		Name string `yaml:"name"`
		Nick string `yaml:"nick,omitempty"`
	} `yaml:"maintainers,omitempty"`
	Emails struct {
		CommercialSupport string `yaml:"commercialSupport,omitempty"`
		Security          string `yaml:"security"`
		Coc               string `yaml:"coc"`
	} `yaml:"emails"`
	Badges []struct {
		Image string `yaml:"image,omitempty"`
		Link  string `yaml:"link,omitempty"`
		Alt   string `yaml:"alt,omitempty"`
	} `yaml:"badges"`
	SupportLinks struct {
		Documentation   string `yaml:"documentation,omitempty"`
		Examples        string `yaml:"examples,omitempty"`
		Troubleshooting string `yaml:"troubleshooting,omitempty"`
	} `yaml:"supportLinks,omitempty"`
	Readme struct {
		UsageExample string `yaml:"usageExample,omitempty"`
	} `yaml:"readme,omitempty"`
	Docs struct {
		Development string `yaml:"development,omitempty"`
	} `yaml:"docs,omitempty"`
	SupportPlatforms []struct {
		Service string `yaml:"service"`
		Link    string `yaml:"link"`
	} `yaml:"supportPlatforms,omitempty"`
	IssueTemplate struct {
		Questions []string `yaml:"questions"`
	} `yaml:"issueTemplate"`
	ContributionLinks struct {
		IssueTemplate string `yaml:"issueTemplate,omitempty"`
		StarterIssues string `yaml:"starterIssues,omitempty"`
	} `yaml:"contributionLinks"`
}
<commit_msg>Add JSON support to config struct<commit_after>package config

type Config struct {
	Project struct {
		Name        string `yaml:"name" json:"name"`
		Description string `yaml:"description" json:"description"`
		State       string `yaml:"state,omitempty" json:"state,omitempty"`
		OneLiner    string `yaml:"oneLiner,omitempty" json:"oneLiner,omitempty"`
		Image       string `yaml:"image,omitempty" json:"image,omitempty"`
		Website     string `yaml:"website,omitempty" json:"website,omitempty"`
		Version     string `yaml:"version,omitempty" json:"version,omitempty"`
		MainLicense string `yaml:"mainLicense,omitempty" json:"mainLicense,omitempty"`
		DocsLicense string `yaml:"docsLicense,omitempty" json:"docsLicense,omitempty"`
	} `yaml:"project" json:"project"`
	Vision struct {
		Type     string   `yaml:"type" json:"type"`
		Items    []string `yaml:"items" json:"items"`
		Concept  string   `yaml:"concept" json:"concept"`
		Overview string   `yaml:"overview" json:"overview"`
		Aim      string   `yaml:"aim" json:"aim"`
	} `yaml:"vision" json:"vision"`
	Repo struct {
		Type string `yaml:"type" json:"type"`
		Link string `yaml:"link" json:"link"`
	} `yaml:"repo" json:"repo"`
	Copyright struct {
		Owner string `yaml:"owner" json:"owner"`
		Year  string `yaml:"year" json:"year"`
	} `yaml:"copyright" json:"copyright"`
	Cla struct {
		CopyrightHolder string `yaml:"copyrightHolder" json:"copyrightHolder"`
	} `yaml:"cla" json:"cla"`
	Maintainers []struct {
		Name string `yaml:"name" json:"name"`
		Nick string `yaml:"nick,omitempty" json:"nick,omitempty"`
	} `yaml:"maintainers,omitempty" json:"maintainers,omitempty"`
	Emails struct {
		CommercialSupport string `yaml:"commercialSupport,omitempty" json:"commercialSupport,omitempty"`
		Security          string `yaml:"security" json:"security"`
		Coc               string `yaml:"coc" json:"coc"`
	} `yaml:"emails" json:"emails"`
	Badges []struct {
		Image string `yaml:"image,omitempty" json:"image,omitempty"`
		Link  string `yaml:"link,omitempty" json:"link,omitempty"`
		Alt   string `yaml:"alt,omitempty" json:"alt,omitempty"`
	} `yaml:"badges" json:"badges"`
	SupportLinks struct {
		Documentation   string `yaml:"documentation,omitempty" json:"documentation,omitempty"`
		Examples        string `yaml:"examples,omitempty" json:"examples,omitempty"`
		Troubleshooting string `yaml:"troubleshooting,omitempty" json:"troubleshooting,omitempty"`
	} `yaml:"supportLinks,omitempty" json:"supportLinks,omitempty"`
	Readme struct {
		UsageExample string `yaml:"usageExample,omitempty" json:"usageExample,omitempty"`
	} `yaml:"readme,omitempty" json:"readme,omitempty"`
	Docs struct {
		Development string `yaml:"development,omitempty" json:"development,omitempty"`
	} `yaml:"docs,omitempty" json:"docs,omitempty"`
	SupportPlatforms []struct {
		Service string `yaml:"service" json:"service"`
		Link    string `yaml:"link" json:"link"`
	} `yaml:"supportPlatforms,omitempty" json:"supportPlatforms,omitempty"`
	IssueTemplate struct {
		Questions []string `yaml:"questions" json:"questions"`
	} `yaml:"issueTemplate" json:"issueTemplate"`
	ContributionLinks struct {
		IssueTemplate string `yaml:"issueTemplate,omitempty" json:"issueTemplate,omitempty"`
		StarterIssues string `yaml:"starterIssues,omitempty" json:"starterIssues,omitempty"`
	} `yaml:"contributionLinks" json:"contributionLinks"`
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/kopia/kopia/storage/logging"

	"github.com/bgentry/speakeasy"
	"github.com/kopia/kopia/repo"
	"github.com/kopia/kopia/storage"
	"github.com/kopia/kopia/vault"
)

var (
	traceStorage = app.Flag("trace-storage", "Enables tracing of storage operations.").Hidden().Bool()

	vaultConfigPath = app.Flag("vaultconfig", "Specify the vault config file to use.").PlaceHolder("PATH").Envar("KOPIA_VAULTCONFIG").String()
	vaultPath       = app.Flag("vault", "Specify the vault to use.").PlaceHolder("PATH").Envar("KOPIA_VAULT").Short('v').String()
	password        = app.Flag("password", "Vault password.").Envar("KOPIA_PASSWORD").Short('p').String()
	passwordFile    = app.Flag("passwordfile", "Read vault password from a file.").PlaceHolder("FILENAME").Envar("KOPIA_PASSWORD_FILE").ExistingFile()
	key             = app.Flag("key", "Specify vault master key (hexadecimal).").Envar("KOPIA_KEY").Short('k').String()
	keyFile         = app.Flag("keyfile", "Read vault master key from file.").PlaceHolder("FILENAME").Envar("KOPIA_KEY_FILE").ExistingFile()
)

func failOnError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
		os.Exit(1)
	}
}

func mustOpenVault() *vault.Vault {
	s, err := openVault()
	failOnError(err)
	return s
}

func mustOpenRepository(extraOptions ...repo.RepositoryOption) repo.Repository {
	_, r := mustOpenVaultAndRepository(extraOptions...)
	return r
}

func mustOpenVaultAndRepository(extraOptions ...repo.RepositoryOption) (*vault.Vault, repo.Repository) {
	v := mustOpenVault()
	r, err := v.OpenRepository(repositoryOptionsFromFlags(extraOptions)...)
	failOnError(err)
	return v, r
}

func repositoryOptionsFromFlags(extraOptions []repo.RepositoryOption) []repo.RepositoryOption {
	var opts []repo.RepositoryOption

	for _, o := range extraOptions {
		opts = append(opts, o)
	}

	if *traceStorage {
		opts = append(opts, repo.EnableLogging(logging.Prefix("[REPOSITORY] ")))
	}
	return opts
}

func getHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}

	return os.Getenv("HOME")
}

func vaultConfigFileName() string {
	if len(*vaultConfigPath) > 0 {
		return *vaultConfigPath
	}
	return filepath.Join(getHomeDir(), ".kopia/vault.config")
}

func persistVaultConfig(v *vault.Vault) error {
	cfg, err := v.Config()
	if err != nil {
		return err
	}

	fname := vaultConfigFileName()
	log.Printf("Saving vault configuration to '%v'.", fname)
	if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
		return err
	}

	f, err := os.Create(fname)
	if err != nil {
		return err
	}
	defer f.Close()

	return json.NewEncoder(f).Encode(cfg)
}

func getPersistedVaultConfig() *vault.Config {
	f, err := os.Open(vaultConfigFileName())
	if err != nil {
		return nil
	}
	defer f.Close()

	vc := &vault.Config{}

	if err := json.NewDecoder(f).Decode(vc); err != nil {
		return nil
	}

	return vc
}

func openVault() (*vault.Vault, error) {
	vc := getPersistedVaultConfig()
	if vc != nil {
		st, err := storage.NewStorage(vc.ConnectionInfo)
		if err != nil {
			return nil, fmt.Errorf("cannot open vault storage: %v", err)
		}

		if *traceStorage {
			st = logging.NewWrapper(st, logging.Prefix("[VAULT] "))
		}

		creds, err := vault.MasterKey(vc.Key)
		if err != nil {
			st.Close()
			return nil, fmt.Errorf("invalid vault config")
		}

		return vault.Open(st, creds)
	}

	if *vaultPath == "" {
		return nil, fmt.Errorf("vault not connected and not specified, use --vault or run 'kopia connect'")
	}

	return openVaultSpecifiedByFlag()
}

func openVaultSpecifiedByFlag() (*vault.Vault, error) {
	if *vaultPath == "" {
		return nil, fmt.Errorf("--vault must be specified")
	}
	storage, err := newStorageFromURL(*vaultPath)
	if err != nil {
		return nil, err
	}

	creds, err := getVaultCredentials(false)
	if err != nil {
		return nil, err
	}

	return vault.Open(storage, creds)
}

func getVaultCredentials(isNew bool) (vault.Credentials, error) {
	if *key != "" {
		k, err := hex.DecodeString(*key)
		if err != nil {
			return nil, fmt.Errorf("invalid key format: %v", err)
		}

		return vault.MasterKey(k)
	}

	if *password != "" {
		return vault.Password(strings.TrimSpace(*password))
	}

	if *keyFile != "" {
		key, err := ioutil.ReadFile(*keyFile)
		if err != nil {
			return nil, fmt.Errorf("unable to read key file: %v", err)
		}

		return vault.MasterKey(key)
	}

	if *passwordFile != "" {
		f, err := ioutil.ReadFile(*passwordFile)
		if err != nil {
			return nil, fmt.Errorf("unable to read password file: %v", err)
		}

		return vault.Password(strings.TrimSpace(string(f)))
	}
	if isNew {
		for {
			p1, err := askPass("Enter password to create new vault: ")
			if err != nil {
				return nil, err
			}
			p2, err := askPass("Re-enter password for verification: ")
			if err != nil {
				return nil, err
			}
			if p1 != p2 {
				fmt.Println("Passwords don't match!")
			} else {
				return vault.Password(p1)
			}
		}
	} else {
		p1, err := askPass("Enter password to open vault: ")
		if err != nil {
			return nil, err
		}
		fmt.Println()
		return vault.Password(p1)
	}
}

func askPass(prompt string) (string, error) {
	for {
		b, err := speakeasy.Ask(prompt)
		if err != nil {
			return "", err
		}

		p := string(b)

		if len(p) == 0 {
			continue
		}

		if len(p) >= vault.MinPasswordLength {
			return p, nil
		}

		fmt.Printf("Password too short, must be at least %v characters, you entered %v. Try again.", vault.MinPasswordLength, len(p))
		fmt.Println()
	}
}
<commit_msg>added KOPIA_TRACE_STORAGE environment variable option to log all vault/repository actions<commit_after>package main

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/kopia/kopia/storage/logging"

	"github.com/bgentry/speakeasy"
	"github.com/kopia/kopia/repo"
	"github.com/kopia/kopia/storage"
	"github.com/kopia/kopia/vault"
)

var (
	traceStorage = app.Flag("trace-storage", "Enables tracing of storage operations.").Hidden().Envar("KOPIA_TRACE_STORAGE").Bool()

	vaultConfigPath = app.Flag("vaultconfig", "Specify the vault config file to use.").PlaceHolder("PATH").Envar("KOPIA_VAULTCONFIG").String()
	vaultPath       = app.Flag("vault", "Specify the vault to use.").PlaceHolder("PATH").Envar("KOPIA_VAULT").Short('v').String()
	password        = app.Flag("password", "Vault password.").Envar("KOPIA_PASSWORD").Short('p').String()
	passwordFile    = app.Flag("passwordfile", "Read vault password from a file.").PlaceHolder("FILENAME").Envar("KOPIA_PASSWORD_FILE").ExistingFile()
	key             = app.Flag("key", "Specify vault master key (hexadecimal).").Envar("KOPIA_KEY").Short('k').String()
	keyFile         = app.Flag("keyfile", "Read vault master key from file.").PlaceHolder("FILENAME").Envar("KOPIA_KEY_FILE").ExistingFile()
)

func failOnError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
		os.Exit(1)
	}
}

func mustOpenVault() *vault.Vault {
	s, err := openVault()
	failOnError(err)
	return s
}

func mustOpenRepository(extraOptions ...repo.RepositoryOption) repo.Repository {
	_, r := mustOpenVaultAndRepository(extraOptions...)
	return r
}

func mustOpenVaultAndRepository(extraOptions ...repo.RepositoryOption) (*vault.Vault, repo.Repository) {
	v := mustOpenVault()
	r, err := v.OpenRepository(repositoryOptionsFromFlags(extraOptions)...)
	failOnError(err)
	return v, r
}

func repositoryOptionsFromFlags(extraOptions []repo.RepositoryOption) []repo.RepositoryOption {
	var opts []repo.RepositoryOption

	for _, o := range extraOptions {
		opts = append(opts, o)
	}

	if *traceStorage {
		opts = append(opts, repo.EnableLogging(logging.Prefix("[REPOSITORY] ")))
	}
	return opts
}

func getHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}

	return os.Getenv("HOME")
}

func vaultConfigFileName() string {
	if len(*vaultConfigPath) > 0 {
		return *vaultConfigPath
	}
	return filepath.Join(getHomeDir(), ".kopia/vault.config")
}

func persistVaultConfig(v *vault.Vault) error {
	cfg, err := v.Config()
	if err != nil {
		return err
	}

	fname := vaultConfigFileName()
	log.Printf("Saving vault configuration to '%v'.", fname)
	if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
		return err
	}

	f, err := os.Create(fname)
	if err != nil {
		return err
	}
	defer f.Close()

	return json.NewEncoder(f).Encode(cfg)
}

func getPersistedVaultConfig() *vault.Config {
	f, err := os.Open(vaultConfigFileName())
	if err != nil {
		return nil
	}
	defer f.Close()

	vc := &vault.Config{}

	if err := json.NewDecoder(f).Decode(vc); err != nil {
		return nil
	}

	return vc
}

func openVault() (*vault.Vault, error) {
	vc := getPersistedVaultConfig()
	if vc != nil {
		st, err := storage.NewStorage(vc.ConnectionInfo)
		if err != nil {
			return nil, fmt.Errorf("cannot open vault storage: %v", err)
		}

		if *traceStorage {
			st = logging.NewWrapper(st, logging.Prefix("[VAULT] "))
		}

		creds, err := vault.MasterKey(vc.Key)
		if err != nil {
			st.Close()
			return nil, fmt.Errorf("invalid vault config")
		}

		return vault.Open(st, creds)
	}

	if *vaultPath == "" {
		return nil, fmt.Errorf("vault not connected and not specified, use --vault or run 'kopia connect'")
	}

	return openVaultSpecifiedByFlag()
}

func openVaultSpecifiedByFlag() (*vault.Vault, error) {
	if *vaultPath == "" {
		return nil, fmt.Errorf("--vault must be specified")
	}
	storage, err := newStorageFromURL(*vaultPath)
	if err != nil {
		return nil, err
	}

	creds, err := getVaultCredentials(false)
	if err != nil {
		return nil, err
	}

	return vault.Open(storage, creds)
}

func getVaultCredentials(isNew bool) (vault.Credentials, error) {
	if *key != "" {
		k, err := hex.DecodeString(*key)
		if err != nil {
			return nil, fmt.Errorf("invalid key format: %v", err)
		}

		return vault.MasterKey(k)
	}

	if *password != "" {
		return vault.Password(strings.TrimSpace(*password))
	}

	if *keyFile != "" {
		key, err := ioutil.ReadFile(*keyFile)
		if err != nil {
			return nil, fmt.Errorf("unable to read key file: %v", err)
		}

		return vault.MasterKey(key)
	}

	if *passwordFile != "" {
		f, err := ioutil.ReadFile(*passwordFile)
		if err != nil {
			return nil, fmt.Errorf("unable to read password file: %v", err)
		}

		return vault.Password(strings.TrimSpace(string(f)))
	}
	if isNew {
		for {
			p1, err := askPass("Enter password to create new vault: ")
			if err != nil {
				return nil, err
			}
			p2, err := askPass("Re-enter password for verification: ")
			if err != nil {
				return nil, err
			}
			if p1 != p2 {
				fmt.Println("Passwords don't match!")
			} else {
				return vault.Password(p1)
			}
		}
	} else {
		p1, err := askPass("Enter password to open vault: ")
		if err != nil {
			return nil, err
		}
		fmt.Println()
		return vault.Password(p1)
	}
}

func askPass(prompt string) (string, error) {
	for {
		b, err := speakeasy.Ask(prompt)
		if err != nil {
			return "", err
		}

		p := string(b)

		if len(p) == 0 {
			continue
		}

		if len(p) >= vault.MinPasswordLength {
			return p, nil
		}

		fmt.Printf("Password too short, must be at least %v characters, you entered %v. Try again.", vault.MinPasswordLength, len(p))
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/freman/go-aurora"

	"github.com/BurntSushi/toml"
	"github.com/matryer/try"
	"github.com/tarm/serial"
)

type result struct {
	Time                time.Time
	Address             byte
	BoosterTemperature  float32
	InverterTemperature float32
	Frequency           float32
	GridVoltage         float32
	GridCurrent         float32
	GridPower           float32
	GridRunTime         duration
	Input1Voltage       float32
	Input1Current       float32
	Input2Voltage       float32
	Input2Current       float32
	Joules              uint16
	DailyEnergy         uint32
	WeeklyEnergy        uint32
	MonthlyEnergy       uint32
	YearlyEnergy        uint32
	TotalEnergy         uint32
	TotalRunTime        duration
	SerialNumber        string
}

type results struct {
	sync.RWMutex
	Results map[byte]*result
}

type serialConfig struct {
	serial.Config
	ReadTimeout duration
}

type duration struct {
	time.Duration
}

func (o *serialConfig) Normalise() *serial.Config {
	o.Config.ReadTimeout = o.ReadTimeout.Duration
	return &o.Config
}

func (d *duration) UnmarshalText(text []byte) (err error) {
	d.Duration, err = time.ParseDuration(string(text))
	return
}

func (d duration) MarshalJSON() ([]byte, error) {
	return json.Marshal(int64(d.Duration.Seconds()))
}

func withDeadline(deadline time.Duration, f func() error) error {
	c := make(chan error, 1)
	defer close(c)
	go func() {
		c <- try.Do(func(attempt int) (bool, error) {
			time.Sleep(time.Duration(attempt) * time.Millisecond)
			err := f()
			return attempt < 3, err
		})
	}()
	select {
	case err := <-c:
		return err
	case <-time.After(deadline):
		return errors.New("Timeout while waiting for operation to complete")
	}
}

type configStruct struct {
	Name          string
	Comms         serialConfig
	UpdateRate    duration
	Deadline      duration
	UnitAddresses []byte
}

func main() {
	config := struct {
		UpdateRate duration
		Deadline   duration
		Listen     string
		Devices    []configStruct
	}{
		UpdateRate: duration{
			Duration: time.Minute,
		},
		Deadline: duration{
			Duration: 5 * time.Second,
		},
		Listen: ":8080",
	}

	fConfig := flag.String("config", "config.toml", "Path to the configuration file")
	flag.Parse()

	_, err := toml.DecodeFile(*fConfig, &config)
	if err != nil {
		log.Fatalf("Unable to parse configuration file due to %v.", err)
	}
	buffer := results{
		Results: map[byte]*result{},
	}

	for _, device := range config.Devices {
		go func(device configStruct) {
			deadline := device.Deadline.Duration
			if deadline == 0 {
				deadline = config.Deadline.Duration
			}

			updateRate := device.UpdateRate.Duration
			if updateRate == 0 {
				updateRate = config.UpdateRate.Duration
			}

			port, err := serial.OpenPort(device.Comms.Normalise())
			if err != nil {
				log.Fatalf("Unable to open serial port due to %v.", err)
			}

			inverter := &aurora.Inverter{
				Conn: port,
			}

			for _, address := range device.UnitAddresses {
				inverter.Address = address
				buffer.Results[address] = &result{
					Address: address,
				}

				err := withDeadline(deadline, func() (err error) {
					buffer.Results[address].SerialNumber, err = inverter.SerialNumber()
					return
				})

				if err != nil {
					log.Fatalf("Unable to communicate with inverter at address %d, error was %v", address, err)
				}
			}

			ticker := time.NewTicker(updateRate)
			now := time.Now()
			for {
				for _, address := range device.UnitAddresses {
					buffer.RLock()
					inverter.Address = address
					r := &result{
						Address:      address,
						SerialNumber: buffer.Results[address].SerialNumber,
						Time:         now,
					}
					buffer.RUnlock()

					err := withDeadline(deadline, func() error {
						var err error
						if r.BoosterTemperature, err = inverter.BoosterTemperature(); err != nil {
							return err
						}
						if r.InverterTemperature, err = inverter.InverterTemperature(); err != nil {
							return err
						}
						if r.Frequency, err = inverter.Frequency(); err != nil {
							return err
						}
						if r.GridVoltage, err = inverter.GridVoltage(); err != nil {
							return err
						}
						if r.GridCurrent, err = inverter.GridCurrent(); err != nil {
							return err
						}
						if r.GridPower, err = inverter.GridPower(); err != nil {
							return err
						}
						if r.GridRunTime.Duration, err = inverter.GridRunTime(); err != nil {
							return err
						}
						if r.Input1Voltage, err = inverter.Input1Voltage(); err != nil {
							return err
						}
						if r.Input1Current, err = inverter.Input1Current(); err != nil {
							return err
						}
						if r.Input2Voltage, err = inverter.Input2Voltage(); err != nil {
							return err
						}
						if r.Input2Current, err = inverter.Input2Current(); err != nil {
							return err
						}
						if r.Joules, err = inverter.Joules(); err != nil {
							return err
						}
						if r.DailyEnergy, err = inverter.DailyEnergy(); err != nil {
							return err
						}
						if r.WeeklyEnergy, err = inverter.WeeklyEnergy(); err != nil {
							return err
						}
						if r.MonthlyEnergy, err = inverter.MonthlyEnergy(); err != nil {
							return err
						}
						if r.YearlyEnergy, err = inverter.YearlyEnergy(); err != nil {
							return err
						}
						if r.TotalEnergy, err = inverter.TotalEnergy(); err != nil {
							return err
						}
						r.TotalRunTime.Duration, err = inverter.TotalRunTime()
						return err
					})

					if err == nil {
						buffer.Lock()
						buffer.Results[address] = r
						buffer.Unlock()
					}
				}
				now = <-ticker.C
			}
		}(device)
	}

	http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		buffer.RLock()
		defer buffer.RUnlock()
		js, err := json.Marshal(buffer.Results)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Cache-Control", "no-cache")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	})

	log.Fatal(http.ListenAndServe(config.Listen, nil))
}
<commit_msg>Include serial port name in the map of inverters<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/freman/go-aurora"

	"github.com/BurntSushi/toml"
	"github.com/matryer/try"
	"github.com/tarm/serial"
)

type result struct {
	Time                time.Time
	Address             byte
	BoosterTemperature  float32
	InverterTemperature float32
	Frequency           float32
	GridVoltage         float32
	GridCurrent         float32
	GridPower           float32
	GridRunTime         duration
	Input1Voltage       float32
	Input1Current       float32
	Input2Voltage       float32
	Input2Current       float32
	Joules              uint16
	DailyEnergy         uint32
	WeeklyEnergy        uint32
	MonthlyEnergy       uint32
	YearlyEnergy        uint32
	TotalEnergy         uint32
	TotalRunTime        duration
	SerialNumber        string
}

type results struct {
	sync.RWMutex
	Results map[string]*result
}

type serialConfig struct {
	serial.Config
	ReadTimeout duration
}

type duration struct {
	time.Duration
}

func (o *serialConfig) Normalise() *serial.Config {
	o.Config.ReadTimeout = o.ReadTimeout.Duration
	return &o.Config
}

func (d *duration) UnmarshalText(text []byte) (err error) {
	d.Duration, err = time.ParseDuration(string(text))
	return
}

func (d duration) MarshalJSON() ([]byte, error) {
	return json.Marshal(int64(d.Duration.Seconds()))
}

func withDeadline(deadline time.Duration, f func() error) error {
	c := make(chan error, 1)
	defer close(c)
	go func() {
		c <- try.Do(func(attempt int) (bool, error) {
			time.Sleep(time.Duration(attempt) * time.Millisecond)
			err := f()
			return attempt < 3, err
		})
	}()
	select {
	case err := <-c:
		return err
	case <-time.After(deadline):
		return errors.New("Timeout while waiting for operation to complete")
	}
}

type configStruct struct {
	Name          string
	Comms         serialConfig
	UpdateRate    duration
	Deadline      duration
	UnitAddresses []byte
}

func main() {
	config := struct {
		UpdateRate duration
		Deadline   duration
		Listen     string
		Devices    []configStruct
	}{
		UpdateRate: duration{
			Duration: time.Minute,
		},
		Deadline: duration{
			Duration: 5 * time.Second,
		},
		Listen: ":8080",
	}

	fConfig := flag.String("config", "config.toml", "Path to the configuration file")
	flag.Parse()

	_, err := toml.DecodeFile(*fConfig, &config)
	if err != nil {
		log.Fatalf("Unable to parse configuration file due to %v.", err)
	}
	buffer := results{
		Results: map[string]*result{},
	}

	for _, device := range config.Devices {
		go func(device configStruct) {
			deadline := device.Deadline.Duration
			if deadline == 0 {
				deadline = config.Deadline.Duration
			}

			updateRate := device.UpdateRate.Duration
			if updateRate == 0 {
				updateRate = config.UpdateRate.Duration
			}

			port, err := serial.OpenPort(device.Comms.Normalise())
			if err != nil {
				log.Fatalf("Unable to open serial port due to %v.", err)
			}

			inverter := &aurora.Inverter{
				Conn: port,
			}

			for _, address := range device.UnitAddresses {
				name := fmt.Sprintf("%s::%d", device.Comms.Name, address)
				inverter.Address = address
				buffer.Results[name] = &result{
					Address: address,
				}

				err := withDeadline(deadline, func() (err error) {
					buffer.Results[name].SerialNumber, err = inverter.SerialNumber()
					return
				})

				if err != nil {
					log.Fatalf("Unable to communicate with inverter on port %s at address %d, error was %v", device.Comms.Name, address, err)
				}
			}

			ticker := time.NewTicker(updateRate)
			now := time.Now()
			for {
				for _, address := range device.UnitAddresses {
					name := fmt.Sprintf("%s::%d", device.Comms.Name, address)
					buffer.RLock()
					inverter.Address = address
					r := &result{
						Address:      address,
						SerialNumber: buffer.Results[name].SerialNumber,
						Time:         now,
					}
					buffer.RUnlock()

					err := withDeadline(deadline, func() error {
						var err error
						if r.BoosterTemperature, err = inverter.BoosterTemperature(); err != nil {
							return err
						}
						if r.InverterTemperature, err = inverter.InverterTemperature(); err != nil {
							return err
						}
						if r.Frequency, err = inverter.Frequency(); err != nil {
							return err
						}
						if r.GridVoltage, err = inverter.GridVoltage(); err != nil {
							return err
						}
						if r.GridCurrent, err = inverter.GridCurrent(); err != nil {
							return err
						}
						if r.GridPower, err = inverter.GridPower(); err != nil {
							return err
						}
						if r.GridRunTime.Duration, err = inverter.GridRunTime(); err != nil {
							return err
						}
						if r.Input1Voltage, err = inverter.Input1Voltage(); err != nil {
							return err
						}
						if r.Input1Current, err = inverter.Input1Current(); err != nil {
							return err
						}
						if r.Input2Voltage, err = inverter.Input2Voltage(); err != nil {
							return err
						}
						if r.Input2Current, err = inverter.Input2Current(); err != nil {
							return err
						}
						if r.Joules, err = inverter.Joules(); err != nil {
							return err
						}
						if r.DailyEnergy, err = inverter.DailyEnergy(); err != nil {
							return err
						}
						if r.WeeklyEnergy, err = inverter.WeeklyEnergy(); err != nil {
							return err
						}
						if r.MonthlyEnergy, err = inverter.MonthlyEnergy(); err != nil {
							return err
						}
						if r.YearlyEnergy, err = inverter.YearlyEnergy(); err != nil {
							return err
						}
						if r.TotalEnergy, err = inverter.TotalEnergy(); err != nil {
							return err
						}
						r.TotalRunTime.Duration, err = inverter.TotalRunTime()
						return err
					})

					if err == nil {
						buffer.Lock()
						buffer.Results[name] = r
						buffer.Unlock()
					}
				}
				now = <-ticker.C
			}
		}(device)
	}

	http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		buffer.RLock()
		defer buffer.RUnlock()
		js, err := json.Marshal(buffer.Results)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Cache-Control", "no-cache")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	})

	log.Fatal(http.ListenAndServe(config.Listen, nil))
}
<|endoftext|>


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

package main

import (
	"context"
	"flag"
	"fmt"
	logpkg "log"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"syscall"

	"cloud.google.com/go/errorreporting"
	"cloud.google.com/go/profiler"
	"contrib.go.opencensus.io/exporter/stackdriver"
	"github.com/neovim/go-client/nvim/plugin"
	"github.com/pkg/errors"
	"go.opencensus.io/stats/view"
	"go.opencensus.io/trace"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"golang.org/x/sync/errgroup"

	"github.com/zchee/nvim-go/pkg/autocmd"
	"github.com/zchee/nvim-go/pkg/buildctxt"
	"github.com/zchee/nvim-go/pkg/command"
	"github.com/zchee/nvim-go/pkg/config"
	"github.com/zchee/nvim-go/pkg/logger"
	"github.com/zchee/nvim-go/pkg/server"
)

const (
	appName = "nvim-go"
)

// flags
var (
	fVersion    = flag.Bool("version", false, "Show the version information.")
	pluginHost  = flag.String("manifest", "", "Write plugin manifest for `host` to stdout")
	vimFilePath = flag.String("location", "", "Manifest is automatically written to `.vim file`")
)

func init() {
	flag.Parse()
	logpkg.SetPrefix("nvim-go: ")
}

func main() {
	if *fVersion {
		fmt.Printf("%s:\n  version: %s\n", appName, version)
		return
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if *pluginHost != "" {
		os.Unsetenv("NVIM_GO_DEBUG")
		fn := func(p *plugin.Plugin) error {
			return func(ctx context.Context, p *plugin.Plugin) error {
				ctx, cancel := context.WithCancel(ctx)
				defer cancel()
				bctxt := buildctxt.NewContext()
				c := command.Register(ctx, p, bctxt)
				autocmd.Register(ctx, cancel, p, bctxt, c)
				return nil
			}(ctx, p)
		}
		if err := Plugin(fn); err != nil {
			logpkg.Fatal(err)
		}
		return
	}

	env, err := config.Process()
	if err != nil {
		logpkg.Fatalf("env.Process: %+v", err)
	}

	var lv zapcore.Level
	if err := lv.UnmarshalText([]byte(env.LogLevel)); err != nil {
		logpkg.Fatalf("failed to parse log level: %s, err: %v", env.LogLevel, err)
	}
	zapLogger, undo := logger.NewRedirectZapLogger(lv)
	defer undo()
	ctx = logger.NewContext(ctx, zapLogger)

	if gcpProjectID := env.GCPProjectID; gcpProjectID != "" {
		// Stackdriver Profiler
		profCfg := profiler.Config{
			Service:        appName,
			ServiceVersion: tag,
			MutexProfiling: true,
			ProjectID:      gcpProjectID,
		}
		if err := profiler.Start(profCfg); err != nil {
			logpkg.Fatalf("failed to start stackdriver profiler: %v", err)
		}

		// OpenCensus tracing
		sdOpts := stackdriver.Options{
			ProjectID: gcpProjectID,
			OnError: func(err error) {
				zapLogger.Error("stackdriver.Exporter", zap.Error(fmt.Errorf("could not log error: %v", err)))
			},
			MetricPrefix: appName,
			Context:      ctx,
		}
		sd, err := stackdriver.NewExporter(sdOpts)
		if err != nil {
			logpkg.Fatalf("failed to create stackdriver exporter: %v", err)
		}
		defer sd.Flush()
		trace.RegisterExporter(sd)
		trace.ApplyConfig(trace.Config{
			DefaultSampler: trace.AlwaysSample(),
		})
		view.RegisterExporter(sd)

		// Stackdriver Error Reporting
		errReportCfg := errorreporting.Config{
			ServiceName:    appName,
			ServiceVersion: tag,
			OnError: func(err error) {
				zapLogger.Error("errorreporting", zap.Error(fmt.Errorf("could not log error: %v", err)))
			},
		}
		errClient, err := errorreporting.NewClient(ctx, gcpProjectID, errReportCfg)
		if err != nil {
			logpkg.Fatalf("failed to create errorreporting client: %v", err)
		}
		defer errClient.Close()
		ctx = context.WithValue(ctx, &errorreporting.Client{}, errClient)
	}

	zapLogger.Info("starting "+appName+" server", zap.Object("env", env))

	eg := new(errgroup.Group)
	eg, ctx = errgroup.WithContext(ctx)
	eg.Go(func() error {
		fn := func(p *plugin.Plugin) error {
			return Main(ctx, p)
		}
		return Plugin(fn)
	})
	eg.Go(func() error {
		return Child(ctx)
	})

	go func() {
		if err := eg.Wait(); err != nil {
			zapLogger.Fatal("eg.Wait", zap.Error(err))
		}
	}()

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-ctx.Done():
		zapLogger.Error("ctx.Done()", zap.Error(ctx.Err()))
		return
	case sig := <-sigc:
		switch sig {
		case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM:
			zapLogger.Info("catch signal", zap.String("name", sig.String()))
			return
		}
	}
}

func Main(ctx context.Context, p *plugin.Plugin) error {
	ctx, cancel := context.WithCancel(ctx)
	ctx = logger.NewContext(ctx, logger.FromContext(ctx).Named("main"))

	bctxt := buildctxt.NewContext()
	autocmd.Register(ctx, cancel, p, bctxt, command.Register(ctx, p, bctxt))

	// switch to unix socket rpc-connection
	if n, err := server.Dial(ctx); err == nil {
		p.Nvim = n
	}

	return nil
}

func Child(ctx context.Context) error {
	log := logger.FromContext(ctx).Named("child")
	ctx = logger.NewContext(ctx, log)

	s, err := server.NewServer(ctx)
	if err != nil {
		return errors.Wrap(err, "failed to create NewServer")
	}
	go s.Serve()
	defer func() {
		if err := s.Close(); err != nil {
			log.Fatal("Close", zap.Error(err))
		}
	}()

	bufs, err := s.Buffers()
	if err != nil {
		return errors.Wrap(err, "failed to get buffers")
	}

	// Get the names using a single atomic call to Nvim.
	names := make([]string, len(bufs))
	b := s.NewBatch()
	for i, buf := range bufs {
		b.BufferName(buf, &names[i])
	}

	if err := b.Execute(); err != nil {
		return errors.Wrap(err, "failed to execute batch")
	}

	for _, name := range names {
		log.Info("buffer", zap.String("name", name))
	}

	return nil
}
<commit_msg>cmd/nvim-go: disable Stackdriver Profiler for now<commit_after>// Copyright 2016 The nvim-go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"context"
	"flag"
	"fmt"
	logpkg "log"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"syscall"

	"cloud.google.com/go/errorreporting"
	"contrib.go.opencensus.io/exporter/stackdriver"
	"github.com/neovim/go-client/nvim/plugin"
	"github.com/pkg/errors"
	"go.opencensus.io/stats/view"
	"go.opencensus.io/trace"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"golang.org/x/sync/errgroup"

	"github.com/zchee/nvim-go/pkg/autocmd"
	"github.com/zchee/nvim-go/pkg/buildctxt"
	"github.com/zchee/nvim-go/pkg/command"
	"github.com/zchee/nvim-go/pkg/config"
	"github.com/zchee/nvim-go/pkg/logger"
	"github.com/zchee/nvim-go/pkg/server"
)

const (
	appName = "nvim-go"
)

// flags
var (
	fVersion    = flag.Bool("version", false, "Show the version information.")
	pluginHost  = flag.String("manifest", "", "Write plugin manifest for `host` to stdout")
	vimFilePath = flag.String("location", "", "Manifest is automatically written to `.vim file`")
)

func init() {
	flag.Parse()
	logpkg.SetPrefix("nvim-go: ")
}

func main() {
	if *fVersion {
		fmt.Printf("%s:\n  version: %s\n", appName, version)
		return
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	if *pluginHost != "" {
		os.Unsetenv("NVIM_GO_DEBUG")
		fn := func(p *plugin.Plugin) error {
			return func(ctx context.Context, p *plugin.Plugin) error {
				ctx, cancel := context.WithCancel(ctx)
				defer cancel()
				bctxt := buildctxt.NewContext()
				c := command.Register(ctx, p, bctxt)
				autocmd.Register(ctx, cancel, p, bctxt, c)
				return nil
			}(ctx, p)
		}
		if err := Plugin(fn); err != nil {
			logpkg.Fatal(err)
		}
		return
	}

	env, err := config.Process()
	if err != nil {
		logpkg.Fatalf("env.Process: %+v", err)
	}

	var lv zapcore.Level
	if err := lv.UnmarshalText([]byte(env.LogLevel)); err != nil {
		logpkg.Fatalf("failed to parse log level: %s, err: %v", env.LogLevel, err)
	}
	zapLogger, undo := logger.NewRedirectZapLogger(lv)
	defer undo()
	ctx = logger.NewContext(ctx, zapLogger)

	if gcpProjectID := env.GCPProjectID; gcpProjectID != "" {
		// Stackdriver Profiler
		// profCfg := profiler.Config{
		// 	Service:        appName,
		// 	ServiceVersion: tag,
		// 	MutexProfiling: true,
		// 	ProjectID:      gcpProjectID,
		// }
		// if err := profiler.Start(profCfg); err != nil {
		// 	logpkg.Fatalf("failed to start stackdriver profiler: %v", err)
		// }

		// OpenCensus tracing
		sdOpts := stackdriver.Options{
			ProjectID: gcpProjectID,
			OnError: func(err error) {
				zapLogger.Error("stackdriver.Exporter", zap.Error(fmt.Errorf("could not log error: %v", err)))
			},
			MetricPrefix: appName,
			Context:      ctx,
		}
		sd, err := stackdriver.NewExporter(sdOpts)
		if err != nil {
			logpkg.Fatalf("failed to create stackdriver exporter: %v", err)
		}
		defer sd.Flush()
		trace.RegisterExporter(sd)
		trace.ApplyConfig(trace.Config{
			DefaultSampler: trace.AlwaysSample(),
		})
		view.RegisterExporter(sd)

		// Stackdriver Error Reporting
		errReportCfg := errorreporting.Config{
			ServiceName:    appName,
			ServiceVersion: tag,
			OnError: func(err error) {
				zapLogger.Error("errorreporting", zap.Error(fmt.Errorf("could not log error: %v", err)))
			},
		}
		errClient, err := errorreporting.NewClient(ctx, gcpProjectID, errReportCfg)
		if err != nil {
			logpkg.Fatalf("failed to create errorreporting client: %v", err)
		}
		defer errClient.Close()
		ctx = context.WithValue(ctx, &errorreporting.Client{}, errClient)
	}

	zapLogger.Info("starting "+appName+" server", zap.Object("env", env))

	eg := new(errgroup.Group)
	eg, ctx = errgroup.WithContext(ctx)
	eg.Go(func() error {
		fn := func(p *plugin.Plugin) error {
			return Main(ctx, p)
		}
		return Plugin(fn)
	})
	eg.Go(func() error {
		return Child(ctx)
	})

	go func() {
		if err := eg.Wait(); err != nil {
			zapLogger.Fatal("eg.Wait", zap.Error(err))
		}
	}()

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-ctx.Done():
		zapLogger.Error("ctx.Done()", zap.Error(ctx.Err()))
		return
	case sig := <-sigc:
		switch sig {
		case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM:
			zapLogger.Info("catch signal", zap.String("name", sig.String()))
			return
		}
	}
}

func Main(ctx context.Context, p *plugin.Plugin) error {
	ctx, cancel := context.WithCancel(ctx)
	ctx = logger.NewContext(ctx, logger.FromContext(ctx).Named("main"))

	bctxt := buildctxt.NewContext()
	autocmd.Register(ctx, cancel, p, bctxt, command.Register(ctx, p, bctxt))

	// switch to unix socket rpc-connection
	if n, err := server.Dial(ctx); err == nil {
		p.Nvim = n
	}

	return nil
}

func Child(ctx context.Context) error {
	log := logger.FromContext(ctx).Named("child")
	ctx = logger.NewContext(ctx, log)

	s, err := server.NewServer(ctx)
	if err != nil {
		return errors.Wrap(err, "failed to create NewServer")
	}
	go s.Serve()
	defer func() {
		if err := s.Close(); err != nil {
			log.Fatal("Close", zap.Error(err))
		}
	}()

	bufs, err := s.Buffers()
	if err != nil {
		return errors.Wrap(err, "failed to get buffers")
	}

	// Get the names using a single atomic call to Nvim.
	names := make([]string, len(bufs))
	b := s.NewBatch()
	for i, buf := range bufs {
		b.BufferName(buf, &names[i])
	}

	if err := b.Execute(); err != nil {
		return errors.Wrap(err, "failed to execute batch")
	}

	for _, name := range names {
		log.Info("buffer", zap.String("name", name))
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"flag"
	"fmt"

	"github.com/leighmcculloch/randstr/lib/randstr"
)

var version string

var printHelp bool
var printVersion bool
var length int
var chars string

func init() {
	flag.BoolVar(&printHelp, "help", false, "display this usage")
	flag.BoolVar(&printVersion, "version", false, "display the version")
	flag.IntVar(&length, "l", 50, "`length` of the string generated")
	flag.StringVar(&chars, "c", randstr.ASCIIChars, "`characters` to potentially use in the string, supporting unicode and emojis")
}

func main() {
	flag.Parse()

	if printVersion {
		fmt.Printf("randstr version %s\n", version)
		return
	}

	if printHelp {
		fmt.Println("Usage:")
		flag.PrintDefaults()
		return
	}

	fmt.Println(randstr.String(rand.Reader, length, randstr.CharsetArray(chars)))
}
<commit_msg>Cleaned up the main code.<commit_after>package main

import (
	"crypto/rand"
	"flag"
	"fmt"

	"github.com/leighmcculloch/randstr/lib/randstr"
)

var version string

var printHelp bool
var printVersion bool
var length int
var chars string

func init() {
	flag.BoolVar(&printHelp, "help", false, "display this usage")
	flag.BoolVar(&printVersion, "version", false, "display the version")
	flag.IntVar(&length, "l", 50, "`length` of the string generated")
	flag.StringVar(&chars, "c", randstr.ASCIIChars, "`characters` to potentially use in the string, supporting unicode and emojis")
}

func main() {
	flag.Parse()

	if printVersion {
		fmt.Printf("randstr version %s\n", version)
		return
	}

	if printHelp {
		fmt.Println("Usage:")
		flag.PrintDefaults()
		return
	}

	charset := randstr.CharsetArray(chars)
	randomString := randstr.String(rand.Reader, length, charset)
	fmt.Println(randomString)
}
<|endoftext|>


<commit_before>/*
rqlite -- replicating SQLite via the Raft consensus protocol..

rqlite is a distributed system that provides a replicated relational database,
using SQLite as the storage engine.

rqlite is written in Go and uses Raft to achieve consensus across all the
instances of the SQLite databases. rqlite ensures that every change made to
the database is made to a majority of underlying SQLite files, or none-at-all.
*/

package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/rqlite/rqlite/auth"
	"github.com/rqlite/rqlite/cluster"
	"github.com/rqlite/rqlite/disco"
	httpd "github.com/rqlite/rqlite/http"
	"github.com/rqlite/rqlite/store"
	"github.com/rqlite/rqlite/tcp"
)

const sqliteDSN = "db.sqlite"

const logo = `
            _ _ _           _
           | (_) |         | |
  _ __ __ _| |_| |_ ___  __| |
 | '__/ _  | | | __/ _ \/ _  |  The lightweight, distributed
 | | | (_| | | | ||  __/ (_| |  relational database.
 |_|  \__, |_|_|\__\___|\__,_|
         | |
         |_|
`

// These variables are populated via the Go linker.
var (
	version   = "3"
	commit    = "unknown"
	branch    = "unknown"
	buildtime = "unknown"
)

const (
	muxRaftHeader = 1 // Raft consensus communications
	muxMetaHeader = 2 // Cluster meta communications
)

const (
	publishPeerDelay   = 1 * time.Second
	publishPeerTimeout = 30 * time.Second
)

var httpAddr string
var httpAdv string
var authFile string
var x509Cert string
var x509Key string
var raftAddr string
var raftAdv string
var joinAddr string
var noVerify bool
var discoURL string
var discoID string
var expvar bool
var pprofEnabled bool
var dsn string
var onDisk bool
var raftSnapThreshold uint64
var raftHeartbeatTimeout string
var raftApplyTimeout string
var raftOpenTimeout string
var showVersion bool
var cpuProfile string
var memProfile string

const desc = `rqlite is a distributed system that provides a replicated relational database.`

func init() {
	flag.StringVar(&httpAddr, "http", "localhost:4001", "HTTP server bind address. For HTTPS, set X.509 cert and key")
	flag.StringVar(&httpAdv, "httpadv", "", "Advertised HTTP address. If not set, same as HTTP server")
	flag.StringVar(&x509Cert, "x509cert", "", "Path to X.509 certificate")
	flag.StringVar(&x509Key, "x509key", "", "Path to X.509 private key for certificate")
	flag.StringVar(&authFile, "auth", "", "Path to authentication and authorization file. If not set, not enabled")
	flag.StringVar(&raftAddr, "raft", "localhost:4002", "Raft communication bind address")
	flag.StringVar(&raftAdv, "raftadv", "", "Advertised Raft communication address. If not set, same as Raft bind")
	flag.StringVar(&joinAddr, "join", "", "Join a cluster via node at protocol://host:port")
	flag.BoolVar(&noVerify, "noverify", false, "Skip verification of remote HTTPS cert when joining cluster")
	flag.StringVar(&discoURL, "disco", "http://discovery.rqlite.com", "Set Discovery Service URL")
	flag.StringVar(&discoID, "discoid", "", "Set Discovery ID. If not set, Discovery Service not used")
	flag.BoolVar(&expvar, "expvar", true, "Serve expvar data on HTTP server")
	flag.BoolVar(&pprofEnabled, "pprof", true, "Serve pprof data on HTTP server")
	flag.StringVar(&dsn, "dsn", "", `SQLite DSN parameters. E.g. "cache=shared&mode=memory"`)
	flag.BoolVar(&onDisk, "ondisk", false, "Use an on-disk SQLite database")
	flag.BoolVar(&showVersion, "version", false, "Show version information and exit")
	flag.StringVar(&raftHeartbeatTimeout, "rafttimeout", "1s", "Raft heartbeat timeout")
	flag.StringVar(&raftApplyTimeout, "raftapplytimeout", "10s", "Raft apply timeout")
	flag.StringVar(&raftOpenTimeout, "raftopentimeout", "120s", "Time for initial Raft logs to be applied. Use 0s duration to skip wait")
	flag.Uint64Var(&raftSnapThreshold, "raftsnap", 8192, "Number of outstanding log entries that trigger snapshot")
	flag.StringVar(&cpuProfile, "cpuprofile", "", "Path to file for CPU profiling information")
	flag.StringVar(&memProfile, "memprofile", "", "Path to file for memory profiling information")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\n%s\n\n", desc)
		fmt.Fprintf(os.Stderr, "Usage: %s [arguments] <data directory>\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	if showVersion {
		fmt.Printf("rqlited %s %s %s (commit %s, branch %s)\n",
			version, runtime.GOOS, runtime.GOARCH, commit, branch)
		os.Exit(0)
	}

	// Ensure the data path is set.
	if flag.NArg() == 0 {
		flag.Usage()
		os.Exit(1)
	}

	dataPath := flag.Arg(0)

	// Display logo.
	fmt.Println(logo)

	// Configure logging and pump out initial message.
	log.SetFlags(log.LstdFlags)
	log.SetOutput(os.Stderr)
	log.SetPrefix("[rqlited] ")
	log.Printf("rqlited starting, version %s, commit %s, branch %s", version, commit, branch)
	log.Printf("target architecture is %s, operating system target is %s", runtime.GOARCH, runtime.GOOS)

	// Start requested profiling.
	startProfile(cpuProfile, memProfile)

	// Set up TCP communication between nodes.
	ln, err := net.Listen("tcp", raftAddr)
	if err != nil {
		log.Fatalf("failed to listen on %s: %s", raftAddr, err.Error())
	}
	var adv net.Addr
	if raftAdv != "" {
		adv, err = net.ResolveTCPAddr("tcp", raftAdv)
		if err != nil {
			log.Fatalf("failed to resolve advertise address %s: %s", raftAdv, err.Error())
		}
	}
	mux := tcp.NewMux(ln, adv)
	go mux.Serve()

	// Start up mux and get transports for cluster.
	raftTn := mux.Listen(muxRaftHeader)

	// Create and open the store.
	dataPath, err = filepath.Abs(dataPath)
	if err != nil {
		log.Fatalf("failed to determine absolute data path: %s", err.Error())
	}
	dbConf := store.NewDBConfig(dsn, !onDisk)

	str := store.New(&store.StoreConfig{
		DBConf: dbConf,
		Dir:    dataPath,
		Tn:     raftTn,
	})

	// Set optional parameters on store.
	str.SnapshotThreshold = raftSnapThreshold
	str.HeartbeatTimeout, err = time.ParseDuration(raftHeartbeatTimeout)
	if err != nil {
		log.Fatalf("failed to parse Raft heartbeat timeout %s: %s", raftHeartbeatTimeout, err.Error())
	}
	str.ApplyTimeout, err = time.ParseDuration(raftApplyTimeout)
	if err != nil {
		log.Fatalf("failed to parse Raft apply timeout %s: %s", raftApplyTimeout, err.Error())
	}
	str.OpenTimeout, err = time.ParseDuration(raftOpenTimeout)
	if err != nil {
		log.Fatalf("failed to parse Raft open timeout %s: %s", raftOpenTimeout, err.Error())
	}

	// Determine join addresses, if necessary.
	ja, err := store.JoinAllowed(dataPath)
	if err != nil {
		log.Fatalf("unable to determine if join permitted: %s", err.Error())
	}

	var joins []string
	if ja {
		joins, err = determineJoinAddresses()
		if err != nil {
			log.Fatalf("unable to determine join addresses: %s", err.Error())
		}
	} else {
		log.Println("node is already member of cluster, skipping determining join addresses")
	}

	// Now, open it.
	if err := str.Open(len(joins) == 0); err != nil {
		log.Fatalf("failed to open store: %s", err.Error())
	}

	// Create and configure cluster service.
	tn := mux.Listen(muxMetaHeader)
	cs := cluster.NewService(tn, str)
	if err := cs.Open(); err != nil {
		log.Fatalf("failed to open cluster service: %s", err.Error())
	}

	// Execute any requested join operation.
	if len(joins) > 0 {
		log.Println("join addresses are:", joins)
		advAddr := raftAddr
		if raftAdv != "" {
			advAddr = raftAdv
		}
		if j, err := cluster.Join(joins, advAddr, noVerify); err != nil {
			log.Fatalf("failed to join cluster at %s: %s", joins, err.Error())
		} else {
			log.Println("successfully joined cluster at", j)
		}

	} else {
		log.Println("no join addresses available")
	}

	// Publish to the cluster the mapping between this Raft address and API address.
	// The Raft layer broadcasts the resolved address, so use that as the key. But
	// only set different HTTP advertise address if set.
	apiAdv := httpAddr
	if httpAdv != "" {
		apiAdv = httpAdv
	}

	if err := publishAPIAddr(cs, raftTn.Addr().String(), apiAdv, publishPeerTimeout); err != nil {
		log.Fatalf("failed to set peer for %s to %s: %s", raftAddr, httpAddr, err.Error())
	}
	log.Printf("set peer for %s to %s", raftTn.Addr().String(), apiAdv)

	// Create HTTP server and load authentication information, if supplied.
	var s *httpd.Service
	if authFile != "" {
		f, err := os.Open(authFile)
		if err != nil {
			log.Fatalf("failed to open authentication file %s: %s", authFile, err.Error())
		}
		credentialStore := auth.NewCredentialsStore()
		if err := credentialStore.Load(f); err != nil {
			log.Fatalf("failed to load authentication file: %s", err.Error())
		}
		s = httpd.New(httpAddr, str, credentialStore)
	} else {
		s = httpd.New(httpAddr, str, nil)
	}

	s.CertFile = x509Cert
	s.KeyFile = x509Key
	s.Expvar = expvar
	s.Pprof = pprofEnabled
	s.BuildInfo = map[string]interface{}{
		"commit":     commit,
		"branch":     branch,
		"version":    version,
		"build_time": buildtime,
	}
	if err := s.Start(); err != nil {
		log.Fatalf("failed to start HTTP server: %s", err.Error())
	}

	terminate := make(chan os.Signal, 1)
	signal.Notify(terminate, os.Interrupt)
	<-terminate
	if err := str.Close(true); err != nil {
		log.Printf("failed to close store: %s", err.Error())
	}
	stopProfile()
	log.Println("rqlite server stopped")
}

func determineJoinAddresses() ([]string, error) {
	apiAdv := httpAddr
	if httpAdv != "" {
		apiAdv = httpAdv
	}

	var addrs []string
	if joinAddr != "" {
		// An explicit join address is first priority.
		addrs = append(addrs, joinAddr)
	}

	if discoID != "" {
		log.Printf("registering with Discovery Service at %s with ID %s", discoURL, discoID)
		c := disco.New(discoURL)
		r, err := c.Register(discoID, apiAdv)
		if err != nil {
			return nil, err
		}
		log.Println("Discovery Service responded with nodes:", r.Nodes)
		for _, a := range r.Nodes {
			if a != apiAdv {
				// Only other nodes can be joined.
				addrs = append(addrs, a)
			}
		}
	}

	return addrs, nil
}

func publishAPIAddr(c *cluster.Service, raftAddr, apiAddr string, t time.Duration) error {
	tck := time.NewTicker(publishPeerDelay)
	defer tck.Stop()
	tmr := time.NewTimer(t)
	defer tmr.Stop()

	for {
		select {
		case <-tck.C:
			if err := c.SetPeer(raftAddr, apiAddr); err != nil {
				log.Printf("failed to set peer for %s to %s: %s (retrying)",
					raftAddr, apiAddr, err.Error())
				continue
			}
			return nil
		case <-tmr.C:
			return fmt.Errorf("set peer timeout expired")
		}
	}
}

// prof stores the file locations of active profiles.
var prof struct {
	cpu *os.File
	mem *os.File
}

// startProfile initializes the CPU and memory profile, if specified.
func startProfile(cpuprofile, memprofile string) {
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatalf("failed to create CPU profile file at %s: %s", cpuprofile, err.Error())
		}
		log.Printf("writing CPU profile to: %s\n", cpuprofile)
		prof.cpu = f
		pprof.StartCPUProfile(prof.cpu)
	}

	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			log.Fatalf("failed to create memory profile file at %s: %s", cpuprofile, err.Error())
		}
		log.Printf("writing memory profile to: %s\n", memprofile)
		prof.mem = f
		runtime.MemProfileRate = 4096
	}
}

// stopProfile closes the CPU and memory profiles if they are running.
func stopProfile() {
	if prof.cpu != nil {
		pprof.StopCPUProfile()
		prof.cpu.Close()
		log.Println("CPU profiling stopped")
	}
	if prof.mem != nil {
		pprof.Lookup("heap").WriteTo(prof.mem, 0)
		prof.mem.Close()
		log.Println("memory profiling stopped")
	}
}
<commit_msg>Tweak join-related logging<commit_after>/*
rqlite -- replicating SQLite via the Raft consensus protocol..

rqlite is a distributed system that provides a replicated relational database,
using SQLite as the storage engine.

rqlite is written in Go and uses Raft to achieve consensus across all the
instances of the SQLite databases. rqlite ensures that every change made to
the database is made to a majority of underlying SQLite files, or none-at-all.
*/

package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/rqlite/rqlite/auth"
	"github.com/rqlite/rqlite/cluster"
	"github.com/rqlite/rqlite/disco"
	httpd "github.com/rqlite/rqlite/http"
	"github.com/rqlite/rqlite/store"
	"github.com/rqlite/rqlite/tcp"
)

const sqliteDSN = "db.sqlite"

const logo = `
            _ _ _           _
           | (_) |         | |
  _ __ __ _| |_| |_ ___  __| |
 | '__/ _  | | | __/ _ \/ _  |  The lightweight, distributed
 | | | (_| | | | ||  __/ (_| |  relational database.
 |_|  \__, |_|_|\__\___|\__,_|
         | |
         |_|
`

// These variables are populated via the Go linker.
var (
	version   = "3"
	commit    = "unknown"
	branch    = "unknown"
	buildtime = "unknown"
)

const (
	muxRaftHeader = 1 // Raft consensus communications
	muxMetaHeader = 2 // Cluster meta communications
)

const (
	publishPeerDelay   = 1 * time.Second
	publishPeerTimeout = 30 * time.Second
)

var httpAddr string
var httpAdv string
var authFile string
var x509Cert string
var x509Key string
var raftAddr string
var raftAdv string
var joinAddr string
var noVerify bool
var discoURL string
var discoID string
var expvar bool
var pprofEnabled bool
var dsn string
var onDisk bool
var raftSnapThreshold uint64
var raftHeartbeatTimeout string
var raftApplyTimeout string
var raftOpenTimeout string
var showVersion bool
var cpuProfile string
var memProfile string

const desc = `rqlite is a distributed system that provides a replicated relational database.`

func init() {
	flag.StringVar(&httpAddr, "http", "localhost:4001", "HTTP server bind address. For HTTPS, set X.509 cert and key")
	flag.StringVar(&httpAdv, "httpadv", "", "Advertised HTTP address. If not set, same as HTTP server")
	flag.StringVar(&x509Cert, "x509cert", "", "Path to X.509 certificate")
	flag.StringVar(&x509Key, "x509key", "", "Path to X.509 private key for certificate")
	flag.StringVar(&authFile, "auth", "", "Path to authentication and authorization file. If not set, not enabled")
	flag.StringVar(&raftAddr, "raft", "localhost:4002", "Raft communication bind address")
	flag.StringVar(&raftAdv, "raftadv", "", "Advertised Raft communication address. If not set, same as Raft bind")
	flag.StringVar(&joinAddr, "join", "", "Join a cluster via node at protocol://host:port")
	flag.BoolVar(&noVerify, "noverify", false, "Skip verification of remote HTTPS cert when joining cluster")
	flag.StringVar(&discoURL, "disco", "http://discovery.rqlite.com", "Set Discovery Service URL")
	flag.StringVar(&discoID, "discoid", "", "Set Discovery ID. If not set, Discovery Service not used")
	flag.BoolVar(&expvar, "expvar", true, "Serve expvar data on HTTP server")
	flag.BoolVar(&pprofEnabled, "pprof", true, "Serve pprof data on HTTP server")
	flag.StringVar(&dsn, "dsn", "", `SQLite DSN parameters. E.g. "cache=shared&mode=memory"`)
	flag.BoolVar(&onDisk, "ondisk", false, "Use an on-disk SQLite database")
	flag.BoolVar(&showVersion, "version", false, "Show version information and exit")
	flag.StringVar(&raftHeartbeatTimeout, "rafttimeout", "1s", "Raft heartbeat timeout")
	flag.StringVar(&raftApplyTimeout, "raftapplytimeout", "10s", "Raft apply timeout")
	flag.StringVar(&raftOpenTimeout, "raftopentimeout", "120s", "Time for initial Raft logs to be applied. Use 0s duration to skip wait")
	flag.Uint64Var(&raftSnapThreshold, "raftsnap", 8192, "Number of outstanding log entries that trigger snapshot")
	flag.StringVar(&cpuProfile, "cpuprofile", "", "Path to file for CPU profiling information")
	flag.StringVar(&memProfile, "memprofile", "", "Path to file for memory profiling information")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\n%s\n\n", desc)
		fmt.Fprintf(os.Stderr, "Usage: %s [arguments] <data directory>\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()

	if showVersion {
		fmt.Printf("rqlited %s %s %s (commit %s, branch %s)\n",
			version, runtime.GOOS, runtime.GOARCH, commit, branch)
		os.Exit(0)
	}

	// Ensure the data path is set.
	if flag.NArg() == 0 {
		flag.Usage()
		os.Exit(1)
	}

	dataPath := flag.Arg(0)

	// Display logo.
	fmt.Println(logo)

	// Configure logging and pump out initial message.
	log.SetFlags(log.LstdFlags)
	log.SetOutput(os.Stderr)
	log.SetPrefix("[rqlited] ")
	log.Printf("rqlited starting, version %s, commit %s, branch %s", version, commit, branch)
	log.Printf("target architecture is %s, operating system target is %s", runtime.GOARCH, runtime.GOOS)

	// Start requested profiling.
	startProfile(cpuProfile, memProfile)

	// Set up TCP communication between nodes.
	ln, err := net.Listen("tcp", raftAddr)
	if err != nil {
		log.Fatalf("failed to listen on %s: %s", raftAddr, err.Error())
	}
	var adv net.Addr
	if raftAdv != "" {
		adv, err = net.ResolveTCPAddr("tcp", raftAdv)
		if err != nil {
			log.Fatalf("failed to resolve advertise address %s: %s", raftAdv, err.Error())
		}
	}
	mux := tcp.NewMux(ln, adv)
	go mux.Serve()

	// Start up mux and get transports for cluster.
	raftTn := mux.Listen(muxRaftHeader)

	// Create and open the store.
	dataPath, err = filepath.Abs(dataPath)
	if err != nil {
		log.Fatalf("failed to determine absolute data path: %s", err.Error())
	}
	dbConf := store.NewDBConfig(dsn, !onDisk)

	str := store.New(&store.StoreConfig{
		DBConf: dbConf,
		Dir:    dataPath,
		Tn:     raftTn,
	})

	// Set optional parameters on store.
	str.SnapshotThreshold = raftSnapThreshold
	str.HeartbeatTimeout, err = time.ParseDuration(raftHeartbeatTimeout)
	if err != nil {
		log.Fatalf("failed to parse Raft heartbeat timeout %s: %s", raftHeartbeatTimeout, err.Error())
	}
	str.ApplyTimeout, err = time.ParseDuration(raftApplyTimeout)
	if err != nil {
		log.Fatalf("failed to parse Raft apply timeout %s: %s", raftApplyTimeout, err.Error())
	}
	str.OpenTimeout, err = time.ParseDuration(raftOpenTimeout)
	if err != nil {
		log.Fatalf("failed to parse Raft open timeout %s: %s", raftOpenTimeout, err.Error())
	}

	// Determine join addresses, if necessary.
	ja, err := store.JoinAllowed(dataPath)
	if err != nil {
		log.Fatalf("unable to determine if join permitted: %s", err.Error())
	}

	var joins []string
	if ja {
		joins, err = determineJoinAddresses()
		if err != nil {
			log.Fatalf("unable to determine join addresses: %s", err.Error())
		}
	} else {
		log.Println("node is already member of cluster, skip determining join addresses")
	}

	// Now, open it.
	if err := str.Open(len(joins) == 0); err != nil {
		log.Fatalf("failed to open store: %s", err.Error())
	}

	// Create and configure cluster service.
	tn := mux.Listen(muxMetaHeader)
	cs := cluster.NewService(tn, str)
	if err := cs.Open(); err != nil {
		log.Fatalf("failed to open cluster service: %s", err.Error())
	}

	// Execute any requested join operation.
	if len(joins) > 0 {
		log.Println("join addresses are:", joins)
		advAddr := raftAddr
		if raftAdv != "" {
			advAddr = raftAdv
		}
		if j, err := cluster.Join(joins, advAddr, noVerify); err != nil {
			log.Fatalf("failed to join cluster at %s: %s", joins, err.Error())
		} else {
			log.Println("successfully joined cluster at", j)
		}

	} else {
		log.Println("no join addresses set")
	}

	// Publish to the cluster the mapping between this Raft address and API address.
	// The Raft layer broadcasts the resolved address, so use that as the key. But
	// only set different HTTP advertise address if set.
	apiAdv := httpAddr
	if httpAdv != "" {
		apiAdv = httpAdv
	}

	if err := publishAPIAddr(cs, raftTn.Addr().String(), apiAdv, publishPeerTimeout); err != nil {
		log.Fatalf("failed to set peer for %s to %s: %s", raftAddr, httpAddr, err.Error())
	}
	log.Printf("set peer for %s to %s", raftTn.Addr().String(), apiAdv)

	// Create HTTP server and load authentication information, if supplied.
	var s *httpd.Service
	if authFile != "" {
		f, err := os.Open(authFile)
		if err != nil {
			log.Fatalf("failed to open authentication file %s: %s", authFile, err.Error())
		}
		credentialStore := auth.NewCredentialsStore()
		if err := credentialStore.Load(f); err != nil {
			log.Fatalf("failed to load authentication file: %s", err.Error())
		}
		s = httpd.New(httpAddr, str, credentialStore)
	} else {
		s = httpd.New(httpAddr, str, nil)
	}

	s.CertFile = x509Cert
	s.KeyFile = x509Key
	s.Expvar = expvar
	s.Pprof = pprofEnabled
	s.BuildInfo = map[string]interface{}{
		"commit":     commit,
		"branch":     branch,
		"version":    version,
		"build_time": buildtime,
	}
	if err := s.Start(); err != nil {
		log.Fatalf("failed to start HTTP server: %s", err.Error())
	}

	terminate := make(chan os.Signal, 1)
	signal.Notify(terminate, os.Interrupt)
	<-terminate
	if err := str.Close(true); err != nil {
		log.Printf("failed to close store: %s", err.Error())
	}
	stopProfile()
	log.Println("rqlite server stopped")
}

func determineJoinAddresses() ([]string, error) {
	apiAdv := httpAddr
	if httpAdv != "" {
		apiAdv = httpAdv
	}

	var addrs []string
	if joinAddr != "" {
		// An explicit join address is first priority.
		addrs = append(addrs, joinAddr)
	}

	if discoID != "" {
		log.Printf("registering with Discovery Service at %s with ID %s", discoURL, discoID)
		c := disco.New(discoURL)
		r, err := c.Register(discoID, apiAdv)
		if err != nil {
			return nil, err
		}
		log.Println("Discovery Service responded with nodes:", r.Nodes)
		for _, a := range r.Nodes {
			if a != apiAdv {
				// Only other nodes can be joined.
				addrs = append(addrs, a)
			}
		}
	}

	return addrs, nil
}

func publishAPIAddr(c *cluster.Service, raftAddr, apiAddr string, t time.Duration) error {
	tck := time.NewTicker(publishPeerDelay)
	defer tck.Stop()
	tmr := time.NewTimer(t)
	defer tmr.Stop()

	for {
		select {
		case <-tck.C:
			if err := c.SetPeer(raftAddr, apiAddr); err != nil {
				log.Printf("failed to set peer for %s to %s: %s (retrying)",
					raftAddr, apiAddr, err.Error())
				continue
			}
			return nil
		case <-tmr.C:
			return fmt.Errorf("set peer timeout expired")
		}
	}
}

// prof stores the file locations of active profiles.
var prof struct {
	cpu *os.File
	mem *os.File
}

// startProfile initializes the CPU and memory profile, if specified.
func startProfile(cpuprofile, memprofile string) {
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatalf("failed to create CPU profile file at %s: %s", cpuprofile, err.Error())
		}
		log.Printf("writing CPU profile to: %s\n", cpuprofile)
		prof.cpu = f
		pprof.StartCPUProfile(prof.cpu)
	}

	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			log.Fatalf("failed to create memory profile file at %s: %s", cpuprofile, err.Error())
		}
		log.Printf("writing memory profile to: %s\n", memprofile)
		prof.mem = f
		runtime.MemProfileRate = 4096
	}
}

// stopProfile closes the CPU and memory profiles if they are running.
func stopProfile() {
	if prof.cpu != nil {
		pprof.StopCPUProfile()
		prof.cpu.Close()
		log.Println("CPU profiling stopped")
	}
	if prof.mem != nil {
		pprof.Lookup("heap").WriteTo(prof.mem, 0)
		prof.mem.Close()
		log.Println("memory profiling stopped")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"crypto/sha256"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"syscall"

	"github.com/zaolin/go-tpm/tpm"
	"golang.org/x/crypto/ed25519"
)

const (
	tpmDevice  string = "/dev/tpm0"
	mountPath  string = "/mnt/vboot"
	filesystem string = "ext3"
)

var (
	publicKey            = flag.String("pubkey", "/etc/sig.pub", "A public key which should verify the signature.")
	pcr                  = flag.Uint("pcr", 12, "The pcr index used for measuring the kernel before kexec.")
	bootDev              = flag.String("boot-device", "/dev/sda1", "The boot device which is used to kexec into a signed kernel.")
	linuxKernel          = flag.String("kernel", "/mnt/vboot/kernel", "Kernel image file path.")
	linuxKernelSignature = flag.String("kernel-sig", "/mnt/vboot/kernel.sig", "Kernel image signature file path.")
	initrd               = flag.String("initrd", "/mnt/vboot/initrd", "Initrd file path.")
	initrdSignature      = flag.String("initrd-sig", "/mnt/vboot/initrd.sig", "Initrd signature file path.")
	debug                = flag.Bool("debug", false, "Enables debug mode.")
	noTPM                = flag.Bool("no-tpm", false, "Disables tpm measuring process.")
)

func die(err error) {
	if *debug {
		panic(err)
	}
	if err := syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF); err != nil {
		log.Fatalf("reboot err: %v", err)
	}
}

func main() {
	flag.Parse()

	if err := os.MkdirAll(mountPath, os.ModePerm); err != nil {
		die(err)
	}

	if err := syscall.Mount(*bootDev, mountPath, filesystem, syscall.MS_RDONLY, ""); err != nil {
		die(err)
	}

	paths := []string{*publicKey, *linuxKernel, *linuxKernelSignature, *initrd, *initrdSignature}
	files := make(map[string][]byte)

	for _, element := range paths {
		data, err := ioutil.ReadFile(element)
		if err != nil {
			die(err)
		} else {
			files[element] = data
		}
	}

	kernelDigest := sha256.Sum256(files[*linuxKernel])
	initrdDigest := sha256.Sum256(files[*initrd])

	pcrDigestKernel := sha1.Sum(files[*linuxKernel])
	pcrDigestInitrd := sha1.Sum(files[*initrd])

	kernelSuccess := ed25519.Verify(files[*publicKey], kernelDigest[:], files[*linuxKernelSignature])
	initrdSuccess := ed25519.Verify(files[*publicKey], initrdDigest[:], files[*linuxKernelSignature])

	if !kernelSuccess || !initrdSuccess {
		die(nil)
	}

	if !*noTPM {
		rwc, err := tpm.OpenTPM(tpmDevice)
		if err != nil {
			die(err)
		}

		tpm.PcrExtend(rwc, uint32(*pcr), pcrDigestKernel)
		tpm.PcrExtend(rwc, uint32(*pcr), pcrDigestInitrd)
	}

	binary, lookErr := exec.LookPath("kexec")
	if lookErr != nil {
		die(lookErr)
	}

	args := []string{"kexec", "-initrd", *initrd, *linuxKernel}
	env := os.Environ()

	if execErr := syscall.Exec(binary, args, env); execErr != nil {
		die(execErr)
	}
}
<commit_msg>cmds/vboot: fix typo.<commit_after>package main

import (
	"crypto/sha1"
	"crypto/sha256"
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"syscall"

	"github.com/zaolin/go-tpm/tpm"
	"golang.org/x/crypto/ed25519"
)

const (
	tpmDevice  string = "/dev/tpm0"
	mountPath  string = "/mnt/vboot"
	filesystem string = "ext3"
)

var (
	publicKey            = flag.String("pubkey", "/etc/sig.pub", "A public key which should verify the signature.")
	pcr                  = flag.Uint("pcr", 12, "The pcr index used for measuring the kernel before kexec.")
	bootDev              = flag.String("boot-device", "/dev/sda1", "The boot device which is used to kexec into a signed kernel.")
	linuxKernel          = flag.String("kernel", "/mnt/vboot/kernel", "Kernel image file path.")
	linuxKernelSignature = flag.String("kernel-sig", "/mnt/vboot/kernel.sig", "Kernel image signature file path.")
	initrd               = flag.String("initrd", "/mnt/vboot/initrd", "Initrd file path.")
	initrdSignature      = flag.String("initrd-sig", "/mnt/vboot/initrd.sig", "Initrd signature file path.")
	debug                = flag.Bool("debug", false, "Enables debug mode.")
	noTPM                = flag.Bool("no-tpm", false, "Disables tpm measuring process.")
)

func die(err error) {
	if *debug {
		panic(err)
	}
	if err := syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF); err != nil {
		log.Fatalf("reboot err: %v", err)
	}
}

func main() {
	flag.Parse()

	if err := os.MkdirAll(mountPath, os.ModePerm); err != nil {
		die(err)
	}

	if err := syscall.Mount(*bootDev, mountPath, filesystem, syscall.MS_RDONLY, ""); err != nil {
		die(err)
	}

	paths := []string{*publicKey, *linuxKernel, *linuxKernelSignature, *initrd, *initrdSignature}
	files := make(map[string][]byte)

	for _, element := range paths {
		data, err := ioutil.ReadFile(element)
		if err != nil {
			die(err)
		} else {
			files[element] = data
		}
	}

	kernelDigest := sha256.Sum256(files[*linuxKernel])
	initrdDigest := sha256.Sum256(files[*initrd])

	pcrDigestKernel := sha1.Sum(files[*linuxKernel])
	pcrDigestInitrd := sha1.Sum(files[*initrd])

	kernelSuccess := ed25519.Verify(files[*publicKey], kernelDigest[:], files[*linuxKernelSignature])
	initrdSuccess := ed25519.Verify(files[*publicKey], initrdDigest[:], files[*initrdKernelSignature])

	if !kernelSuccess || !initrdSuccess {
		die(nil)
	}

	if !*noTPM {
		rwc, err := tpm.OpenTPM(tpmDevice)
		if err != nil {
			die(err)
		}

		tpm.PcrExtend(rwc, uint32(*pcr), pcrDigestKernel)
		tpm.PcrExtend(rwc, uint32(*pcr), pcrDigestInitrd)
	}

	binary, lookErr := exec.LookPath("kexec")
	if lookErr != nil {
		die(lookErr)
	}

	args := []string{"kexec", "-initrd", *initrd, *linuxKernel}
	env := os.Environ()

	if execErr := syscall.Exec(binary, args, env); execErr != nil {
		die(execErr)
	}
}
<|endoftext|>


<commit_before>package farm

// This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1)
// and a 128-bit hash equivalent to CityHash128 (v1.1.1).  It also provides
// a seeded 32-bit hash function similar to CityHash32.

func hash32Len13to24Seed(s []byte, seed uint32) uint32 {
	slen := len(s)
	a := fetch32(s, -4+(slen>>1))
	b := fetch32(s, 4)
	c := fetch32(s, slen-8)
	d := fetch32(s, (slen >> 1))
	e := fetch32(s, 0)
	f := fetch32(s, slen-4)
	h := d*c1 + uint32(slen) + seed
	a = rotate32(a, 12) + f
	h = mur(c, h) + a
	a = rotate32(a, 3) + c
	h = mur(e, h) + a
	a = rotate32(a+f, 12) + d
	h = mur(b^seed, h) + a
	return fmix(h)
}

func hash32Len0to4(s []byte, seed uint32) uint32 {
	slen := len(s)
	b := seed
	c := uint32(9)
	for i := 0; i < slen; i++ {
		v := int8(s[i])
		b = uint32(b*c1) + uint32(v)
		c ^= b
	}
	return fmix(mur(b, mur(uint32(slen), c)))
}

func hash128to64(x uint128) uint64 {
	// Murmur-inspired hashing.
	const mul uint64 = 0x9ddfea08eb382d69
	a := (x.lo ^ x.hi) * mul
	a ^= (a >> 47)
	b := (x.hi ^ a) * mul
	b ^= (b >> 47)
	b *= mul
	return b
}

type uint128 struct {
	lo uint64
	hi uint64
}

// A subroutine for CityHash128().  Returns a decent 128-bit hash for strings
// of any length representable in signed long.  Based on City and Murmur.
func cityMurmur(s []byte, seed uint128) uint128 {
	slen := len(s)
	a := seed.lo
	b := seed.hi
	c := uint64(0)
	d := uint64(0)
	l := slen - 16
	if l <= 0 { // len <= 16
		a = shiftMix(a*k1) * k1
		c = b*k1 + hashLen0to16(s)
		if slen >= 8 {
			d = shiftMix(a + fetch64(s, 0))
		} else {
			d = shiftMix(a + c)
		}
	} else { // len > 16
		c = hashLen16(fetch64(s, int(slen-8))+k1, a)
		d = hashLen16(b+uint64(slen), c+fetch64(s, int(slen-16)))
		a += d
		for {
			a ^= shiftMix(fetch64(s, 0)*k1) * k1
			a *= k1
			b ^= a
			c ^= shiftMix(fetch64(s, 8)*k1) * k1
			c *= k1
			d ^= c
			s = s[16:]
			l -= 16
			if l <= 0 {
				break
			}
		}
	}
	a = hashLen16(a, c)
	b = hashLen16(d, b)
	return uint128{a ^ b, hashLen16(b, a)}
}

func cityHash128WithSeed(s []byte, seed uint128) uint128 {
	slen := len(s)
	if slen < 128 {
		return cityMurmur(s, seed)
	}

	endIdx := ((slen - 1) / 128) * 128
	lastBlockIdx := endIdx + ((slen - 1) & 127) - 127
	last := s[lastBlockIdx:]

	// We expect len >= 128 to be the common case.  Keep 56 bytes of state:
	// v, w, x, y, and z.
	var v1, v2 uint64
	var w1, w2 uint64
	x := seed.lo
	y := seed.hi
	z := uint64(slen) * k1
	v1 = rotate64(y^k1, 49)*k1 + fetch64(s, 0)
	v2 = rotate64(v1, 42)*k1 + fetch64(s, 8)
	w1 = rotate64(y+z, 35)*k1 + x
	w2 = rotate64(x+fetch64(s, 88), 53) * k1

	// This is the same inner loop as CityHash64(), manually unrolled.
	for {
		x = rotate64(x+y+v1+fetch64(s, 8), 37) * k1
		y = rotate64(y+v2+fetch64(s, 48), 42) * k1
		x ^= w2
		y += v1 + fetch64(s, 40)
		z = rotate64(z+w1, 33) * k1
		v1, v2 = weakHashLen32WithSeeds(s, v2*k1, x+w1)
		w1, w2 = weakHashLen32WithSeeds(s[32:], z+w2, y+fetch64(s, 16))
		z, x = x, z
		s = s[64:]
		x = rotate64(x+y+v1+fetch64(s, 8), 37) * k1
		y = rotate64(y+v2+fetch64(s, 48), 42) * k1
		x ^= w2
		y += v1 + fetch64(s, 40)
		z = rotate64(z+w1, 33) * k1
		v1, v2 = weakHashLen32WithSeeds(s, v2*k1, x+w1)
		w1, w2 = weakHashLen32WithSeeds(s[32:], z+w2, y+fetch64(s, 16))
		z, x = x, z
		s = s[64:]
		slen -= 128
		if slen < 128 {
			break
		}
	}
	x += rotate64(v1+z, 49) * k0
	y = y*k0 + rotate64(w2, 37)
	z = z*k0 + rotate64(w1, 27)
	w1 *= 9
	v1 *= k0
	// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
	for tailDone := 0; tailDone < slen; {
		tailDone += 32
		y = rotate64(x+y, 42)*k0 + v2
		w1 += fetch64(last, 128-tailDone+16)
		x = x*k0 + w1
		z += w2 + fetch64(last, 128-tailDone)
		w2 += v1
		v1, v2 = weakHashLen32WithSeeds(last[128-tailDone:], v1+z, v2)
		v1 *= k0
	}

	// At this point our 56 bytes of state should contain more than
	// enough information for a strong 128-bit hash.  We use two
	// different 56-byte-to-8-byte hashes to get a 16-byte final result.
	x = hashLen16(x, v1)
	y = hashLen16(y+z, w1)
	return uint128{hashLen16(x+v2, w2) + y,
		hashLen16(x+w2, y+v2)}
}

func cityHash128(s []byte) uint128 {
	slen := len(s)
	if slen >= 16 {
		return cityHash128WithSeed(s[16:], uint128{fetch64(s, 0), fetch64(s, 8) + k0})
	}
	return cityHash128WithSeed(s, uint128{k0, k1})
}

// Fingerprint128 is a 128-bit fingerprint function for byte-slices
func Fingerprint128(s []byte) (lo, hi uint64) {
	h := cityHash128(s)
	return h.lo, h.hi
}

// Fingerprint64 is a 64-bit fingerprint function for byte-slices
func Fingerprint64(s []byte) uint64 {
	return Hash64(s)
}

// Fingerprint32 is a 32-bit fingerprint function for byte-slices
func Fingerprint32(s []byte) uint32 {
	return Hash32(s)
}

// Hash128 is a 128-bit hash function for byte-slices
func Hash128(s []byte) (lo, hi uint64) {
	return Fingerprint128(s)
}

// Hash128WithSeed is a 128-bit hash function for byte-slices and a 128-bit seed
func Hash128WithSeed(s []byte, seed0, seed1 uint64) (lo, hi uint64) {
	h := cityHash128WithSeed(s, uint128{seed0, seed1})
	return h.lo, h.hi
}
<commit_msg>Fix ineffassign errors<commit_after>package farm

// This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1)
// and a 128-bit hash equivalent to CityHash128 (v1.1.1).  It also provides
// a seeded 32-bit hash function similar to CityHash32.

func hash32Len13to24Seed(s []byte, seed uint32) uint32 {
	slen := len(s)
	a := fetch32(s, -4+(slen>>1))
	b := fetch32(s, 4)
	c := fetch32(s, slen-8)
	d := fetch32(s, (slen >> 1))
	e := fetch32(s, 0)
	f := fetch32(s, slen-4)
	h := d*c1 + uint32(slen) + seed
	a = rotate32(a, 12) + f
	h = mur(c, h) + a
	a = rotate32(a, 3) + c
	h = mur(e, h) + a
	a = rotate32(a+f, 12) + d
	h = mur(b^seed, h) + a
	return fmix(h)
}

func hash32Len0to4(s []byte, seed uint32) uint32 {
	slen := len(s)
	b := seed
	c := uint32(9)
	for i := 0; i < slen; i++ {
		v := int8(s[i])
		b = uint32(b*c1) + uint32(v)
		c ^= b
	}
	return fmix(mur(b, mur(uint32(slen), c)))
}

func hash128to64(x uint128) uint64 {
	// Murmur-inspired hashing.
	const mul uint64 = 0x9ddfea08eb382d69
	a := (x.lo ^ x.hi) * mul
	a ^= (a >> 47)
	b := (x.hi ^ a) * mul
	b ^= (b >> 47)
	b *= mul
	return b
}

type uint128 struct {
	lo uint64
	hi uint64
}

// A subroutine for CityHash128().  Returns a decent 128-bit hash for strings
// of any length representable in signed long.  Based on City and Murmur.
func cityMurmur(s []byte, seed uint128) uint128 {
	slen := len(s)
	a := seed.lo
	b := seed.hi
	var c uint64
	var d uint64
	l := slen - 16
	if l <= 0 { // len <= 16
		a = shiftMix(a*k1) * k1
		c = b*k1 + hashLen0to16(s)
		if slen >= 8 {
			d = shiftMix(a + fetch64(s, 0))
		} else {
			d = shiftMix(a + c)
		}
	} else { // len > 16
		c = hashLen16(fetch64(s, int(slen-8))+k1, a)
		d = hashLen16(b+uint64(slen), c+fetch64(s, int(slen-16)))
		a += d
		for {
			a ^= shiftMix(fetch64(s, 0)*k1) * k1
			a *= k1
			b ^= a
			c ^= shiftMix(fetch64(s, 8)*k1) * k1
			c *= k1
			d ^= c
			s = s[16:]
			l -= 16
			if l <= 0 {
				break
			}
		}
	}
	a = hashLen16(a, c)
	b = hashLen16(d, b)
	return uint128{a ^ b, hashLen16(b, a)}
}

func cityHash128WithSeed(s []byte, seed uint128) uint128 {
	slen := len(s)
	if slen < 128 {
		return cityMurmur(s, seed)
	}

	endIdx := ((slen - 1) / 128) * 128
	lastBlockIdx := endIdx + ((slen - 1) & 127) - 127
	last := s[lastBlockIdx:]

	// We expect len >= 128 to be the common case.  Keep 56 bytes of state:
	// v, w, x, y, and z.
	var v1, v2 uint64
	var w1, w2 uint64
	x := seed.lo
	y := seed.hi
	z := uint64(slen) * k1
	v1 = rotate64(y^k1, 49)*k1 + fetch64(s, 0)
	v2 = rotate64(v1, 42)*k1 + fetch64(s, 8)
	w1 = rotate64(y+z, 35)*k1 + x
	w2 = rotate64(x+fetch64(s, 88), 53) * k1

	// This is the same inner loop as CityHash64(), manually unrolled.
	for {
		x = rotate64(x+y+v1+fetch64(s, 8), 37) * k1
		y = rotate64(y+v2+fetch64(s, 48), 42) * k1
		x ^= w2
		y += v1 + fetch64(s, 40)
		z = rotate64(z+w1, 33) * k1
		v1, v2 = weakHashLen32WithSeeds(s, v2*k1, x+w1)
		w1, w2 = weakHashLen32WithSeeds(s[32:], z+w2, y+fetch64(s, 16))
		z, x = x, z
		s = s[64:]
		x = rotate64(x+y+v1+fetch64(s, 8), 37) * k1
		y = rotate64(y+v2+fetch64(s, 48), 42) * k1
		x ^= w2
		y += v1 + fetch64(s, 40)
		z = rotate64(z+w1, 33) * k1
		v1, v2 = weakHashLen32WithSeeds(s, v2*k1, x+w1)
		w1, w2 = weakHashLen32WithSeeds(s[32:], z+w2, y+fetch64(s, 16))
		z, x = x, z
		s = s[64:]
		slen -= 128
		if slen < 128 {
			break
		}
	}
	x += rotate64(v1+z, 49) * k0
	y = y*k0 + rotate64(w2, 37)
	z = z*k0 + rotate64(w1, 27)
	w1 *= 9
	v1 *= k0
	// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
	for tailDone := 0; tailDone < slen; {
		tailDone += 32
		y = rotate64(x+y, 42)*k0 + v2
		w1 += fetch64(last, 128-tailDone+16)
		x = x*k0 + w1
		z += w2 + fetch64(last, 128-tailDone)
		w2 += v1
		v1, v2 = weakHashLen32WithSeeds(last[128-tailDone:], v1+z, v2)
		v1 *= k0
	}

	// At this point our 56 bytes of state should contain more than
	// enough information for a strong 128-bit hash.  We use two
	// different 56-byte-to-8-byte hashes to get a 16-byte final result.
	x = hashLen16(x, v1)
	y = hashLen16(y+z, w1)
	return uint128{hashLen16(x+v2, w2) + y,
		hashLen16(x+w2, y+v2)}
}

func cityHash128(s []byte) uint128 {
	slen := len(s)
	if slen >= 16 {
		return cityHash128WithSeed(s[16:], uint128{fetch64(s, 0), fetch64(s, 8) + k0})
	}
	return cityHash128WithSeed(s, uint128{k0, k1})
}

// Fingerprint128 is a 128-bit fingerprint function for byte-slices
func Fingerprint128(s []byte) (lo, hi uint64) {
	h := cityHash128(s)
	return h.lo, h.hi
}

// Fingerprint64 is a 64-bit fingerprint function for byte-slices
func Fingerprint64(s []byte) uint64 {
	return Hash64(s)
}

// Fingerprint32 is a 32-bit fingerprint function for byte-slices
func Fingerprint32(s []byte) uint32 {
	return Hash32(s)
}

// Hash128 is a 128-bit hash function for byte-slices
func Hash128(s []byte) (lo, hi uint64) {
	return Fingerprint128(s)
}

// Hash128WithSeed is a 128-bit hash function for byte-slices and a 128-bit seed
func Hash128WithSeed(s []byte, seed0, seed1 uint64) (lo, hi uint64) {
	h := cityHash128WithSeed(s, uint128{seed0, seed1})
	return h.lo, h.hi
}
<|endoftext|>


<commit_before>package pgs

// FieldType describes the type of a Field.
type FieldType interface {
	// Field returns the parent Field of this type. While two FieldTypes might be
	// equivalent, each instance of a FieldType is tied to its Field.
	Field() Field

	// Name returns the TypeName for this Field, which represents the type of the
	// field as it would exist in Go source code.
	Name() TypeName

	// IsRepeated returns true if and only if the field is marked as "repeated".
	// While map fields may be labeled as repeated, this method will not return
	// true for them.
	IsRepeated() bool

	// IsMap returns true if the field is a map type.
	IsMap() bool

	// IsEnum returns true if the field is a singular enum value. Maps or
	// repeated fields containing enums will still return false.
	IsEnum() bool

	// IsEmbed returns true if the field is a singular message value. Maps or
	// repeated fields containing embeds will still return false.
	IsEmbed() bool

	// IsOptional returns true if the message's syntax is not Proto2 or
	// the field is prefixed as optional.
	IsOptional() bool

	// IsRequired returns true if and only if the field is prefixed as required.
	IsRequired() bool

	// IsSlice returns true if the field is represented in Go as a slice. This
	// method returns true only for repeated and bytes-type fields.
	IsSlice() bool

	// ProtoType returns the ProtoType value for this field.
	ProtoType() ProtoType

	// ProtoLabel returns the ProtoLabel value for this field.
	ProtoLabel() ProtoLabel

	// Imports includes all external packages required by this field.
	Imports() []Package

	// Enum returns the Enum associated with this FieldType. If IsEnum returns
	// false, this value will be nil.
	Enum() Enum

	// Embed returns the embedded Message associated with this FieldType. If
	// IsEmbed returns false, this value will be nil.
	Embed() Message

	// Element returns the FieldTypeElem representing the element component of
	// the type. Nil will be returned if IsRepeated and IsMap return false.
	Element() FieldTypeElem

	// Key returns the FieldTypeElem representing the key component of the type.
	// Nil will be return sif IsMap returns false.
	Key() FieldTypeElem

	setField(f Field)
	toElem() FieldTypeElem
}

type scalarT struct {
	fld  Field
	name TypeName
}

func (s *scalarT) Field() Field           { return s.fld }
func (s *scalarT) IsRepeated() bool       { return false }
func (s *scalarT) IsMap() bool            { return false }
func (s *scalarT) IsEnum() bool           { return false }
func (s *scalarT) IsEmbed() bool          { return false }
func (s *scalarT) Name() TypeName         { return s.name }
func (s *scalarT) IsSlice() bool          { return s.ProtoType().IsSlice() }
func (s *scalarT) ProtoType() ProtoType   { return ProtoType(s.fld.Descriptor().GetType()) }
func (s *scalarT) ProtoLabel() ProtoLabel { return ProtoLabel(s.fld.Descriptor().GetLabel()) }
func (s *scalarT) Imports() []Package     { return nil }
func (s *scalarT) setField(f Field)       { s.fld = f }
func (s *scalarT) Enum() Enum             { return nil }
func (s *scalarT) Embed() Message         { return nil }
func (s *scalarT) Element() FieldTypeElem { return nil }
func (s *scalarT) Key() FieldTypeElem     { return nil }

func (s *scalarT) IsOptional() bool {
	return !s.fld.Syntax().SupportsRequiredPrefix() || s.ProtoLabel() == Optional
}

func (s *scalarT) IsRequired() bool {
	return s.fld.Syntax().SupportsRequiredPrefix() && s.ProtoLabel() == Required
}

func (s *scalarT) toElem() FieldTypeElem {
	return &scalarE{
		typ:   s,
		ptype: s.ProtoType(),
		name:  s.name,
	}
}

type enumT struct {
	*scalarT
	enum Enum
}

func (e *enumT) Enum() Enum   { return e.enum }
func (e *enumT) IsEnum() bool { return true }

func (e *enumT) Imports() []Package {
	if pkg := e.enum.Package(); pkg.GoName() != e.fld.Package().GoName() {
		return []Package{pkg}
	}
	return nil
}

func (e *enumT) toElem() FieldTypeElem {
	return &enumE{
		scalarE: e.scalarT.toElem().(*scalarE),
		enum:    e.enum,
	}
}

type embedT struct {
	*scalarT
	msg Message
}

func (e *embedT) Embed() Message { return e.msg }
func (e *embedT) IsEmbed() bool  { return true }

func (e *embedT) Imports() []Package {
	if pkg := e.msg.Package(); pkg.GoName() != e.fld.Package().GoName() {
		return []Package{pkg}
	}
	return nil
}

func (e *embedT) toElem() FieldTypeElem {
	return &embedE{
		scalarE: e.scalarT.toElem().(*scalarE),
		msg:     e.msg,
	}
}

type repT struct {
	*scalarT
	el FieldTypeElem
}

func (r *repT) IsRepeated() bool       { return true }
func (r *repT) Element() FieldTypeElem { return r.el }
func (r *repT) IsSlice() bool          { return true }

func (r *repT) Imports() []Package { return r.el.Imports() }

func (r *repT) toElem() FieldTypeElem { panic("cannot convert repeated FieldType to FieldTypeElem") }

type mapT struct {
	*repT
	key FieldTypeElem
}

func (m *mapT) IsRepeated() bool   { return false }
func (m *mapT) IsMap() bool        { return true }
func (m *mapT) IsSlice() bool      { return false }
func (m *mapT) Key() FieldTypeElem { return m.key }

var (
	_ FieldType = (*scalarT)(nil)
	_ FieldType = (*enumT)(nil)
	_ FieldType = (*embedT)(nil)
	_ FieldType = (*repT)(nil)
	_ FieldType = (*mapT)(nil)
)
<commit_msg>Slightly improve FieldType documentation. (#12)<commit_after>package pgs

// FieldType describes the type of a Field.
type FieldType interface {
	// Field returns the parent Field of this type. While two FieldTypes might be
	// equivalent, each instance of a FieldType is tied to its Field.
	Field() Field

	// Name returns the TypeName for this Field, which represents the type of the
	// field as it would exist in Go source code.
	Name() TypeName

	// IsRepeated returns true if and only if the field is marked as "repeated".
	// While map fields may be labeled as repeated, this method will not return
	// true for them.
	IsRepeated() bool

	// IsMap returns true if the field is a map type.
	IsMap() bool

	// IsEnum returns true if the field is a singular enum value. Maps or
	// repeated fields containing enums will still return false.
	IsEnum() bool

	// IsEmbed returns true if the field is a singular message value. Maps or
	// repeated fields containing embeds will still return false.
	IsEmbed() bool

	// IsOptional returns true if the message's syntax is not Proto2 or
	// the field is prefixed as optional.
	IsOptional() bool

	// IsRequired returns true if and only if the field is prefixed as required.
	IsRequired() bool

	// IsSlice returns true if the field is represented in Go as a slice. This
	// method returns true only for repeated and bytes-type fields.
	IsSlice() bool

	// ProtoType returns the ProtoType value for this field.
	ProtoType() ProtoType

	// ProtoLabel returns the ProtoLabel value for this field.
	ProtoLabel() ProtoLabel

	// Imports includes all external packages required by this field.
	Imports() []Package

	// Enum returns the Enum associated with this FieldType. If IsEnum returns
	// false, this value will be nil.
	Enum() Enum

	// Embed returns the embedded Message associated with this FieldType. If
	// IsEmbed returns false, this value will be nil.
	Embed() Message

	// Element returns the FieldTypeElem representing the element component of
	// the type.
	//
	// For repeated fields, the returned type describes the type being repeated (i.e.,
	// the element type in the list implied by the repeated field).
	//
	// For maps, the returned type describes the type of values in the map.
	//
	// Nil will be returned if IsRepeated and IsMap both return false.
	Element() FieldTypeElem

	// Key returns the FieldTypeElem representing the key component of the type (i.e,
	// the type of keys in a map).
	//
	// Nil will be returned if IsMap returns false.
	Key() FieldTypeElem

	setField(f Field)
	toElem() FieldTypeElem
}

type scalarT struct {
	fld  Field
	name TypeName
}

func (s *scalarT) Field() Field           { return s.fld }
func (s *scalarT) IsRepeated() bool       { return false }
func (s *scalarT) IsMap() bool            { return false }
func (s *scalarT) IsEnum() bool           { return false }
func (s *scalarT) IsEmbed() bool          { return false }
func (s *scalarT) Name() TypeName         { return s.name }
func (s *scalarT) IsSlice() bool          { return s.ProtoType().IsSlice() }
func (s *scalarT) ProtoType() ProtoType   { return ProtoType(s.fld.Descriptor().GetType()) }
func (s *scalarT) ProtoLabel() ProtoLabel { return ProtoLabel(s.fld.Descriptor().GetLabel()) }
func (s *scalarT) Imports() []Package     { return nil }
func (s *scalarT) setField(f Field)       { s.fld = f }
func (s *scalarT) Enum() Enum             { return nil }
func (s *scalarT) Embed() Message         { return nil }
func (s *scalarT) Element() FieldTypeElem { return nil }
func (s *scalarT) Key() FieldTypeElem     { return nil }

func (s *scalarT) IsOptional() bool {
	return !s.fld.Syntax().SupportsRequiredPrefix() || s.ProtoLabel() == Optional
}

func (s *scalarT) IsRequired() bool {
	return s.fld.Syntax().SupportsRequiredPrefix() && s.ProtoLabel() == Required
}

func (s *scalarT) toElem() FieldTypeElem {
	return &scalarE{
		typ:   s,
		ptype: s.ProtoType(),
		name:  s.name,
	}
}

type enumT struct {
	*scalarT
	enum Enum
}

func (e *enumT) Enum() Enum   { return e.enum }
func (e *enumT) IsEnum() bool { return true }

func (e *enumT) Imports() []Package {
	if pkg := e.enum.Package(); pkg.GoName() != e.fld.Package().GoName() {
		return []Package{pkg}
	}
	return nil
}

func (e *enumT) toElem() FieldTypeElem {
	return &enumE{
		scalarE: e.scalarT.toElem().(*scalarE),
		enum:    e.enum,
	}
}

type embedT struct {
	*scalarT
	msg Message
}

func (e *embedT) Embed() Message { return e.msg }
func (e *embedT) IsEmbed() bool  { return true }

func (e *embedT) Imports() []Package {
	if pkg := e.msg.Package(); pkg.GoName() != e.fld.Package().GoName() {
		return []Package{pkg}
	}
	return nil
}

func (e *embedT) toElem() FieldTypeElem {
	return &embedE{
		scalarE: e.scalarT.toElem().(*scalarE),
		msg:     e.msg,
	}
}

type repT struct {
	*scalarT
	el FieldTypeElem
}

func (r *repT) IsRepeated() bool       { return true }
func (r *repT) Element() FieldTypeElem { return r.el }
func (r *repT) IsSlice() bool          { return true }

func (r *repT) Imports() []Package { return r.el.Imports() }

func (r *repT) toElem() FieldTypeElem { panic("cannot convert repeated FieldType to FieldTypeElem") }

type mapT struct {
	*repT
	key FieldTypeElem
}

func (m *mapT) IsRepeated() bool   { return false }
func (m *mapT) IsMap() bool        { return true }
func (m *mapT) IsSlice() bool      { return false }
func (m *mapT) Key() FieldTypeElem { return m.key }

var (
	_ FieldType = (*scalarT)(nil)
	_ FieldType = (*enumT)(nil)
	_ FieldType = (*embedT)(nil)
	_ FieldType = (*repT)(nil)
	_ FieldType = (*mapT)(nil)
)
<|endoftext|>


<commit_before>package main

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

// FileSystem is equivalent to fuse.FS, ie filesystem to be mounted. FileSystem
// is a bit misleading since Fuse allows even folders to be mounted.
type FileSystem struct {
	Transport

	// ExternalMountPath is path of folder in user VM to be mounted locally.
	ExternalMountPath string

	// InternalMountPath is path of folder in local to serve as mount point.
	InternalMountPath string

	// MountName is identifier for mount.
	MountName string

	// MountOptions is slice of options for mounting Fuse.
	MountOptions []fuse.MountOption
}

// Root returns root for FileSystem. Required by Fuse.
func (f *FileSystem) Root() (fs.Node, error) {
	return nil, nil
}

// Statfs returns metadata for FileSystem. Required by Fuse.
func (f *FileSystem) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error {
	return nil
}

func (f *FileSystem) Mount() error {
	c, err := fuse.Mount(
		f.InternalMountPath,
		fuse.FSName(f.MountName),
		fuse.Subtype(f.MountName),
		fuse.VolumeName(f.MountName),
		fuse.LocalVolume(),
	)
	if err != nil {
		return err
	}

	if err := fs.Serve(c, f); err != nil {
		return err
	}

	<-c.Ready

	return c.MountError
}
<commit_msg>remove unused FileSystem#MountOptions<commit_after>package main

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

// FileSystem is equivalent to fuse.FS, ie filesystem to be mounted. FileSystem
// is a bit misleading since Fuse allows even folders to be mounted.
type FileSystem struct {
	Transport

	// ExternalMountPath is path of folder in user VM to be mounted locally.
	ExternalMountPath string

	// InternalMountPath is path of folder in local to serve as mount point.
	InternalMountPath string

	// MountName is identifier for mount.
	MountName string
}

// Root returns root for FileSystem. Required by Fuse.
func (f *FileSystem) Root() (fs.Node, error) {
	return nil, nil
}

// Statfs returns metadata for FileSystem. Required by Fuse.
func (f *FileSystem) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error {
	return nil
}

func (f *FileSystem) Mount() error {
	c, err := fuse.Mount(
		f.InternalMountPath,
		fuse.FSName(f.MountName),
		fuse.Subtype(f.MountName),
		fuse.VolumeName(f.MountName),
		fuse.LocalVolume(),
	)
	if err != nil {
		return err
	}

	if err := fs.Serve(c, f); err != nil {
		return err
	}

	<-c.Ready

	return c.MountError
}
<|endoftext|>


<commit_before>package flagx_test

import (
	"bytes"
	"flag"
	"reflect"
	"strings"
	"testing"

	"github.com/dolmen-go/flagx"
)

// Check that our flagx.Value is the same as flag.Getter
var _ flag.Getter = flagx.Value(nil)

type varBuilder func() (flag.Getter, interface{})

type varTester struct {
	t        *testing.T
	flagName string
	buildVar varBuilder
}

func (tester *varTester) CheckParse(args []string, expected interface{}) {
	flagValue, pvalue := tester.buildVar()
	if reflect.TypeOf(pvalue).Kind() != reflect.Ptr {
		panic("varBuilder must return a pointer")
	}

	flags := flag.NewFlagSet("Test", flag.ContinueOnError)
	var output bytes.Buffer
	flags.SetOutput(&output)
	if args == nil {
		args = []string{}
	}

	flags.Var(flagValue, tester.flagName, "Value")

	if err := flags.Parse(args); err != nil {
		tester.t.Fatalf("Unexpected error: %s\nError output:\n%s", err, output.String())
	}
	// Dereference pvalue
	value := reflect.ValueOf(pvalue).Elem().Interface()
	if !reflect.DeepEqual(value, expected) {
		tester.t.Errorf("got %#v expected %#v", value, expected)
	}
	if output.Len() > 0 {
		tester.t.Errorf("Error output:\n%s", output.String())
	}
}

func (tester *varTester) CheckHelp() {
	flagValue, pvalue := tester.buildVar()
	if reflect.TypeOf(pvalue).Kind() != reflect.Ptr {
		panic("varBuilder must return a pointer")
	}

	flags := flag.NewFlagSet("Test", flag.ContinueOnError)
	var output bytes.Buffer
	flags.SetOutput(&output)

	flags.Var(flagValue, tester.flagName, "set arg `v`")

	err := flags.Parse([]string{"-h"})
	if err != flag.ErrHelp {
		tester.t.Fatalf("ErrHelp expected, got %q", err)
	}

	out := output.String()
	if !strings.Contains(out, "-"+tester.flagName) {
		tester.t.Errorf("Incorrect usage message: expected mention of `-%s`, but got:\n%s", tester.flagName, out)
	} else {
		tester.t.Logf("Help message:\n%s", out)
	}
}
<commit_msg>flagx_test: check Get() method of a flagx.Value<commit_after>package flagx_test

import (
	"bytes"
	"flag"
	"reflect"
	"strings"
	"testing"

	"github.com/dolmen-go/flagx"
)

// Check that our flagx.Value is the same as flag.Getter
var _ flag.Getter = flagx.Value(nil)

type varBuilder func() (flag.Getter, interface{})

type varTester struct {
	t        *testing.T
	flagName string
	buildVar varBuilder
}

func (tester *varTester) CheckParse(args []string, expected interface{}) {
	flagValue, pvalue := tester.buildVar()
	if reflect.TypeOf(pvalue).Kind() != reflect.Ptr {
		panic("varBuilder must return a pointer")
	}

	flags := flag.NewFlagSet("Test", flag.ContinueOnError)
	var output bytes.Buffer
	flags.SetOutput(&output)
	if args == nil {
		args = []string{}
	}

	flags.Var(flagValue, tester.flagName, "Value")

	if err := flags.Parse(args); err != nil {
		tester.t.Fatalf("Unexpected error: %s\nError output:\n%s", err, output.String())
	}
	// Dereference pvalue
	value := reflect.ValueOf(pvalue).Elem().Interface()
	if !reflect.DeepEqual(value, expected) {
		tester.t.Errorf("got %#v expected %#v", value, expected)
	}
	flgVar := flags.Lookup(tester.flagName).Value.(flag.Getter)
	valueFromFlag := flgVar.Get()
	if !reflect.DeepEqual(valueFromFlag, expected) {
		tester.t.Errorf("got %#v expected %#v", valueFromFlag, expected)
	}
	_ = flgVar.String()

	if output.Len() > 0 {
		tester.t.Errorf("Error output:\n%s", output.String())
	}
}

func (tester *varTester) CheckHelp() {
	flagValue, pvalue := tester.buildVar()
	if reflect.TypeOf(pvalue).Kind() != reflect.Ptr {
		panic("varBuilder must return a pointer")
	}

	flags := flag.NewFlagSet("Test", flag.ContinueOnError)
	var output bytes.Buffer
	flags.SetOutput(&output)

	flags.Var(flagValue, tester.flagName, "set arg `v`")

	err := flags.Parse([]string{"-h"})
	if err != flag.ErrHelp {
		tester.t.Fatalf("ErrHelp expected, got %q", err)
	}

	out := output.String()
	if !strings.Contains(out, "-"+tester.flagName) {
		tester.t.Errorf("Incorrect usage message: expected mention of `-%s`, but got:\n%s", tester.flagName, out)
	} else {
		tester.t.Logf("Help message:\n%s", out)
	}
}
<|endoftext|>