<commit_before>package cli

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"

	"github.com/opentable/sous/ext/docker"
	"github.com/opentable/sous/ext/git"
	"github.com/opentable/sous/ext/singularity"
	"github.com/opentable/sous/ext/storage"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/cmdr"
	"github.com/opentable/sous/util/docker_registry"
	"github.com/opentable/sous/util/shell"
	"github.com/samsalisbury/psyringe"
	"github.com/samsalisbury/semv"
)

type (
	// Out is an output used for real data a Command returns. This should only
	// be used when a command needs to write directly to stdout, using the
	// formatting options that come with an output. Usually, you should use a
	// SuccessResult with Data to return data.
	Out struct{ *cmdr.Output }
	// ErrOut is an output used for logging from a Command. This should only be
	// used when a Command needs to write a lot of data to stderr, using the
	// formatting options that come with and Output. Usually you should use and
	// ErrorResult to return error messages.
	ErrOut struct{ *cmdr.Output }
	// SousCLIGraph is a dependency injector used to flesh out Sous commands
	// with their dependencies.
	SousCLIGraph struct{ *psyringe.Psyringe }
	// Version represents a version of Sous.
	Version struct{ semv.Version }
	// LocalUser is the currently logged in user.
	LocalUser struct{ *User }
	// LocalSousConfig is the configuration for Sous.
	LocalSousConfig struct{ *sous.Config }
	// LocalWorkDir is the user's current working directory when they invoke Sous.
	LocalWorkDir string
	// LocalWorkDirShell is a shell for working in the user's current working
	// directory.
	LocalWorkDirShell struct{ *shell.Sh }
	// LocalGitClient is a git client rooted in WorkdirShell.Dir.
	LocalGitClient struct{ *git.Client }
	// LocalGitRepo is the git repository containing WorkDir.
	LocalGitRepo struct{ *git.Repo }
	// ScratchDirShell is a shell for working in the scratch area where things
	// like artefacts, and build metadata are stored. It is a new, empty
	// directory, and should be cleaned up eventually.
	ScratchDirShell struct{ *shell.Sh }
	// LocalDockerClient is a docker client object
	LocalDockerClient struct{ docker_registry.Client }
	// LocalStateReader wraps a storage.StateReader, and should be configured
	// to use the current user's local storage.
	LocalStateReader struct{ storage.StateReader }
	// LocalStateWriter wraps a storage.StateWriter, and should be configured to
	// use the current user's local storage.
	LocalStateWriter struct{ storage.StateWriter }
	// CurrentGDM is a snapshot of the GDM at application start. In a CLI
	// context, which this is, that is all we need to simply read the GDM.
	CurrentGDM struct{ *sous.State }
)

// BuildGraph builds the dependency injection graph, used to populate commands
// invoked by the user.
func BuildGraph(s *Sous, c *cmdr.CLI) (*SousCLIGraph, error) {
	g := &SousCLIGraph{psyringe.New()}
	return g, g.Fill(
		s, c,
		newOut,
		newErrOut,
		newLocalUser,
		newLocalSousConfig,
		newLocalWorkDir,
		newLocalWorkDirShell,
		newScratchDirShell,
		newLocalGitClient,
		newLocalGitRepo,
		newSourceContext,
		newBuildContext,
		newDockerClient,
		newBuilder,
		newDeployer,
		newRegistry,
		newLocalDiskStateManager,
		newLocalStateReader,
		newLocalStateWriter,
		newCurrentGDM,
	)
}

func newOut(c *cmdr.CLI) Out {
	return Out{c.Out}
}

func newErrOut(c *cmdr.CLI) ErrOut {
	return ErrOut{c.Err}
}

func newSourceContext(g LocalGitRepo) (c *sous.SourceContext, err error) {
	c, err = g.SourceContext()
	return c, initErr(err, "getting local git context")
}

func newBuildContext(wd LocalWorkDirShell, c *sous.SourceContext) *sous.BuildContext {
	return &sous.BuildContext{
		Sh:     wd.Sh,
		Source: *c,
	}
}

func newLocalWorkDir() (LocalWorkDir, error) {
	s, err := os.Getwd()
	return LocalWorkDir(s), initErr(err, "determining working directory")
}

func newLocalUser() (v LocalUser, err error) {
	u, err := user.Current()
	v.User = &User{u}
	return v, initErr(err, "getting current user")
}

func newLocalSousConfig(u LocalUser) (v LocalSousConfig, err error) {
	v.Config, err = newConfig(u.User)
	return v, initErr(err, "getting default config")
}

func newLocalWorkDirShell(l LocalWorkDir) (v LocalWorkDirShell, err error) {
	v.Sh, err = shell.DefaultInDir(string(l))
	v.TeeEcho = os.Stdout
	v.TeeOut = os.Stdout
	v.TeeErr = os.Stderr
	return v, initErr(err, "getting current working directory")
}

// TODO: This should register a cleanup task with the cli, to delete the temp
// dir.
func newScratchDirShell() (v ScratchDirShell, err error) {
	what := "getting scratch directory"
	dir, err := ioutil.TempDir("", "sous")
	if err != nil {
		return v, initErr(err, what)
	}
	v.Sh, err = shell.DefaultInDir(dir)
	v.TeeOut = os.Stdout
	v.TeeErr = os.Stderr
	return v, initErr(err, what)
}

func newLocalGitClient(sh LocalWorkDirShell) (v LocalGitClient, err error) {
	v.Client, err = git.NewClient(sh.Sh)
	return v, initErr(err, "initialising git client")
}

func newLocalGitRepo(c LocalGitClient) (v LocalGitRepo, err error) {
	v.Repo, err = c.OpenRepo(".")
	return v, initErr(err, "opening local git repository")
}

func newBuilder(cl LocalDockerClient, ctx *sous.SourceContext, source LocalWorkDirShell, scratch ScratchDirShell, u LocalUser) (sous.Builder, error) {
	return makeDockerBuilder(cl, ctx, source, scratch, u)
}

func newRegistry(cl LocalDockerClient, u LocalUser) (sous.Registry, error) {
	return makeDockerRegistry(cl, u)
}

func makeDockerRegistry(cl LocalDockerClient, u LocalUser) (*docker.NameCache, error) {
	cfg := u.DefaultConfig()
	dbCfg := &docker.DBConfig{Driver: cfg.DatabaseDriver, Connection: cfg.DatabaseConnection}
	db, err := docker.GetDatabase(dbCfg)
	if err != nil {
		return nil, fmt.Errorf("unable to build name cache DB: ", err)
	}
	return &docker.NameCache{cl.Client, db}, nil
}

func makeDockerBuilder(cl LocalDockerClient, ctx *sous.SourceContext, source LocalWorkDirShell, scratch ScratchDirShell, u LocalUser) (*docker.Builder, error) {
	nc, err := makeDockerRegistry(cl, u)
	if err != nil {
		return nil, err
	}
	// TODO: Get this from config.
	drh := "docker.otenv.com"
	return docker.NewBuilder(nc, drh, ctx, source.Sh, scratch.Sh)
}

func newDeployer(r sous.Registry) (sous.Deployer, error) {
	ra := singularity.NewRectiAgent(r)
	return singularity.NewDeployer(r, ra), nil
}

func newDockerClient() LocalDockerClient {
	return LocalDockerClient{docker_registry.NewClient()}
}

func newLocalDiskStateManager(c LocalSousConfig) (*storage.DiskStateManager, error) {
	sm, err := storage.NewDiskStateManager(c.StateLocation)
	return sm, initErr(err, "initialising sous state")
}

func newLocalStateReader(sm *storage.DiskStateManager) LocalStateReader {
	return LocalStateReader{sm}
}

func newLocalStateWriter(sm *storage.DiskStateManager) LocalStateWriter {
	return LocalStateWriter{sm}
}

func newCurrentGDM(sr LocalStateReader) (CurrentGDM, error) {
	gdm, err := sr.ReadState()
	return CurrentGDM{gdm}, initErr(err, "reading sous state")
}

// initErr returns nil if error is nil, otherwise an initialisation error.
func initErr(err error, what string) error {
	if err == nil {
		return nil
	}
	message := fmt.Sprintf("error %s:", what)
	if shellErr, ok := err.(shell.Error); ok {
		message += fmt.Sprintf("\ncommand failed:\nshell> %s\n%s",
			shellErr.Command.String(), shellErr.Result.Combined.String())
	} else {
		message += " " + err.Error()
	}
	return fmt.Errorf(message)
}
<commit_msg>cli: Tidy up DI graph a bit.<commit_after>package cli

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"

	"github.com/opentable/sous/ext/docker"
	"github.com/opentable/sous/ext/git"
	"github.com/opentable/sous/ext/singularity"
	"github.com/opentable/sous/ext/storage"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/cmdr"
	"github.com/opentable/sous/util/docker_registry"
	"github.com/opentable/sous/util/shell"
	"github.com/samsalisbury/psyringe"
	"github.com/samsalisbury/semv"
)

type (
	// Out is an output used for real data a Command returns. This should only
	// be used when a command needs to write directly to stdout, using the
	// formatting options that come with an output. Usually, you should use a
	// SuccessResult with Data to return data.
	Out struct{ *cmdr.Output }
	// ErrOut is an output used for logging from a Command. This should only be
	// used when a Command needs to write a lot of data to stderr, using the
	// formatting options that come with and Output. Usually you should use and
	// ErrorResult to return error messages.
	ErrOut struct{ *cmdr.Output }
	// SousCLIGraph is a dependency injector used to flesh out Sous commands
	// with their dependencies.
	SousCLIGraph struct{ *psyringe.Psyringe }
	// Version represents a version of Sous.
	Version struct{ semv.Version }
	// LocalUser is the currently logged in user.
	LocalUser struct{ *User }
	// LocalSousConfig is the configuration for Sous.
	LocalSousConfig struct{ *sous.Config }
	// LocalWorkDir is the user's current working directory when they invoke Sous.
	LocalWorkDir string
	// LocalWorkDirShell is a shell for working in the user's current working
	// directory.
	LocalWorkDirShell struct{ *shell.Sh }
	// LocalGitClient is a git client rooted in WorkdirShell.Dir.
	LocalGitClient struct{ *git.Client }
	// LocalGitRepo is the git repository containing WorkDir.
	LocalGitRepo struct{ *git.Repo }
	// ScratchDirShell is a shell for working in the scratch area where things
	// like artefacts, and build metadata are stored. It is a new, empty
	// directory, and should be cleaned up eventually.
	ScratchDirShell struct{ *shell.Sh }
	// LocalDockerClient is a docker client object
	LocalDockerClient struct{ docker_registry.Client }
	// LocalStateReader wraps a storage.StateReader, and should be configured
	// to use the current user's local storage.
	LocalStateReader struct{ storage.StateReader }
	// LocalStateWriter wraps a storage.StateWriter, and should be configured to
	// use the current user's local storage.
	LocalStateWriter struct{ storage.StateWriter }
	// CurrentGDM is a snapshot of the GDM at application start. In a CLI
	// context, which this is, that is all we need to simply read the GDM.
	CurrentGDM struct{ *sous.State }
)

