<commit_before>package cmd

import (
	"fmt"
	//"log"
	"os"
	"path"
	"regexp"
	"runtime"
	"strings"

	"github.com/Masterminds/cookoo"
	v "github.com/Masterminds/vcs"
)

func init() {
	// Precompile the regular expressions used to check VCS locations.
	for _, v := range vcsList {
		v.regex = regexp.MustCompile(v.pattern)
	}

	// Uncomment the line below and the log import to see the output
	// from the vcs commands executed for each project.
	//v.Logger = log.New(os.Stdout, "go-vcs", log.LstdFlags)
}

const (
	NoVCS = ""
	Git   = "git"
	Bzr   = "bzr"
	Hg    = "hg"
	Svn   = "svn"
)

// Get fetches a single package and puts it in vendor/.
//
// Params:
//	- package (string): Name of the package to get.
// 	- verbose (bool): default false
//
// Returns:
// 	- *Dependency: A dependency describing this package.
func Get(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	name := p.Get("package", "").(string)
	cfg := p.Get("conf", nil).(*Config)

	cwd, err := VendorPath(c)
	if err != nil {
		return nil, err
	}

	root := getRepoRootFromPackage(name)
	if len(root) == 0 {
		return nil, fmt.Errorf("Package name is required.")
	}

	if cfg.HasDependency(root) {
		return nil, fmt.Errorf("Package '%s' is already in glide.yaml", root)
	}

	dest := path.Join(cwd, root)
	repoUrl := "https://" + root
	repo, err := v.NewRepo(repoUrl, dest)
	if err != nil {
		return false, err
	}

	dep := &Dependency{
		Name:    root,
		VcsType: string(repo.Vcs()),

		// Should this assume a remote https root at all times?
		Repository: repoUrl,
	}
	subpkg := strings.TrimPrefix(name, root)
	if len(subpkg) > 0 && subpkg != "/" {
		dep.Subpackages = []string{subpkg}
	}

	if err := repo.Get(); err != nil {
		return dep, err
	}

	cfg.Imports = append(cfg.Imports, dep)

	return dep, nil
}

// GetImports iterates over the imported packages and gets them.
func GetImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", nil).(*Config)
	cwd, err := VendorPath(c)
	if err != nil {
		Error("Failed to prepare vendor directory: %s", err)
		return false, err
	}

	if len(cfg.Imports) == 0 {
		Info("No dependencies found. Nothing downloaded.\n")
		return false, nil
	}

	for _, dep := range cfg.Imports {
		if err := VcsGet(dep, cwd); err != nil {
			Warn("Skipped getting %s: %v\n", dep.Name, err)
		}
	}

	return true, nil
}

// UpdateImports iterates over the imported packages and updates them.
func UpdateImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", nil).(*Config)
	force := p.Get("force", true).(bool)
	cwd, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	if len(cfg.Imports) == 0 {
		Info("No dependencies found. Nothing updated.\n")
		return false, nil
	}

	for _, dep := range cfg.Imports {
		if err := VcsUpdate(dep, cwd, force); err != nil {
			Warn("Update failed for %s: %s\n", dep.Name, err)
		}
	}

	return true, nil
}

func SetReference(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", nil).(*Config)
	cwd, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	if len(cfg.Imports) == 0 {
		Info("No references set.\n")
		return false, nil
	}

	for _, dep := range cfg.Imports {
		if err := VcsVersion(dep, cwd); err != nil {
			Warn("Failed to set version on %s to %s: %s\n", dep.Name, dep.Reference, err)
		}
	}

	return true, nil
}

// filterArchOs indicates a dependency should be filtered out because it is
// the wrong GOOS or GOARCH.
func filterArchOs(dep *Dependency) bool {
	found := false
	if len(dep.Arch) > 0 {
		for _, a := range dep.Arch {
			if a == runtime.GOARCH {
				found = true
			}
		}
		// If it's not found, it should be filtered out.
		if !found {
			return true
		}
	}

	found = false
	if len(dep.Os) > 0 {
		for _, o := range dep.Os {
			if o == runtime.GOOS {
				found = true
			}
		}
		if !found {
			return true
		}

	}

	return false
}

func VcsExists(dep *Dependency, dest string) bool {
	repo, err := dep.GetRepo(dest)
	if err != nil {
		return false
	}

	return repo.CheckLocal()
}

// VcsGet figures out how to fetch a dependency, and then gets it.
//
// VcsGet installs into the dest.
func VcsGet(dep *Dependency, dest string) error {

	repo, err := dep.GetRepo(dest)
	if err != nil {
		return err
	}

	return repo.Get()
}

// VcsUpdate updates to a particular checkout based on the VCS setting.
func VcsUpdate(dep *Dependency, vend string, force bool) error {
	Info("Fetching updates for %s.\n", dep.Name)

	if filterArchOs(dep) {
		Info("%s is not used for %s/%s.\n", dep.Name, runtime.GOOS, runtime.GOARCH)
		return nil
	}

	dest := path.Join(vend, dep.Name)
	// If destination doesn't exist we need to perform an initial checkout.
	if _, err := os.Stat(dest); os.IsNotExist(err) {
		if err = VcsGet(dep, dest); err != nil {
			Warn("Unable to checkout %s\n", dep.Name)
			return err
		}
	} else {
		repo, err := dep.GetRepo(dest)

		// Tried to checkout a repo to a path that does not work. Either the
		// type or endpoint has changed. Force is being passed in so the old
		// location can be removed and replaced with the new one.
		// Warning, any changes in the old location will be deleted.
		// TODO: Put dirty checking in on the existing local checkout.
		if (err == v.ErrWrongVCS || err == v.ErrWrongRemote) && force == true {
			var newRemote string
			if len(dep.Repository) > 0 {
				newRemote = dep.Repository
			} else {
				newRemote = "https://" + dep.Name
			}

			Warn("Replacing %s with contents from %s\n", dep.Name, newRemote)
			rerr := os.RemoveAll(dest)
			if rerr != nil {
				return rerr
			}
			if err = VcsGet(dep, dest); err != nil {
				Warn("Unable to checkout %s\n", dep.Name)
				return err
			}
		} else if err != nil {
			return err
		} else {
			if err := repo.Update(); err != nil {
				Warn("Download failed.\n")
				return err
			}
		}
	}

	return nil
}

func VcsVersion(dep *Dependency, vend string) error {
	// If there is no refernece configured there is nothing to set.
	if dep.Reference == "" {
		return nil
	}

	Info("Setting version for %s.\n", dep.Name)

	cwd := path.Join(vend, dep.Name)
	repo, err := dep.GetRepo(cwd)
	if err != nil {
		return err
	}

	if err := repo.UpdateVersion(dep.Reference); err != nil {
		Error("Failed to set version to %s: %s\n", dep.Reference, err)
		return err
	}

	return nil
}

func VcsLastCommit(dep *Dependency, vend string) (string, error) {
	cwd := path.Join(vend, dep.Name)
	repo, err := dep.GetRepo(cwd)
	if err != nil {
		return "", err
	}

	version, err := repo.Version()
	if err != nil {
		return "", err
	}

	return version, nil
}

// From a package name find the root repo. For example,
// the package github.com/Masterminds/cookoo/io has a root repo
// at github.com/Masterminds/cookoo
func getRepoRootFromPackage(pkg string) string {
	for _, v := range vcsList {
		m := v.regex.FindStringSubmatch(pkg)
		if m == nil {
			continue
		}

		if m[1] != "" {
			return m[1]
		}
	}

	// Default to returning the package name passed in if no matches.
	// Should this be an error?
	return pkg
}

type vcsInfo struct {
	host    string
	pattern string
	regex   *regexp.Regexp
}