// BuildGraph builds the dependency injection graph, used to populate commands
// invoked by the user.
func BuildGraph(s *Sous, c *cmdr.CLI) (*SousCLIGraph, error) {
	g := &SousCLIGraph{psyringe.New()}
	return g, g.Fill(
		s, c,
		newOut,
		newErrOut,
		newLocalUser,
		newLocalSousConfig,
		newLocalWorkDir,
		newLocalWorkDirShell,
		newScratchDirShell,
		newLocalGitClient,
		newLocalGitRepo,
		newSourceContext,
		newBuildContext,
		newDockerClient,
		newBuilder,
		newDeployer,
		newRegistry,
		newLocalDiskStateManager,
		newLocalStateReader,
		newLocalStateWriter,
		newCurrentGDM,
	)
}

func newOut(c *cmdr.CLI) Out {
	return Out{c.Out}
}

func newErrOut(c *cmdr.CLI) ErrOut {
	return ErrOut{c.Err}
}

func newSourceContext(g LocalGitRepo) (*sous.SourceContext, error) {
	c, err := g.SourceContext()
	return c, initErr(err, "getting local git context")
}

func newBuildContext(wd LocalWorkDirShell, c *sous.SourceContext) *sous.BuildContext {
	return &sous.BuildContext{
		Sh:     wd.Sh,
		Source: *c,
	}
}

func newLocalWorkDir() (LocalWorkDir, error) {
	s, err := os.Getwd()
	return LocalWorkDir(s), initErr(err, "determining working directory")
}

func newLocalUser() (v LocalUser, err error) {
	u, err := user.Current()
	v.User = &User{u}
	return v, initErr(err, "getting current user")
}

func newLocalSousConfig(u LocalUser) (v LocalSousConfig, err error) {
	v.Config, err = newConfig(u.User)
	return v, initErr(err, "getting configuration")
}

func newLocalWorkDirShell(l LocalWorkDir) (v LocalWorkDirShell, err error) {
	v.Sh, err = shell.DefaultInDir(string(l))
	v.TeeEcho = os.Stdout
	v.TeeOut = os.Stdout
	v.TeeErr = os.Stderr
	return v, initErr(err, "getting current working directory")
}

// TODO: This should register a cleanup task with the cli, to delete the temp
// dir.
func newScratchDirShell() (v ScratchDirShell, err error) {
	const what = "getting scratch directory"
	dir, err := ioutil.TempDir("", "sous")
	if err != nil {
		return v, initErr(err, what)
	}
	v.Sh, err = shell.DefaultInDir(dir)
	v.TeeOut = os.Stdout
	v.TeeErr = os.Stderr
	return v, initErr(err, what)
}

func newLocalGitClient(sh LocalWorkDirShell) (v LocalGitClient, err error) {
	v.Client, err = git.NewClient(sh.Sh)
	return v, initErr(err, "initialising git client")
}

func newLocalGitRepo(c LocalGitClient) (v LocalGitRepo, err error) {
	v.Repo, err = c.OpenRepo(".")
	return v, initErr(err, "opening local git repository")
}

func newBuilder(cfg LocalSousConfig, cl LocalDockerClient, ctx *sous.SourceContext, source LocalWorkDirShell, scratch ScratchDirShell, u LocalUser) (sous.Builder, error) {
	return makeDockerBuilder(cfg, cl, ctx, source, scratch)
}

func newRegistry(cfg LocalSousConfig, cl LocalDockerClient) (sous.Registry, error) {
	// Eventually, based on configuration, we may make different decisions here.
	r, err := makeDockerRegistry(cfg, cl)
	return r, initErr(err, "getting container registry")
}

func newDeployer(r sous.Registry) sous.Deployer {
	// Eventually, based on configuration, we may make different decisions here.
	return singularity.NewDeployer(r, singularity.NewRectiAgent(r))
}

func newDockerClient() LocalDockerClient {
	return LocalDockerClient{docker_registry.NewClient()}
}

func newLocalDiskStateManager(c LocalSousConfig) (*storage.DiskStateManager, error) {
	sm, err := storage.NewDiskStateManager(c.StateLocation)
	return sm, initErr(err, "initialising sous state")
}

func newLocalStateReader(sm *storage.DiskStateManager) LocalStateReader {
	return LocalStateReader{sm}
}

func newLocalStateWriter(sm *storage.DiskStateManager) LocalStateWriter {
	return LocalStateWriter{sm}
}

func newCurrentGDM(sr LocalStateReader) (CurrentGDM, error) {
	gdm, err := sr.ReadState()
	return CurrentGDM{gdm}, initErr(err, "reading sous state")
}

// The funcs named makeXXX below are used to create specific implementations of
// sous native types.

// makeDockerRegistry creates a Docker version of sous.Registry
func makeDockerRegistry(cfg LocalSousConfig, cl LocalDockerClient) (*docker.NameCache, error) {
	dbCfg := &docker.DBConfig{Driver: cfg.DatabaseDriver, Connection: cfg.DatabaseConnection}
	db, err := docker.GetDatabase(dbCfg)
	if err != nil {
		return nil, fmt.Errorf("unable to build name cache DB: %s", err)
	}
	return &docker.NameCache{cl.Client, db}, nil
}

// makeDockerBuilder creates a Docker version of sous.Builder
func makeDockerBuilder(cfg LocalSousConfig, cl LocalDockerClient, ctx *sous.SourceContext, source LocalWorkDirShell, scratch ScratchDirShell) (*docker.Builder, error) {
	nc, err := makeDockerRegistry(cfg, cl)
	if err != nil {
		return nil, err
	}
	// TODO: Get this from config.
	drh := "docker.otenv.com"
	return docker.NewBuilder(nc, drh, ctx, source.Sh, scratch.Sh)
}

// initErr returns nil if error is nil, otherwise an initialisation error.
// The second argument "what" should be a very short description of the
// initialisation task, e.g. "getting widget" or "reading state" etc.
func initErr(err error, what string) error {
	if err == nil {
		return nil
	}
	message := fmt.Sprintf("error %s:", what)
	if shellErr, ok := err.(shell.Error); ok {
		message += fmt.Sprintf("\ncommand failed:\nshell> %s\n%s",
			shellErr.Command.String(), shellErr.Result.Combined.String())
	} else {
		message += " " + err.Error()
	}
	return fmt.Errorf(message)
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/WatchBeam/clock"
	kitlog "github.com/go-kit/kit/log"
	kitprometheus "github.com/go-kit/kit/metrics/prometheus"
	"github.com/kolide/kolide-ose/server/config"
	"github.com/kolide/kolide-ose/server/datastore"
	"github.com/kolide/kolide-ose/server/kolide"
	"github.com/kolide/kolide-ose/server/mail"
	"github.com/kolide/kolide-ose/server/service"
	"github.com/kolide/kolide-ose/server/version"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

func createServeCmd(configManager config.Manager) *cobra.Command {
	var devMode bool = false

	serveCmd := &cobra.Command{
		Use:   "serve",
		Short: "Launch the kolide server",
		Long: `
Launch the kolide server

Use kolide serve to run the main HTTPS server. The Kolide server bundles
together all static assets and dependent libraries into a statically linked go
binary (which you're executing right now). Use the options below to customize
the way that the kolide server works.
`,
		Run: func(cmd *cobra.Command, args []string) {
			var (
				httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
				ctx      = context.Background()
				logger   kitlog.Logger
			)
			flag.Parse()

			config := configManager.LoadConfig()

			logger = kitlog.NewLogfmtLogger(os.Stderr)
			logger = kitlog.NewContext(logger).With("ts", kitlog.DefaultTimestampUTC)

			var mailService kolide.MailService
			if devMode {
				mailService = devMailService{}
			} else {
				mailService = mail.NewService(config.SMTP)
			}

			var ds kolide.Datastore
			var err error
			if devMode {
				fmt.Println(
					"Dev mode enabled, using in-memory DB.\n",
					"Warning: Changes will not be saved across process restarts. This should NOT be used in production.",
				)
				ds, err = datastore.New("inmem", "")
				if err != nil {
					initFatal(err, "initializing datastore")
				}

			} else {
				connString := datastore.GetMysqlConnectionString(config.Mysql)
				ds, err = datastore.New("gorm-mysql", connString)
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			}

			svc, err := service.NewService(ds, logger, config, mailService, clock.C)
			if err != nil {
				initFatal(err, "initializing service")
			}

			if devMode {
				// Bootstrap a few users when using the in-memory database.
				// Each user's default password will just be their username.
				users := []kolide.User{
					{
						Name:     "Admin User",
						Username: "admin",
						Email:    "admin@kolide.co",
						Position: "Director of Security",
						Admin:    true,
						Enabled:  true,
					},
					{
						Name:     "Normal User",
						Username: "user",
						Email:    "user@kolide.co",
						Position: "Security Engineer",
						Admin:    false,
						Enabled:  true,
					},
				}

				for _, user := range users {
					user := user
					err := user.SetPassword(user.Username, config.Auth.SaltKeySize, config.Auth.BcryptCost)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
					_, err = ds.NewUser(&user)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
				}
				devOrgInfo := &kolide.OrgInfo{
					OrgName:    "Kolide",
					OrgLogoURL: fmt.Sprintf("%s/logo.png", config.Server.Address),
				}
				_, err := svc.NewOrgInfo(ctx, kolide.OrgInfoPayload{
					OrgName:    &devOrgInfo.OrgName,
					OrgLogoURL: &devOrgInfo.OrgLogoURL,
				})
				if err != nil {
					initFatal(err, "creating fake org info")
				}
			}

			fieldKeys := []string{"method", "error"}
			requestCount := kitprometheus.NewCounterFrom(prometheus.CounterOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_count",
				Help:      "Number of requests received.",
			}, fieldKeys)
			requestLatency := kitprometheus.NewSummaryFrom(prometheus.SummaryOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_latency_microseconds",
				Help:      "Total duration of requests in microseconds.",
			}, fieldKeys)

			svcLogger := kitlog.NewContext(logger).With("component", "service")
			svc = service.NewLoggingService(svc, svcLogger)
			svc = service.NewMetricsService(svc, requestCount, requestLatency)

			httpLogger := kitlog.NewContext(logger).With("component", "http")

			apiHandler := service.MakeHandler(ctx, svc, config.Auth.JwtKey, httpLogger)
			http.Handle("/api/", accessControl(apiHandler))
			http.Handle("/version", version.Handler())
			http.Handle("/metrics", prometheus.Handler())
			http.Handle("/assets/", service.ServeStaticAssets("/assets/"))
			http.Handle("/", service.ServeFrontend())

			errs := make(chan error, 2)
			go func() {
				if !config.Server.TLS || (devMode && !configManager.IsSet("server.tls")) {
					logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServe(*httpAddr, nil)
				} else {
					logger.Log("transport", "https", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServeTLS(
						*httpAddr,
						config.Server.Cert,
						config.Server.Key,
						nil,
					)
				}
			}()
			go func() {
				c := make(chan os.Signal)
				signal.Notify(c, syscall.SIGINT)
				errs <- fmt.Errorf("%s", <-c)
			}()

			logger.Log("terminated", <-errs)
		},
	}

	serveCmd.PersistentFlags().BoolVar(&devMode, "dev", false, "Use dev settings (in-mem DB, etc.)")

	return serveCmd
}

// used in devMode to print an email
// which would otherwise be sent via SMTP
type devMailService struct{}

func (devMailService) SendEmail(e kolide.Email) error {
	fmt.Println("---dev mode: printing email---")
	defer fmt.Println("---dev mode: email printed---")
	msg, err := e.Msg.Message()
	if err != nil {
		return err
	}
	fmt.Printf("From: %q To: %q \n", e.From, e.To)
	_, err = os.Stdout.Write(msg)
	return err

}

// cors headers
func accessControl(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")

		if r.Method == "OPTIONS" {
			return
		}

		h.ServeHTTP(w, r)
	})
}
<commit_msg>Perform migration at startup when using inmem datastore (#270)<commit_after>package cli

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/WatchBeam/clock"
	kitlog "github.com/go-kit/kit/log"
	kitprometheus "github.com/go-kit/kit/metrics/prometheus"
	"github.com/kolide/kolide-ose/server/config"
	"github.com/kolide/kolide-ose/server/datastore"
	"github.com/kolide/kolide-ose/server/kolide"
	"github.com/kolide/kolide-ose/server/mail"
	"github.com/kolide/kolide-ose/server/service"
	"github.com/kolide/kolide-ose/server/version"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

func createServeCmd(configManager config.Manager) *cobra.Command {
	var devMode bool = false

	serveCmd := &cobra.Command{
		Use:   "serve",
		Short: "Launch the kolide server",
		Long: `
Launch the kolide server

Use kolide serve to run the main HTTPS server. The Kolide server bundles
together all static assets and dependent libraries into a statically linked go
binary (which you're executing right now). Use the options below to customize
the way that the kolide server works.
`,
		Run: func(cmd *cobra.Command, args []string) {
			var (
				httpAddr = flag.String("http.addr", ":8080", "HTTP listen address")
				ctx      = context.Background()
				logger   kitlog.Logger
			)
			flag.Parse()

			config := configManager.LoadConfig()

			logger = kitlog.NewLogfmtLogger(os.Stderr)
			logger = kitlog.NewContext(logger).With("ts", kitlog.DefaultTimestampUTC)

			var mailService kolide.MailService
			if devMode {
				mailService = devMailService{}
			} else {
				mailService = mail.NewService(config.SMTP)
			}

			var ds kolide.Datastore
			var err error
			if devMode {
				fmt.Println(
					"Dev mode enabled, using in-memory DB.\n",
					"Warning: Changes will not be saved across process restarts. This should NOT be used in production.",
				)
				ds, err = datastore.New("inmem", "")
				if err != nil {
					initFatal(err, "initializing datastore")
				}

				err = ds.Migrate()
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			} else {
				connString := datastore.GetMysqlConnectionString(config.Mysql)
				ds, err = datastore.New("gorm-mysql", connString)
				if err != nil {
					initFatal(err, "initializing datastore")
				}
			}

			svc, err := service.NewService(ds, logger, config, mailService, clock.C)
			if err != nil {
				initFatal(err, "initializing service")
			}

			if devMode {
				// Bootstrap a few users when using the in-memory database.
				// Each user's default password will just be their username.
				users := []kolide.User{
					{
						Name:     "Admin User",
						Username: "admin",
						Email:    "admin@kolide.co",
						Position: "Director of Security",
						Admin:    true,
						Enabled:  true,
					},
					{
						Name:     "Normal User",
						Username: "user",
						Email:    "user@kolide.co",
						Position: "Security Engineer",
						Admin:    false,
						Enabled:  true,
					},
				}

				for _, user := range users {
					user := user
					err := user.SetPassword(user.Username, config.Auth.SaltKeySize, config.Auth.BcryptCost)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
					_, err = ds.NewUser(&user)
					if err != nil {
						initFatal(err, "creating bootstrap user")
					}
				}
				devOrgInfo := &kolide.OrgInfo{
					OrgName:    "Kolide",
					OrgLogoURL: fmt.Sprintf("%s/logo.png", config.Server.Address),
				}
				_, err := svc.NewOrgInfo(ctx, kolide.OrgInfoPayload{
					OrgName:    &devOrgInfo.OrgName,
					OrgLogoURL: &devOrgInfo.OrgLogoURL,
				})
				if err != nil {
					initFatal(err, "creating fake org info")
				}
			}

			fieldKeys := []string{"method", "error"}
			requestCount := kitprometheus.NewCounterFrom(prometheus.CounterOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_count",
				Help:      "Number of requests received.",
			}, fieldKeys)
			requestLatency := kitprometheus.NewSummaryFrom(prometheus.SummaryOpts{
				Namespace: "api",
				Subsystem: "service",
				Name:      "request_latency_microseconds",
				Help:      "Total duration of requests in microseconds.",
			}, fieldKeys)

			svcLogger := kitlog.NewContext(logger).With("component", "service")
			svc = service.NewLoggingService(svc, svcLogger)
			svc = service.NewMetricsService(svc, requestCount, requestLatency)

			httpLogger := kitlog.NewContext(logger).With("component", "http")

			apiHandler := service.MakeHandler(ctx, svc, config.Auth.JwtKey, httpLogger)
			http.Handle("/api/", accessControl(apiHandler))
			http.Handle("/version", version.Handler())
			http.Handle("/metrics", prometheus.Handler())
			http.Handle("/assets/", service.ServeStaticAssets("/assets/"))
			http.Handle("/", service.ServeFrontend())

			errs := make(chan error, 2)
			go func() {
				if !config.Server.TLS || (devMode && !configManager.IsSet("server.tls")) {
					logger.Log("transport", "http", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServe(*httpAddr, nil)
				} else {
					logger.Log("transport", "https", "address", *httpAddr, "msg", "listening")
					errs <- http.ListenAndServeTLS(
						*httpAddr,
						config.Server.Cert,
						config.Server.Key,
						nil,
					)
				}
			}()
			go func() {
				c := make(chan os.Signal)
				signal.Notify(c, syscall.SIGINT)
				errs <- fmt.Errorf("%s", <-c)
			}()

			logger.Log("terminated", <-errs)
		},
	}

	serveCmd.PersistentFlags().BoolVar(&devMode, "dev", false, "Use dev settings (in-mem DB, etc.)")

	return serveCmd
}

// used in devMode to print an email
// which would otherwise be sent via SMTP
type devMailService struct{}

func (devMailService) SendEmail(e kolide.Email) error {
	fmt.Println("---dev mode: printing email---")
	defer fmt.Println("---dev mode: email printed---")
	msg, err := e.Msg.Message()
	if err != nil {
		return err
	}
	fmt.Printf("From: %q To: %q \n", e.From, e.To)
	_, err = os.Stdout.Write(msg)
	return err

}

// cors headers
func accessControl(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type")

		if r.Method == "OPTIONS" {
			return
		}

		h.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package widget

import (
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/event"
	"github.com/richardwilkes/ui/geom"
	"github.com/richardwilkes/ui/layout"
	"github.com/richardwilkes/ui/theme"
	"github.com/richardwilkes/xmath"
	"time"
)

// RadioButton represents a radio button with an optional label.
type RadioButton struct {
	Block
	Theme    *theme.RadioButton // The theme the button will use to draw itself.
	Title    string             // An optional title for the button.
	group    *RadioButtonGroup
	selected bool
	pressed  bool
}

// NewRadioButton creates a new radio button with the specified title.
func NewRadioButton(title string) *RadioButton {
	button := &RadioButton{}
	button.Title = title
	button.Theme = theme.StdRadioButton
	button.SetFocusable(true)
	button.SetSizer(button)
	handlers := button.EventHandlers()
	handlers.Add(event.PaintType, button.paint)
	handlers.Add(event.MouseDownType, button.mouseDown)
	handlers.Add(event.MouseDraggedType, button.mouseDragged)
	handlers.Add(event.MouseUpType, button.mouseUp)
	handlers.Add(event.FocusGainedType, button.focusChanged)
	handlers.Add(event.FocusLostType, button.focusChanged)
	handlers.Add(event.KeyDownType, button.keyDown)
	return button
}

// Sizes implements Sizer
func (button *RadioButton) Sizes(hint geom.Size) (min, pref, max geom.Size) {
	var size geom.Size
	box := xmath.CeilFloat32(button.Theme.Font.Ascent())
	if button.Title != "" {
		if hint.Width != layout.NoHint {
			hint.Width -= button.Theme.HorizontalGap + box
			if hint.Width < 1 {
				hint.Width = 1
			}
		}
		if hint.Height != layout.NoHint {
			if hint.Height < 1 {
				hint.Height = 1
			}
		}
		size := button.Theme.Font.Size(button.Title)
		size.GrowToInteger()
		size.ConstrainForHint(hint)
		size.Width += button.Theme.HorizontalGap + box
		if size.Height < box {
			size.Height = box
		}
	} else {
		size.Width = box
		size.Height = box
	}
	if border := button.Border(); border != nil {
		size.AddInsets(border.Insets())
	}
	return size, size, layout.DefaultMaxSize(size)
}

func (button *RadioButton) paint(evt event.Event) {
	box := xmath.CeilFloat32(button.Theme.Font.Ascent())
	bounds := button.LocalInsetBounds()
	bounds.Width = box
	bounds.Y += (bounds.Height - box) / 2
	bounds.Height = box
	path := geom.NewPath()
	path.Ellipse(bounds)
	gc := evt.(*event.Paint).GC()
	gc.AddPath(path)
	gc.Save()
	gc.Clip()
	base := button.BaseBackground()
	if button.Enabled() {
		gc.DrawLinearGradient(button.Theme.Gradient(base), bounds.X, bounds.Y, bounds.X, bounds.Y+bounds.Height)
	} else {
		gc.SetFillColor(color.Background)
		gc.FillRect(bounds)
	}
	gc.AddPath(path)
	c := base.AdjustBrightness(button.Theme.OutlineAdjustment)
	gc.SetStrokeColor(c)
	gc.StrokePath()
	gc.Restore()
	if button.selected {
		bounds.InsetUniform(0.2 * box)
		if button.Enabled() {
			c = color.KeyboardFocus
		}
		gc.SetFillColor(c)
		gc.FillEllipse(bounds)
	}
	if button.Title != "" {
		bounds = button.LocalInsetBounds()
		bounds.X += box + button.Theme.HorizontalGap
		bounds.Width -= box + button.Theme.HorizontalGap
		if bounds.Width > 0 {
			gc.SetFillColor(button.TextColor())
			gc.SetFont(button.Theme.Font)
			gc.DrawString(bounds.X, bounds.Y+(bounds.Height-button.Theme.Font.Height())/2, button.Title)
		}
	}
}

func (button *RadioButton) mouseDown(evt event.Event) {
	button.pressed = true
	button.Repaint()
}

func (button *RadioButton) mouseDragged(evt event.Event) {
	bounds := button.LocalInsetBounds()
	pressed := bounds.Contains(button.FromWindow(evt.(*event.MouseDragged).Where()))
	if button.pressed != pressed {
		button.pressed = pressed
		button.Repaint()
	}
}

func (button *RadioButton) mouseUp(evt event.Event) {
	button.pressed = false
	button.Repaint()
	bounds := button.LocalInsetBounds()
	if bounds.Contains(button.FromWindow(evt.(*event.MouseUp).Where())) {
		button.Click()
	}
}

func (button *RadioButton) focusChanged(evt event.Event) {
	button.Repaint()
}

// Click performs any animation associated with a click and calls the OnClick() function if it is
// set.
func (button *RadioButton) Click() {
	button.SetSelected(true)
	pressed := button.pressed
	button.pressed = true
	button.Repaint()
	button.Window().FlushPainting()
	button.pressed = pressed
	time.Sleep(button.Theme.ClickAnimationTime)
	button.Repaint()
	event.Dispatch(event.NewClick(button))
}

func (button *RadioButton) keyDown(evt event.Event) {
	if evt.(*event.KeyDown).IsControlActionKey() {
		evt.Finish()
		button.Click()
	}
}

// BaseBackground returns this button's current base background color.
func (button *RadioButton) BaseBackground() color.Color {
	switch {
	case !button.Enabled():
		return button.Theme.Background.AdjustBrightness(button.Theme.DisabledAdjustment)
	case button.pressed:
		return button.Theme.BackgroundWhenPressed
	case button.Focused():
		return button.Theme.Background.Blend(color.KeyboardFocus, 0.5)
	default:
		return button.Theme.Background
	}
}

// TextColor returns this button's current text color.
func (button *RadioButton) TextColor() color.Color {
	if button.Enabled() {
		return button.Theme.TextWhenLight
	}
	return button.Theme.TextWhenDisabled
}

// Selected returns true if the radio button is currently selected.
func (button *RadioButton) Selected() bool {
	return button.selected
}

// SetSelected sets the button's selected state.
func (button *RadioButton) SetSelected(selected bool) {
	if button.group != nil {
		button.group.Select(button)
	} else {
		button.setSelected(selected)
	}
}

func (button *RadioButton) setSelected(selected bool) {
	if button.selected != selected {
		button.selected = selected
		button.Repaint()
	}
}
<commit_msg>Fix inadvertant shadowing of the size variable<commit_after>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package widget

import (
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/event"
	"github.com/richardwilkes/ui/geom"
	"github.com/richardwilkes/ui/layout"
	"github.com/richardwilkes/ui/theme"
	"github.com/richardwilkes/xmath"
	"time"
)

// RadioButton represents a radio button with an optional label.
type RadioButton struct {
	Block
	Theme    *theme.RadioButton // The theme the button will use to draw itself.
	Title    string             // An optional title for the button.
	group    *RadioButtonGroup
	selected bool
	pressed  bool
}

// NewRadioButton creates a new radio button with the specified title.
func NewRadioButton(title string) *RadioButton {
	button := &RadioButton{}
	button.Title = title
	button.Theme = theme.StdRadioButton
	button.SetFocusable(true)
	button.SetSizer(button)
	handlers := button.EventHandlers()
	handlers.Add(event.PaintType, button.paint)
	handlers.Add(event.MouseDownType, button.mouseDown)
	handlers.Add(event.MouseDraggedType, button.mouseDragged)
	handlers.Add(event.MouseUpType, button.mouseUp)
	handlers.Add(event.FocusGainedType, button.focusChanged)
	handlers.Add(event.FocusLostType, button.focusChanged)
	handlers.Add(event.KeyDownType, button.keyDown)
	return button
}

// Sizes implements Sizer
func (button *RadioButton) Sizes(hint geom.Size) (min, pref, max geom.Size) {
	var size geom.Size
	box := xmath.CeilFloat32(button.Theme.Font.Ascent())
	if button.Title != "" {
		if hint.Width != layout.NoHint {
			hint.Width -= button.Theme.HorizontalGap + box
			if hint.Width < 1 {
				hint.Width = 1
			}
		}
		if hint.Height != layout.NoHint {
			if hint.Height < 1 {
				hint.Height = 1
			}
		}
		size = button.Theme.Font.Size(button.Title)
		size.GrowToInteger()
		size.ConstrainForHint(hint)
		size.Width += button.Theme.HorizontalGap + box
		if size.Height < box {
			size.Height = box
		}
	} else {
		size.Width = box
		size.Height = box
	}
	if border := button.Border(); border != nil {
		size.AddInsets(border.Insets())
	}
	return size, size, layout.DefaultMaxSize(size)
}

func (button *RadioButton) paint(evt event.Event) {
	box := xmath.CeilFloat32(button.Theme.Font.Ascent())
	bounds := button.LocalInsetBounds()
	bounds.Width = box
	bounds.Y += (bounds.Height - box) / 2
	bounds.Height = box
	path := geom.NewPath()
	path.Ellipse(bounds)
	gc := evt.(*event.Paint).GC()
	gc.AddPath(path)
	gc.Save()
	gc.Clip()
	base := button.BaseBackground()
	if button.Enabled() {
		gc.DrawLinearGradient(button.Theme.Gradient(base), bounds.X, bounds.Y, bounds.X, bounds.Y+bounds.Height)
	} else {
		gc.SetFillColor(color.Background)
		gc.FillRect(bounds)
	}
	gc.AddPath(path)
	c := base.AdjustBrightness(button.Theme.OutlineAdjustment)
	gc.SetStrokeColor(c)
	gc.StrokePath()
	gc.Restore()
	if button.selected {
		bounds.InsetUniform(0.2 * box)
		if button.Enabled() {
			c = color.KeyboardFocus
		}
		gc.SetFillColor(c)
		gc.FillEllipse(bounds)
	}
	if button.Title != "" {
		bounds = button.LocalInsetBounds()
		bounds.X += box + button.Theme.HorizontalGap
		bounds.Width -= box + button.Theme.HorizontalGap
		if bounds.Width > 0 {
			gc.SetFillColor(button.TextColor())
			gc.SetFont(button.Theme.Font)
			gc.DrawString(bounds.X, bounds.Y+(bounds.Height-button.Theme.Font.Height())/2, button.Title)
		}
	}
}

func (button *RadioButton) mouseDown(evt event.Event) {
	button.pressed = true
	button.Repaint()
}

func (button *RadioButton) mouseDragged(evt event.Event) {
	bounds := button.LocalInsetBounds()
	pressed := bounds.Contains(button.FromWindow(evt.(*event.MouseDragged).Where()))
	if button.pressed != pressed {
		button.pressed = pressed
		button.Repaint()
	}
}

func (button *RadioButton) mouseUp(evt event.Event) {
	button.pressed = false
	button.Repaint()
	bounds := button.LocalInsetBounds()
	if bounds.Contains(button.FromWindow(evt.(*event.MouseUp).Where())) {
		button.Click()
	}
}

func (button *RadioButton) focusChanged(evt event.Event) {
	button.Repaint()
}

// Click performs any animation associated with a click and calls the OnClick() function if it is
// set.
func (button *RadioButton) Click() {
	button.SetSelected(true)
	pressed := button.pressed
	button.pressed = true
	button.Repaint()
	button.Window().FlushPainting()
	button.pressed = pressed
	time.Sleep(button.Theme.ClickAnimationTime)
	button.Repaint()
	event.Dispatch(event.NewClick(button))
}

func (button *RadioButton) keyDown(evt event.Event) {
	if evt.(*event.KeyDown).IsControlActionKey() {
		evt.Finish()
		button.Click()
	}
}

// BaseBackground returns this button's current base background color.
func (button *RadioButton) BaseBackground() color.Color {
	switch {
	case !button.Enabled():
		return button.Theme.Background.AdjustBrightness(button.Theme.DisabledAdjustment)
	case button.pressed:
		return button.Theme.BackgroundWhenPressed
	case button.Focused():
		return button.Theme.Background.Blend(color.KeyboardFocus, 0.5)
	default:
		return button.Theme.Background
	}
}

// TextColor returns this button's current text color.
func (button *RadioButton) TextColor() color.Color {
	if button.Enabled() {
		return button.Theme.TextWhenLight
	}
	return button.Theme.TextWhenDisabled
}

// Selected returns true if the radio button is currently selected.
func (button *RadioButton) Selected() bool {
	return button.selected
}

// SetSelected sets the button's selected state.
func (button *RadioButton) SetSelected(selected bool) {
	if button.group != nil {
		button.group.Select(button)
	} else {
		button.setSelected(selected)
	}
}

func (button *RadioButton) setSelected(selected bool) {
	if button.selected != selected {
		button.selected = selected
		button.Repaint()
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 The Jaeger 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 spanstore

import (
	"hash"
	"hash/fnv"
	"math"
	"math/big"
	"sync"

	"github.com/uber/jaeger-lib/metrics"

	"github.com/jaegertracing/jaeger/model"
)

const defaultHashSalt = "downsampling-default-salt"

var (
	traceIDByteSize = (&model.TraceID{}).Size()
)

// hasher includes data we want to put in sync.Pool.
type hasher struct {
	hash   hash.Hash64
	buffer []byte
}

// downsamplingWriterMetrics keeping track of total number of dropped spans and accepted spans.
type downsamplingWriterMetrics struct {
	SpansDropped  metrics.Counter `metric:"spans_dropped"`
	SpansAccepted metrics.Counter `metric:"spans_accepted"`
}

// DownsamplingWriter is a span Writer that drops spans with a predefined downsamplingRatio.
type DownsamplingWriter struct {
	spanWriter Writer
	metrics    downsamplingWriterMetrics
	sampler    Sampler
}

// DownsamplingOptions contains the options for constructing a DownsamplingWriter.
type DownsamplingOptions struct {
	Ratio          float64
	HashSalt       string
	MetricsFactory metrics.Factory
}

// NewDownsamplingWriter creates a DownsamplingWriter.
func NewDownsamplingWriter(spanWriter Writer, downsamplingOptions DownsamplingOptions) *DownsamplingWriter {
	writeMetrics := &downsamplingWriterMetrics{}
	metrics.Init(writeMetrics, downsamplingOptions.MetricsFactory, nil)
	return &DownsamplingWriter{
		sampler:    NewSampler(downsamplingOptions.Ratio, downsamplingOptions.HashSalt),
		spanWriter: spanWriter,
		metrics:    *writeMetrics,
	}
}

// WriteSpan calls WriteSpan on wrapped span writer.
func (ds *DownsamplingWriter) WriteSpan(span *model.Span) error {
	if !ds.sampler.ShouldSample(span) {
		// Drops spans when hashVal falls beyond computed threshold.
		ds.metrics.SpansDropped.Inc(1)
		return nil
	}
	ds.metrics.SpansAccepted.Inc(1)
	return ds.spanWriter.WriteSpan(span)
}

// hashBytes returns the uint64 hash value of byte slice.
func (h *hasher) hashBytes() uint64 {
	h.hash.Reset()
	// Currently fnv.Write() implementation doesn't throw any error so metric is not necessary here.
	_, _ = h.hash.Write(h.buffer)
	return h.hash.Sum64()
}

// Sampler decides if we should sample a span
type Sampler struct {
	hasherPool   *sync.Pool
	lengthOfSalt int
	threshold    uint64
}

// NewSampler creates SamplingExecutor
func NewSampler(ratio float64, hashSalt string) Sampler {
	if hashSalt == "" {
		hashSalt = defaultHashSalt
	}
	hashSaltBytes := []byte(hashSalt)
	pool := &sync.Pool{
		New: func() interface{} {
			buffer := make([]byte, len(hashSaltBytes)+traceIDByteSize)
			copy(buffer, hashSaltBytes)
			return &hasher{
				hash:   fnv.New64a(),
				buffer: buffer,
			}
		},
	}
	return Sampler{
		threshold:    calculateThreshold(ratio),
		hasherPool:   pool,
		lengthOfSalt: len(hashSaltBytes),
	}
}

func calculateThreshold(ratio float64) uint64 {
	// Use big.Float and big.Int to calculate threshold because directly convert
	// math.MaxUint64 to float64 will cause digits/bits to be cut off if the converted value
	// doesn't fit into bits that are used to store digits for float64 in Golang
	boundary := new(big.Float).SetInt(new(big.Int).SetUint64(math.MaxUint64))
	res, _ := boundary.Mul(boundary, big.NewFloat(ratio)).Uint64()
	return res
}

// ShouldSample decides if a span should be sampled
func (s *Sampler) ShouldSample(span *model.Span) bool {
	hasherInstance := s.hasherPool.Get().(*hasher)
	// Currently MarshalTo will only return err if size of traceIDBytes is smaller than 16
	// Since we force traceIDBytes to be size of 16 metrics is not necessary here.
	_, _ = span.TraceID.MarshalTo(hasherInstance.buffer[s.lengthOfSalt:])
	hashVal := hasherInstance.hashBytes()
	s.hasherPool.Put(hasherInstance)
	return hashVal <= s.threshold
}
<commit_msg>Return Sampler as pointer (#1666)<commit_after>// Copyright (c) 2019 The Jaeger 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 spanstore

import (
	"hash"
	"hash/fnv"
	"math"
	"math/big"
	"sync"

	"github.com/uber/jaeger-lib/metrics"

	"github.com/jaegertracing/jaeger/model"
)

const defaultHashSalt = "downsampling-default-salt"

var (
	traceIDByteSize = (&model.TraceID{}).Size()
)

// hasher includes data we want to put in sync.Pool.
type hasher struct {
	hash   hash.Hash64
	buffer []byte
}

// downsamplingWriterMetrics keeping track of total number of dropped spans and accepted spans.
type downsamplingWriterMetrics struct {
	SpansDropped  metrics.Counter `metric:"spans_dropped"`
	SpansAccepted metrics.Counter `metric:"spans_accepted"`
}

// DownsamplingWriter is a span Writer that drops spans with a predefined downsamplingRatio.
type DownsamplingWriter struct {
	spanWriter Writer
	metrics    downsamplingWriterMetrics
	sampler    *Sampler
}

// DownsamplingOptions contains the options for constructing a DownsamplingWriter.
type DownsamplingOptions struct {
	Ratio          float64
	HashSalt       string
	MetricsFactory metrics.Factory
}

// NewDownsamplingWriter creates a DownsamplingWriter.
func NewDownsamplingWriter(spanWriter Writer, downsamplingOptions DownsamplingOptions) *DownsamplingWriter {
	writeMetrics := &downsamplingWriterMetrics{}
	metrics.Init(writeMetrics, downsamplingOptions.MetricsFactory, nil)
	return &DownsamplingWriter{
		sampler:    NewSampler(downsamplingOptions.Ratio, downsamplingOptions.HashSalt),
		spanWriter: spanWriter,
		metrics:    *writeMetrics,
	}
}

// WriteSpan calls WriteSpan on wrapped span writer.
func (ds *DownsamplingWriter) WriteSpan(span *model.Span) error {
	if !ds.sampler.ShouldSample(span) {
		// Drops spans when hashVal falls beyond computed threshold.
		ds.metrics.SpansDropped.Inc(1)
		return nil
	}
	ds.metrics.SpansAccepted.Inc(1)
	return ds.spanWriter.WriteSpan(span)
}

// hashBytes returns the uint64 hash value of byte slice.
func (h *hasher) hashBytes() uint64 {
	h.hash.Reset()
	// Currently fnv.Write() implementation doesn't throw any error so metric is not necessary here.
	_, _ = h.hash.Write(h.buffer)
	return h.hash.Sum64()
}

// Sampler decides if we should sample a span
type Sampler struct {
	hasherPool   *sync.Pool
	lengthOfSalt int
	threshold    uint64
}

// NewSampler creates SamplingExecutor
func NewSampler(ratio float64, hashSalt string) *Sampler {
	if hashSalt == "" {
		hashSalt = defaultHashSalt
	}
	hashSaltBytes := []byte(hashSalt)
	pool := &sync.Pool{
		New: func() interface{} {
			buffer := make([]byte, len(hashSaltBytes)+traceIDByteSize)
			copy(buffer, hashSaltBytes)
			return &hasher{
				hash:   fnv.New64a(),
				buffer: buffer,
			}
		},
	}
	return &Sampler{
		threshold:    calculateThreshold(ratio),
		hasherPool:   pool,
		lengthOfSalt: len(hashSaltBytes),
	}
}

func calculateThreshold(ratio float64) uint64 {
	// Use big.Float and big.Int to calculate threshold because directly convert
	// math.MaxUint64 to float64 will cause digits/bits to be cut off if the converted value
	// doesn't fit into bits that are used to store digits for float64 in Golang
	boundary := new(big.Float).SetInt(new(big.Int).SetUint64(math.MaxUint64))
	res, _ := boundary.Mul(boundary, big.NewFloat(ratio)).Uint64()
	return res
}

// ShouldSample decides if a span should be sampled
func (s *Sampler) ShouldSample(span *model.Span) bool {
	hasherInstance := s.hasherPool.Get().(*hasher)
	// Currently MarshalTo will only return err if size of traceIDBytes is smaller than 16
	// Since we force traceIDBytes to be size of 16 metrics is not necessary here.
	_, _ = span.TraceID.MarshalTo(hasherInstance.buffer[s.lengthOfSalt:])
	hashVal := hasherInstance.hashBytes()
	s.hasherPool.Put(hasherInstance)
	return hashVal <= s.threshold
}
<|endoftext|>


<commit_before>package brightbox

type CloudIP struct {
	Resource
	Name            string
	PublicIP        string `json:"public_ip"`
	Status          string
	ReverseDns      string           `json:"reverse_dns"`
	PortTranslators []PortTranslator `json:"port_translators"`
	Account         Account
	Interface       *ServerInterface
	Server          *Server
	//LoadBalancer
	//DatabaseServer
}

type PortTranslator struct {
	Incoming int
	Outgoing int
	Protocol string
}

func (c *Client) CloudIPs() (*[]CloudIP, error) {
	cloudips := new([]CloudIP)
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips", nil, cloudips)
	if err != nil {
		return nil, err
	}
	return cloudips, err
}

func (c *Client) CloudIP(identifier string) (*CloudIP, error) {
	cloudip := new(CloudIP)
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips/"+identifier, nil, cloudip)
	if err != nil {
		return nil, err
	}
	return cloudip, err
}

func (c *Client) DestroyCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("DELETE", "/1.0/cloud_ips/"+identifier, nil, nil)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>cloudip map and unmap support<commit_after>package brightbox

import (
	"fmt"
)

type CloudIP struct {
	Resource
	Name            string
	PublicIP        string `json:"public_ip"`
	Status          string
	ReverseDns      string           `json:"reverse_dns"`
	PortTranslators []PortTranslator `json:"port_translators"`
	Account         Account
	Interface       *ServerInterface
	Server          *Server
	//LoadBalancer
	//DatabaseServer
}

type PortTranslator struct {
	Incoming int
	Outgoing int
	Protocol string
}

func (c *Client) CloudIPs() (*[]CloudIP, error) {
	cloudips := new([]CloudIP)
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips", nil, cloudips)
	if err != nil {
		return nil, err
	}
	return cloudips, err
}

func (c *Client) CloudIP(identifier string) (*CloudIP, error) {
	cloudip := new(CloudIP)
	_, err := c.MakeApiRequest("GET", "/1.0/cloud_ips/"+identifier, nil, cloudip)
	if err != nil {
		return nil, err
	}
	return cloudip, err
}

func (c *Client) DestroyCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("DELETE", "/1.0/cloud_ips/"+identifier, nil, nil)
	if err != nil {
		return err
	}
	return nil
}

// MapCloudIP issues a request to map the cloud ip to the destination. The
// destination can be an identifier of any resource capable of receiving a Cloud
// IP, such as a server interface, a load balancer, or a cloud sql instace.
//
// To map a Cloud IP to a server, first lookup the server to get it's interface
// identifier (or use the MapCloudIPtoServer convenience method)
func (c *Client) MapCloudIP(identifier string, destination string) error {
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips/"+identifier+"/map",
		map[string]string{"destination": destination}, nil)
	if err != nil {
		return err
	}
	return nil
}

// Convenience method to map a Cloud IP to a server. First looks up the server
// to get the network interface id. Uses the first interface found.
func (c *Client) MapCloudIPtoServer(identifier string, serverid string) error {
	server, err := c.Server(serverid)
	if err != nil {
		return err
	}
	if len(server.Interfaces) == 0 {
		return fmt.Errorf("Server %s has no interfaces to map cloud ip %s to", server.Id, identifier)
	}
	destination := server.Interfaces[0].Id
	err = c.MapCloudIP(identifier, destination)
	if err != nil {
		return err
	}
	return nil
}

// UnMapCloudIP issues a request to unmap the cloud ip.
func (c *Client) UnMapCloudIP(identifier string) error {
	_, err := c.MakeApiRequest("POST", "/1.0/cloud_ips/"+identifier+"/unmap", nil, nil)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Package pfsutil provides utility functions that wrap a pfs.ApiClient
to make the calling code slightly cleaner.
*/
package pfsutil

import (
	"io"
	"io/ioutil"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pkg/protoutil"
	"golang.org/x/net/context"
)

const (
	GetAll int64 = 1<<63 - 1
)

func InitRepository(apiClient pfs.ApiClient, repositoryName string) error {
	_, err := apiClient.InitRepository(
		context.Background(),
		&pfs.InitRepositoryRequest{
			Repository: &pfs.Repository{
				Name: repositoryName,
			},
		},
	)
	return err
}

func Branch(apiClient pfs.ApiClient, repositoryName string, commitID string) (*pfs.BranchResponse, error) {
	return apiClient.Branch(
		context.Background(),
		&pfs.BranchRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
		},
	)
}

func MakeDirectory(apiClient pfs.ApiClient, repositoryName string, commitID string, path string) error {
	_, err := apiClient.MakeDirectory(
		context.Background(),
		&pfs.MakeDirectoryRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	return err
}

func PutFile(apiClient pfs.ApiClient, repositoryName string, commitID string, path string, offset int64, reader io.Reader) (int64, error) {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return 0, err
	}
	_, err = apiClient.PutFile(
		context.Background(),
		&pfs.PutFileRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
			OffsetBytes: offset,
			Value:       value,
		},
	)
	return int64(len(value)), err
}

func GetFile(apiClient pfs.ApiClient, repositoryName string, commitID string, path string, offset int64, size int64, writer io.Writer) error {
	apiGetFileClient, err := apiClient.GetFile(
		context.Background(),
		&pfs.GetFileRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
			OffsetBytes: offset,
			SizeBytes:   size,
		},
	)
	if err != nil {
		return err
	}
	if err := protoutil.WriteFromStreamingBytesClient(apiGetFileClient, writer); err != nil {
		return err
	}
	return nil
}

func GetFileInfo(apiClient pfs.ApiClient, repositoryName string, commitID string, path string) (*pfs.GetFileInfoResponse, error) {
	return apiClient.GetFileInfo(
		context.Background(),
		&pfs.GetFileInfoRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
}

func ListFiles(apiClient pfs.ApiClient, repositoryName string, commitID string, path string, shard uint64, modulus uint64) (*pfs.ListFilesResponse, error) {
	return apiClient.ListFiles(
		context.Background(),
		&pfs.ListFilesRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
}

func Commit(apiClient pfs.ApiClient, repositoryName string, commitID string) error {
	_, err := apiClient.Commit(
		context.Background(),
		&pfs.CommitRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func GetCommitInfo(apiClient pfs.ApiClient, repositoryName string, commitID string) (*pfs.GetCommitInfoResponse, error) {
	return apiClient.GetCommitInfo(
		context.Background(),
		&pfs.GetCommitInfoRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
		},
	)
}

func ListCommits(apiClient pfs.ApiClient, repositoryName string) (*pfs.ListCommitsResponse, error) {
	return apiClient.ListCommits(
		context.Background(),
		&pfs.ListCommitsRequest{
			Repository: &pfs.Repository{
				Name: repositoryName,
			},
		},
	)
}

func PullDiff(internalApiClient pfs.InternalApiClient, repositoryName string, commitID string, shard uint64, writer io.Writer) error {
	apiPullDiffClient, err := internalApiClient.PullDiff(
		context.Background(),
		&pfs.PullDiffRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return err
	}
	if err := protoutil.WriteFromStreamingBytesClient(apiPullDiffClient, writer); err != nil {
		return err
	}
	return nil
}
<commit_msg>Adds PushDiff to pfsutil.<commit_after>/*
Package pfsutil provides utility functions that wrap a pfs.ApiClient
to make the calling code slightly cleaner.
*/
package pfsutil

import (
	"io"
	"io/ioutil"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pkg/protoutil"
	"golang.org/x/net/context"
)

const (
	GetAll int64 = 1<<63 - 1
)

func InitRepository(apiClient pfs.ApiClient, repositoryName string) error {
	_, err := apiClient.InitRepository(
		context.Background(),
		&pfs.InitRepositoryRequest{
			Repository: &pfs.Repository{
				Name: repositoryName,
			},
		},
	)
	return err
}

func Branch(apiClient pfs.ApiClient, repositoryName string, commitID string) (*pfs.BranchResponse, error) {
	return apiClient.Branch(
		context.Background(),
		&pfs.BranchRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
		},
	)
}

func MakeDirectory(apiClient pfs.ApiClient, repositoryName string, commitID string, path string) error {
	_, err := apiClient.MakeDirectory(
		context.Background(),
		&pfs.MakeDirectoryRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
	return err
}

func PutFile(apiClient pfs.ApiClient, repositoryName string, commitID string, path string, offset int64, reader io.Reader) (int64, error) {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return 0, err
	}
	_, err = apiClient.PutFile(
		context.Background(),
		&pfs.PutFileRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
			OffsetBytes: offset,
			Value:       value,
		},
	)
	return int64(len(value)), err
}

func GetFile(apiClient pfs.ApiClient, repositoryName string, commitID string, path string, offset int64, size int64, writer io.Writer) error {
	apiGetFileClient, err := apiClient.GetFile(
		context.Background(),
		&pfs.GetFileRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
			OffsetBytes: offset,
			SizeBytes:   size,
		},
	)
	if err != nil {
		return err
	}
	if err := protoutil.WriteFromStreamingBytesClient(apiGetFileClient, writer); err != nil {
		return err
	}
	return nil
}

func GetFileInfo(apiClient pfs.ApiClient, repositoryName string, commitID string, path string) (*pfs.GetFileInfoResponse, error) {
	return apiClient.GetFileInfo(
		context.Background(),
		&pfs.GetFileInfoRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
		},
	)
}