var vcsList = []*vcsInfo{
	{
		host:    "github.com",
		pattern: `^(?P<rootpkg>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
	},
	{
		host:    "bitbucket.org",
		pattern: `^(?P<rootpkg>bitbucket\.org/([A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
	},
	{
		host:    "launchpad.net",
		pattern: `^(?P<rootpkg>launchpad\.net/(([A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
	},
	{
		host:    "git.launchpad.net",
		pattern: `^(?P<rootpkg>git\.launchpad\.net/(([A-Za-z0-9_.\-]+)|~[A-Za-z0-9_.\-]+/(\+git|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))$`,
	},
	{
		host:    "go.googlesource.com",
		pattern: `^(?P<rootpkg>go\.googlesource\.com/[A-Za-z0-9_.\-]+/?)$`,
	},
	// TODO: Once Google Code becomes fully deprecated this can be removed.
	{
		host:    "code.google.com",
		pattern: `^(?P<rootpkg>code\.google\.com/[pr]/([a-z0-9\-]+)(\.([a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
	},
	// Alternative Google setup. This is the previous structure but it still works... until Google Code goes away.
	{
		pattern: `^(?P<rootpkg>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(/.*)?$`,
	},
	// If none of the previous detect the type they will fall to this looking for the type in a generic sense
	// by the extension to the path.
	{
		pattern: `^(?P<rootpkg>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
	},
}
<commit_msg>Added code comment.<commit_after>package cmd

import (
	"fmt"
	//"log"
	"os"
	"path"
	"regexp"
	"runtime"
	"strings"

	"github.com/Masterminds/cookoo"
	v "github.com/Masterminds/vcs"
)

func init() {
	// Precompile the regular expressions used to check VCS locations.
	for _, v := range vcsList {
		v.regex = regexp.MustCompile(v.pattern)
	}

	// Uncomment the line below and the log import to see the output
	// from the vcs commands executed for each project.
	//v.Logger = log.New(os.Stdout, "go-vcs", log.LstdFlags)
}

const (
	NoVCS = ""
	Git   = "git"
	Bzr   = "bzr"
	Hg    = "hg"
	Svn   = "svn"
)

// Get fetches a single package and puts it in vendor/.
//
// Params:
//	- package (string): Name of the package to get.
// 	- verbose (bool): default false
//
// Returns:
// 	- *Dependency: A dependency describing this package.
func Get(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	name := p.Get("package", "").(string)
	cfg := p.Get("conf", nil).(*Config)

	cwd, err := VendorPath(c)
	if err != nil {
		return nil, err
	}

	root := getRepoRootFromPackage(name)
	if len(root) == 0 {
		return nil, fmt.Errorf("Package name is required.")
	}

	if cfg.HasDependency(root) {
		return nil, fmt.Errorf("Package '%s' is already in glide.yaml", root)
	}

	dest := path.Join(cwd, root)
	repoUrl := "https://" + root
	repo, err := v.NewRepo(repoUrl, dest)
	if err != nil {
		return false, err
	}

	dep := &Dependency{
		Name:    root,
		VcsType: string(repo.Vcs()),

		// Should this assume a remote https root at all times?
		Repository: repoUrl,
	}
	subpkg := strings.TrimPrefix(name, root)
	if len(subpkg) > 0 && subpkg != "/" {
		dep.Subpackages = []string{subpkg}
	}

	if err := repo.Get(); err != nil {
		return dep, err
	}

	cfg.Imports = append(cfg.Imports, dep)

	return dep, nil
}

// GetImports iterates over the imported packages and gets them.
func GetImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", nil).(*Config)
	cwd, err := VendorPath(c)
	if err != nil {
		Error("Failed to prepare vendor directory: %s", err)
		return false, err
	}

	if len(cfg.Imports) == 0 {
		Info("No dependencies found. Nothing downloaded.\n")
		return false, nil
	}

	for _, dep := range cfg.Imports {
		if err := VcsGet(dep, cwd); err != nil {
			Warn("Skipped getting %s: %v\n", dep.Name, err)
		}
	}

	return true, nil
}

// UpdateImports iterates over the imported packages and updates them.
func UpdateImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", nil).(*Config)
	force := p.Get("force", true).(bool)
	cwd, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	if len(cfg.Imports) == 0 {
		Info("No dependencies found. Nothing updated.\n")
		return false, nil
	}

	for _, dep := range cfg.Imports {
		if err := VcsUpdate(dep, cwd, force); err != nil {
			Warn("Update failed for %s: %s\n", dep.Name, err)
		}
	}

	return true, nil
}

func SetReference(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", nil).(*Config)
	cwd, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	if len(cfg.Imports) == 0 {
		Info("No references set.\n")
		return false, nil
	}

	for _, dep := range cfg.Imports {
		if err := VcsVersion(dep, cwd); err != nil {
			Warn("Failed to set version on %s to %s: %s\n", dep.Name, dep.Reference, err)
		}
	}

	return true, nil
}

// filterArchOs indicates a dependency should be filtered out because it is
// the wrong GOOS or GOARCH.
func filterArchOs(dep *Dependency) bool {
	found := false
	if len(dep.Arch) > 0 {
		for _, a := range dep.Arch {
			if a == runtime.GOARCH {
				found = true
			}
		}
		// If it's not found, it should be filtered out.
		if !found {
			return true
		}
	}

	found = false
	if len(dep.Os) > 0 {
		for _, o := range dep.Os {
			if o == runtime.GOOS {
				found = true
			}
		}
		if !found {
			return true
		}

	}

	return false
}

func VcsExists(dep *Dependency, dest string) bool {
	repo, err := dep.GetRepo(dest)
	if err != nil {
		return false
	}

	return repo.CheckLocal()
}

// VcsGet figures out how to fetch a dependency, and then gets it.
//
// VcsGet installs into the dest.
func VcsGet(dep *Dependency, dest string) error {

	repo, err := dep.GetRepo(dest)
	if err != nil {
		return err
	}

	return repo.Get()
}

// VcsUpdate updates to a particular checkout based on the VCS setting.
func VcsUpdate(dep *Dependency, vend string, force bool) error {
	Info("Fetching updates for %s.\n", dep.Name)

	if filterArchOs(dep) {
		Info("%s is not used for %s/%s.\n", dep.Name, runtime.GOOS, runtime.GOARCH)
		return nil
	}

	dest := path.Join(vend, dep.Name)
	// If destination doesn't exist we need to perform an initial checkout.
	if _, err := os.Stat(dest); os.IsNotExist(err) {
		if err = VcsGet(dep, dest); err != nil {
			Warn("Unable to checkout %s\n", dep.Name)
			return err
		}
	} else {
		repo, err := dep.GetRepo(dest)

		// Tried to checkout a repo to a path that does not work. Either the
		// type or endpoint has changed. Force is being passed in so the old
		// location can be removed and replaced with the new one.
		// Warning, any changes in the old location will be deleted.
		// TODO: Put dirty checking in on the existing local checkout.
		if (err == v.ErrWrongVCS || err == v.ErrWrongRemote) && force == true {
			var newRemote string
			if len(dep.Repository) > 0 {
				newRemote = dep.Repository
			} else {
				newRemote = "https://" + dep.Name
			}

			Warn("Replacing %s with contents from %s\n", dep.Name, newRemote)
			rerr := os.RemoveAll(dest)
			if rerr != nil {
				return rerr
			}
			if err = VcsGet(dep, dest); err != nil {
				Warn("Unable to checkout %s\n", dep.Name)
				return err
			}
		} else if err != nil {
			return err
		} else {
			if err := repo.Update(); err != nil {
				Warn("Download failed.\n")
				return err
			}
		}
	}

	return nil
}

func VcsVersion(dep *Dependency, vend string) error {
	// If there is no refernece configured there is nothing to set.
	if dep.Reference == "" {
		return nil
	}

	Info("Setting version for %s.\n", dep.Name)

	cwd := path.Join(vend, dep.Name)
	repo, err := dep.GetRepo(cwd)
	if err != nil {
		return err
	}

	if err := repo.UpdateVersion(dep.Reference); err != nil {
		Error("Failed to set version to %s: %s\n", dep.Reference, err)
		return err
	}

	return nil
}

// VcsLastCommit gets the last commit ID from the given dependency.
func VcsLastCommit(dep *Dependency, vend string) (string, error) {
	cwd := path.Join(vend, dep.Name)
	repo, err := dep.GetRepo(cwd)
	if err != nil {
		return "", err
	}

	version, err := repo.Version()
	if err != nil {
		return "", err
	}

	return version, nil
}

// From a package name find the root repo. For example,
// the package github.com/Masterminds/cookoo/io has a root repo
// at github.com/Masterminds/cookoo
func getRepoRootFromPackage(pkg string) string {
	for _, v := range vcsList {
		m := v.regex.FindStringSubmatch(pkg)
		if m == nil {
			continue
		}

		if m[1] != "" {
			return m[1]
		}
	}

	// Default to returning the package name passed in if no matches.
	// Should this be an error?
	return pkg
}

type vcsInfo struct {
	host    string
	pattern string
	regex   *regexp.Regexp
}

var vcsList = []*vcsInfo{
	{
		host:    "github.com",
		pattern: `^(?P<rootpkg>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
	},
	{
		host:    "bitbucket.org",
		pattern: `^(?P<rootpkg>bitbucket\.org/([A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
	},
	{
		host:    "launchpad.net",
		pattern: `^(?P<rootpkg>launchpad\.net/(([A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
	},
	{
		host:    "git.launchpad.net",
		pattern: `^(?P<rootpkg>git\.launchpad\.net/(([A-Za-z0-9_.\-]+)|~[A-Za-z0-9_.\-]+/(\+git|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))$`,
	},
	{
		host:    "go.googlesource.com",
		pattern: `^(?P<rootpkg>go\.googlesource\.com/[A-Za-z0-9_.\-]+/?)$`,
	},
	// TODO: Once Google Code becomes fully deprecated this can be removed.
	{
		host:    "code.google.com",
		pattern: `^(?P<rootpkg>code\.google\.com/[pr]/([a-z0-9\-]+)(\.([a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
	},
	// Alternative Google setup. This is the previous structure but it still works... until Google Code goes away.
	{
		pattern: `^(?P<rootpkg>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(/.*)?$`,
	},
	// If none of the previous detect the type they will fall to this looking for the type in a generic sense
	// by the extension to the path.
	{
		pattern: `^(?P<rootpkg>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
	},
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/valyala/fasthttp"
	"github.com/valyala/httpteleport"
	"github.com/valyala/tcplisten"
	"log"
	"time"
)

var (
	reusePort = flag.Bool("reusePort", false, "Whether to enable SO_REUSEPORT on listenAddr")

	batchDelay  = flag.Duration("batchDelay", time.Millisecond, "How long to wait before flushing incoming requests to httpts")
	concurrency = flag.Int("concurrency", 100000, "The maximum number of concurrent incoming connections the client may handle")
	listenAddr  = flag.String("listenAddr", ":8042", "TCP address to listen to for incoming HTTP requests")
	serverAddr  = flag.String("serverAddr", "127.0.0.1:8043", "TCP address of httpts server to route incoming requests to")
	timeout     = flag.Duration("timeout", time.Second, "Maximum duration for waiting response from httpteleport server")
)

func main() {
	flag.Parse()

	c = httpteleport.Client{
		Addr:               *serverAddr,
		MaxBatchDelay:      *batchDelay,
		MaxPendingRequests: *concurrency,
	}

	cfg := tcplisten.Config{
		ReusePort: *reusePort,
	}
	ln, err := cfg.NewListener("tcp4", *listenAddr)
	if err != nil {
		log.Fatalf("cannot listen to -listenAddr=%q: %s", *listenAddr, err)
	}

	s := fasthttp.Server{
		Handler:     requestHandler,
		Concurrency: *concurrency,
	}

	log.Printf("listening for HTTP requests on %q", *listenAddr)
	log.Printf("forwarding requests to httpts %q", *serverAddr)

	if err := s.Serve(ln); err != nil {
		log.Fatalf("error in fasthttp server: %s", err)
	}
}

var c httpteleport.Client

func requestHandler(ctx *fasthttp.RequestCtx) {
	err := c.DoTimeout(&ctx.Request, &ctx.Response, *timeout)
	if err == nil {
		return
	}

	ctx.ResetBody()
	fmt.Fprintf(ctx, "httptc proxying error: %s", err)
	if err == httpteleport.ErrTimeout {
		ctx.SetStatusCode(fasthttp.StatusGatewayTimeout)
	} else {
		ctx.SetStatusCode(fasthttp.StatusBadGateway)
	}
}
<commit_msg>httptc: pass client ip via X-Forwarded-For header<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/valyala/fasthttp"
	"github.com/valyala/httpteleport"
	"github.com/valyala/tcplisten"
	"log"
	"time"
)

var (
	reusePort = flag.Bool("reusePort", false, "Whether to enable SO_REUSEPORT on listenAddr")

	batchDelay  = flag.Duration("batchDelay", time.Millisecond, "How long to wait before flushing incoming requests to httpts")
	concurrency = flag.Int("concurrency", 100000, "The maximum number of concurrent incoming connections the client may handle")
	listenAddr  = flag.String("listenAddr", ":8042", "TCP address to listen to for incoming HTTP requests")
	serverAddr  = flag.String("serverAddr", "127.0.0.1:8043", "TCP address of httpts server to route incoming requests to")
	timeout     = flag.Duration("timeout", time.Second, "Maximum duration for waiting response from httpteleport server")
)

func main() {
	flag.Parse()

	c = httpteleport.Client{
		Addr:               *serverAddr,
		MaxBatchDelay:      *batchDelay,
		MaxPendingRequests: *concurrency,
	}

	cfg := tcplisten.Config{
		ReusePort: *reusePort,
	}
	ln, err := cfg.NewListener("tcp4", *listenAddr)
	if err != nil {
		log.Fatalf("cannot listen to -listenAddr=%q: %s", *listenAddr, err)
	}

	s := fasthttp.Server{
		Handler:     requestHandler,
		Concurrency: *concurrency,
	}

	log.Printf("listening for HTTP requests on %q", *listenAddr)
	log.Printf("forwarding requests to httpts %q", *serverAddr)

	if err := s.Serve(ln); err != nil {
		log.Fatalf("error in fasthttp server: %s", err)
	}
}

var c httpteleport.Client

func requestHandler(ctx *fasthttp.RequestCtx) {
	var buf [16]byte
	ip := fasthttp.AppendIPv4(buf[:0], ctx.RemoteIP())
	ctx.Request.Header.SetBytesV("X-Forwarded-For", ip)

	err := c.DoTimeout(&ctx.Request, &ctx.Response, *timeout)
	if err == nil {
		return
	}

	ctx.ResetBody()
	fmt.Fprintf(ctx, "httptc proxying error: %s", err)
	if err == httpteleport.ErrTimeout {
		ctx.SetStatusCode(fasthttp.StatusGatewayTimeout)
	} else {
		ctx.SetStatusCode(fasthttp.StatusBadGateway)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"launchpad.net/gnuflag"
	"launchpad.net/juju/go/cmd"
	"launchpad.net/juju/go/state"
	"regexp"
	"strings"
)

// requiredError is useful when complaining about missing command-line options.
func requiredError(name string) error {
	return fmt.Errorf("--%s option must be set", name)
}

// stateInfoValue implements gnuflag.Value on a state.Info.
type stateInfoValue state.Info

var validAddr = regexp.MustCompile("^.*:[0-9]+$")

// Set splits value into zookeeper addresses.
func (v *stateInfoValue) Set(value string) error {
	v.Addrs = strings.Split(value, ",")
	for _, addr := range v.Addrs {
		if !validAddr.MatchString(addr) {
			return fmt.Errorf("%q is not a valid zookeeper address", addr)
		}
	}
	return nil
}

// String returns the original value passed to Set.
func (v *stateInfoValue) String() string {
	if v.Addrs != nil {
		return strings.Join(v.Addrs, ",")
	}
	return ""
}

// stateInfoVar sets up a gnuflag flag analagously to FlagSet.*Var methods.
func stateInfoVar(fs *gnuflag.FlagSet, target *state.Info, name string, value []string, usage string) {
	target.Addrs = value
	fs.Var((*stateInfoValue)(target), name, usage)
}

// agent provides common agent functionality.
type agent struct {
	name      string
	jujuDir   string // Defaults to "/var/lib/juju".
	stateInfo state.Info
}

// Info returns a decription of the agent command.
func (a *agent) Info() *cmd.Info {
	return &cmd.Info{a.name, "", fmt.Sprintf("run a juju %s agent", a.name), ""}
}

// addFlags injects common agent flags into f.
func (a *agent) addFlags(f *gnuflag.FlagSet) {
	f.StringVar(&a.jujuDir, "juju-directory", "/var/lib/juju", "juju working directory")
	stateInfoVar(f, &a.stateInfo, "zookeeper-servers", nil, "zookeeper servers to connect to")
}

// checkArgs checks that required flags have been set and that args is empty.
func (a *agent) checkArgs(args []string) error {
	if a.jujuDir == "" {
		return requiredError("juju-directory")
	}
	if a.stateInfo.Addrs == nil {
		return requiredError("zookeeper-servers")
	}
	return cmd.CheckEmpty(args)
}
<commit_msg>wip, needs merge<commit_after>package main

import (
	"fmt"
	"launchpad.net/gnuflag"
	"launchpad.net/juju/go/cmd"
	"launchpad.net/juju/go/state"
	"regexp"
	"strings"
)

// requiredError is useful when complaining about missing command-line options.
func requiredError(name string) error {
	return fmt.Errorf("--%s option must be set", name)
}

// stateInfoValue implements gnuflag.Value on a state.Info.
type stateInfoValue state.Info

var validAddr = regexp.MustCompile("^.+:[0-9]+$")

// Set splits the comma-separated list of ZooKeeper addresses and stores
// onto v's Addrs. Addresses must include port numbers.
func (v *stateInfoValue) Set(value string) error {
	addrs := strings.Split(value, ",")
	for _, addr := range addrs {
		if !validAddr.MatchString(addr) {
			return fmt.Errorf("%q is not a valid zookeeper address", addr)
		}
	}
	v.Addrs = addrs
	return nil
}

// String returns the list of ZooKeeper addresses joined by commas.
func (v *stateInfoValue) String() string {
	if v.Addrs != nil {
		return strings.Join(v.Addrs, ",")
	}
	return ""
}

// stateInfoVar sets up a gnuflag flag analagously to FlagSet.*Var methods.
func stateInfoVar(fs *gnuflag.FlagSet, target *state.Info, name string, value []string, usage string) {
	target.Addrs = value
	fs.Var((*stateInfoValue)(target), name, usage)
}

// commonFlags handles command-line flags shared by all agents.
type agent struct {
	JujuDir   string // Defaults to "/var/lib/juju".
	StateInfo state.Info
}

// addFlags injects common agent flags into f.
func (a *agent) addFlags(f *gnuflag.FlagSet) {
	f.StringVar(&a.JujuDir, "juju-directory", "/var/lib/juju", "juju working directory")
	stateInfoVar(f, &a.StateInfo, "zookeeper-servers", nil, "zookeeper servers to connect to")
}

// checkArgs checks that required flags have been set and that args is empty.
func (a *agent) checkArgs(args []string) error {
	if a.JujuDir == "" {
		return requiredError("juju-directory")
	}
	if a.StateInfo.Addrs == nil {
		return requiredError("zookeeper-servers")
	}
	return cmd.CheckEmpty(args)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package main

import (
	"fmt"
	"os"
	"strings"

	"k8s.io/kops/util/pkg/ui"

	"github.com/spf13/cobra"
	flag "github.com/spf13/pflag"
)

var confirmDelete bool

// deleteCmd represents the delete command
var deleteCmd = &cobra.Command{
	Use:        "delete",
	Short:      "delete clusters",
	Long:       `Delete clusters`,
	SuggestFor: []string{"rm"},
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		// cobra doesn't give you the full arg list even though it should.
		flag.Parse()
		args = flag.Args()

		// args should be [delete, resource, resource name]
		// if there are less args than 3 confirming isnt necessary as the child command will fail
		if !confirmDelete && len(args) >= 3 {
			message := fmt.Sprintf(
				"Do you really want to %s? This action cannot be undone. (Y/n)",
				strings.Join(args, " "),
			)
			if !ui.GetConfirm(os.Stdout, message, "") {
				os.Exit(1)
			}

		}
	},
}

func init() {
	deleteCmd.PersistentFlags().BoolVarP(&confirmDelete, "yes", "y", false, "Auto confirm deletetion.")

	rootCommand.AddCommand(deleteCmd)
}
<commit_msg>using Parse here causes Cobra's own use parsing to screw up.<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package main

import (
	"fmt"
	"os"
	"strings"

	"k8s.io/kops/util/pkg/ui"

	"github.com/spf13/cobra"
)

var confirmDelete bool

// deleteCmd represents the delete command
var deleteCmd = &cobra.Command{
	Use:        "delete",
	Short:      "delete clusters",
	Long:       `Delete clusters`,
	SuggestFor: []string{"rm"},
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		// cobra doesn't give you the full arg list even though it should.
		args = os.Args

		// args should be [delete, resource, resource name]
		// if there are less args than 3 confirming isnt necessary as the child command will fail
		if !confirmDelete && len(args) >= 3 {
			message := fmt.Sprintf(
				"Do you really want to %s? This action cannot be undone. (Y/n)",
				strings.Join(args, " "),
			)
			if !ui.GetConfirm(os.Stdout, message, "") {
				os.Exit(1)
			}

		}
	},
}

func init() {
	deleteCmd.PersistentFlags().BoolVarP(&confirmDelete, "yes", "y", false, "Auto confirm deletetion.")

	rootCommand.AddCommand(deleteCmd)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"github.com/tdewolff/minify/js"
	"github.com/tdewolff/minify/json"
	"github.com/tdewolff/minify/svg"
	"github.com/tdewolff/minify/xml"
)

var extMime = map[string]string{
	".css":  "text/css",
	".html": "text/html",
	".js":   "application/javascript",
	".json": "application/json",
	".svg":  "image/svg+xml",
	".xml":  "text/xml",
}

func main() {
	input := ""
	output := ""
	ext := ""
	directory := ""
	recursive := false

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] [file]\nOptions:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&output, "o", "", "Output file (stdout when empty)")
	flag.StringVar(&ext, "x", "", "File extension (css, html, js, json, svg or xml), optional for input files")
	flag.StringVar(&directory, "d", "", "Directory to search for files")
	flag.BoolVar(&recursive, "r", false, "Recursively minify everything")
	flag.Parse()
	if len(flag.Args()) > 0 {
		input = flag.Arg(0)
	}

	mediatype := ""
	r := io.Reader(os.Stdin)
	w := io.Writer(os.Stdout)
	m := minify.New()
	m.AddFunc("text/css", css.Minify)
	m.AddFunc("text/html", html.Minify)
	m.AddFunc("application/javascript", js.Minify)
	m.AddFunc("image/svg+xml", svg.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)

	filenames := make(map[string]string)
	if directory != "" {
		filenames = ioNames(directory, recursive)
	} else {
		filenames[input] = output
	}

	for in, out := range filenames {
		input = in
		output = out
		if input != "" {
			in, err := os.Open(input)
			if err != nil {
				fmt.Println("Error:", err)
				os.Exit(1)
			}
			defer in.Close()
			r = in
			if input == output {
				b := &bytes.Buffer{}
				io.Copy(b, r)
				r = b
			}
			if ext == "" {
				ext = filepath.Ext(input)
			}
		}
		if output != "" {
			out, err := os.Create(output)
			if err != nil {
				fmt.Println("Error:", err)
				os.Exit(1)
			}
			defer out.Close()
			w = out
		}
		if ext != "" {
			mediatype = extMime[ext]
		}
		if err := m.Minify(mediatype, w, r); err != nil {
			if err == minify.ErrNotExist {
				io.Copy(w, r)
			} else {
				fmt.Println("Error:", err)
				os.Exit(1)
			}
		}
	}
}

// ioNames returns a map of input paths and output paths.
func ioNames(startDir string, recursive bool) map[string]string {
	names := map[string]string{}
	if recursive {
		filepath.Walk(startDir, func(path string, info os.FileInfo, _ error) error {
			if !validFile(info) {
				return nil
			}
			names[path] = minExt(path)
			return nil
		})
		return names
	}
	infos, err := ioutil.ReadDir(startDir)
	if err != nil {
		return map[string]string{}
	}
	for _, info := range infos {
		if !validFile(info) {
			continue
		}
		fullPath := filepath.Join(startDir, info.Name())
		names[fullPath] = minExt(fullPath)
	}
	return names
}

// validFile checks to see if a file is a directory, hidden, already has the
// minified extension, or if it's one of the minifiable extensions.
func validFile(info os.FileInfo) bool {
	if info.IsDir() {
		return false
	}
	if info.Name()[0] == '.' {
		return false
	}
	// don't want to reminify already minified files
	if strings.Contains(info.Name(), ".min.") {
		return false
	}
	_, exists := extMime[strings.ToLower(filepath.Ext(info.Name()))]
	return exists
}

// minExt adds .min before a file's extension. If a file doesn't have an
// extension then .min will become the file's extension.
func minExt(path string) string {
	dot := strings.LastIndex(path, ".")
	if dot == -1 {
		return path + ".min"
	}
	return path[:dot] + ".min" + path[dot:]
}
<commit_msg>Refactor<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"github.com/tdewolff/minify/js"
	"github.com/tdewolff/minify/json"
	"github.com/tdewolff/minify/svg"
	"github.com/tdewolff/minify/xml"
)

var extMime = map[string]string{
	".css":  "text/css",
	".html": "text/html",
	".js":   "application/javascript",
	".json": "application/json",
	".svg":  "image/svg+xml",
	".xml":  "text/xml",
}

func main() {
	input := ""
	output := ""
	ext := ""
	directory := ""
	recursive := false

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] [file]\nOptions:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&output, "o", "", "Output file (stdout when empty)")
	flag.StringVar(&ext, "x", "", "File extension (css, html, js, json, svg or xml), optional for input files")
	flag.StringVar(&directory, "d", "", "Directory to search for files")
	flag.BoolVar(&recursive, "r", false, "Recursively minify everything")
	flag.Parse()
	if len(flag.Args()) > 0 {
		input = flag.Arg(0)
	}

	mediatype := ""
	r := io.Reader(os.Stdin)
	w := io.Writer(os.Stdout)
	m := minify.New()
	m.AddFunc("text/css", css.Minify)
	m.AddFunc("text/html", html.Minify)
	m.AddFunc("application/javascript", js.Minify)
	m.AddFunc("image/svg+xml", svg.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)

	filenames := make(map[string]string)
	if directory != "" {
		filenames = ioNames(directory, recursive)
	} else {
		filenames[input] = output
	}

	for in, out := range filenames {
		input = in
		output = out
		if input != "" {
			in, err := os.Open(input)
			if err != nil {
				fmt.Println("Error:", err)
				os.Exit(1)
			}
			defer in.Close()
			r = in
			if input == output {
				b := &bytes.Buffer{}
				io.Copy(b, r)
				r = b
			}
			if ext == "" {
				ext = filepath.Ext(input)
			}
		}
		if output != "" {
			out, err := os.Create(output)
			if err != nil {
				fmt.Println("Error:", err)
				os.Exit(1)
			}
			defer out.Close()
			w = out
		}
		if ext != "" {
			mediatype = extMime[ext]
		}
		if err := m.Minify(mediatype, w, r); err != nil {
			if err == minify.ErrNotExist {
				io.Copy(w, r)
			} else {
				fmt.Println("Error:", err)
				os.Exit(1)
			}
		}
	}
}

// ioNames returns a map of input paths and output paths.
func ioNames(root string, recursive bool) map[string]string {
	names := map[string]string{}
	if recursive {
		filepath.Walk(root, func(path string, info os.FileInfo, _ error) error {
			if validFile(info) {
				names[path] = minExt(path)
			}
			return nil
		})
	} else if infos, err := ioutil.ReadDir(root); err == nil {
		for _, info := range infos {
			if validFile(info) {
				path := filepath.Join(root, info.Name())
				names[path] = minExt(path)
			}
		}
	}
	return names
}

// validFile checks to see if a file is a directory, hidden, already has the
// minified extension, or if it's one of the minifiable extensions.
func validFile(info os.FileInfo) bool {
	if info.IsDir() || len(info.Name()) > 0 && (info.Name()[0] == '.' || strings.Contains(info.Name(), ".min.")) {
		return false
	}
	_, exists := extMime[strings.ToLower(filepath.Ext(info.Name()))]
	return exists
}

// minExt adds .min before a file's extension. If a file doesn't have an
// extension then .min will become the file's extension.
func minExt(path string) string {
	if dot := strings.LastIndex(path, "."); dot != -1 {
		return path[:dot] + ".min" + path[dot:]
	}
	return path + ".min"
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"strings"

	"github.com/BellerophonMobile/hippo"
	"github.com/BellerophonMobile/logberry"
)

type claims map[string]interface{}

func (c claims) String() string {
	bytes, _ := json.Marshal(c)
	return string(bytes)
}

func (c claims) Set(flag string) error {
	v := strings.SplitAfterN(flag, ",", 2)
	if len(v) != 2 {
		return fmt.Errorf("Claim format is \"key,value\"")
	}

	key := v[0][:len(v[0])-1]

	dec := json.NewDecoder(strings.NewReader(v[1]))
	dec.UseNumber()

	tok, err := dec.Token()
	if err != nil {
		return fmt.Errorf("Invalid claim value format")
	}

	switch tok := tok.(type) {
	case bool, string:
		c[key] = tok

	case json.Number:
		// First try to decode as int
		c[key], err = tok.Int64()
		if err == nil {
			break
		}
		// Next try float
		c[key], err = tok.Float64()
		if err == nil {
			break
		}
		// Finally, just store the string value
		c[key] = tok.String()

	default:
		return fmt.Errorf("Invalid claim value type")
	}

	return nil
}

type chain hippo.Chain

func (c *chain) String() string {
	bytes, _ := json.Marshal(c)
	return string(bytes)
}

func (c *chain) Set(flag string) error {
	cert, err := hippo.CertificateFromFile(flag)
	if err != nil {
		return err
	}

	*c = append(*c, cert.Declarations...)

	return nil
}

func main() {
	certId := flag.String("certid", "", "Certificate ID.")
	subjectId := flag.String("subjectid", "", "Subject ID.")
	publicKeyFile := flag.String("subjectkey", "", "Subject public key.")
	signingKeyFile := flag.String("signingkey", "", "Signing private key.")
	outFile := flag.String("out", "", "Output certificate.")

	claims := make(claims)
	var chain chain

	flag.Var(claims, "claim", "Add claim \"key,value\".")
	flag.Var(&chain, "chain", "Add chained certificates.")

	flag.Parse()

	fmt.Printf("Chains: %v\n", chain)

	publicKey := readPublicKey(*publicKeyFile)

	testament := hippo.NewTestament(*subjectId, *publicKey)
	testament.Claims = claims

	signer := makeSigner(*signingKeyFile)
	decl := sign(*certId, testament, signer)

	cert := &hippo.Certificate{Declarations: hippo.Chain{decl}}
	cert.Declarations = append(cert.Declarations, chain...)

	writeCert(cert, *outFile)

}

func readPublicKey(filename string) *hippo.PublicKey {
	task := logberry.Main.Task("Read public key", logberry.D{"filename": filename})
	key, err := hippo.PublicKeyFromFile(filename)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return key
}

func readPrivateKey(filename string) *hippo.PrivateKey {
	task := logberry.Main.Task("Read private key", logberry.D{"filename": filename})
	key, err := hippo.PrivateKeyFromFile(filename)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return key
}

func makeSigner(filename string) hippo.Credentials {
	task := logberry.Main.Task("Load signer", logberry.D{"filename": filename})
	credentials, err := hippo.NewSigner(*readPrivateKey(filename))
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return credentials
}

func sign(id string, testament *hippo.Testament, signer hippo.Credentials) *hippo.Declaration {
	task := logberry.Main.Task("Sign certificate", logberry.D{"id": id})
	decl, err := testament.Sign(id, signer)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return decl
}

func writeCert(cert *hippo.Certificate, filename string) {
	task := logberry.Main.Task("Write certificate")
	err := cert.ToFile(filename)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
}
<commit_msg>Remove debug logging.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"strings"

	"github.com/BellerophonMobile/hippo"
	"github.com/BellerophonMobile/logberry"
)

type claims map[string]interface{}

func (c claims) String() string {
	bytes, _ := json.Marshal(c)
	return string(bytes)
}

func (c claims) Set(flag string) error {
	v := strings.SplitAfterN(flag, ",", 2)
	if len(v) != 2 {
		return fmt.Errorf("Claim format is \"key,value\"")
	}

	key := v[0][:len(v[0])-1]

	dec := json.NewDecoder(strings.NewReader(v[1]))
	dec.UseNumber()

	tok, err := dec.Token()
	if err != nil {
		return fmt.Errorf("Invalid claim value format")
	}

	switch tok := tok.(type) {
	case bool, string:
		c[key] = tok

	case json.Number:
		// First try to decode as int
		c[key], err = tok.Int64()
		if err == nil {
			break
		}
		// Next try float
		c[key], err = tok.Float64()
		if err == nil {
			break
		}
		// Finally, just store the string value
		c[key] = tok.String()

	default:
		return fmt.Errorf("Invalid claim value type")
	}

	return nil
}

type chain hippo.Chain

func (c *chain) String() string {
	bytes, _ := json.Marshal(c)
	return string(bytes)
}

func (c *chain) Set(flag string) error {
	cert, err := hippo.CertificateFromFile(flag)
	if err != nil {
		return err
	}

	*c = append(*c, cert.Declarations...)

	return nil
}

func main() {
	certId := flag.String("certid", "", "Certificate ID.")
	subjectId := flag.String("subjectid", "", "Subject ID.")
	publicKeyFile := flag.String("subjectkey", "", "Subject public key.")
	signingKeyFile := flag.String("signingkey", "", "Signing private key.")
	outFile := flag.String("out", "", "Output certificate.")

	claims := make(claims)
	var chain chain

	flag.Var(claims, "claim", "Add claim \"key,value\".")
	flag.Var(&chain, "chain", "Add chained certificates.")

	flag.Parse()

	publicKey := readPublicKey(*publicKeyFile)

	testament := hippo.NewTestament(*subjectId, *publicKey)
	testament.Claims = claims

	signer := makeSigner(*signingKeyFile)
	decl := sign(*certId, testament, signer)

	cert := &hippo.Certificate{Declarations: hippo.Chain{decl}}
	cert.Declarations = append(cert.Declarations, chain...)

	writeCert(cert, *outFile)
}

func readPublicKey(filename string) *hippo.PublicKey {
	task := logberry.Main.Task("Read public key", logberry.D{"filename": filename})
	key, err := hippo.PublicKeyFromFile(filename)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return key
}

func readPrivateKey(filename string) *hippo.PrivateKey {
	task := logberry.Main.Task("Read private key", logberry.D{"filename": filename})
	key, err := hippo.PrivateKeyFromFile(filename)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return key
}

func makeSigner(filename string) hippo.Credentials {
	task := logberry.Main.Task("Load signer", logberry.D{"filename": filename})
	credentials, err := hippo.NewSigner(*readPrivateKey(filename))
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return credentials
}

func sign(id string, testament *hippo.Testament, signer hippo.Credentials) *hippo.Declaration {
	task := logberry.Main.Task("Sign certificate", logberry.D{"id": id})
	decl, err := testament.Sign(id, signer)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
	return decl
}

func writeCert(cert *hippo.Certificate, filename string) {
	task := logberry.Main.Task("Write certificate")
	err := cert.ToFile(filename)
	if err != nil {
		task.Fatal(err)
	}
	task.Success()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"time"

	"github.com/sirupsen/logrus"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/util/retry"
	apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
	"k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"

	"github.com/operator-framework/api/pkg/operators/v1alpha1"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
)

const (
	pollInterval = 1 * time.Second
	pollDuration = 5 * time.Minute
)

type checkResourceFunc func() error
type deleteResourceFunc func() error
type mutateMeta func(obj metav1.Object) (mutated bool)

func cleanup(logger *logrus.Logger, c operatorclient.ClientInterface, crc versioned.Interface) {
	if err := waitForDelete(checkCatalogSource(crc, "olm-operators"), deleteCatalogSource(crc, "olm-operators")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkConfigMap(c, "olm-operators"), deleteConfigMap(c, "olm-operators")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkSubscription(crc, "packageserver"), deleteSubscription(crc, "packageserver")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.10.0"), deleteClusterServiceVersion(crc, "packageserver.v0.10.0")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.10.1"), deleteClusterServiceVersion(crc, "packageserver.v0.10.0")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.9.0"), deleteClusterServiceVersion(crc, "packageserver.v0.9.0")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := cleanupOwnerReferences(c, crc); err != nil {
		logger.WithError(err).Fatal("couldn't cleanup cross-namespace ownerreferences")
	}

	if err := ensureAPIServiceLabels(c.ApiregistrationV1Interface()); err != nil {
		logger.WithError(err).Fatal("couldn't ensure APIService labels")
	}
}

func waitForDelete(checkResource checkResourceFunc, deleteResource deleteResourceFunc) error {
	if err := checkResource(); err != nil && errors.IsNotFound(err) {
		return nil
	}
	if err := deleteResource(); err != nil {
		return err
	}
	err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
		err := checkResource()
		if errors.IsNotFound(err) {
			return true, nil
		}
		if err != nil {
			return false, err
		}
		return false, nil
	})

	return err
}

func checkClusterServiceVersion(crc versioned.Interface, name string) checkResourceFunc {
	return func() error {
		_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteClusterServiceVersion(crc versioned.Interface, name string) deleteResourceFunc {
	return func() error {
		return crc.OperatorsV1alpha1().ClusterServiceVersions(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

func checkSubscription(crc versioned.Interface, name string) checkResourceFunc {
	return func() error {
		_, err := crc.OperatorsV1alpha1().Subscriptions(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteSubscription(crc versioned.Interface, name string) deleteResourceFunc {
	return func() error {
		return crc.OperatorsV1alpha1().Subscriptions(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

func checkConfigMap(c operatorclient.ClientInterface, name string) checkResourceFunc {
	return func() error {
		_, err := c.KubernetesInterface().CoreV1().ConfigMaps(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteConfigMap(c operatorclient.ClientInterface, name string) deleteResourceFunc {
	return func() error {
		return c.KubernetesInterface().CoreV1().ConfigMaps(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

func checkCatalogSource(crc versioned.Interface, name string) checkResourceFunc {
	return func() error {
		_, err := crc.OperatorsV1alpha1().CatalogSources(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteCatalogSource(crc versioned.Interface, name string) deleteResourceFunc {
	return func() error {
		return crc.OperatorsV1alpha1().CatalogSources(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

// cleanupOwnerReferences cleans up inter-namespace and cluster-to-namespace scoped OwnerReferences to ClusterServiceVersions.
//
// Cross-namespace and cluster-to-namespace scoped OwnerReferences may cause sibling resources in the owner namespace to be
// deleted sporadically (see CVE-2019-3884 https://access.redhat.com/security/cve/cve-2019-3884). Older versions of OLM use both types of
// OwnerReference, and in cases where OLM is updated, they must be removed to prevent erroneous deletion of OLM's self-hosted components.
func cleanupOwnerReferences(c operatorclient.ClientInterface, crc versioned.Interface) error {
	listOpts := metav1.ListOptions{}
	csvs, err := crc.OperatorsV1alpha1().ClusterServiceVersions(metav1.NamespaceAll).List(context.TODO(), listOpts)
	if err != nil {
		return err
	}

	uidNamespaces := map[types.UID]string{}
	for _, csv := range csvs.Items {
		uidNamespaces[csv.GetUID()] = csv.GetNamespace()
	}
	removeBadRefs := crossNamespaceOwnerReferenceRemoval(v1alpha1.ClusterServiceVersionKind, uidNamespaces)

	// Cleanup cross-namespace OwnerReferences on CSVs, ClusterRoles/Bindings, and Roles/Bindings
	var objs []metav1.Object
	for _, obj := range csvs.Items {
		objs = append(objs, &obj)
	}

	clusterRoles, _ := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.TODO(), listOpts)
	for _, obj := range clusterRoles.Items {
		objs = append(objs, &obj)
	}

	clusterRoleBindings, _ := c.KubernetesInterface().RbacV1().ClusterRoleBindings().List(context.TODO(), listOpts)
	for _, obj := range clusterRoleBindings.Items {
		objs = append(objs, &obj)
	}

	roles, _ := c.KubernetesInterface().RbacV1().Roles(metav1.NamespaceAll).List(context.TODO(), listOpts)
	for _, obj := range roles.Items {
		objs = append(objs, &obj)
	}
	roleBindings, _ := c.KubernetesInterface().RbacV1().RoleBindings(metav1.NamespaceAll).List(context.TODO(), listOpts)
	for _, obj := range roleBindings.Items {
		objs = append(objs, &obj)
	}

	apiServices, _ := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().List(context.TODO(), listOpts)
	for _, obj := range apiServices.Items {
		objs = append(objs, &obj)
	}

	for _, obj := range objs {
		if !removeBadRefs(obj) {
			continue
		}

		update := func() error {
			// If this is not a type we care about, do nothing
			return nil
		}
		switch v := obj.(type) {
		case *v1alpha1.ClusterServiceVersion:
			update = func() error {
				_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(v.GetNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.ClusterRole:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().ClusterRoles().Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.ClusterRoleBinding:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.Role:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().Roles(v.GetNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.RoleBinding:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().RoleBindings(v.GetNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *apiregv1.APIService:
			update = func() error {
				_, err = c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		}

		if err := retry.RetryOnConflict(retry.DefaultBackoff, update); err != nil {
			return err
		}
	}

	return nil
}

func crossNamespaceOwnerReferenceRemoval(kind string, uidNamespaces map[types.UID]string) mutateMeta {
	return func(obj metav1.Object) (mutated bool) {
		var cleanRefs []metav1.OwnerReference
		objNamespace := obj.GetNamespace()
		for _, ref := range obj.GetOwnerReferences() {
			if ref.Kind == kind {
				refNamespace, ok := uidNamespaces[ref.UID]
				if !ok || (refNamespace != metav1.NamespaceAll && refNamespace != objNamespace) {
					mutated = true
					continue
				}
			}

			cleanRefs = append(cleanRefs, ref)
		}

		if mutated {
			obj.SetOwnerReferences(cleanRefs)
		}

		return
	}
}

// ensureAPIServiceLabels checks the labels of existing APIService objects to ensure ownership is set correctly.
// If the APIService label does not correspond to the expected packageserver owner the APIService labels are updated
func ensureAPIServiceLabels(c clientset.Interface) error {
	apiService, err := c.ApiregistrationV1().APIServices().Get(context.TODO(), olm.PackageserverName, metav1.GetOptions{})
	if err != nil && !k8serrors.IsNotFound(err) {
		logrus.WithField("apiService", "packageserver").Debugf("get error: %s", err)
		return err
	}
	if apiService == nil || k8serrors.IsNotFound(err) || apiService.Name == "" {
		logrus.WithField("apiService", "packageserver").Debugf("not found")
		return nil
	}

	if l := apiService.GetLabels(); l == nil {
		apiService.Labels = make(map[string]string)
	}

	if apiService.Labels[ownerutil.OwnerKey] != ownerutil.OwnerPackageServer {
		apiService.Labels[ownerutil.OwnerKey] = ownerutil.OwnerPackageServer
		update := func() error {
			_, err := c.ApiregistrationV1().APIServices().Update(context.TODO(), apiService, metav1.UpdateOptions{})
			return err
		}
		if err := retry.RetryOnConflict(retry.DefaultBackoff, update); err != nil {
			logrus.WithField("apiService", apiService.Name).Warnf("update error: %s", err)
			return err
		}
	}

	return nil
}
<commit_msg>cleanup: delete duplicated import in olm<commit_after>package main

import (
	"context"
	"time"

	"github.com/sirupsen/logrus"
	rbacv1 "k8s.io/api/rbac/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/util/retry"
	apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
	"k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"

	"github.com/operator-framework/api/pkg/operators/v1alpha1"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
)

const (
	pollInterval = 1 * time.Second
	pollDuration = 5 * time.Minute
)

type checkResourceFunc func() error
type deleteResourceFunc func() error
type mutateMeta func(obj metav1.Object) (mutated bool)

func cleanup(logger *logrus.Logger, c operatorclient.ClientInterface, crc versioned.Interface) {
	if err := waitForDelete(checkCatalogSource(crc, "olm-operators"), deleteCatalogSource(crc, "olm-operators")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkConfigMap(c, "olm-operators"), deleteConfigMap(c, "olm-operators")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkSubscription(crc, "packageserver"), deleteSubscription(crc, "packageserver")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.10.0"), deleteClusterServiceVersion(crc, "packageserver.v0.10.0")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.10.1"), deleteClusterServiceVersion(crc, "packageserver.v0.10.0")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := waitForDelete(checkClusterServiceVersion(crc, "packageserver.v0.9.0"), deleteClusterServiceVersion(crc, "packageserver.v0.9.0")); err != nil {
		logger.WithError(err).Fatal("couldn't clean previous release")
	}

	if err := cleanupOwnerReferences(c, crc); err != nil {
		logger.WithError(err).Fatal("couldn't cleanup cross-namespace ownerreferences")
	}

	if err := ensureAPIServiceLabels(c.ApiregistrationV1Interface()); err != nil {
		logger.WithError(err).Fatal("couldn't ensure APIService labels")
	}
}

func waitForDelete(checkResource checkResourceFunc, deleteResource deleteResourceFunc) error {
	if err := checkResource(); err != nil && k8serrors.IsNotFound(err) {
		return nil
	}
	if err := deleteResource(); err != nil {
		return err
	}
	err := wait.Poll(pollInterval, pollDuration, func() (bool, error) {
		err := checkResource()
		if k8serrors.IsNotFound(err) {
			return true, nil
		}
		if err != nil {
			return false, err
		}
		return false, nil
	})

	return err
}

func checkClusterServiceVersion(crc versioned.Interface, name string) checkResourceFunc {
	return func() error {
		_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteClusterServiceVersion(crc versioned.Interface, name string) deleteResourceFunc {
	return func() error {
		return crc.OperatorsV1alpha1().ClusterServiceVersions(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

func checkSubscription(crc versioned.Interface, name string) checkResourceFunc {
	return func() error {
		_, err := crc.OperatorsV1alpha1().Subscriptions(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteSubscription(crc versioned.Interface, name string) deleteResourceFunc {
	return func() error {
		return crc.OperatorsV1alpha1().Subscriptions(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

func checkConfigMap(c operatorclient.ClientInterface, name string) checkResourceFunc {
	return func() error {
		_, err := c.KubernetesInterface().CoreV1().ConfigMaps(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteConfigMap(c operatorclient.ClientInterface, name string) deleteResourceFunc {
	return func() error {
		return c.KubernetesInterface().CoreV1().ConfigMaps(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

func checkCatalogSource(crc versioned.Interface, name string) checkResourceFunc {
	return func() error {
		_, err := crc.OperatorsV1alpha1().CatalogSources(*namespace).Get(context.TODO(), name, metav1.GetOptions{})
		return err
	}
}

func deleteCatalogSource(crc versioned.Interface, name string) deleteResourceFunc {
	return func() error {
		return crc.OperatorsV1alpha1().CatalogSources(*namespace).Delete(context.TODO(), name, *metav1.NewDeleteOptions(0))
	}
}

// cleanupOwnerReferences cleans up inter-namespace and cluster-to-namespace scoped OwnerReferences to ClusterServiceVersions.
//
// Cross-namespace and cluster-to-namespace scoped OwnerReferences may cause sibling resources in the owner namespace to be
// deleted sporadically (see CVE-2019-3884 https://access.redhat.com/security/cve/cve-2019-3884). Older versions of OLM use both types of
// OwnerReference, and in cases where OLM is updated, they must be removed to prevent erroneous deletion of OLM's self-hosted components.
func cleanupOwnerReferences(c operatorclient.ClientInterface, crc versioned.Interface) error {
	listOpts := metav1.ListOptions{}
	csvs, err := crc.OperatorsV1alpha1().ClusterServiceVersions(metav1.NamespaceAll).List(context.TODO(), listOpts)
	if err != nil {
		return err
	}

	uidNamespaces := map[types.UID]string{}
	for _, csv := range csvs.Items {
		uidNamespaces[csv.GetUID()] = csv.GetNamespace()
	}
	removeBadRefs := crossNamespaceOwnerReferenceRemoval(v1alpha1.ClusterServiceVersionKind, uidNamespaces)

	// Cleanup cross-namespace OwnerReferences on CSVs, ClusterRoles/Bindings, and Roles/Bindings
	var objs []metav1.Object
	for _, obj := range csvs.Items {
		objs = append(objs, &obj)
	}

	clusterRoles, _ := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.TODO(), listOpts)
	for _, obj := range clusterRoles.Items {
		objs = append(objs, &obj)
	}

	clusterRoleBindings, _ := c.KubernetesInterface().RbacV1().ClusterRoleBindings().List(context.TODO(), listOpts)
	for _, obj := range clusterRoleBindings.Items {
		objs = append(objs, &obj)
	}

	roles, _ := c.KubernetesInterface().RbacV1().Roles(metav1.NamespaceAll).List(context.TODO(), listOpts)
	for _, obj := range roles.Items {
		objs = append(objs, &obj)
	}
	roleBindings, _ := c.KubernetesInterface().RbacV1().RoleBindings(metav1.NamespaceAll).List(context.TODO(), listOpts)
	for _, obj := range roleBindings.Items {
		objs = append(objs, &obj)
	}

	apiServices, _ := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().List(context.TODO(), listOpts)
	for _, obj := range apiServices.Items {
		objs = append(objs, &obj)
	}

	for _, obj := range objs {
		if !removeBadRefs(obj) {
			continue
		}

		update := func() error {
			// If this is not a type we care about, do nothing
			return nil
		}
		switch v := obj.(type) {
		case *v1alpha1.ClusterServiceVersion:
			update = func() error {
				_, err := crc.OperatorsV1alpha1().ClusterServiceVersions(v.GetNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.ClusterRole:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().ClusterRoles().Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.ClusterRoleBinding:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.Role:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().Roles(v.GetNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *rbacv1.RoleBinding:
			update = func() error {
				_, err = c.KubernetesInterface().RbacV1().RoleBindings(v.GetNamespace()).Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		case *apiregv1.APIService:
			update = func() error {
				_, err = c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Update(context.TODO(), v, metav1.UpdateOptions{})
				return err
			}
		}

		if err := retry.RetryOnConflict(retry.DefaultBackoff, update); err != nil {
			return err
		}
	}

	return nil
}

func crossNamespaceOwnerReferenceRemoval(kind string, uidNamespaces map[types.UID]string) mutateMeta {
	return func(obj metav1.Object) (mutated bool) {
		var cleanRefs []metav1.OwnerReference
		objNamespace := obj.GetNamespace()
		for _, ref := range obj.GetOwnerReferences() {
			if ref.Kind == kind {
				refNamespace, ok := uidNamespaces[ref.UID]
				if !ok || (refNamespace != metav1.NamespaceAll && refNamespace != objNamespace) {
					mutated = true
					continue
				}
			}

			cleanRefs = append(cleanRefs, ref)
		}

		if mutated {
			obj.SetOwnerReferences(cleanRefs)
		}

		return
	}
}

// ensureAPIServiceLabels checks the labels of existing APIService objects to ensure ownership is set correctly.
// If the APIService label does not correspond to the expected packageserver owner the APIService labels are updated
func ensureAPIServiceLabels(c clientset.Interface) error {
	apiService, err := c.ApiregistrationV1().APIServices().Get(context.TODO(), olm.PackageserverName, metav1.GetOptions{})
	if err != nil && !k8serrors.IsNotFound(err) {
		logrus.WithField("apiService", "packageserver").Debugf("get error: %s", err)
		return err
	}
	if apiService == nil || k8serrors.IsNotFound(err) || apiService.Name == "" {
		logrus.WithField("apiService", "packageserver").Debugf("not found")
		return nil
	}

	if l := apiService.GetLabels(); l == nil {
		apiService.Labels = make(map[string]string)
	}

	if apiService.Labels[ownerutil.OwnerKey] != ownerutil.OwnerPackageServer {
		apiService.Labels[ownerutil.OwnerKey] = ownerutil.OwnerPackageServer
		update := func() error {
			_, err := c.ApiregistrationV1().APIServices().Update(context.TODO(), apiService, metav1.UpdateOptions{})
			return err
		}
		if err := retry.RetryOnConflict(retry.DefaultBackoff, update); err != nil {
			logrus.WithField("apiService", apiService.Name).Warnf("update error: %s", err)
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"strings"

	"github.com/nboughton/go-dice"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
)

var defaultprec = 1000000

func main() {
	d := flag.String("d", "2d6", "Dice set to test. Can be a single value (2d10) or multiple values delineated by commas (2d4,3d10...)")
	r := flag.Int("r", defaultprec, "Set number of rolls to try")
	flag.Parse()

	bag, err := dice.NewBag(strings.Split(*d, ",")...)
	if err != nil {
		log.Fatal(err)
	}

	// New plot
	pl, err := plot.New()
	if err != nil {
		log.Fatal(err)
	}
	pl.Title.Text = "Distribution For " + bag.String()
	pl.X.Label.Text = "Rolled"
	pl.X.Min = float64(bag.Min())
	pl.X.Max = float64(bag.Max())

	pl.Y.Label.Text = "Probability (%)"
	pl.Y.Min = 0
	//pl.Y.Max =

	pl.X.Tick.Marker = customTicks{}
	pl.Y.Tick.Marker = customTicks{}
	pl.Add(plotter.NewGrid())

	// Generate plot data
	l, err := plotter.NewLine(lineData(bag, *r))
	if err != nil {
		log.Fatal(err)
	}
	l.LineStyle.Width = vg.Points(1)

	// Add plot data
	pl.Add(l)

	// Save to png
	if err := pl.Save(20*vg.Centimeter, 15*vg.Centimeter, fmt.Sprintf("%s.png", *d)); err != nil {
		log.Fatal(err)
	}
}

func lineData(bag *dice.Bag, prec int) plotter.XYs {
	var (
		min  = bag.Min()
		max  = bag.Max()
		xLen = max - min + 1
		xy   = make(plotter.XYs, xLen)
	)

	for i := 0; i < prec; i++ {
		t, _ := bag.Roll()
		xy[t-min].Y++
	}

	for i := range xy {
		xy[i].X = float64(i + min)
		xy[i].Y = xy[i].Y / float64(prec) * 100
	}

	return xy
}

type customTicks struct{}

func (customTicks) Ticks(min, max float64) []plot.Tick {
	var tks []plot.Tick

	for i := 0.; i < max; i++ {
		t := plot.Tick{Value: float64(i + 1)}

		switch {
		case max > 20 && max <= 50:
			t.Label = label(i, 2)
		case max > 50 && max <= 100:
			t.Label = label(i, 5)
		case max > 100:
			t.Label = label(i, int(max/4))
		default:
			t.Label = label(i, 1)
		}

		tks = append(tks, t)
	}

	return tks
}

func label(i float64, mod int) string {
	if int(i+1)%mod == 0 {
		return fmt.Sprintf("%d", int(i+1))
	}

	return ""
}
<commit_msg>better variable naming Y max set at 50 for comparable graphs<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"strings"

	"github.com/nboughton/go-dice"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
)

var defaultrolls = 1000000

func main() {
	d := flag.String("d", "2d6", "Dice set to test. Can be a single value (2d10) or multiple values delineated by commas (2d4,3d10...)")
	r := flag.Int("r", defaultrolls, "Set number of rolls to try")
	flag.Parse()

	bag, err := dice.NewBag(strings.Split(*d, ",")...)
	if err != nil {
		log.Fatal(err)
	}

	// New plot
	pl, err := plot.New()
	if err != nil {
		log.Fatal(err)
	}
	pl.Title.Text = "Distribution For " + bag.String()
	pl.X.Label.Text = "Rolled"
	pl.X.Min = float64(bag.Min())
	pl.X.Max = float64(bag.Max())

	pl.Y.Label.Text = "Probability (%)"
	pl.Y.Min = 0
	pl.Y.Max = 50

	pl.X.Tick.Marker = customTicks{}
	pl.Y.Tick.Marker = customTicks{}
	pl.Add(plotter.NewGrid())

	// Generate plot data
	l, err := plotter.NewLine(lineData(bag, *r))
	if err != nil {
		log.Fatal(err)
	}
	l.LineStyle.Width = vg.Points(1)

	// Add plot data
	pl.Add(l)

	// Save to png
	if err := pl.Save(20*vg.Centimeter, 15*vg.Centimeter, fmt.Sprintf("%s.png", *d)); err != nil {
		log.Fatal(err)
	}
}

func lineData(bag *dice.Bag, rolls int) plotter.XYs {
	var (
		min  = bag.Min()
		max  = bag.Max()
		xLen = max - min + 1
		xy   = make(plotter.XYs, xLen)
	)

	for i := 0; i < rolls; i++ {
		t, _ := bag.Roll()
		xy[t-min].Y++
	}

	for i := range xy {
		xy[i].X = float64(i + min)
		xy[i].Y = xy[i].Y / float64(rolls) * 100
	}

	return xy
}

type customTicks struct{}

func (customTicks) Ticks(min, max float64) []plot.Tick {
	var tks []plot.Tick

	for i := 0.; i < max; i++ {
		t := plot.Tick{Value: float64(i + 1)}

		switch {
		case max > 20 && max <= 50:
			t.Label = label(i, 2)
		case max > 50 && max <= 100:
			t.Label = label(i, 5)
		case max > 100:
			t.Label = label(i, int(max/4))
		default:
			t.Label = label(i, 1)
		}

		tks = append(tks, t)
	}

	return tks
}

func label(i float64, mod int) string {
	if int(i+1)%mod == 0 {
		return fmt.Sprintf("%d", int(i+1))
	}

	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/GeertJohan/go.rice"
	"github.com/boltdb/bolt"
	"github.com/cswank/quimby"
	"github.com/cswank/quimby/cmd/quimby/handlers"
	"github.com/cswank/quimby/cmd/quimby/utils"
	"github.com/cswank/rex"
	"github.com/justinas/alice"
	"gopkg.in/alecthomas/kingpin.v2"
)

const (
	version = "0.7.0"
)

var (
	users        = kingpin.Command("users", "User management")
	userAdd      = users.Command("add", "Add a new user.")
	userName     = users.Flag("username", "Username for a new user").String()
	userPW       = users.Flag("password", "Password for a new user").String()
	userPerm     = users.Flag("permission", "Permission (read, write, or admin").String()
	userList     = users.Command("list", "List users.")
	userEdit     = users.Command("edit", "Update a user.")
	cert         = kingpin.Command("cert", "Make an tls cert.")
	domain       = cert.Flag("domain", "The domain for the tls cert.").Required().Short('d').String()
	pth          = cert.Flag("path", "The directory where the cert files will be written").Required().Short('p').String()
	serve        = kingpin.Command("serve", "Start the server.")
	setup        = kingpin.Command("setup", "Set up the the server (keys and init scripts and what not.")
	net          = setup.Flag("net", "network interface").Short('n').Default("eth0").String()
	setupDomain  = setup.Flag("domain", "network interface").Required().Short('d').String()
	command      = kingpin.Command("command", "Send a command.")
	method       = kingpin.Command("method", "Send a method.")
	gadgets      = kingpin.Command("gadgets", "Commands for managing gadgets")
	gadgetAdd    = gadgets.Command("add", "Add a gadget.")
	gadgetName   = gadgets.Flag("name", "Name of the gadget.").String()
	gadgetHost   = gadgets.Flag("host", "ip address of gadget (id http://<ipaddr>:6111)").String()
	gadgetList   = gadgets.Command("list", "List the gadgets.")
	gadgetEdit   = gadgets.Command("edit", "List the gadgets.")
	gadgetDelete = gadgets.Command("delete", "Delete a gadget.")
	token        = kingpin.Command("token", "Generate a jwt token")
	bootstrap    = kingpin.Command("bootstrap", "Set up a bunch of stuff")

	keyPath  = os.Getenv("QUIMBY_TLS_KEY")
	certPath = os.Getenv("QUIMBY_TLS_CERT")
	iface    = os.Getenv("QUIMBY_INTERFACE")

	box *rice.Box
)

func main() {
	kingpin.UsageTemplate(kingpin.CompactUsageTemplate).Version(version).Author("Craig Swank")
	switch kingpin.Parse() {
	case "cert":
		utils.GenerateCert(*domain, *pth)
	case "users add":
		doUser(utils.AddUser)
	case "users list":
		addDB(utils.ListUsers)
	case "users edit":
		addDB(utils.EditUser)
	case "gadgets add":
		doGadget(utils.AddGadget)
	case "gadgets list":
		addDB(utils.ListGadgets)
	case "gadgets edit":
		addDB(utils.EditGadget)
	case "gadgets delete":
		addDB(utils.DeleteGadget)
	case "command":
		addDB(utils.SendCommand)
	case "token":
		utils.GetToken()
	case "bootstrap":
		utils.Bootstrap()
	case "serve":
		box = rice.MustFindBox("static")
		handlers.Init(box)
		addDB(startServer)
	case "setup":
		utils.SetupServer(*setupDomain, *net)
	}
}

type dbNeeder func(*bolt.DB)
type userNeeder func(*quimby.User)
type gadgetNeeder func(*quimby.Gadget)

func getDB() *bolt.DB {
	pth := os.Getenv("QUIMBY_DB")
	if pth == "" {
		log.Fatal("you must specify a db location with QUIMBY_DB")
	}
	db, err := quimby.GetDB(pth)
	if err != nil {
		log.Fatalf("could not open db at %s - %v", pth, err)
	}
	return db
}

func doUser(f userNeeder) {
	db := getDB()
	u := quimby.NewUser(
		*userName,
		quimby.UserDB(db),
		quimby.UserPassword(*userPW),
		quimby.UserPermission(*userPerm),
	)
	f(u)
	defer db.Close()
}

func doGadget(f gadgetNeeder) {
	db := getDB()
	g := &quimby.Gadget{
		DB:   db,
		Name: *gadgetName,
		Host: *gadgetHost,
	}
	f(g)
	db.Close()
}

func addDB(f dbNeeder) {
	db := getDB()
	f(db)
	defer db.Close()
}

func startServer(db *bolt.DB) {
	port := os.Getenv("QUIMBY_PORT")
	if port == "" {
		log.Fatal("you must specify a port with QUIMBY_PORT")
	}

	domain := os.Getenv("QUIMBY_DOMAIN")
	if domain == "" {
		log.Fatal("you must specify a domain with QUIMBY_DOMAIN")
	}

	internalPort := os.Getenv("QUIMBY_INTERNAL_PORT")
	if port == "" {
		log.Fatal("you must specify a port with QUIMBY_INTERNAL_PORT")
	}

	var lg *log.Logger
	if os.Getenv("QUIMBY_NULLLOG") != "" {
		lg = log.New(ioutil.Discard, "quimby ", log.Ltime)
	} else {
		lg = log.New(os.Stdout, "quimby ", log.Ltime)
	}
	clients := quimby.NewClientHolder()
	tfa := quimby.NewTFA(domain)
	start(db, port, internalPort, "/", "/api", lg, clients, tfa)
}

func getMiddleware(perm handlers.ACL, f http.HandlerFunc) http.Handler {
	return alice.New(handlers.Perm(perm)).Then(http.HandlerFunc(f))
}

func start(db *bolt.DB, port, internalPort, root string, iRoot string, lg quimby.Logger, clients *quimby.ClientHolder, tfa quimby.TFAer) {

	quimby.Clients = clients
	quimby.DB = db
	quimby.LG = lg
	handlers.DB = db
	handlers.LG = lg
	handlers.TFA = tfa

	go startInternal(iRoot, db, lg, internalPort)
	go startHomeKit(db, lg)

	r := rex.New("main")
	r.Get("/", getMiddleware(handlers.Read, handlers.IndexPage))
	r.Get("/gadgets/{id}", getMiddleware(handlers.Read, handlers.GadgetPage))
	r.Get("/login.html", getMiddleware(handlers.Anyone, handlers.LoginPage))
	r.Get("/logout.html", getMiddleware(handlers.Read, handlers.LogoutPage))
	r.Post("/login.html", getMiddleware(handlers.Anyone, handlers.LoginForm))
	r.Get("/admin.html", getMiddleware(handlers.Admin, handlers.AdminPage))
	r.Get("/admin/gadgets/{id}", getMiddleware(handlers.Admin, handlers.GadgetEditPage))
	r.Post("/admin/gadgets/{id}", getMiddleware(handlers.Admin, handlers.GadgetForm))
	r.Get("/admin/users/{username}", getMiddleware(handlers.Admin, handlers.UserEditPage))
	r.Get("/admin/users/{username}/password", getMiddleware(handlers.Admin, handlers.UserPasswordPage))
	r.Post("/admin/users/{username}/password", getMiddleware(handlers.Admin, handlers.UserChangePasswordPage))
	r.Post("/admin/users/{username}/tfa", getMiddleware(handlers.Admin, handlers.UserTFAPage))
	r.Post("/admin/users/{username}/do-delete", getMiddleware(handlers.Admin, handlers.DeleteUserPage))
	r.Get("/admin/users/{username}/delete", getMiddleware(handlers.Admin, handlers.DeleteUserConfirmPage))
	r.Post("/admin/users/{username}", getMiddleware(handlers.Admin, handlers.UserForm))

	//api
	r.Post("/api/login", http.HandlerFunc(handlers.Login))
	r.Post("/api/logout", http.HandlerFunc(handlers.Logout))
	r.Get("/api/ping", getMiddleware(handlers.Read, handlers.Ping))
	r.Get("/api/currentuser", getMiddleware(handlers.Read, handlers.GetCurrentUser))
	r.Get("/api/users", getMiddleware(handlers.Admin, handlers.GetUsers))
	r.Post("/api/users", getMiddleware(handlers.Admin, handlers.AddUser))
	r.Delete("/api/users/{username}", getMiddleware(handlers.Admin, handlers.DeleteUser))
	r.Post("/api/users/{username}/permission", getMiddleware(handlers.Admin, handlers.UpdateUserPermission))
	r.Post("/api/users/{username}/password", getMiddleware(handlers.Admin, handlers.UpdateUserPassword))
	r.Get("/api/users/{username}", getMiddleware(handlers.Admin, handlers.GetUser))
	r.Get("/api/gadgets", getMiddleware(handlers.Read, handlers.GetGadgets))
	r.Post("/api/gadgets", getMiddleware(handlers.Read, handlers.AddGadget))
	r.Get("/api/gadgets/{id}", getMiddleware(handlers.Read, handlers.GetGadget))
	r.Post("/api/gadgets/{id}", getMiddleware(handlers.Write, handlers.UpdateGadget))
	r.Delete("/api/gadgets/{id}", getMiddleware(handlers.Write, handlers.DeleteGadget))
	r.Post("/api/gadgets/{id}/command", getMiddleware(handlers.Write, handlers.SendCommand))
	r.Post("/api/gadgets/{id}/method", getMiddleware(handlers.Write, handlers.SendMethod))
	r.Get("/api/gadgets/{id}/websocket", getMiddleware(handlers.Write, handlers.Connect))
	r.Get("/api/gadgets/{id}/values", getMiddleware(handlers.Read, handlers.GetUpdates))
	r.Get("/api/gadgets/{id}/status", getMiddleware(handlers.Read, handlers.GetStatus))
	r.Post("/api/gadgets/{id}/notes", getMiddleware(handlers.Write, handlers.AddNote))
	r.Get("/api/gadgets/{id}/notes", getMiddleware(handlers.Read, handlers.GetNotes))
	r.Get("/api/gadgets/{id}/locations/{location}/devices/{device}/status", getMiddleware(handlers.Read, handlers.GetDevice))
	r.Post("/api/gadgets/{id}/locations/{location}/devices/{device}/status", getMiddleware(handlers.Write, handlers.UpdateDevice))
	r.Get("/api/gadgets/{id}/sources/{name}", getMiddleware(handlers.Read, handlers.GetDataPoints))
	r.Get("/api/gadgets/{id}/sources/{name}/csv", getMiddleware(handlers.Read, handlers.GetDataPointsCSV))
	r.Get("/api/beer/{name}", getMiddleware(handlers.Read, handlers.GetRecipe))
	r.Get("/api/admin/clients", getMiddleware(handlers.Admin, handlers.GetClients))

	r.ServeFiles(http.FileServer(box.HTTPBox()))

	chain := alice.New(handlers.Auth(db, lg, "main"), handlers.FetchGadget(), handlers.Error(lg)).Then(r)
	http.Handle(root, chain)

	addr := fmt.Sprintf("%s:%s", iface, port)
	lg.Printf("listening on %s\n", addr)
	if keyPath == "" {
		lg.Println(http.ListenAndServe(addr, chain))
	} else {
		lg.Println(http.ListenAndServeTLS(fmt.Sprintf("%s:443", iface), certPath, keyPath, chain))
	}
}

func startHomeKit(db *bolt.DB, lg quimby.Logger) {
	key := os.Getenv("QUIMBY_HOMEKIT")
	if key == "" {
		lg.Println("QUIMBY_HOMEKIT not set, not starting homekit")
		return
	}
	hk := quimby.NewHomeKit(key, db)
	hk.Start()
}

//This is the endpoint that the gadgets report to. It is
//served on a separate port so it doesn't have to be exposed
//publicly if the main port is exposed.
func startInternal(iRoot string, db *bolt.DB, lg quimby.Logger, port string) {
	r := rex.New("internal")
	r.Post("/internal/updates", getMiddleware(handlers.Write, handlers.RelayMessage))
	r.Post("/internal/gadgets/{id}/sources/{name}", getMiddleware(handlers.Write, handlers.AddDataPoint))

	chain := alice.New(handlers.Auth(db, lg, "internal"), handlers.FetchGadget()).Then(r)

	http.Handle(iRoot, chain)
	a := fmt.Sprintf(":%s", port)
	lg.Printf("listening on %s", a)
	err := http.ListenAndServe(a, chain)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>updated version<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/GeertJohan/go.rice"
	"github.com/boltdb/bolt"
	"github.com/cswank/quimby"
	"github.com/cswank/quimby/cmd/quimby/handlers"
	"github.com/cswank/quimby/cmd/quimby/utils"
	"github.com/cswank/rex"
	"github.com/justinas/alice"
	"gopkg.in/alecthomas/kingpin.v2"
)

const (
	version = "1.0.0"
)

var (
	users        = kingpin.Command("users", "User management")
	userAdd      = users.Command("add", "Add a new user.")
	userName     = users.Flag("username", "Username for a new user").String()
	userPW       = users.Flag("password", "Password for a new user").String()
	userPerm     = users.Flag("permission", "Permission (read, write, or admin").String()
	userList     = users.Command("list", "List users.")
	userEdit     = users.Command("edit", "Update a user.")
	cert         = kingpin.Command("cert", "Make an tls cert.")
	domain       = cert.Flag("domain", "The domain for the tls cert.").Required().Short('d').String()
	pth          = cert.Flag("path", "The directory where the cert files will be written").Required().Short('p').String()
	serve        = kingpin.Command("serve", "Start the server.")
	setup        = kingpin.Command("setup", "Set up the the server (keys and init scripts and what not.")
	net          = setup.Flag("net", "network interface").Short('n').Default("eth0").String()
	setupDomain  = setup.Flag("domain", "network interface").Required().Short('d').String()
	command      = kingpin.Command("command", "Send a command.")
	method       = kingpin.Command("method", "Send a method.")
	gadgets      = kingpin.Command("gadgets", "Commands for managing gadgets")
	gadgetAdd    = gadgets.Command("add", "Add a gadget.")
	gadgetName   = gadgets.Flag("name", "Name of the gadget.").String()
	gadgetHost   = gadgets.Flag("host", "ip address of gadget (id http://<ipaddr>:6111)").String()
	gadgetList   = gadgets.Command("list", "List the gadgets.")
	gadgetEdit   = gadgets.Command("edit", "List the gadgets.")
	gadgetDelete = gadgets.Command("delete", "Delete a gadget.")
	token        = kingpin.Command("token", "Generate a jwt token")
	bootstrap    = kingpin.Command("bootstrap", "Set up a bunch of stuff")

	keyPath  = os.Getenv("QUIMBY_TLS_KEY")
	certPath = os.Getenv("QUIMBY_TLS_CERT")
	iface    = os.Getenv("QUIMBY_INTERFACE")

	box *rice.Box
)

func main() {
	kingpin.UsageTemplate(kingpin.CompactUsageTemplate).Version(version).Author("Craig Swank")
	switch kingpin.Parse() {
	case "cert":
		utils.GenerateCert(*domain, *pth)
	case "users add":
		doUser(utils.AddUser)
	case "users list":
		addDB(utils.ListUsers)
	case "users edit":
		addDB(utils.EditUser)
	case "gadgets add":
		doGadget(utils.AddGadget)
	case "gadgets list":
		addDB(utils.ListGadgets)
	case "gadgets edit":
		addDB(utils.EditGadget)
	case "gadgets delete":
		addDB(utils.DeleteGadget)
	case "command":
		addDB(utils.SendCommand)
	case "token":
		utils.GetToken()
	case "bootstrap":
		utils.Bootstrap()
	case "serve":
		box = rice.MustFindBox("static")
		handlers.Init(box)
		addDB(startServer)
	case "setup":
		utils.SetupServer(*setupDomain, *net)
	}
}

type dbNeeder func(*bolt.DB)
type userNeeder func(*quimby.User)
type gadgetNeeder func(*quimby.Gadget)

func getDB() *bolt.DB {
	pth := os.Getenv("QUIMBY_DB")
	if pth == "" {
		log.Fatal("you must specify a db location with QUIMBY_DB")
	}
	db, err := quimby.GetDB(pth)
	if err != nil {
		log.Fatalf("could not open db at %s - %v", pth, err)
	}
	return db
}

func doUser(f userNeeder) {
	db := getDB()
	u := quimby.NewUser(
		*userName,
		quimby.UserDB(db),
		quimby.UserPassword(*userPW),
		quimby.UserPermission(*userPerm),
	)
	f(u)
	defer db.Close()
}

func doGadget(f gadgetNeeder) {
	db := getDB()
	g := &quimby.Gadget{
		DB:   db,
		Name: *gadgetName,
		Host: *gadgetHost,
	}
	f(g)
	db.Close()
}

func addDB(f dbNeeder) {
	db := getDB()
	f(db)
	defer db.Close()
}

func startServer(db *bolt.DB) {
	port := os.Getenv("QUIMBY_PORT")
	if port == "" {
		log.Fatal("you must specify a port with QUIMBY_PORT")
	}

	domain := os.Getenv("QUIMBY_DOMAIN")
	if domain == "" {
		log.Fatal("you must specify a domain with QUIMBY_DOMAIN")
	}

	internalPort := os.Getenv("QUIMBY_INTERNAL_PORT")
	if port == "" {
		log.Fatal("you must specify a port with QUIMBY_INTERNAL_PORT")
	}

	var lg *log.Logger
	if os.Getenv("QUIMBY_NULLLOG") != "" {
		lg = log.New(ioutil.Discard, "quimby ", log.Ltime)
	} else {
		lg = log.New(os.Stdout, "quimby ", log.Ltime)
	}
	clients := quimby.NewClientHolder()
	tfa := quimby.NewTFA(domain)
	start(db, port, internalPort, "/", "/api", lg, clients, tfa)
}

func getMiddleware(perm handlers.ACL, f http.HandlerFunc) http.Handler {
	return alice.New(handlers.Perm(perm)).Then(http.HandlerFunc(f))
}

func start(db *bolt.DB, port, internalPort, root string, iRoot string, lg quimby.Logger, clients *quimby.ClientHolder, tfa quimby.TFAer) {

	quimby.Clients = clients
	quimby.DB = db
	quimby.LG = lg
	handlers.DB = db
	handlers.LG = lg
	handlers.TFA = tfa

	go startInternal(iRoot, db, lg, internalPort)
	go startHomeKit(db, lg)

	r := rex.New("main")
	r.Get("/", getMiddleware(handlers.Read, handlers.IndexPage))
	r.Get("/gadgets/{id}", getMiddleware(handlers.Read, handlers.GadgetPage))
	r.Get("/login.html", getMiddleware(handlers.Anyone, handlers.LoginPage))
	r.Get("/logout.html", getMiddleware(handlers.Read, handlers.LogoutPage))
	r.Post("/login.html", getMiddleware(handlers.Anyone, handlers.LoginForm))
	r.Get("/admin.html", getMiddleware(handlers.Admin, handlers.AdminPage))
	r.Get("/admin/gadgets/{id}", getMiddleware(handlers.Admin, handlers.GadgetEditPage))
	r.Post("/admin/gadgets/{id}", getMiddleware(handlers.Admin, handlers.GadgetForm))
	r.Get("/admin/users/{username}", getMiddleware(handlers.Admin, handlers.UserEditPage))
	r.Get("/admin/users/{username}/password", getMiddleware(handlers.Admin, handlers.UserPasswordPage))
	r.Post("/admin/users/{username}/password", getMiddleware(handlers.Admin, handlers.UserChangePasswordPage))
	r.Post("/admin/users/{username}/tfa", getMiddleware(handlers.Admin, handlers.UserTFAPage))
	r.Post("/admin/users/{username}/do-delete", getMiddleware(handlers.Admin, handlers.DeleteUserPage))
	r.Get("/admin/users/{username}/delete", getMiddleware(handlers.Admin, handlers.DeleteUserConfirmPage))
	r.Post("/admin/users/{username}", getMiddleware(handlers.Admin, handlers.UserForm))

	//api
	r.Post("/api/login", http.HandlerFunc(handlers.Login))
	r.Post("/api/logout", http.HandlerFunc(handlers.Logout))
	r.Get("/api/ping", getMiddleware(handlers.Read, handlers.Ping))
	r.Get("/api/currentuser", getMiddleware(handlers.Read, handlers.GetCurrentUser))
	r.Get("/api/users", getMiddleware(handlers.Admin, handlers.GetUsers))
	r.Post("/api/users", getMiddleware(handlers.Admin, handlers.AddUser))
	r.Delete("/api/users/{username}", getMiddleware(handlers.Admin, handlers.DeleteUser))
	r.Post("/api/users/{username}/permission", getMiddleware(handlers.Admin, handlers.UpdateUserPermission))
	r.Post("/api/users/{username}/password", getMiddleware(handlers.Admin, handlers.UpdateUserPassword))
	r.Get("/api/users/{username}", getMiddleware(handlers.Admin, handlers.GetUser))
	r.Get("/api/gadgets", getMiddleware(handlers.Read, handlers.GetGadgets))
	r.Post("/api/gadgets", getMiddleware(handlers.Read, handlers.AddGadget))
	r.Get("/api/gadgets/{id}", getMiddleware(handlers.Read, handlers.GetGadget))
	r.Post("/api/gadgets/{id}", getMiddleware(handlers.Write, handlers.UpdateGadget))
	r.Delete("/api/gadgets/{id}", getMiddleware(handlers.Write, handlers.DeleteGadget))
	r.Post("/api/gadgets/{id}/command", getMiddleware(handlers.Write, handlers.SendCommand))
	r.Post("/api/gadgets/{id}/method", getMiddleware(handlers.Write, handlers.SendMethod))
	r.Get("/api/gadgets/{id}/websocket", getMiddleware(handlers.Write, handlers.Connect))
	r.Get("/api/gadgets/{id}/values", getMiddleware(handlers.Read, handlers.GetUpdates))
	r.Get("/api/gadgets/{id}/status", getMiddleware(handlers.Read, handlers.GetStatus))
	r.Post("/api/gadgets/{id}/notes", getMiddleware(handlers.Write, handlers.AddNote))
	r.Get("/api/gadgets/{id}/notes", getMiddleware(handlers.Read, handlers.GetNotes))
	r.Get("/api/gadgets/{id}/locations/{location}/devices/{device}/status", getMiddleware(handlers.Read, handlers.GetDevice))
	r.Post("/api/gadgets/{id}/locations/{location}/devices/{device}/status", getMiddleware(handlers.Write, handlers.UpdateDevice))
	r.Get("/api/gadgets/{id}/sources/{name}", getMiddleware(handlers.Read, handlers.GetDataPoints))
	r.Get("/api/gadgets/{id}/sources/{name}/csv", getMiddleware(handlers.Read, handlers.GetDataPointsCSV))
	r.Get("/api/beer/{name}", getMiddleware(handlers.Read, handlers.GetRecipe))
	r.Get("/api/admin/clients", getMiddleware(handlers.Admin, handlers.GetClients))

	r.ServeFiles(http.FileServer(box.HTTPBox()))

	chain := alice.New(handlers.Auth(db, lg, "main"), handlers.FetchGadget(), handlers.Error(lg)).Then(r)
	http.Handle(root, chain)

	addr := fmt.Sprintf("%s:%s", iface, port)
	lg.Printf("listening on %s\n", addr)
	if keyPath == "" {
		lg.Println(http.ListenAndServe(addr, chain))
	} else {
		lg.Println(http.ListenAndServeTLS(fmt.Sprintf("%s:443", iface), certPath, keyPath, chain))
	}
}

func startHomeKit(db *bolt.DB, lg quimby.Logger) {
	key := os.Getenv("QUIMBY_HOMEKIT")
	if key == "" {
		lg.Println("QUIMBY_HOMEKIT not set, not starting homekit")
		return
	}
	hk := quimby.NewHomeKit(key, db)
	hk.Start()
}

//This is the endpoint that the gadgets report to. It is
//served on a separate port so it doesn't have to be exposed
//publicly if the main port is exposed.
func startInternal(iRoot string, db *bolt.DB, lg quimby.Logger, port string) {
	r := rex.New("internal")
	r.Post("/internal/updates", getMiddleware(handlers.Write, handlers.RelayMessage))
	r.Post("/internal/gadgets/{id}/sources/{name}", getMiddleware(handlers.Write, handlers.AddDataPoint))

	chain := alice.New(handlers.Auth(db, lg, "internal"), handlers.FetchGadget()).Then(r)

	http.Handle(iRoot, chain)
	a := fmt.Sprintf(":%s", port)
	lg.Printf("listening on %s", a)
	err := http.ListenAndServe(a, chain)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	gopaths = strings.Split(os.Getenv("GOPATH"), ":")
	cwd     string

	build     = flag.Bool("build", false, "build the current build as slurp-bin")
	install   = flag.Bool("install", false, "install current slurp.Go as slurp.PKG.")
	bare      = flag.Bool("bare", false, "Run/Install the slurp.go file without any other files.")
	slurpfile = flag.String("slurpfile", "slurp.go", "The file that includes the Slurp(*s.Build) function, use by -bare")

	keep = flag.Bool("keep", false, "keep the generated source under $GOPATH/src/slurp-run-*")
)

func main() {

	flag.Parse()

	if len(gopaths) == 0 || gopaths[0] == "" {
		log.Fatal("$GOPATH must be set.")
	}

	err := run()
	if err != nil {
		log.Fatal(err)
	}
}

func run() error {
	path, err := generate()
	if err != nil {
		return err
	}

	//Don't forget to clean up.
	if !*keep {
		defer os.RemoveAll(path)
	}

	get := exec.Command("go", "get", "-tags=slurp", "-v")
	get.Dir = path
	get.Stdin = os.Stdin
	get.Stdout = os.Stdout
	get.Stderr = os.Stderr

	if *build || *install {
		err := get.Run()
		if err != nil {
			return err
		}
	}

	var args []string

	if *build {
		args = []string{"build", "-tags=slurp", "-o=slurp-bin", path}

	} else if *install {
		args = []string{"install", "-tags=slurp", path}

	} else {
		params := flag.Args()

		if len(params) > 0 && params[0] == "init" {
			err := get.Run()
			if err != nil {
				return err
			}
		}

		args = []string{"run", "-tags=slurp", filepath.Join(path, "main.go")}
		args = append(args, params...)
	}

	cmd := exec.Command("go", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err = cmd.Run()

	if err != nil {
		return err
	}

	return nil
}

func generate() (string, error) {

	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}

	// find the correct gopath
	var gopathsrc string
	var pkgpath string
	for _, gopath := range gopaths {
		gopathsrcTest := filepath.Join(gopath, "src")
		// the target package import path.
		pkgpath, err = filepath.Rel(gopathsrcTest, cwd)
		if err != nil {
			return "", err
		}
		if base := filepath.Base(pkgpath); base == "." || base == ".." {
			continue // cwd is outside this gopath
		}
		gopathsrc = gopathsrcTest
	}

	if gopathsrc == "" {
		return "", errors.New("forbidden path. Your CWD must be under $GOPATH/src.")
	}

	//build our package path.
	path := filepath.Join(gopathsrc, "slurp", pkgpath)

	//Clean it up.
	os.RemoveAll(path)

	//log.Println("Creating temporary build path...", path)
	//Create the runner package directory.
	err = os.MkdirAll(path, 0700)
	if err != nil {
		return path, err
	}

	//TODO, copy [*.go !_test.go] files into tmp first,
	// this would allow slurp to work for broken packages
	// with "-bare" as the package files will be excluded.
	fset := token.NewFileSet() // positions are relative to fset

	var pkgs map[string]*ast.Package

	//log.Printf("Parsing %s...", pkgpath)

	if *bare {
		pkgs = make(map[string]*ast.Package)
		src, err := parser.ParseFile(fset, *slurpfile, nil, parser.PackageClauseOnly)
		if err != nil {
			return path, err
		}
		pkgs[src.Name.Name] = &ast.Package{
			Name:  src.Name.Name,
			Files: map[string]*ast.File{filepath.Join(cwd, *slurpfile): src},
		}
	} else {
		pkgs, err = parser.ParseDir(fset, cwd, nil, parser.PackageClauseOnly)
		if err != nil {
			return path, err
		}
	}

	if len(pkgs) > 1 {
		return path, errors.New("Error: Multiple packages detected.")
	}

	_, ok := pkgs["main"]

	if ok {
		//Create the target package directory.
		tmp := filepath.Join(path, "tmp")
		err = os.Mkdir(tmp, 0700)
		if err != nil {
			return path, err
		}

		for _, pkg := range pkgs {
			for file, f := range pkg.Files {
				name, err := filepath.Rel(cwd, file)
				if err != nil {
					//Should never get error. But just incase.
					return path, err
				}
				dstfile, err := os.Create(filepath.Join(tmp, name))
				if err != nil {
					return path, err
				}
				defer dstfile.Close()
				srcfile, err := os.Open(file)
				if err != nil {
					return path, err
				}
				defer srcfile.Close()
				_, err = io.Copy(dstfile, srcfile)
				if err != nil {
					return path, err
				}

				err = dstfile.Sync()
				if err != nil {
					return path, err
				}

				pos := fset.Position(f.Name.NamePos)

				_, err = dstfile.Seek(int64(pos.Offset), 0)
				if err != nil {
					return path, err
				}

				_, err = dstfile.Write([]byte(`niam`))
				if err != nil {
					return path, err
				}

			}
		}

		pkgpath = filepath.Join("slurp", pkgpath, "tmp")
	}

	//log.Println("Generating the runner...")
	file, err := os.Create(filepath.Join(path, "main.go"))
	if err != nil {
		return path, err
	}

	//tmp = filepath.Join(tmp, "tmp")

	err = runnerSrc.Execute(file, filepath.ToSlash(pkgpath))
	if err != nil {
		return path, err
	}

	err = file.Close()
	if err != nil {
		return path, err
	}

	return path, nil

}
<commit_msg>cmd/slurp: Drop uncessary loop. Drop unnecessary sync to disk<commit_after>package main

import (
	"errors"
	"flag"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	gopaths = strings.Split(os.Getenv("GOPATH"), ":")
	cwd     string

	build     = flag.Bool("build", false, "build the current build as slurp-bin")
	install   = flag.Bool("install", false, "install current slurp.Go as slurp.PKG.")
	bare      = flag.Bool("bare", false, "Run/Install the slurp.go file without any other files.")
	slurpfile = flag.String("slurpfile", "slurp.go", "The file that includes the Slurp(*s.Build) function, use by -bare")

	keep = flag.Bool("keep", false, "keep the generated source under $GOPATH/src/slurp-run-*")
)

func main() {

	flag.Parse()

	if len(gopaths) == 0 || gopaths[0] == "" {
		log.Fatal("$GOPATH must be set.")
	}

	err := run()
	if err != nil {
		log.Fatal(err)
	}
}

func run() error {
	path, err := generate()
	if err != nil {
		return err
	}

	//Don't forget to clean up.
	if !*keep {
		defer os.RemoveAll(path)
	}

	get := exec.Command("go", "get", "-tags=slurp", "-v")
	get.Dir = path
	get.Stdin = os.Stdin
	get.Stdout = os.Stdout
	get.Stderr = os.Stderr

	if *build || *install {
		err := get.Run()
		if err != nil {
			return err
		}
	}

	var args []string

	if *build {
		args = []string{"build", "-tags=slurp", "-o=slurp-bin", path}

	} else if *install {
		args = []string{"install", "-tags=slurp", path}

	} else {
		params := flag.Args()

		if len(params) > 0 && params[0] == "init" {
			err := get.Run()
			if err != nil {
				return err
			}
		}

		args = []string{"run", "-tags=slurp", filepath.Join(path, "main.go")}
		args = append(args, params...)
	}

	cmd := exec.Command("go", args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err = cmd.Run()

	if err != nil {
		return err
	}

	return nil
}

func generate() (string, error) {

	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}

	// find the correct gopath
	var gopathsrc string
	var pkgpath string
	for _, gopath := range gopaths {
		gopathsrcTest := filepath.Join(gopath, "src")
		// the target package import path.
		pkgpath, err = filepath.Rel(gopathsrcTest, cwd)
		if err != nil {
			return "", err
		}
		if base := filepath.Base(pkgpath); base == "." || base == ".." {
			continue // cwd is outside this gopath
		}
		gopathsrc = gopathsrcTest
	}

	if gopathsrc == "" {
		return "", errors.New("forbidden path. Your CWD must be under $GOPATH/src.")
	}

	//build our package path.
	path := filepath.Join(gopathsrc, "slurp", pkgpath)

	//Clean it up.
	os.RemoveAll(path)

	//log.Println("Creating temporary build path...", path)
	//Create the runner package directory.
	err = os.MkdirAll(path, 0700)
	if err != nil {
		return path, err
	}

	//TODO, copy [*.go !_test.go] files into tmp first,
	// this would allow slurp to work for broken packages
	// with "-bare" as the package files will be excluded.
	fset := token.NewFileSet() // positions are relative to fset

	var pkgs map[string]*ast.Package

	//log.Printf("Parsing %s...", pkgpath)

	if *bare {
		pkgs = make(map[string]*ast.Package)
		src, err := parser.ParseFile(fset, *slurpfile, nil, parser.PackageClauseOnly)
		if err != nil {
			return path, err
		}
		pkgs[src.Name.Name] = &ast.Package{
			Name:  src.Name.Name,
			Files: map[string]*ast.File{filepath.Join(cwd, *slurpfile): src},
		}
	} else {
		pkgs, err = parser.ParseDir(fset, cwd, nil, parser.PackageClauseOnly)
		if err != nil {
			return path, err
		}
	}

	if len(pkgs) > 1 {
		return path, errors.New("Error: Multiple packages detected.")
	}

	main, ok := pkgs["main"]

	if ok {
		//Create the target package directory.
		tmp := filepath.Join(path, "tmp")
		err = os.Mkdir(tmp, 0700)
		if err != nil {
			return path, err
		}

		for file, f := range main.Files {
			name, err := filepath.Rel(cwd, file)
			if err != nil {
				//Should never get error. But just incase.
				return path, err
			}
			dstfile, err := os.Create(filepath.Join(tmp, name))
			if err != nil {
				return path, err
			}
			defer dstfile.Close()
			srcfile, err := os.Open(file)
			if err != nil {
				return path, err
			}
			defer srcfile.Close()
			_, err = io.Copy(dstfile, srcfile)
			if err != nil {
				return path, err
			}

			pos := fset.Position(f.Name.NamePos)

			_, err = dstfile.Seek(int64(pos.Offset), 0)
			if err != nil {
				return path, err
			}

			_, err = dstfile.Write([]byte(`niam`))
			if err != nil {
				return path, err
			}
		}

		pkgpath = filepath.Join("slurp", pkgpath, "tmp")
	}

	//log.Println("Generating the runner...")
	file, err := os.Create(filepath.Join(path, "main.go"))
	if err != nil {
		return path, err
	}

	//tmp = filepath.Join(tmp, "tmp")

	err = runnerSrc.Execute(file, filepath.ToSlash(pkgpath))
	if err != nil {
		return path, err
	}

	err = file.Close()
	if err != nil {
		return path, err
	}

	return path, nil

}
<|endoftext|>