func ListFiles(apiClient pfs.ApiClient, repositoryName string, commitID string, path string, shard uint64, modulus uint64) (*pfs.ListFilesResponse, error) {
	return apiClient.ListFiles(
		context.Background(),
		&pfs.ListFilesRequest{
			Path: &pfs.Path{
				Commit: &pfs.Commit{
					Repository: &pfs.Repository{
						Name: repositoryName,
					},
					Id: commitID,
				},
				Path: path,
			},
			Shard: &pfs.Shard{
				Number: shard,
				Modulo: modulus,
			},
		},
	)
}

func Commit(apiClient pfs.ApiClient, repositoryName string, commitID string) error {
	_, err := apiClient.Commit(
		context.Background(),
		&pfs.CommitRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
		},
	)
	return err
}

func GetCommitInfo(apiClient pfs.ApiClient, repositoryName string, commitID string) (*pfs.GetCommitInfoResponse, error) {
	return apiClient.GetCommitInfo(
		context.Background(),
		&pfs.GetCommitInfoRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
		},
	)
}

func ListCommits(apiClient pfs.ApiClient, repositoryName string) (*pfs.ListCommitsResponse, error) {
	return apiClient.ListCommits(
		context.Background(),
		&pfs.ListCommitsRequest{
			Repository: &pfs.Repository{
				Name: repositoryName,
			},
		},
	)
}

func PullDiff(internalApiClient pfs.InternalApiClient, repositoryName string, commitID string, shard uint64, writer io.Writer) error {
	apiPullDiffClient, err := internalApiClient.PullDiff(
		context.Background(),
		&pfs.PullDiffRequest{
			Commit: &pfs.Commit{
				Repository: &pfs.Repository{
					Name: repositoryName,
				},
				Id: commitID,
			},
			Shard: shard,
		},
	)
	if err != nil {
		return err
	}
	if err := protoutil.WriteFromStreamingBytesClient(apiPullDiffClient, writer); err != nil {
		return err
	}
	return nil
}

func PushDiff(internalApiClient pfs.InternalApiClient, repositoryName string, reader io.Reader) error {
	value, err := ioutil.ReadAll(reader)
	if err != nil {
		return err
	}
	_, err = internalApiClient.PushDiff(
		context.Background(),
		&pfs.PushDiffRequest{
			Repository: &pfs.Repository{
				Name: repositoryName,
			},
			Value: value,
		},
	)
	return err
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"

	nndb "github.com/rtyer/nndb/lib"
	"github.com/spf13/cobra"
)

var sourceDirectory string
var outfile string

// parseCmd represents the parse command
var parseCmd = &cobra.Command{
	Use:   "parse",
	Short: "Parses the standard format from national nutrient database into a consolidated format.",
	Long:  `Parses the standard format from national nutrient database into a consolidated format.`,
	Run: func(cmd *cobra.Command, args []string) {
		// fmt.Printf("parse called with %v\n", sourceDirectory)

		parser, err := nndb.NewParser(
			newReaderForFilename(sourceDirectory, nndb.FoodDesFile),
			newReaderForFilename(sourceDirectory, nndb.FoodGroupFile),
			newReaderForFilename(sourceDirectory, nndb.NutrDefFile),
			newReaderForFilename(sourceDirectory, nndb.WeightFile))
		if err != nil {
			fmt.Println(err)
		} else {
			food, err := parser.Parse()
			if err != nil {
				fmt.Println(err)
			}
			b, err := json.Marshal(food)

			if err != nil {
				fmt.Println(err)
			}
			err = ioutil.WriteFile(outfile, b, 0644)
			if err != nil {
				fmt.Println(err)
			}
		}
	},
}

func init() {
	RootCmd.AddCommand(parseCmd)

	parseCmd.Flags().StringVarP(&sourceDirectory, "source", "s", "", "source directory to read from")
	parseCmd.Flags().StringVarP(&outfile, "outfile", "o", "", "file to output to")
}

func newReaderForFilename(folder string, filename string) io.Reader {
	path := folder + "/" + filename
	// fmt.Printf("called with %v\n", path)
	file, err := os.Open(path)

	if err != nil {
		fmt.Println(err)
	}
	return file
}
<commit_msg>cleaned up fmt<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"

	nndb "github.com/rtyer/nndb/lib"
	"github.com/spf13/cobra"
)

var sourceDirectory string
var outfile string

// parseCmd represents the parse command
var parseCmd = &cobra.Command{
	Use:   "parse",
	Short: "Parses the standard format from national nutrient database into a consolidated format.",
	Long:  `Parses the standard format from national nutrient database into a consolidated format.`,
	Run: func(cmd *cobra.Command, args []string) {
		parser, err := nndb.NewParser(
			newReaderForFilename(sourceDirectory, nndb.FoodDesFile),
			newReaderForFilename(sourceDirectory, nndb.FoodGroupFile),
			newReaderForFilename(sourceDirectory, nndb.NutrDefFile),
			newReaderForFilename(sourceDirectory, nndb.WeightFile))
		if err != nil {
			fmt.Println(err)
		} else {
			food, err := parser.Parse()
			if err != nil {
				fmt.Println(err)
			}
			b, err := json.Marshal(food)

			if err != nil {
				fmt.Println(err)
			}
			err = ioutil.WriteFile(outfile, b, 0644)
			if err != nil {
				fmt.Println(err)
			}
		}
	},
}

func init() {
	RootCmd.AddCommand(parseCmd)

	parseCmd.Flags().StringVarP(&sourceDirectory, "source", "s", "", "source directory to read from")
	parseCmd.Flags().StringVarP(&outfile, "outfile", "o", "", "file to output to")
}

func newReaderForFilename(folder string, filename string) io.Reader {
	path := folder + "/" + filename
	file, err := os.Open(path)

	if err != nil {
		fmt.Println(err)
	}
	return file
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.

package commands

import (
  "fmt"
  "os"

  cobra "github.com/spf13/cobra"

  log  "github.com/eris-ltd/eris-logger"

  config "github.com/eris-ltd/eris-db/config"
  util   "github.com/eris-ltd/eris-db/util"
)

var ServeCmd = &cobra.Command {
  Use:   "serve",
  Short: "Eris-DB serve starts an eris-db node with client API enabled by default.",
  Long:  `Eris-DB serve starts an eris-db node with client API enabled by default.
The Eris-DB node is modularly configured for the consensus engine and application
manager.  The client API can be disabled.`,
  Example: `$ eris-db serve -- will start the Eris-DB node based on the configuration file "server_config.toml" in the current working directory
$ eris-db serve --work-dir <path-to-working-directory> -- will start the Eris-DB node based on the configuration file "server_config.toml" in the provided working directory`,
  PreRun: func(cmd *cobra.Command, args []string) {
    // if WorkDir was not set by a flag or by $ERIS_DB_WORKDIR
    // NOTE [ben]: we can consider an `Explicit` flag that eliminates
    // the use of any assumptions while starting Eris-DB
    if do.WorkDir == "" {
      if currentDirectory, err := os.Getwd(); err != nil {
        log.Fatalf("No directory provided and failed to get current working directory: %v", err)
        os.Exit(1)
      } else {
        log.Warn("No working directory provided in ERIS_DB_WORKDIR or --work-dir\n" +
          "Will use current working directory ", currentDirectory)
        do.WorkDir = currentDirectory
      }
    }
    if !util.IsDir(do.WorkDir) {
      log.Fatalf("Provided working directory %s is not a directory", do.WorkDir)
    }
    log.Debug("Working directory is set as %s", do.WorkDir)
  },
  Run: Serve,
}

// build the serve subcommand
func buildServeCommand() {
  addServeFlags()
}

func addServeFlags() {
  ServeCmd.PersistentFlags().StringVarP(&do.WorkDir, "work-dir", "w",
    defaultWorkDir(), "specify the working directory for the chain to run.  If omitted, and no path set in $ERIS_DB_WORKDIR, the current working directory is taken.")
  ServeCmd.PersistentFlags().StringVarP(&do.DataDir, "data-dir", "a",
    defaultDataDir(), "specify the data directory.  If omitted and not set in $ERIS_DB_DATADIR, <working_directory>/data is taken.")
}

//------------------------------------------------------------------------------
// functions

// serve() prepares the environment and sets up the core for Eris_DB to run.
// After the setup succeeds, serve() starts the core and halts for core to
// terminate.
func Serve(cmd *cobra.Command, args []string) {
  // load configuration from a single location to avoid a wrong configuration
  // file is loaded.
  if err := do.ReadConfig(do.WorkDir, "server_config", "toml"); err != nil {
    log.Fatalf("Fatal error reading server_config.toml : %s \n work directory: %s \n",
      err, do.WorkDir)
    os.Exit(1)
  }
  // load chain_id for assertion
  if do.ChainId = do.Config.GetString("chain.assert_chain_id");
    do.ChainId == "" {
    log.Fatalf("Failed to read non-empty string for ChainId from config.")
    os.Exit(1)
  }
  log.Info("Eris-DB serve initializing ", do.ChainId, " from ", do.WorkDir)

  // Ensure data directory is set and accesible
  if err := do.InitialiseDataDirectory(); err != nil {
    log.Fatalf("Failed to initialise data directory (%s): %v", do.DataDir, err)
    os.Exit(1)
  }
  log.Debug(fmt.Sprintf("Data directory is set at %s", do.DataDir))

  consensusConfig, err := config.LoadConsensusModuleConfig(do)
  if err != nil {
    log.Fatalf("Failed to load consensus module configuration: %s.", err)
    os.Exit(1)
  }

  managerConfig, err := config.LoadApplicationManagerModuleConfig(do)
  if err != nil {
    log.Fatalf("Failed to load application manager module configuration: %s.", err)
    os.Exit(1)
  }

  fmt.Printf("Consensus %s, App %s\n", consensusConfig.Version, managerConfig.Version)

}

//------------------------------------------------------------------------------
// Defaults

func defaultWorkDir() string {
  // if ERIS_DB_WORKDIR environment variable is not set, keep do.WorkDir empty
  return setDefaultString("ERIS_DB_WORKDIR", "")
}

func defaultDataDir() string {
  // As the default data directory depends on the default working directory,
  // wait setting a default value, and initialise the data directory from serve()
  return setDefaultString("ERIS_DB_DATADIR", "")
}
<commit_msg>make cmd/serve depend on core<commit_after>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.

package commands

import (
  "fmt"
  "os"

  cobra "github.com/spf13/cobra"

  log  "github.com/eris-ltd/eris-logger"

  core "github.com/eris-ltd/eris-db/core"
  util "github.com/eris-ltd/eris-db/util"
)

var ServeCmd = &cobra.Command {
  Use:   "serve",
  Short: "Eris-DB serve starts an eris-db node with client API enabled by default.",
  Long:  `Eris-DB serve starts an eris-db node with client API enabled by default.
The Eris-DB node is modularly configured for the consensus engine and application
manager.  The client API can be disabled.`,
  Example: `$ eris-db serve -- will start the Eris-DB node based on the configuration file "server_config.toml" in the current working directory
$ eris-db serve --work-dir <path-to-working-directory> -- will start the Eris-DB node based on the configuration file "server_config.toml" in the provided working directory`,
  PreRun: func(cmd *cobra.Command, args []string) {
    // if WorkDir was not set by a flag or by $ERIS_DB_WORKDIR
    // NOTE [ben]: we can consider an `Explicit` flag that eliminates
    // the use of any assumptions while starting Eris-DB
    if do.WorkDir == "" {
      if currentDirectory, err := os.Getwd(); err != nil {
        log.Fatalf("No directory provided and failed to get current working directory: %v", err)
        os.Exit(1)
      } else {
        log.Warn("No working directory provided in ERIS_DB_WORKDIR or --work-dir\n" +
          "Will use current working directory ", currentDirectory)
        do.WorkDir = currentDirectory
      }
    }
    if !util.IsDir(do.WorkDir) {
      log.Fatalf("Provided working directory %s is not a directory", do.WorkDir)
    }
    log.Debug("Working directory is set as %s", do.WorkDir)
  },
  Run: Serve,
}

// build the serve subcommand
func buildServeCommand() {
  addServeFlags()
}

func addServeFlags() {
  ServeCmd.PersistentFlags().StringVarP(&do.WorkDir, "work-dir", "w",
    defaultWorkDir(), "specify the working directory for the chain to run.  If omitted, and no path set in $ERIS_DB_WORKDIR, the current working directory is taken.")
  ServeCmd.PersistentFlags().StringVarP(&do.DataDir, "data-dir", "a",
    defaultDataDir(), "specify the data directory.  If omitted and not set in $ERIS_DB_DATADIR, <working_directory>/data is taken.")
}

//------------------------------------------------------------------------------
// functions

// serve() prepares the environment and sets up the core for Eris_DB to run.
// After the setup succeeds, serve() starts the core and halts for core to
// terminate.
func Serve(cmd *cobra.Command, args []string) {
  // load configuration from a single location to avoid a wrong configuration
  // file is loaded.
  if err := do.ReadConfig(do.WorkDir, "server_config", "toml"); err != nil {
    log.Fatalf("Fatal error reading server_config.toml : %s \n work directory: %s \n",
      err, do.WorkDir)
    os.Exit(1)
  }
  // load chain_id for assertion
  if do.ChainId = do.Config.GetString("chain.assert_chain_id");
    do.ChainId == "" {
    log.Fatalf("Failed to read non-empty string for ChainId from config.")
    os.Exit(1)
  }
  log.Info("Eris-DB serve initializing ", do.ChainId, " from ", do.WorkDir)

  // Ensure data directory is set and accesible
  if err := do.InitialiseDataDirectory(); err != nil {
    log.Fatalf("Failed to initialise data directory (%s): %v", do.DataDir, err)
    os.Exit(1)
  }
  log.Debug(fmt.Sprintf("Data directory is set at %s", do.DataDir))

  consensusConfig, err := core.LoadConsensusModuleConfig(do)
  if err != nil {
    log.Fatalf("Failed to load consensus module configuration: %s.", err)
    os.Exit(1)
  }

  managerConfig, err := core.LoadApplicationManagerModuleConfig(do)
  if err != nil {
    log.Fatalf("Failed to load application manager module configuration: %s.", err)
    os.Exit(1)
  }

  fmt.Printf("Consensus %s, App %s\n", consensusConfig.Version, managerConfig.Version)

}

//------------------------------------------------------------------------------
// Defaults

func defaultWorkDir() string {
  // if ERIS_DB_WORKDIR environment variable is not set, keep do.WorkDir empty
  return setDefaultString("ERIS_DB_WORKDIR", "")
}

func defaultDataDir() string {
  // As the default data directory depends on the default working directory,
  // wait setting a default value, and initialise the data directory from serve()
  return setDefaultString("ERIS_DB_DATADIR", "")
}
<|endoftext|>


<commit_before>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
)

var (
	update  = flag.Bool("update", false, "update or install the default signature file")
	version = flag.Bool("version", false, "display version information")
	sig     = flag.String("sig", config.Signature(), "set the signature file")
	home    = flag.String("home", config.Home(), "override the default home directory")
	serve   = flag.String("serve", "false", "not yet implemented - coming with v1")
)

func getHttp(url string) ([]byte, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	_, timeout, transport := config.UpdateOptions()
	req.Header.Add("User-Agent", "siegfried/siegbot (+https://github.com/richardlehane/siegfried)")
	req.Header.Add("Cache-Control", "no-cache")
	timer := time.AfterFunc(timeout, func() {
		transport.CancelRequest(req)
	})
	defer timer.Stop()
	client := http.Client{
		Transport: transport,
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

type Update struct {
	SfVersion  [3]int
	SigVersion int
	GobSize    int
	UpdateURL  string
}

func updateSigs() (string, error) {
	url, _, _ := config.UpdateOptions()
	if url == "" {
		return "Update is not available for this distribution of Siegfried", nil
	}
	response, err := getHttp(url)
	if err != nil {
		return "", err
	}
	var u Update
	if err := json.Unmarshal(response, &u); err != nil {
		return "", err
	}
	version := config.Version()
	if version[0] < u.SfVersion[0] || (u.SfVersion[0] == version[0] && version[1] < u.SfVersion[1]) {
		return "Your version of Siegfried is out of date; please install latest from http://www.itforarchivists.com/siegfried before continuing.", nil
	}
	s, err := siegfried.Load(config.Signature())
	if err == nil {
		if !s.Update(u.SigVersion) {
			return "You are already up to date!", nil
		}
	} else {
		err = os.MkdirAll(config.Home(), os.ModePerm)
		if err != nil {
			return "", err
		}
	}
	fmt.Println("... downloading latest signature file ...")
	response, err = getHttp(u.UpdateURL)
	if err != nil {
		return "", err
	}
	if len(response) != u.GobSize {
		return "", fmt.Errorf("Error retrieving pronom.gob; expecting %d bytes, got %d bytes", u.GobSize, len(response))
	}
	err = ioutil.WriteFile(config.Signature(), response, os.ModePerm)
	if err != nil {
		return "", err
	}
	fmt.Printf("... writing %s ...\n", config.Signature())
	return "Your signature file has been updated", nil
}

func load() (*siegfried.Siegfried, error) {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return nil, err
	}
	return s, nil
}

func identify(s *siegfried.Siegfried, p string) ([]string, error) {
	ids := make([]string, 0)
	file, err := os.Open(p)
	if err != nil {
		return nil, fmt.Errorf("failed to open %v, got: %v", p, err)
	}
	c, err := s.Identify(file, p)
	if err != nil {
		return nil, fmt.Errorf("failed to identify %v, got: %v", p, err)
	}
	for i := range c {
		ids = append(ids, i.String())
	}
	err = file.Close()
	if err != nil {
		return nil, err
	}
	return ids, nil
}

func multiIdentify(s *siegfried.Siegfried, r string) ([][]string, error) {
	set := make([][]string, 0)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		ids, err := identify(s, path)
		if err != nil {
			return err
		}
		set = append(set, ids)
		return nil
	}
	err := filepath.Walk(r, wf)
	return set, err
}

func multiIdentifyP(s *siegfried.Siegfried, r string) error {
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		file, err := os.Open(path)
		if err != nil {
			return fmt.Errorf("failed to open %v, got: %v", path, err)
		}
		c, err := s.Identify(file, path)
		if err != nil {
			file.Close()
			return fmt.Errorf("failed to identify %v, got: %v", path, err)
		}
		PrintFile(path, info.Size())
		for i := range c {
			fmt.Print(i.Yaml())
		}
		file.Close()
		return nil
	}
	return filepath.Walk(r, wf)
}

func PrintFile(name string, sz int64) {
	fmt.Println("---")
	fmt.Printf("filename : \"%v\"\n", name)
	fmt.Printf("filesize : %d\n", sz)
	fmt.Print("matches  :\n")
}

func PrintError(err error) {
	fmt.Println("---")
	fmt.Printf("Error : %v", err)
	fmt.Println("---")
}

func main() {

	flag.Parse()

	if *home != config.Home() {
		config.SetHome(*home)()
	}

	if *sig != config.SignatureBase() {
		config.SetSignature(*sig)()
	}

	if *version {
		version := config.Version()
		fmt.Printf("Siegfried version: %d.%d.%d\n", version[0], version[1], version[2])
		return
	}

	if *update {
		msg, err := updateSigs()
		if err != nil {
			log.Fatalf("Error: error updating signature file, %v", err)
		}
		fmt.Println(msg)
		return
	}

	if *serve != "false" {
		fmt.Println("sf server not yet implemented; expect by v1")
	}

	if flag.NArg() != 1 {
		log.Fatal("Error: expecting a single file or directory argument")
	}

	var err error
	file, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatalf("Error: error opening %v, got: %v", flag.Arg(0), err)
	}
	info, err := file.Stat()
	if err != nil {
		log.Fatalf("Error: error getting info for %v, got: %v", flag.Arg(0), err)
	}

	s, err := load()
	if err != nil {
		log.Fatalf("Error: error loading signature file, got: %v", err)

	}

	if info.IsDir() {
		file.Close()
		fmt.Print(s.Yaml())
		err = multiIdentifyP(s, flag.Arg(0))
		if err != nil {
			PrintError(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	fmt.Print(s.Yaml())
	c, err := s.Identify(file, flag.Arg(0))
	if err != nil {
		PrintError(err)
		file.Close()
		os.Exit(1)
	}
	PrintFile(flag.Arg(0), info.Size())
	for i := range c {
		fmt.Print(i.Yaml())
	}
	file.Close()

	os.Exit(0)
}
<commit_msg>ross directory bug<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/richardlehane/siegfried"
	"github.com/richardlehane/siegfried/config"
)

var (
	update  = flag.Bool("update", false, "update or install the default signature file")
	version = flag.Bool("version", false, "display version information")
	sig     = flag.String("sig", config.Signature(), "set the signature file")
	home    = flag.String("home", config.Home(), "override the default home directory")
	serve   = flag.String("serve", "false", "not yet implemented - coming with v1")
)

func getHttp(url string) ([]byte, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	_, timeout, transport := config.UpdateOptions()
	req.Header.Add("User-Agent", "siegfried/siegbot (+https://github.com/richardlehane/siegfried)")
	req.Header.Add("Cache-Control", "no-cache")
	timer := time.AfterFunc(timeout, func() {
		transport.CancelRequest(req)
	})
	defer timer.Stop()
	client := http.Client{
		Transport: transport,
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

type Update struct {
	SfVersion  [3]int
	SigVersion int
	GobSize    int
	UpdateURL  string
}

func updateSigs() (string, error) {
	url, _, _ := config.UpdateOptions()
	if url == "" {
		return "Update is not available for this distribution of Siegfried", nil
	}
	response, err := getHttp(url)
	if err != nil {
		return "", err
	}
	var u Update
	if err := json.Unmarshal(response, &u); err != nil {
		return "", err
	}
	version := config.Version()
	if version[0] < u.SfVersion[0] || (u.SfVersion[0] == version[0] && version[1] < u.SfVersion[1]) {
		return "Your version of Siegfried is out of date; please install latest from http://www.itforarchivists.com/siegfried before continuing.", nil
	}
	s, err := siegfried.Load(config.Signature())
	if err == nil {
		if !s.Update(u.SigVersion) {
			return "You are already up to date!", nil
		}
	} else {
		// this hairy bit of golang exception handling is thanks to Ross! :)
		if _, err = os.Stat(config.Home()); err != nil {
			if os.IsNotExist(err) {
				err = os.MkdirAll(config.Home(), os.ModePerm)
				if err != nil {
					return "", fmt.Errorf("Siegfried: cannot create home directory %s, %v", config.Home(), err)
				}
			} else {
				return "", fmt.Errorf("Siegfried: error opening directory %s, %v", config.Home(), err)
			}
		}
	}
	fmt.Println("... downloading latest signature file ...")
	response, err = getHttp(u.UpdateURL)
	if err != nil {
		return "", err
	}
	if len(response) != u.GobSize {
		return "", fmt.Errorf("Error retrieving pronom.gob; expecting %d bytes, got %d bytes", u.GobSize, len(response))
	}
	err = ioutil.WriteFile(config.Signature(), response, os.ModePerm)
	if err != nil {
		return "", fmt.Errorf("Siegfried: error writing to directory, %v", err)
	}
	fmt.Printf("... writing %s ...\n", config.Signature())
	return "Your signature file has been updated", nil
}

func load() (*siegfried.Siegfried, error) {
	s, err := siegfried.Load(config.Signature())
	if err != nil {
		return nil, err
	}
	return s, nil
}

func identify(s *siegfried.Siegfried, p string) ([]string, error) {
	ids := make([]string, 0)
	file, err := os.Open(p)
	if err != nil {
		return nil, fmt.Errorf("failed to open %v, got: %v", p, err)
	}
	c, err := s.Identify(file, p)
	if err != nil {
		return nil, fmt.Errorf("failed to identify %v, got: %v", p, err)
	}
	for i := range c {
		ids = append(ids, i.String())
	}
	err = file.Close()
	if err != nil {
		return nil, err
	}
	return ids, nil
}

func multiIdentify(s *siegfried.Siegfried, r string) ([][]string, error) {
	set := make([][]string, 0)
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		ids, err := identify(s, path)
		if err != nil {
			return err
		}
		set = append(set, ids)
		return nil
	}
	err := filepath.Walk(r, wf)
	return set, err
}

func multiIdentifyP(s *siegfried.Siegfried, r string) error {
	wf := func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		file, err := os.Open(path)
		if err != nil {
			return fmt.Errorf("failed to open %v, got: %v", path, err)
		}
		c, err := s.Identify(file, path)
		if err != nil {
			file.Close()
			return fmt.Errorf("failed to identify %v, got: %v", path, err)
		}
		PrintFile(path, info.Size())
		for i := range c {
			fmt.Print(i.Yaml())
		}
		file.Close()
		return nil
	}
	return filepath.Walk(r, wf)
}

func PrintFile(name string, sz int64) {
	fmt.Println("---")
	fmt.Printf("filename : \"%v\"\n", name)
	fmt.Printf("filesize : %d\n", sz)
	fmt.Print("matches  :\n")
}

func PrintError(err error) {
	fmt.Println("---")
	fmt.Printf("Error : %v", err)
	fmt.Println("---")
}

func main() {

	flag.Parse()

	if *home != config.Home() {
		config.SetHome(*home)()
	}

	if *sig != config.SignatureBase() {
		config.SetSignature(*sig)()
	}

	if *version {
		version := config.Version()
		fmt.Printf("Siegfried version: %d.%d.%d\n", version[0], version[1], version[2])
		return
	}

	if *update {
		msg, err := updateSigs()
		if err != nil {
			log.Fatalf("Error: error updating signature file, %v", err)
		}
		fmt.Println(msg)
		return
	}

	if *serve != "false" {
		fmt.Println("sf server not yet implemented; expect by v1")
	}

	if flag.NArg() != 1 {
		log.Fatal("Error: expecting a single file or directory argument")
	}

	var err error
	file, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatalf("Error: error opening %v, got: %v", flag.Arg(0), err)
	}
	info, err := file.Stat()
	if err != nil {
		log.Fatalf("Error: error getting info for %v, got: %v", flag.Arg(0), err)
	}

	s, err := load()
	if err != nil {
		log.Fatalf("Error: error loading signature file, got: %v", err)

	}

	if info.IsDir() {
		file.Close()
		fmt.Print(s.Yaml())
		err = multiIdentifyP(s, flag.Arg(0))
		if err != nil {
			PrintError(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	fmt.Print(s.Yaml())
	c, err := s.Identify(file, flag.Arg(0))
	if err != nil {
		PrintError(err)
		file.Close()
		os.Exit(1)
	}
	PrintFile(flag.Arg(0), info.Size())
	for i := range c {
		fmt.Print(i.Yaml())
	}
	file.Close()

	os.Exit(0)
}
<|endoftext|>


<commit_before>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2021-01-15 03:49:05.456428 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "08e6a297e0687350eac5385f3bd539d9005954d5"
<commit_msg>"Autogenerated build info"<commit_after>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2021-01-17 06:10:17.316481 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "46d61f90cacc76d093205e56d8f758250bd1a657"
<|endoftext|>


<commit_before>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2019-08-11 20:53:40.361775 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "e94156ce02cadc61acaefca47ed9cab88640ba03"
<commit_msg>"Autogenerated build info"<commit_after>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2019-08-11 20:54:29.648019 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "9cb358ac9de07b2b5dcaba1b57a367d899f19076"
<|endoftext|>