<commit_before>package images // import "github.com/docker/docker/daemon/images"

import (
	"context"
	"fmt"
	"os"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/leases"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/container"
	daemonevents "github.com/docker/docker/daemon/events"
	"github.com/docker/docker/distribution/metadata"
	"github.com/docker/docker/distribution/xfer"
	"github.com/docker/docker/image"
	"github.com/docker/docker/layer"
	dockerreference "github.com/docker/docker/reference"
	"github.com/docker/docker/registry"
	"github.com/docker/libtrust"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
	"golang.org/x/sync/singleflight"
)

type containerStore interface {
	// used by image delete
	First(container.StoreFilter) *container.Container
	// used by image prune, and image list
	List() []*container.Container
	// TODO: remove, only used for CommitBuildStep
	Get(string) *container.Container
}

// ImageServiceConfig is the configuration used to create a new ImageService
type ImageServiceConfig struct {
	ContainerStore            containerStore
	DistributionMetadataStore metadata.Store
	EventsService             *daemonevents.Events
	ImageStore                image.Store
	LayerStore                layer.Store
	MaxConcurrentDownloads    int
	MaxConcurrentUploads      int
	MaxDownloadAttempts       int
	ReferenceStore            dockerreference.Store
	RegistryService           registry.Service
	TrustKey                  libtrust.PrivateKey
	ContentStore              content.Store
	Leases                    leases.Manager
	ContentNamespace          string
}

// NewImageService returns a new ImageService from a configuration
func NewImageService(config ImageServiceConfig) *ImageService {
	return &ImageService{
		containers:                config.ContainerStore,
		distributionMetadataStore: config.DistributionMetadataStore,
		downloadManager:           xfer.NewLayerDownloadManager(config.LayerStore, config.MaxConcurrentDownloads, xfer.WithMaxDownloadAttempts(config.MaxDownloadAttempts)),
		eventsService:             config.EventsService,
		imageStore:                &imageStoreWithLease{Store: config.ImageStore, leases: config.Leases, ns: config.ContentNamespace},
		layerStore:                config.LayerStore,
		referenceStore:            config.ReferenceStore,
		registryService:           config.RegistryService,
		trustKey:                  config.TrustKey,
		uploadManager:             xfer.NewLayerUploadManager(config.MaxConcurrentUploads),
		leases:                    config.Leases,
		content:                   config.ContentStore,
		contentNamespace:          config.ContentNamespace,
	}
}

// ImageService provides a backend for image management
type ImageService struct {
	containers                containerStore
	distributionMetadataStore metadata.Store
	downloadManager           *xfer.LayerDownloadManager
	eventsService             *daemonevents.Events
	imageStore                image.Store
	layerStore                layer.Store
	pruneRunning              int32
	referenceStore            dockerreference.Store
	registryService           registry.Service
	trustKey                  libtrust.PrivateKey
	uploadManager             *xfer.LayerUploadManager
	leases                    leases.Manager
	content                   content.Store
	contentNamespace          string
	usage                     singleflight.Group
}

// DistributionServices provides daemon image storage services
type DistributionServices struct {
	DownloadManager   *xfer.LayerDownloadManager
	V2MetadataService metadata.V2MetadataService
	LayerStore        layer.Store
	ImageStore        image.Store
	ReferenceStore    dockerreference.Store
}

// DistributionServices return services controlling daemon image storage
func (i *ImageService) DistributionServices() DistributionServices {
	return DistributionServices{
		DownloadManager:   i.downloadManager,
		V2MetadataService: metadata.NewV2MetadataService(i.distributionMetadataStore),
		LayerStore:        i.layerStore,
		ImageStore:        i.imageStore,
		ReferenceStore:    i.referenceStore,
	}
}

// CountImages returns the number of images stored by ImageService
// called from info.go
func (i *ImageService) CountImages() int {
	return i.imageStore.Len()
}

// Children returns the children image.IDs for a parent image.
// called from list.go to filter containers
// TODO: refactor to expose an ancestry for image.ID?
func (i *ImageService) Children(id image.ID) []image.ID {
	return i.imageStore.Children(id)
}

// CreateLayer creates a filesystem layer for a container.
// called from create.go
// TODO: accept an opt struct instead of container?
func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
	var layerID layer.ChainID
	if container.ImageID != "" {
		img, err := i.imageStore.Get(container.ImageID)
		if err != nil {
			return nil, err
		}
		layerID = img.RootFS.ChainID()
	}

	rwLayerOpts := &layer.CreateRWLayerOpts{
		MountLabel: container.MountLabel,
		InitFunc:   initFunc,
		StorageOpt: container.HostConfig.StorageOpt,
	}

	// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
	// caller), and guaranteed non-nil
	return i.layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
}

// GetLayerByID returns a layer by ID
// called from daemon.go Daemon.restore(), and Daemon.containerExport()
func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
	return i.layerStore.GetRWLayer(cid)
}

// LayerStoreStatus returns the status for each layer store
// called from info.go
func (i *ImageService) LayerStoreStatus() [][2]string {
	return i.layerStore.DriverStatus()
}

// GetLayerMountID returns the mount ID for a layer
// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
// TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
func (i *ImageService) GetLayerMountID(cid string) (string, error) {
	return i.layerStore.GetMountID(cid)
}

// Cleanup resources before the process is shutdown.
// called from daemon.go Daemon.Shutdown()
func (i *ImageService) Cleanup() error {
	if err := i.layerStore.Cleanup(); err != nil {
		return errors.Wrap(err, "error during layerStore.Cleanup()")
	}
	return nil
}

// GraphDriverName returns the name of the graph drvier
// moved from Daemon.GraphDriverName, used by:
// - newContainer
// - to report an error in Daemon.Mount(container)
func (i *ImageService) GraphDriverName() string {
	return i.layerStore.DriverName()
}

// ReleaseLayer releases a layer allowing it to be removed
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
	metadata, err := i.layerStore.ReleaseRWLayer(rwlayer)
	layer.LogReleaseMetadata(metadata)
	if err != nil && !errors.Is(err, layer.ErrMountDoesNotExist) && !errors.Is(err, os.ErrNotExist) {
		return errors.Wrapf(err, "driver %q failed to remove root filesystem",
			i.layerStore.DriverName())
	}
	return nil
}

// LayerDiskUsage returns the number of bytes used by layer stores
// called from disk_usage.go
func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
	ch := i.usage.DoChan("LayerDiskUsage", func() (interface{}, error) {
		var allLayersSize int64
		layerRefs := i.getLayerRefs()
		allLayers := i.layerStore.Map()
		for _, l := range allLayers {
			select {
			case <-ctx.Done():
				return allLayersSize, ctx.Err()
			default:
				size := l.DiffSize()
				if _, ok := layerRefs[l.ChainID()]; ok {
					allLayersSize += size
				}
			}
		}
		return allLayersSize, nil
	})
	select {
	case <-ctx.Done():
		return 0, ctx.Err()
	case res := <-ch:
		if res.Err != nil {
			return 0, res.Err
		}
		return res.Val.(int64), nil
	}
}

func (i *ImageService) getLayerRefs() map[layer.ChainID]int {
	tmpImages := i.imageStore.Map()
	layerRefs := map[layer.ChainID]int{}
	for id, img := range tmpImages {
		dgst := digest.Digest(id)
		if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 {
			continue
		}

		rootFS := *img.RootFS
		rootFS.DiffIDs = nil
		for _, id := range img.RootFS.DiffIDs {
			rootFS.Append(id)
			chid := rootFS.ChainID()
			layerRefs[chid]++
		}
	}

	return layerRefs
}

// ImageDiskUsage returns information about image data disk usage.
func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) {
	ch := i.usage.DoChan("ImageDiskUsage", func() (interface{}, error) {
		// Get all top images with extra attributes
		images, err := i.Images(ctx, types.ImageListOptions{
			Filters:        filters.NewArgs(),
			SharedSize:     true,
			ContainerCount: true,
		})
		if err != nil {
			return nil, fmt.Errorf("failed to retrieve image list: %v", err)
		}
		return images, nil
	})
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case res := <-ch:
		if res.Err != nil {
			return nil, res.Err
		}
		return res.Val.([]*types.ImageSummary), nil
	}
}

// UpdateConfig values
//
// called from reload.go
func (i *ImageService) UpdateConfig(maxDownloads, maxUploads *int) {
	if i.downloadManager != nil && maxDownloads != nil {
		i.downloadManager.SetConcurrency(*maxDownloads)
	}
	if i.uploadManager != nil && maxUploads != nil {
		i.uploadManager.SetConcurrency(*maxUploads)
	}
}
<commit_msg>Remove comment that is no longer relevant<commit_after>package images // import "github.com/docker/docker/daemon/images"

import (
	"context"
	"fmt"
	"os"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/leases"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/container"
	daemonevents "github.com/docker/docker/daemon/events"
	"github.com/docker/docker/distribution/metadata"
	"github.com/docker/docker/distribution/xfer"
	"github.com/docker/docker/image"
	"github.com/docker/docker/layer"
	dockerreference "github.com/docker/docker/reference"
	"github.com/docker/docker/registry"
	"github.com/docker/libtrust"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
	"golang.org/x/sync/singleflight"
)

type containerStore interface {
	// used by image delete
	First(container.StoreFilter) *container.Container
	// used by image prune, and image list
	List() []*container.Container
	// TODO: remove, only used for CommitBuildStep
	Get(string) *container.Container
}

// ImageServiceConfig is the configuration used to create a new ImageService
type ImageServiceConfig struct {
	ContainerStore            containerStore
	DistributionMetadataStore metadata.Store
	EventsService             *daemonevents.Events
	ImageStore                image.Store
	LayerStore                layer.Store
	MaxConcurrentDownloads    int
	MaxConcurrentUploads      int
	MaxDownloadAttempts       int
	ReferenceStore            dockerreference.Store
	RegistryService           registry.Service
	TrustKey                  libtrust.PrivateKey
	ContentStore              content.Store
	Leases                    leases.Manager
	ContentNamespace          string
}

// NewImageService returns a new ImageService from a configuration
func NewImageService(config ImageServiceConfig) *ImageService {
	return &ImageService{
		containers:                config.ContainerStore,
		distributionMetadataStore: config.DistributionMetadataStore,
		downloadManager:           xfer.NewLayerDownloadManager(config.LayerStore, config.MaxConcurrentDownloads, xfer.WithMaxDownloadAttempts(config.MaxDownloadAttempts)),
		eventsService:             config.EventsService,
		imageStore:                &imageStoreWithLease{Store: config.ImageStore, leases: config.Leases, ns: config.ContentNamespace},
		layerStore:                config.LayerStore,
		referenceStore:            config.ReferenceStore,
		registryService:           config.RegistryService,
		trustKey:                  config.TrustKey,
		uploadManager:             xfer.NewLayerUploadManager(config.MaxConcurrentUploads),
		leases:                    config.Leases,
		content:                   config.ContentStore,
		contentNamespace:          config.ContentNamespace,
	}
}

// ImageService provides a backend for image management
type ImageService struct {
	containers                containerStore
	distributionMetadataStore metadata.Store
	downloadManager           *xfer.LayerDownloadManager
	eventsService             *daemonevents.Events
	imageStore                image.Store
	layerStore                layer.Store
	pruneRunning              int32
	referenceStore            dockerreference.Store
	registryService           registry.Service
	trustKey                  libtrust.PrivateKey
	uploadManager             *xfer.LayerUploadManager
	leases                    leases.Manager
	content                   content.Store
	contentNamespace          string
	usage                     singleflight.Group
}

// DistributionServices provides daemon image storage services
type DistributionServices struct {
	DownloadManager   *xfer.LayerDownloadManager
	V2MetadataService metadata.V2MetadataService
	LayerStore        layer.Store
	ImageStore        image.Store
	ReferenceStore    dockerreference.Store
}

// DistributionServices return services controlling daemon image storage
func (i *ImageService) DistributionServices() DistributionServices {
	return DistributionServices{
		DownloadManager:   i.downloadManager,
		V2MetadataService: metadata.NewV2MetadataService(i.distributionMetadataStore),
		LayerStore:        i.layerStore,
		ImageStore:        i.imageStore,
		ReferenceStore:    i.referenceStore,
	}
}

// CountImages returns the number of images stored by ImageService
// called from info.go
func (i *ImageService) CountImages() int {
	return i.imageStore.Len()
}

// Children returns the children image.IDs for a parent image.
// called from list.go to filter containers
// TODO: refactor to expose an ancestry for image.ID?
func (i *ImageService) Children(id image.ID) []image.ID {
	return i.imageStore.Children(id)
}

// CreateLayer creates a filesystem layer for a container.
// called from create.go
// TODO: accept an opt struct instead of container?
func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
	var layerID layer.ChainID
	if container.ImageID != "" {
		img, err := i.imageStore.Get(container.ImageID)
		if err != nil {
			return nil, err
		}
		layerID = img.RootFS.ChainID()
	}

	rwLayerOpts := &layer.CreateRWLayerOpts{
		MountLabel: container.MountLabel,
		InitFunc:   initFunc,
		StorageOpt: container.HostConfig.StorageOpt,
	}

	return i.layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
}

// GetLayerByID returns a layer by ID
// called from daemon.go Daemon.restore(), and Daemon.containerExport()
func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) {
	return i.layerStore.GetRWLayer(cid)
}

// LayerStoreStatus returns the status for each layer store
// called from info.go
func (i *ImageService) LayerStoreStatus() [][2]string {
	return i.layerStore.DriverStatus()
}

// GetLayerMountID returns the mount ID for a layer
// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
// TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
func (i *ImageService) GetLayerMountID(cid string) (string, error) {
	return i.layerStore.GetMountID(cid)
}

// Cleanup resources before the process is shutdown.
// called from daemon.go Daemon.Shutdown()
func (i *ImageService) Cleanup() error {
	if err := i.layerStore.Cleanup(); err != nil {
		return errors.Wrap(err, "error during layerStore.Cleanup()")
	}
	return nil
}

// GraphDriverName returns the name of the graph drvier
// moved from Daemon.GraphDriverName, used by:
// - newContainer
// - to report an error in Daemon.Mount(container)
func (i *ImageService) GraphDriverName() string {
	return i.layerStore.DriverName()
}

// ReleaseLayer releases a layer allowing it to be removed
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
	metadata, err := i.layerStore.ReleaseRWLayer(rwlayer)
	layer.LogReleaseMetadata(metadata)
	if err != nil && !errors.Is(err, layer.ErrMountDoesNotExist) && !errors.Is(err, os.ErrNotExist) {
		return errors.Wrapf(err, "driver %q failed to remove root filesystem",
			i.layerStore.DriverName())
	}
	return nil
}

// LayerDiskUsage returns the number of bytes used by layer stores
// called from disk_usage.go
func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
	ch := i.usage.DoChan("LayerDiskUsage", func() (interface{}, error) {
		var allLayersSize int64
		layerRefs := i.getLayerRefs()
		allLayers := i.layerStore.Map()
		for _, l := range allLayers {
			select {
			case <-ctx.Done():
				return allLayersSize, ctx.Err()
			default:
				size := l.DiffSize()
				if _, ok := layerRefs[l.ChainID()]; ok {
					allLayersSize += size
				}
			}
		}
		return allLayersSize, nil
	})
	select {
	case <-ctx.Done():
		return 0, ctx.Err()
	case res := <-ch:
		if res.Err != nil {
			return 0, res.Err
		}
		return res.Val.(int64), nil
	}
}

func (i *ImageService) getLayerRefs() map[layer.ChainID]int {
	tmpImages := i.imageStore.Map()
	layerRefs := map[layer.ChainID]int{}
	for id, img := range tmpImages {
		dgst := digest.Digest(id)
		if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 {
			continue
		}

		rootFS := *img.RootFS
		rootFS.DiffIDs = nil
		for _, id := range img.RootFS.DiffIDs {
			rootFS.Append(id)
			chid := rootFS.ChainID()
			layerRefs[chid]++
		}
	}

	return layerRefs
}

// ImageDiskUsage returns information about image data disk usage.
func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) {
	ch := i.usage.DoChan("ImageDiskUsage", func() (interface{}, error) {
		// Get all top images with extra attributes
		images, err := i.Images(ctx, types.ImageListOptions{
			Filters:        filters.NewArgs(),
			SharedSize:     true,
			ContainerCount: true,
		})
		if err != nil {
			return nil, fmt.Errorf("failed to retrieve image list: %v", err)
		}
		return images, nil
	})
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case res := <-ch:
		if res.Err != nil {
			return nil, res.Err
		}
		return res.Val.([]*types.ImageSummary), nil
	}
}

// UpdateConfig values
//
// called from reload.go
func (i *ImageService) UpdateConfig(maxDownloads, maxUploads *int) {
	if i.downloadManager != nil && maxDownloads != nil {
		i.downloadManager.SetConcurrency(*maxDownloads)
	}
	if i.uploadManager != nil && maxUploads != nil {
		i.uploadManager.SetConcurrency(*maxUploads)
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"io/ioutil"
	"os"

	"github.com/opentable/sous/config"
	"github.com/opentable/sous/ext/git"
	"github.com/opentable/sous/graph"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/server"
	"github.com/opentable/sous/util/cmdr"
	"github.com/opentable/sous/util/shell"
)

// A SousServer represents the `sous server` command.
type SousServer struct {
	Sous *Sous
	*config.Verbosity
	config.DeployFilterFlags
	*sous.AutoResolver

	Config graph.LocalSousConfig
	Log    *sous.LogSet
	flags  struct {
		dryrun,
		// laddr is the listen address in the form [host]:port
		laddr,
		// gdmRepo is a repository to clone into config.SourceLocation
		// in the case that config.SourceLocation is empty.
		gdmRepo string
	}
}

func init() { TopLevelCommands["server"] = &SousServer{} }

const sousServerHelp = `
Runs the API server for Sous

usage: sous server
`

// Help is part of the cmdr.Command interface(s).
func (ss *SousServer) Help() string {
	return sousServerHelp
}

// AddFlags is part of the cmdr.Command interfaces(s).
func (ss *SousServer) AddFlags(fs *flag.FlagSet) {
	MustAddFlags(fs, &ss.DeployFilterFlags, ClusterFilterFlagsHelp)
	fs.StringVar(&ss.flags.dryrun, "dry-run", "none",
		"prevent rectify from actually changing things - "+
			"values are none,scheduler,registry,both")
	fs.StringVar(&ss.flags.laddr, `listen`, `:80`, "The address to listen on, like '127.0.0.1:https'")
	fs.StringVar(&ss.flags.gdmRepo, "gdm-repo", "", "Git repo containing the GDM (cloned into config.SourceLocation)")
}

// RegisterOn adds the DeploymentConfig to the psyringe to configure the
// labeller and registrar.
func (ss *SousServer) RegisterOn(psy Addable) {
	psy.Add(graph.DryrunOption(ss.flags.dryrun))
	psy.Add(&ss.DeployFilterFlags)
}

// Execute is part of the cmdr.Command interface(s).
func (ss *SousServer) Execute(args []string) cmdr.Result {
	if err := ensureGDMExists(ss.flags.gdmRepo, ss.Config.StateLocation, ss.Log.Info.Printf); err != nil {
		return EnsureErrorResult(err)
	}
	ss.Log.Info.Println("Starting scheduled GDM resolution.")
	ss.AutoResolver.Kickoff()
	ss.Log.Info.Printf("Sous Server v%s running at %s", ss.Sous.Version, ss.flags.laddr)
	return EnsureErrorResult(server.RunServer(ss.Verbosity, ss.flags.laddr)) //always non-nil
}

func ensureGDMExists(repo, localPath string, log func(string, ...interface{})) error {
	s, err := os.Stat(localPath)
	if err == nil && s.IsDir() {
		files, err := ioutil.ReadDir(localPath)
		if err != nil {
			return err
		}
		if len(files) != 0 {
			// The directory exists and is not empty, do nothing.
			if repo != "" {
				log("not pulling repo %q; directory already exist and is not empty: %q", repo, localPath)
			}
			return nil
		}
	}
	if err := config.EnsureDirExists(localPath); err != nil {
		return EnsureErrorResult(err)
	}
	sh, err := shell.DefaultInDir(localPath)
	if err != nil {
		return EnsureErrorResult(err)
	}
	g, err := git.NewClient(sh)
	if err != nil {
		return EnsureErrorResult(err)
	}
	log("cloning %q into %q ...", repo, localPath)
	if err := g.CloneRepo(repo, localPath); err != nil {
		return EnsureErrorResult(err)
	}
	log("done")
	return nil
}
<commit_msg>cli: Deanonymise SousServer fields.<commit_after>package cli

import (
	"flag"
	"io/ioutil"
	"os"

	"github.com/opentable/sous/config"
	"github.com/opentable/sous/ext/git"
	"github.com/opentable/sous/graph"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/server"
	"github.com/opentable/sous/util/cmdr"
	"github.com/opentable/sous/util/shell"
)

// A SousServer represents the `sous server` command.
type SousServer struct {
	Sous              *Sous
	Verbosity         *config.Verbosity
	DeployFilterFlags config.DeployFilterFlags
	AutoResolver      *sous.AutoResolver
	Config            graph.LocalSousConfig
	Log               *sous.LogSet
	flags             struct {
		dryrun,
		// laddr is the listen address in the form [host]:port
		laddr,
		// gdmRepo is a repository to clone into config.SourceLocation
		// in the case that config.SourceLocation is empty.
		gdmRepo string
	}
}

func init() { TopLevelCommands["server"] = &SousServer{} }

const sousServerHelp = `
Runs the API server for Sous

usage: sous server
`

// Help is part of the cmdr.Command interface(s).
func (ss *SousServer) Help() string {
	return sousServerHelp
}

// AddFlags is part of the cmdr.Command interfaces(s).
func (ss *SousServer) AddFlags(fs *flag.FlagSet) {
	MustAddFlags(fs, &ss.DeployFilterFlags, ClusterFilterFlagsHelp)
	fs.StringVar(&ss.flags.dryrun, "dry-run", "none",
		"prevent rectify from actually changing things - "+
			"values are none,scheduler,registry,both")
	fs.StringVar(&ss.flags.laddr, `listen`, `:80`, "The address to listen on, like '127.0.0.1:https'")
	fs.StringVar(&ss.flags.gdmRepo, "gdm-repo", "", "Git repo containing the GDM (cloned into config.SourceLocation)")
}

// RegisterOn adds the DeploymentConfig to the psyringe to configure the
// labeller and registrar.
func (ss *SousServer) RegisterOn(psy Addable) {
	psy.Add(graph.DryrunOption(ss.flags.dryrun))
	psy.Add(&ss.DeployFilterFlags)
}

// Execute is part of the cmdr.Command interface(s).
func (ss *SousServer) Execute(args []string) cmdr.Result {
	if err := ensureGDMExists(ss.flags.gdmRepo, ss.Config.StateLocation, ss.Log.Info.Printf); err != nil {
		return EnsureErrorResult(err)
	}
	ss.Log.Info.Println("Starting scheduled GDM resolution.")
	ss.AutoResolver.Kickoff()
	ss.Log.Info.Printf("Sous Server v%s running at %s", ss.Sous.Version, ss.flags.laddr)
	return EnsureErrorResult(server.RunServer(ss.Verbosity, ss.flags.laddr)) //always non-nil
}

func ensureGDMExists(repo, localPath string, log func(string, ...interface{})) error {
	s, err := os.Stat(localPath)
	if err == nil && s.IsDir() {
		files, err := ioutil.ReadDir(localPath)
		if err != nil {
			return err
		}
		if len(files) != 0 {
			// The directory exists and is not empty, do nothing.
			if repo != "" {
				log("not pulling repo %q; directory already exist and is not empty: %q", repo, localPath)
			}
			return nil
		}
	}
	if err := config.EnsureDirExists(localPath); err != nil {
		return EnsureErrorResult(err)
	}
	sh, err := shell.DefaultInDir(localPath)
	if err != nil {
		return EnsureErrorResult(err)
	}
	g, err := git.NewClient(sh)
	if err != nil {
		return EnsureErrorResult(err)
	}
	log("cloning %q into %q ...", repo, localPath)
	if err := g.CloneRepo(repo, localPath); err != nil {
		return EnsureErrorResult(err)
	}
	log("done")
	return nil
}
<|endoftext|>


<commit_before>package horizon

import (
	"net/http"

	"github.com/jagregory/halgo"
	"github.com/rcrowley/go-metrics"
	"github.com/stellar/go-horizon/db"
	"github.com/stellar/go-horizon/render/hal"
	"github.com/zenazn/goji/web"
)

// MetricsAction collects and renders a snapshot from the metrics system that
// will inlude any previously registered metrics.
type MetricsAction struct {
	Action `json:"-"`
	halgo.Links
	Snapshot map[string]interface{} `json:",inline"`
}

// ServeHTTPC is a method for web.Handler
func (action MetricsAction) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request) {
	ap := &action.Action
	ap.Prepare(c, w, r)
	ap.Execute(&action)
}

// JSON is a method for actions.JSON
func (action *MetricsAction) JSON() {
	db.UpdateLedgerState(action.Ctx, action.App.HistoryQuery(), action.App.CoreQuery())
	action.LoadSnapshot()
	hal.Render(action.W, action)
}

// LoadSnapshot populates action.Snapshot
//
// Original code copied from github.com/rcrowley/go-metrics MarshalJSON
func (action *MetricsAction) LoadSnapshot() {

	action.Snapshot = make(map[string]interface{})

	action.App.metrics.Each(func(name string, i interface{}) {
		values := make(map[string]interface{})
		switch metric := i.(type) {
		case metrics.Counter:
			values["count"] = metric.Count()
		case metrics.Gauge:
			values["value"] = metric.Value()
		case metrics.GaugeFloat64:
			values["value"] = metric.Value()
		case metrics.Healthcheck:
			values["error"] = nil
			metric.Check()
			if err := metric.Error(); nil != err {
				values["error"] = metric.Error().Error()
			}
		case metrics.Histogram:
			h := metric.Snapshot()
			ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
			values["count"] = h.Count()
			values["min"] = h.Min()
			values["max"] = h.Max()
			values["mean"] = h.Mean()
			values["stddev"] = h.StdDev()
			values["median"] = ps[0]
			values["75%"] = ps[1]
			values["95%"] = ps[2]
			values["99%"] = ps[3]
			values["99.9%"] = ps[4]
		case metrics.Meter:
			m := metric.Snapshot()
			values["count"] = m.Count()
			values["1m.rate"] = m.Rate1()
			values["5m.rate"] = m.Rate5()
			values["15m.rate"] = m.Rate15()
			values["mean.rate"] = m.RateMean()
		case metrics.Timer:
			t := metric.Snapshot()
			ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
			values["count"] = t.Count()
			values["min"] = t.Min()
			values["max"] = t.Max()
			values["mean"] = t.Mean()
			values["stddev"] = t.StdDev()
			values["median"] = ps[0]
			values["75%"] = ps[1]
			values["95%"] = ps[2]
			values["99%"] = ps[3]
			values["99.9%"] = ps[4]
			values["1m.rate"] = t.Rate1()
			values["5m.rate"] = t.Rate5()
			values["15m.rate"] = t.Rate15()
			values["mean.rate"] = t.RateMean()
		}
		action.Snapshot[name] = values
	})

}
<commit_msg>Fix metrics rendering.  boy do I wish that inline worked.<commit_after>package horizon

import (
	"net/http"

	"github.com/jagregory/halgo"
	"github.com/rcrowley/go-metrics"
	"github.com/stellar/go-horizon/db"
	"github.com/stellar/go-horizon/render/hal"
	"github.com/zenazn/goji/web"
)

// MetricsAction collects and renders a snapshot from the metrics system that
// will inlude any previously registered metrics.
type MetricsAction struct {
	Action
	halgo.Links
	Snapshot map[string]interface{}
}

// ServeHTTPC is a method for web.Handler
func (action MetricsAction) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request) {
	ap := &action.Action
	ap.Prepare(c, w, r)
	ap.Execute(&action)
}

// JSON is a method for actions.JSON
func (action *MetricsAction) JSON() {
	db.UpdateLedgerState(action.Ctx, action.App.HistoryQuery(), action.App.CoreQuery())
	action.LoadSnapshot()
	action.Snapshot["_links"] = map[string]interface{}{
		"self": halgo.Link{Href: "/metrics"},
	}

	hal.Render(action.W, action.Snapshot)
}

// LoadSnapshot populates action.Snapshot
//
// Original code copied from github.com/rcrowley/go-metrics MarshalJSON
func (action *MetricsAction) LoadSnapshot() {

	action.Snapshot = make(map[string]interface{})

	action.App.metrics.Each(func(name string, i interface{}) {
		values := make(map[string]interface{})
		switch metric := i.(type) {
		case metrics.Counter:
			values["count"] = metric.Count()
		case metrics.Gauge:
			values["value"] = metric.Value()
		case metrics.GaugeFloat64:
			values["value"] = metric.Value()
		case metrics.Healthcheck:
			values["error"] = nil
			metric.Check()
			if err := metric.Error(); nil != err {
				values["error"] = metric.Error().Error()
			}
		case metrics.Histogram:
			h := metric.Snapshot()
			ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
			values["count"] = h.Count()
			values["min"] = h.Min()
			values["max"] = h.Max()
			values["mean"] = h.Mean()
			values["stddev"] = h.StdDev()
			values["median"] = ps[0]
			values["75%"] = ps[1]
			values["95%"] = ps[2]
			values["99%"] = ps[3]
			values["99.9%"] = ps[4]
		case metrics.Meter:
			m := metric.Snapshot()
			values["count"] = m.Count()
			values["1m.rate"] = m.Rate1()
			values["5m.rate"] = m.Rate5()
			values["15m.rate"] = m.Rate15()
			values["mean.rate"] = m.RateMean()
		case metrics.Timer:
			t := metric.Snapshot()
			ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
			values["count"] = t.Count()
			values["min"] = t.Min()
			values["max"] = t.Max()
			values["mean"] = t.Mean()
			values["stddev"] = t.StdDev()
			values["median"] = ps[0]
			values["75%"] = ps[1]
			values["95%"] = ps[2]
			values["99%"] = ps[3]
			values["99.9%"] = ps[4]
			values["1m.rate"] = t.Rate1()
			values["5m.rate"] = t.Rate5()
			values["15m.rate"] = t.Rate15()
			values["mean.rate"] = t.RateMean()
		}
		action.Snapshot[name] = values
	})

}
<|endoftext|>


<commit_before>package sde

import (
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/THUNDERGROOVE/SDETool2/log"
	"reflect"
	"regexp"
	"strconv"
	"time"
)

const (
	// SkillLevels
	LevelZero SkillLevel = iota
	LevelOne
	LevelTwo
	LevelThree
	LevelFour
	LevelFive
)

func init() {
	//gob.Register(SkillLevel{})
	gob.Register(CLFMetadata{})
	gob.Register(CLFPreset{})
	gob.Register(CLFSuit{})
	gob.Register(CLFModule{})
	gob.Register(Fit{})
	gob.Register(Stats{})
}

// SkillLevel is a type for each skill level available
type SkillLevel uint8

// CLFMetadata holds the metadata portion of a CLF fit
type CLFMetadata struct {
	Title string `json:"title"`
}

// CLFPreset is an individual preset in a CLF fit
type CLFPreset struct {
	Name    string       `json:"presetname"`
	Modules []*CLFModule `json:"modules"`
}

// CLFSuit houses the "ship" portion of a CLF fit
type CLFSuit struct {
	TypeID  string   `json:"typeid"`
	SDEType *SDEType `json:"-"`
}

// CLFModule holds an individual module in the fit
type CLFModule struct {
	SDEType  SDEType `json:"-"`
	TypeID   string  `json:"typeid"`
	SlotType string  `json:"slottype"`
	Index    int     `json:"index"`
}

// Fit is a structure representing a CLF fit for DUST514 and internal
// structures for calculating stats.
type Fit struct {
	CLFVersion     int         `json:"clf-version"`
	CLFType        string      `json:"X-clf-type"`
	CLFGeneratedBy string      `json:"X-generatedby"`
	Metadata       CLFMetadata `json:"metadata"`
	Suit           CLFSuit     `json:"ship"`
	Fitting        CLFPreset   `json:"presets"`
}

// Stats is a general structure to output all of the stats of a fit.
// Fields values are automatically inserted via ApplySuitBonuses.
// This structure is ready to be exported via JSON.
type Stats struct {
	HealArmorRate       int64   `sde:"mVICProp.healArmorRate"                       json:"repairRate"`
	Shields             int64   `sde:"mVICProp.maxShield"                           json:"shield"`
	Armor               int64   `sde:"mVICProp.maxArmor"                            json:"armor"`
	HealShieldRate      int64   `sde:"mVICProp.healShieldRate"                      json:"shieldRecharge"`
	ShieldDepletedDelay int64   `sde:"mVICProp.shieldRechargePauseOnShieldDepleted" json:"depletedDelay"`
	CPU                 int64   `sde:"mVICProp.maxPowerReserve"                     json:"cpu"`
	CPUUsed             int64   `json:"cpuUsed`
	CPUPercent          int     `json:"cpuPercent"`
	PG                  int64   `sde:"mVICProp.maxPowerReserve"                     json:"pg"`
	PGUsed              int64   `json:"pgUsed"`
	PGPercent           int     `json:"pgPercent"`
	Stamina             float64 `sde:"mCharProp.maxStamina"                         json:"stamina"`
	StaminaRecovery     float64 `sde:"mCharProp.staminaRecoveryPerSecond"           json:"staminaRecovery"`
	ScanPrecision       int64   `sde:"mVICProp.signatureScanPrecision"              json:"scanPrecision"`
	ScanProfile         int64   `sde:"mVICProp.signatureScanProfile"                json:"scanProfile"`
	ScanRadius          int64   `sde:"mVICProp.signatureScanRadius"                 json:"scanRadius"`
	MetaLevel           int64   `sde:"metaLevel"                                    json:"metaLevel"`
}

// FillFields is an internal function used to fill all the extra non-json
// within the SDEFit structure and sub structures.
func (s *Fit) FillFields() {
	log.Info("Filling fields for fit with type", s.Suit.TypeID)
	defer Debug(time.Now())

	if PrimarySDE == nil {
		log.LogError("Error filling SDEFit fields the PrimarySDE is nil.	Set it with GiveSDE()\n")
		return
	}
	typeid, _ := strconv.Atoi(s.Suit.TypeID)
	if typeid <= 0 {
		log.LogError("Fill fields called with no suit")
	}
	t, err := PrimarySDE.GetType(typeid)
	s.Suit.SDEType = &t
	if err != nil {
		log.LogError("Error filling SDEFit fields:", err.Error())
	}

	for _, v := range s.Fitting.Modules {
		tid, _ := strconv.Atoi(v.TypeID)
		if tid <= 0 {
			continue
		} else {
			log.Info(v.TypeID)
		}
		var err1 error
		v.SDEType, err1 = PrimarySDE.GetType(tid)
		if err1 != nil {
			log.LogError("Error filling SDEFit fields:", err.Error())
		}
	}
}

// Stats returns a Stats for a fit.  Assumes all Lvl5 skills.
func (s *Fit) Stats() *Stats {
	ss := &Stats{}
	for _, v := range s.Fitting.Modules {
		log.Info("Fit:", s.Metadata.Title, "module found", v.SDEType.GetName())
	}
	s.ApplySuitBonus(ss, LevelFive)

	t := reflect.TypeOf(Stats{})

	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		value := f.Tag.Get("sde")

		if value == "" {
			continue
		}

		if _, ok := s.Suit.SDEType.Attributes[value]; ok {
			attAssert(s.Suit.SDEType, i, ss, value)

		} else {
			log.LogError("Unable to unpack Stats field", value, "from attributes")
		}
	}

	// Static stats
	if ss.PGUsed == 0 {
		ss.PGPercent = 0
	} else {
		ss.PGPercent = int((ss.PGUsed / ss.PG) * 100)
	}
	if ss.CPUUsed == 0 {
		ss.CPUUsed = 0
	} else {
		ss.CPUPercent = int((ss.CPUUsed / ss.PGUsed) * 100)
	}
	return ss
}

// ApplySuitBonus applies bonuses for the suit using the skill level provided.
func (f *Fit) ApplySuitBonus(stats *Stats, skill SkillLevel) {
	f.Suit.SDEType.GetAttributes()
	if v, ok := f.Suit.SDEType.Attributes["requiredSkills.0.skillTypeID"]; ok {
		s, _ := PrimarySDE.GetType(v.(int))
		s.GetAttributes()

		var modcount int
		var bonuscount int

		reg, err := regexp.Compile("(modifier.)(\\d+)(.modifierValue)")
		breg, err2 := regexp.Compile("(bonusModifiers.)(\\d+)(.modifierValue)")
		if err != nil {
			log.LogError("Error compiling regex", err.Error())
		}
		if err2 != nil {
			log.LogError("Error compiling regex", err.Error())
		}

		for k, _ := range s.Attributes {
			if reg.Match([]byte(k)) {
				log.Info("Found modifier", k)
				modcount++
			}
			if breg.Match([]byte(k)) {
				log.Info("Found bonus modifier", k)
				bonuscount++
			}
		}

		log.Info("Attempting to apply modifiers")

		modcount--
		bonuscount--
		log.Info("modcount: %v bonuscount: %v\n", modcount, bonuscount)
		for i := 0; i <= modcount; i++ {
			log.Info("Applying modifier", i)
			var (
				err    error
				ival   interface{}
				itype  interface{}
				istack interface{}
				iname  interface{}
			)
			ival, err = getAttribute(s, fmt.Sprintf("modifier.%v.modifierValue", i))
			itype, err = getAttribute(s, fmt.Sprintf("modifier.%v.modifierType", i))
			istack, err = getAttribute(s, fmt.Sprintf("modifier.%v.stackingPenalized", i))
			iname, err = getAttribute(s, fmt.Sprintf("modifier.%v.attributeName", i))
			if err != nil {
				log.LogError("Unable to get attributes for modifer.  :/", err.Error())
				continue
			}
			val := ival.(float64)
			typ := itype.(string)
			stack := istack.(string)
			name := iname.(string)

			f.applySkill(val, typ, stack, name, skill)

		}

	} else {
		log.LogError("No required skills for type.", v)
		// log.Info("Dumping attributes:")
		// for k, v := range f.Suit.SDEType.Attributes {
		// 	fmt.Printf("\t[%v] => %v\n", k, v)
		// }
	}
}

// ToJSON returns an indented marshaled JSON string of our Stats object.
func (s *Stats) ToJSON() string {
	data, err := json.MarshalIndent(s, "", "  ")
	if err != nil {
		log.LogError("Error marshaling stats", err.Error())
	}
	return string(data)
}

// Private helper methods

// applySkill applys a raw skill value
func (f *Fit) applySkill(val float64, typ, stack, name string, level SkillLevel) {
	if f.Suit.SDEType == nil || f.Suit.SDEType.Attributes == nil {
		log.LogError("applySkill called with nil suit SDEType")
		return
	}
	if _, ok := f.Suit.SDEType.Attributes[name]; ok {
		switch reflect.TypeOf(f.Suit.SDEType.Attributes[name]).Kind() {
		case reflect.Int:
			ov := f.Suit.SDEType.Attributes[name].(int)

			for i := 1; i <= int(level); i++ {
				ov = ov * int(val)
			}
			log.Info("Setting attribute", name, "to", ov)
			f.Suit.SDEType.Attributes[name] = ov
		case reflect.Float64:
			ov := f.Suit.SDEType.Attributes[name].(float64)

			for i := 1; i <= int(level); i++ {
				ov = ov * val
				log.Info("Applying level", i, ov)
			}
			log.Info("Setting attribute", name, "to", ov)
			f.Suit.SDEType.Attributes[name] = ov
		default:
			log.LogError("Unsupported type in applySkill")
		}
	} else {
		log.LogError("applySkill called with name of attribute that doesn't exist.")
	}

}

// Private helpers

// getAttribute is a helper to get an attribute from an SDEType.
func getAttribute(s SDEType, a string) (interface{}, error) {
	if v, ok := s.Attributes[a]; ok {
		return v, nil
	} else {
		log.LogError("Wasn't cable to find attribute", a)
	}
	return nil, errors.New("attribute not found" + a)
}

// attAssert is a helper to get a value from SDEType and insert it into
// out Stats using reflection.  It's ugly... No really don't look...
func attAssert(s *SDEType, index int, stats *Stats, value string) {
	t := reflect.TypeOf(Stats{})
	ss := reflect.ValueOf(stats).Elem()
	a := s.Attributes[value]
	log.Info("attAssert with index", index)
	if ss.Field(index).CanSet() == false {
		log.LogError("For whatever reason we cannot set the value at index", index)
		return
	} else {
		switch reflect.TypeOf(a).Kind() {
		case reflect.Float64:
			switch ss.Field(index).Type().Kind() {
			case reflect.Float64: // Field is float.  Can set without conversion
				ss.Field(index).SetFloat(a.(float64))
			case reflect.Int: // Field is int.  Must convert
				ss.Field(index).SetInt(int64(a.(float64)))
			case reflect.Int64:
				ss.Field(index).SetInt(int64(a.(float64)))
			default:
				log.Info("Unsupported type in attAssert", t.Field(index).Type.Kind())
			}
		case reflect.Int:
			switch t.Field(index).Type.Kind() {
			case reflect.Float64: // Field is float.  Convert
				ss.Field(index).SetFloat(float64(a.(int)))
			case reflect.Int: // Field is int.  Must convert int64
				ss.Field(index).SetInt(int64(a.(int)))
			case reflect.Int64:
				ss.Field(index).SetInt(int64(a.(int)))
			default:
				log.Info("Unsupported type in attAssert", t.Field(index).Type.Kind())
			}
		case reflect.Int64:
			switch t.Field(index).Type.Kind() {
			case reflect.Float64: // Field is float.  Convert
				ss.Field(index).SetInt(int64(a.(float64)))
			case reflect.Int: // Field is int.  Must convert int64
				ss.Field(index).SetInt(int64(a.(int)))
			default:
				log.Info("Unsupported type in attAssert", t.Field(index).Type.Kind())
			}
		default:
			log.Info("Unsupported type in main switch attAssert", reflect.TypeOf(a).Kind())
		case reflect.String:
		}
	}
}
<commit_msg>Pushing for changes made for GoFit<commit_after>package sde

import (
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/THUNDERGROOVE/SDETool2/log"
	"reflect"
	"regexp"
	"strconv"
	"time"
)

const (
	// SkillLevels
	LevelZero SkillLevel = iota
	LevelOne
	LevelTwo
	LevelThree
	LevelFour
	LevelFive
)

func init() {
	//gob.Register(SkillLevel{})
	gob.Register(CLFMetadata{})
	gob.Register(CLFPreset{})
	gob.Register(CLFSuit{})
	gob.Register(CLFModule{})
	gob.Register(Fit{})
	gob.Register(Stats{})
}

// SkillLevel is a type for each skill level available
type SkillLevel uint8

// CLFMetadata holds the metadata portion of a CLF fit
type CLFMetadata struct {
	Title string `json:"title"`
}

// CLFPreset is an individual preset in a CLF fit
type CLFPreset struct {
	Name    string       `json:"presetname"`
	Modules []*CLFModule `json:"modules"`
}

// CLFSuit houses the "ship" portion of a CLF fit
type CLFSuit struct {
	TypeID  string   `json:"typeid"`
	SDEType *SDEType `json:"-"`
}

// CLFModule holds an individual module in the fit
type CLFModule struct {
	SDEType  SDEType `json:"-"`
	TypeID   string  `json:"typeid"`
	SlotType string  `json:"slottype"`
	Index    int     `json:"index"`
}

// Fit is a structure representing a CLF fit for DUST514 and internal
// structures for calculating stats.
type Fit struct {
	CLFVersion     int         `json:"clf-version"`
	CLFType        string      `json:"X-clf-type"`
	CLFGeneratedBy string      `json:"X-generatedby"`
	Metadata       CLFMetadata `json:"metadata"`
	Suit           CLFSuit     `json:"ship"`
	Fitting        CLFPreset   `json:"presets"`
}

// Stats is a general structure to output all of the stats of a fit.
// Fields values are automatically inserted via ApplySuitBonuses.
// This structure is ready to be exported via JSON.
type Stats struct {
	HealArmorRate       int64   `sde:"mVICProp.healArmorRate"                       json:"repairRate"`
	Shields             int64   `sde:"mVICProp.maxShield"                           json:"shield"`
	Armor               int64   `sde:"mVICProp.maxArmor"                            json:"armor"`
	HealShieldRate      int64   `sde:"mVICProp.healShieldRate"                      json:"shieldRecharge"`
	ShieldDepletedDelay int64   `sde:"mVICProp.shieldRechargePauseOnShieldDepleted" json:"depletedDelay"`
	CPU                 int64   `sde:"mVICProp.maxPowerReserve"                     json:"cpu"`
	CPUUsed             int64   `json:"cpuUsed`
	CPUPercent          int     `json:"cpuPercent"`
	PG                  int64   `sde:"mVICProp.maxPowerReserve"                     json:"pg"`
	PGUsed              int64   `json:"pgUsed"`
	PGPercent           int     `json:"pgPercent"`
	Stamina             float64 `sde:"mCharProp.maxStamina"                         json:"stamina"`
	StaminaRecovery     float64 `sde:"mCharProp.staminaRecoveryPerSecond"           json:"staminaRecovery"`
	ScanPrecision       int64   `sde:"mVICProp.signatureScanPrecision"              json:"scanPrecision"`
	ScanProfile         int64   `sde:"mVICProp.signatureScanProfile"                json:"scanProfile"`
	ScanRadius          int64   `sde:"mVICProp.signatureScanRadius"                 json:"scanRadius"`
	MetaLevel           int64   `sde:"metaLevel"                                    json:"metaLevel"`
}

// FillFields is an internal function used to fill all the extra non-json
// within the SDEFit structure and sub structures.
func (s *Fit) FillFields() {
	log.Info("Filling fields for fit with type", s.Suit.TypeID)
	defer Debug(time.Now())

	if PrimarySDE == nil {
		log.LogError("Error filling SDEFit fields the PrimarySDE is nil.	Set it with GiveSDE()\n")
		return
	}
	typeid, _ := strconv.Atoi(s.Suit.TypeID)
	if typeid <= 0 {
		log.LogError("Fill fields called with no suit")
	}
	t, err := PrimarySDE.GetType(typeid)
	s.Suit.SDEType = &t
	if err != nil {
		log.LogError("Error filling SDEFit fields:", err.Error())
	}

	for _, v := range s.Fitting.Modules {
		tid, _ := strconv.Atoi(v.TypeID)
		if tid <= 0 {
			continue
		} else {
			log.Info(v.TypeID)
		}
		var err1 error
		v.SDEType, err1 = PrimarySDE.GetType(tid)
		if err1 != nil {
			log.LogError("Error filling SDEFit fields:", err.Error())
		}
	}
}

// Stats returns a Stats for a fit.  Assumes all Lvl5 skills.
func (s *Fit) Stats() *Stats {
	ss := &Stats{}
	for _, v := range s.Fitting.Modules {
		log.Info("Fit:", s.Metadata.Title, "module found", v.SDEType.GetName())
	}
	s.ApplySuitBonus(ss, LevelFive)

	t := reflect.TypeOf(Stats{})

	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		value := f.Tag.Get("sde")

		if value == "" {
			continue
		}

		if _, ok := s.Suit.SDEType.Attributes[value]; ok {
			attAssert(s.Suit.SDEType, i, ss, value)

		} else {
			log.LogError("Unable to unpack Stats field", value, "from attributes")
		}
	}

	// Static stats
	if ss.PGUsed == 0 {
		ss.PGPercent = 0
	} else {
		ss.PGPercent = int((ss.PGUsed / ss.PG) * 100)
	}
	if ss.CPUUsed == 0 {
		ss.CPUUsed = 0
	} else {
		ss.CPUPercent = int((ss.CPUUsed / ss.PGUsed) * 100)
	}
	return ss
}

// ApplySuitBonus applies bonuses for the suit using the skill level provided.
func (f *Fit) ApplySuitBonus(stats *Stats, skill SkillLevel) {
	f.Suit.SDEType.GetAttributes()
	if v, ok := f.Suit.SDEType.Attributes["requiredSkills.0.skillTypeID"]; ok {
		s, _ := PrimarySDE.GetType(v.(int))
		s.GetAttributes()

		var modcount int
		var bonuscount int

		reg, err := regexp.Compile("(modifier.)(\\d+)(.modifierValue)")
		breg, err2 := regexp.Compile("(bonusModifiers.)(\\d+)(.modifierValue)")
		if err != nil {
			log.LogError("Error compiling regex", err.Error())
		}
		if err2 != nil {
			log.LogError("Error compiling regex", err.Error())
		}

		for k, _ := range s.Attributes {
			if reg.Match([]byte(k)) {
				log.Info("Found modifier", k)
				modcount++
			}
			if breg.Match([]byte(k)) {
				log.Info("Found bonus modifier", k)
				bonuscount++
			}
		}

		log.Info("Attempting to apply modifiers")

		modcount--
		bonuscount--
		log.Info("modcount: %v bonuscount: %v\n", modcount, bonuscount)
		for i := 0; i <= modcount; i++ {
			log.Info("Applying modifier", i)
			var (
				err    error
				ival   interface{}
				itype  interface{}
				istack interface{}
				iname  interface{}
			)
			ival, err = getAttribute(s, fmt.Sprintf("modifier.%v.modifierValue", i))
			itype, err = getAttribute(s, fmt.Sprintf("modifier.%v.modifierType", i))
			istack, err = getAttribute(s, fmt.Sprintf("modifier.%v.stackingPenalized", i))
			iname, err = getAttribute(s, fmt.Sprintf("modifier.%v.attributeName", i))
			if err != nil {
				log.LogError("Unable to get attributes for modifer.  :/", err.Error())
				continue
			}
			val := ival.(float64)
			typ := itype.(string)
			stack := istack.(string)
			name := iname.(string)

			f.applySkill(val, typ, stack, name, skill)

		}

	} else {
		log.LogError("No required skills for type.", v)
		// log.Info("Dumping attributes:")
		// for k, v := range f.Suit.SDEType.Attributes {
		// 	fmt.Printf("\t[%v] => %v\n", k, v)
		// }
	}
}

// ToJSON returns an indented marshaled JSON string of our Stats object.
func (s *Stats) ToJSON() string {
	data, err := json.MarshalIndent(s, "", "  ")
	if err != nil {
		log.LogError("Error marshaling stats", err.Error())
	}
	return string(data)
}

// Private helper methods

// applySkill applys a raw skill value
func (f *Fit) applySkill(val float64, typ, stack, name string, level SkillLevel) {
	if f.Suit.SDEType == nil || f.Suit.SDEType.Attributes == nil {
		log.LogError("applySkill called with nil suit SDEType")
		return
	}
	if _, ok := f.Suit.SDEType.Attributes[name]; ok {
		switch reflect.TypeOf(f.Suit.SDEType.Attributes[name]).Kind() {
		case reflect.Int:
			ov := f.Suit.SDEType.Attributes[name].(int)

			for i := 1; i <= int(level); i++ {
				ov = ov * int(val)
			}
			log.Info("Setting attribute", name, "to", ov)
			f.Suit.SDEType.Attributes[name] = ov
		case reflect.Float64:
			ov := f.Suit.SDEType.Attributes[name].(float64)

			for i := 1; i <= int(level); i++ {
				ov = ov * val
				log.Info("Applying level", i, ov)
			}
			log.Info("Setting attribute", name, "to", ov)
			f.Suit.SDEType.Attributes[name] = ov
		default:
			log.LogError("Unsupported type in applySkill")
		}
	} else {
		log.LogError("applySkill called with name of attribute that doesn't exist:", name)
	}

}

// Private helpers

// getAttribute is a helper to get an attribute from an SDEType.
func getAttribute(s SDEType, a string) (interface{}, error) {
	if v, ok := s.Attributes[a]; ok {
		return v, nil
	} else {
		log.LogError("Wasn't cable to find attribute", a)
	}
	return nil, errors.New("attribute not found" + a)
}

// attAssert is a helper to get a value from SDEType and insert it into
// out Stats using reflection.  It's ugly... No really don't look...
func attAssert(s *SDEType, index int, stats *Stats, value string) {
	t := reflect.TypeOf(Stats{})
	ss := reflect.ValueOf(stats).Elem()
	a := s.Attributes[value]
	log.Info("attAssert with index", index)
	if ss.Field(index).CanSet() == false {
		log.LogError("For whatever reason we cannot set the value at index", index)
		return
	} else {
		switch reflect.TypeOf(a).Kind() {
		case reflect.Float64:
			switch ss.Field(index).Type().Kind() {
			case reflect.Float64: // Field is float.  Can set without conversion
				ss.Field(index).SetFloat(a.(float64))
			case reflect.Int: // Field is int.  Must convert
				ss.Field(index).SetInt(int64(a.(float64)))
			case reflect.Int64:
				ss.Field(index).SetInt(int64(a.(float64)))
			default:
				log.Info("Unsupported type in attAssert", t.Field(index).Type.Kind())
			}
		case reflect.Int:
			switch t.Field(index).Type.Kind() {
			case reflect.Float64: // Field is float.  Convert
				ss.Field(index).SetFloat(float64(a.(int)))
			case reflect.Int: // Field is int.  Must convert int64
				ss.Field(index).SetInt(int64(a.(int)))
			case reflect.Int64:
				ss.Field(index).SetInt(int64(a.(int)))
			default:
				log.Info("Unsupported type in attAssert", t.Field(index).Type.Kind())
			}
		case reflect.Int64:
			switch t.Field(index).Type.Kind() {
			case reflect.Float64: // Field is float.  Convert
				ss.Field(index).SetInt(int64(a.(float64)))
			case reflect.Int: // Field is int.  Must convert int64
				ss.Field(index).SetInt(int64(a.(int)))
			default:
				log.Info("Unsupported type in attAssert", t.Field(index).Type.Kind())
			}
		default:
			log.Info("Unsupported type in main switch attAssert", reflect.TypeOf(a).Kind())
		case reflect.String:
		}
	}
}
<|endoftext|>


<commit_before>// Package sdl provides a binding of SDL2 and SDL2_image with an object-oriented twist.
package sdl

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
import "C"

// An InitFlag represents a set of SDL subsystems to initialize.
type InitFlag uint32

// InitFlag masks.
const (
	InitTimer          InitFlag = C.SDL_INIT_TIMER
	InitAudio          InitFlag = C.SDL_INIT_AUDIO
	InitVideo          InitFlag = C.SDL_INIT_VIDEO    // InitVideo implies InitEvents
	InitJoystick       InitFlag = C.SDL_INIT_JOYSTICK // InitJoystick implies InitEvents
	InitHaptic         InitFlag = C.SDL_INIT_HAPTIC
	InitGameController InitFlag = C.SDL_INIT_GAMECONTROLLER // InitGameController implies InitJoystick
	InitEvents         InitFlag = C.SDL_INIT_EVENTS
	InitNoParachute    InitFlag = C.SDL_INIT_NOPARACHUTE // Don't catch fatal signals

	InitEverything InitFlag = C.SDL_INIT_EVERYTHING
)

// Init initializes SDL and its subsystems.  Multiple flags will be ORed together.
// Init must be called before calling other functions in this package.
func Init(flags ...InitFlag) error {
	var f InitFlag
	for i := range flags {
		f |= flags[i]
	}
	if C.SDL_Init(C.Uint32(f)) != 0 {
		return getError()
	}
	return nil
}

// Quit cleans up SDL.
func Quit() {
	C.SDL_Quit()
}

// Error stores an SDL error.
type Error string

func (e Error) Error() string {
	return "sdl: " + string(e)
}

// getError returns the current SDL error as a Go error value.
func getError() error {
	e := C.SDL_GetError()
	if *e == 0 {
		// empty string, no error.
		return nil
	}
	return Error(C.GoString(e))
}
<commit_msg>Export sdl.GetError<commit_after>// Package sdl provides a binding of SDL2 and SDL2_image with an object-oriented twist.
package sdl

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
import "C"

// An InitFlag represents a set of SDL subsystems to initialize.
type InitFlag uint32

// InitFlag masks.
const (
	InitTimer          InitFlag = C.SDL_INIT_TIMER
	InitAudio          InitFlag = C.SDL_INIT_AUDIO
	InitVideo          InitFlag = C.SDL_INIT_VIDEO    // InitVideo implies InitEvents
	InitJoystick       InitFlag = C.SDL_INIT_JOYSTICK // InitJoystick implies InitEvents
	InitHaptic         InitFlag = C.SDL_INIT_HAPTIC
	InitGameController InitFlag = C.SDL_INIT_GAMECONTROLLER // InitGameController implies InitJoystick
	InitEvents         InitFlag = C.SDL_INIT_EVENTS
	InitNoParachute    InitFlag = C.SDL_INIT_NOPARACHUTE // Don't catch fatal signals

	InitEverything InitFlag = C.SDL_INIT_EVERYTHING
)

// Init initializes SDL and its subsystems.  Multiple flags will be ORed together.
// Init must be called before calling other functions in this package.
func Init(flags ...InitFlag) error {
	var f InitFlag
	for i := range flags {
		f |= flags[i]
	}
	if C.SDL_Init(C.Uint32(f)) != 0 {
		return getError()
	}
	return nil
}

// Quit cleans up SDL.
func Quit() {
	C.SDL_Quit()
}

// Error stores an SDL error.
type Error string

func (e Error) Error() string {
	return "sdl: " + string(e)
}

// GetError returns the current SDL error as a Go error value.
// This is internal to SDL but exported because it is cross-package.
func GetError() error {
	// TODO(light): synchronize access?
	e := C.SDL_GetError()
	if *e == 0 {
		// empty string, no error.
		return nil
	}
	return Error(C.GoString(e))
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Bartosz Kratochwil
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.

//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.

//     * Neither the name of Aaron France nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package hpcloud

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
)

/*
 ListDBInstances will list all the available database instances

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/list-database-instances.html
*/
func (a Access) ListDBInstances() (*DBInstances, error) {
	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}
	dbs := &DBInstances{}
	err = json.Unmarshal(body, dbs)
	return dbs, err
}

/*
 This function takes instance ID and deletes database instance with this ID.

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/delete-instance.html
*/
func (a Access) DeleteDBInstance(instanceID string) error {
	url := fmt.Sprintf("%s%s/instances/%s", RDB_URL, a.TenantID,
		instanceID)
	_, err := a.baseRequest(url, "DELETE", nil)
	return err
}

/*
 This function takes instance ID and restarts DB instance with this ID.

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/restart-instance.html
*/
func (a Access) RestartDBInstance(instanceID string) error {
	b := `{"restart":{}}`
	url := fmt.Sprintf("%s%s/instances/%s/action", RDB_URL,
		a.TenantID, instanceID)
	_, err := a.baseRequest(url, "POST", strings.NewReader(b))
	return err
}

/*
 ListAllFlavors lists all available database flavors.
 This function implements interface as described in:-
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/list-flavors.html
*/
func (a Access) ListAllFlavors() (*DBFlavors, error) {
	url := fmt.Sprintf("%s%s/flavors", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}

	flv := &DBFlavors{}
	err = json.Unmarshal(body, flv)
	return flv, err
}

/*
 This function returns flavor specs for given flavor.

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/get-flavor.html
*/
func (a Access) GetDBFlavor(ID string) (*DBFlavor, error) {
	url := fmt.Sprintf("%s/flavors/%s", RDB_URL, ID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}

	flv := &DBFlavor{}
	err = json.Unmarshal(body, flv)
	if err != nil {
		return nil, err
	}
	return flv, nil
}

/*
 CreateDBInstance creates new database instance in the HPCloud using
settings found in the DatabaseReq instance passed to this function

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/create-instance.html
*/
func (a Access) CreateDBInstance(db DatabaseReq) (*NewDBInstance, error) {
	b, err := db.MarshalJSON()
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)

	body, err := a.baseRequest(url, "POST",
		strings.NewReader(string(b)))
	if err != nil {
		return nil, err
	}

	type respDB struct {
		Instance NewDBInstance `json:"instance"`
	}

	sr := &respDB{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return &sr.Instance, nil
}

/*
 This function retrieves details of the instance with provided ID.

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/get-instance.html
*/
func (a Access) GetDBInstance(id string) (*InstDetails, error) {
	url := fmt.Sprintf("%s%s/instances/%s", RDB_URL, a.TenantID, id)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}
	det := &InstDetails{}
	err = json.Unmarshal(body, det)
	return det, err
}

/*
 This function takes instance ID and resets password for this instance. It
 returns a new instance password.

 This function implements the interface as decribed in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/reset-instance-password.html
*/
func (a Access) ResetDBPassword(id string) (*DBCredentials, error) {
	b := `{"reset-password":{}}`
	url := fmt.Sprintf("%s%s/instances/%s/action", RDB_URL,
		a.TenantID, id)
	body, err := a.baseRequest(url, "POST", strings.NewReader(b))

	sr := &DBCredentials{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return sr, nil
}

/*
 This function lists all the security groups available for tenant.

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/list-security-groups.html
*/
func (a Access) GetDBSecurityGroups(*SecurityGroup, error) {
	url := fmt.Sprintf("%s%s/security-groups", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)

	type resp struct {
		SecurityGroups SecurityGroup `json:"security-groups"`
	}
	sr := &resp{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return &sr.SecurityGroups, nil
}

type DBInstance struct {
	Created string `json:"created"`
	Id      string `json:"id"`
	Links   []Link `json:"links"`
	Name    string `json:"name"`
	Status  string `json:"name"`
	Flavor  struct {
		Name  string `json:"name"`
		ID    string `json:"id"`
		Links []Link `json:"links"`
	} `json:"flavor"`
}

type DBInstances struct {
	Instances []DBInstance `json:"instances"`
}

type Database struct {
	Name      string `json:"name"`
	FlavorRef string `json:"flavorRef"`
	Port      int    `json:"port"`
	DBType    struct {
		Name    string `json:"name"`
		Version string `json:"version"`
	} `json:"dbtype"`
}

type DBFlavors struct {
	Flavors []DBFlavor `json:"flavors"`
}

/*
 Instance Details type that is returned by server
*/
type InstDetails struct {
	Created        string          `json:"created"`
	Hostname       string          `json:"hostname"`
	ID             string          `json:"id"`
	Links          []Link          `json:"links"`
	Name           string          `json:"name"`
	Port           int             `json:"port"`
	SecurityGroups []SecurityGroup `json:"security_groups"`
	Status         string          `json:"status"`
	Updated        string          `json:"updated"`
	Flavor         struct {
		Name  string `json:"name"`
		ID    string `json:"id"`
		Links []Link `json:"links"`
	} `json:"flavor"`
}

/*
 Type describing database flavor
*/
type DBFlavor struct {
	Id    int    `json:"id"`
	Links []Link `json:"links"`
	Name  string `json:"name"`
	Ram   int    `json:"ram"`
	Vcpu  int    `json:"vcpu"`
}

/*
 This type describes the JSON data which should be sent to the
create database instance resource.
*/
type DatabaseReq struct {
	Instance Database `json:"instance"`
}

/*
 This type describes JSON response from a successful CreateDBInstance
 call.
*/
type NewDBInstance struct {
	Created    string        `json:"created"`
	Credential DBCredentials `json:"credential"`
	Flavor     struct {
		Name  string `json:"name"`
		ID    string `json:"id"`
		Links []Link `json:"links"`
	} `json:"flavor"`
	Hostname       string        `json:"hostname"`
	Id             string        `json:"id"`
	Links          []Link        `json:"links"`
	Name           string        `json:"name"`
	SecurityGroups []DBSecGroups `json:"security_groups"`
	Status         string        `json:"status"`
}

/*
 This type describes Database Security groups
*/
type DBSecGroups struct {
	Id    string `json:"id"`
	Links []Link `json:"links"`
}

/*
 This type describes Database Credentials
*/
type DBCredentials struct {
	Password string `json:"password"`
	Username string `json:"username"`
}

func (f DBFlavors) GetFlavorRef(fn string) string {
	for _, val := range f.Flavors {
		if val.Name == fn {
			return val.Links[0].HREF
		}
	}
	panic("Flavor not found")
}

func (db DatabaseReq) MarshalJSON() ([]byte, error) {
	b := bytes.NewBufferString(`{"instance":{`)
	if db.Instance.Name == "" {
		return nil, errors.New("A name is required")
	}
	b.WriteString(fmt.Sprintf(`"name":"%s",`, db.Instance.Name))
	if db.Instance.FlavorRef == "" {
		return nil, errors.New("Flavor is required")
	}
	b.WriteString(fmt.Sprintf(`"flavorRef":"%s",`,
		db.Instance.FlavorRef))
	if db.Instance.Port == 0 {
		b.WriteString(`"port":"3306",`)
	} else {
		b.WriteString(fmt.Sprintf(`"port":"%s",`, db.Instance.Port))
	}
	b.WriteString(`"dbtype":{`)
	b.WriteString(`"name":"mysql",`)
	b.WriteString(`"version":"5.5"}}}`)

	return b.Bytes(), nil
}
<commit_msg>fixed function declaration<commit_after>// Copyright (c) 2013, Bartosz Kratochwil
// All rights reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:

//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.

//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.

//     * Neither the name of Aaron France nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package hpcloud

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
)

/*
 ListDBInstances will list all the available database instances

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/list-database-instances.html
*/
func (a Access) ListDBInstances() (*DBInstances, error) {
	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}
	dbs := &DBInstances{}
	err = json.Unmarshal(body, dbs)
	return dbs, err
}

/*
 This function takes instance ID and deletes database instance with this ID.

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/delete-instance.html
*/
func (a Access) DeleteDBInstance(instanceID string) error {
	url := fmt.Sprintf("%s%s/instances/%s", RDB_URL, a.TenantID,
		instanceID)
	_, err := a.baseRequest(url, "DELETE", nil)
	return err
}

/*
 This function takes instance ID and restarts DB instance with this ID.

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/restart-instance.html
*/
func (a Access) RestartDBInstance(instanceID string) error {
	b := `{"restart":{}}`
	url := fmt.Sprintf("%s%s/instances/%s/action", RDB_URL,
		a.TenantID, instanceID)
	_, err := a.baseRequest(url, "POST", strings.NewReader(b))
	return err
}

/*
 ListAllFlavors lists all available database flavors.
 This function implements interface as described in:-
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/list-flavors.html
*/
func (a Access) ListAllFlavors() (*DBFlavors, error) {
	url := fmt.Sprintf("%s%s/flavors", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}

	flv := &DBFlavors{}
	err = json.Unmarshal(body, flv)
	return flv, err
}

/*
 This function returns flavor specs for given flavor.

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/get-flavor.html
*/
func (a Access) GetDBFlavor(ID string) (*DBFlavor, error) {
	url := fmt.Sprintf("%s/flavors/%s", RDB_URL, ID)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}

	flv := &DBFlavor{}
	err = json.Unmarshal(body, flv)
	if err != nil {
		return nil, err
	}
	return flv, nil
}

/*
 CreateDBInstance creates new database instance in the HPCloud using
settings found in the DatabaseReq instance passed to this function

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/create-instance.html
*/
func (a Access) CreateDBInstance(db DatabaseReq) (*NewDBInstance, error) {
	b, err := db.MarshalJSON()
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("%s%s/instances", RDB_URL, a.TenantID)

	body, err := a.baseRequest(url, "POST",
		strings.NewReader(string(b)))
	if err != nil {
		return nil, err
	}

	type respDB struct {
		Instance NewDBInstance `json:"instance"`
	}

	sr := &respDB{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return &sr.Instance, nil
}

/*
 This function retrieves details of the instance with provided ID.

This function implements the interface as described in:
http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/get-instance.html
*/
func (a Access) GetDBInstance(id string) (*InstDetails, error) {
	url := fmt.Sprintf("%s%s/instances/%s", RDB_URL, a.TenantID, id)
	body, err := a.baseRequest(url, "GET", nil)
	if err != nil {
		return nil, err
	}
	det := &InstDetails{}
	err = json.Unmarshal(body, det)
	return det, err
}

/*
 This function takes instance ID and resets password for this instance. It
 returns a new instance password.

 This function implements the interface as decribed in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/reset-instance-password.html
*/
func (a Access) ResetDBPassword(id string) (*DBCredentials, error) {
	b := `{"reset-password":{}}`
	url := fmt.Sprintf("%s%s/instances/%s/action", RDB_URL,
		a.TenantID, id)
	body, err := a.baseRequest(url, "POST", strings.NewReader(b))

	sr := &DBCredentials{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return sr, nil
}

/*
 This function lists all the security groups available for tenant.

 This function implements the interface as described in:
 http://api-docs.hpcloud.com/hpcloud-rdb-mysql/1.0/content/list-security-groups.html
*/
func (a Access) GetDBSecurityGroups() (*SecurityGroup, error) {
	url := fmt.Sprintf("%s%s/security-groups", RDB_URL, a.TenantID)
	body, err := a.baseRequest(url, "GET", nil)

	type resp struct {
		SecurityGroups SecurityGroup `json:"security-groups"`
	}
	sr := &resp{}
	err = json.Unmarshal(body, sr)
	if err != nil {
		return nil, err
	}
	return &sr.SecurityGroups, nil
}

type DBInstance struct {
	Created string `json:"created"`
	Id      string `json:"id"`
	Links   []Link `json:"links"`
	Name    string `json:"name"`
	Status  string `json:"name"`
	Flavor  struct {
		Name  string `json:"name"`
		ID    string `json:"id"`
		Links []Link `json:"links"`
	} `json:"flavor"`
}

type DBInstances struct {
	Instances []DBInstance `json:"instances"`
}

type Database struct {
	Name      string `json:"name"`
	FlavorRef string `json:"flavorRef"`
	Port      int    `json:"port"`
	DBType    struct {
		Name    string `json:"name"`
		Version string `json:"version"`
	} `json:"dbtype"`
}

type DBFlavors struct {
	Flavors []DBFlavor `json:"flavors"`
}

/*
 Instance Details type that is returned by server
*/
type InstDetails struct {
	Created        string          `json:"created"`
	Hostname       string          `json:"hostname"`
	ID             string          `json:"id"`
	Links          []Link          `json:"links"`
	Name           string          `json:"name"`
	Port           int             `json:"port"`
	SecurityGroups []SecurityGroup `json:"security_groups"`
	Status         string          `json:"status"`
	Updated        string          `json:"updated"`
	Flavor         struct {
		Name  string `json:"name"`
		ID    string `json:"id"`
		Links []Link `json:"links"`
	} `json:"flavor"`
}

/*
 Type describing database flavor
*/
type DBFlavor struct {
	Id    int    `json:"id"`
	Links []Link `json:"links"`
	Name  string `json:"name"`
	Ram   int    `json:"ram"`
	Vcpu  int    `json:"vcpu"`
}

/*
 This type describes the JSON data which should be sent to the
create database instance resource.
*/
type DatabaseReq struct {
	Instance Database `json:"instance"`
}

/*
 This type describes JSON response from a successful CreateDBInstance
 call.
*/
type NewDBInstance struct {
	Created    string        `json:"created"`
	Credential DBCredentials `json:"credential"`
	Flavor     struct {
		Name  string `json:"name"`
		ID    string `json:"id"`
		Links []Link `json:"links"`
	} `json:"flavor"`
	Hostname       string        `json:"hostname"`
	Id             string        `json:"id"`
	Links          []Link        `json:"links"`
	Name           string        `json:"name"`
	SecurityGroups []DBSecGroups `json:"security_groups"`
	Status         string        `json:"status"`
}

/*
 This type describes Database Security groups
*/
type DBSecGroups struct {
	Id    string `json:"id"`
	Links []Link `json:"links"`
}

/*
 This type describes Database Credentials
*/
type DBCredentials struct {
	Password string `json:"password"`
	Username string `json:"username"`
}

func (f DBFlavors) GetFlavorRef(fn string) string {
	for _, val := range f.Flavors {
		if val.Name == fn {
			return val.Links[0].HREF
		}
	}
	panic("Flavor not found")
}

func (db DatabaseReq) MarshalJSON() ([]byte, error) {
	b := bytes.NewBufferString(`{"instance":{`)
	if db.Instance.Name == "" {
		return nil, errors.New("A name is required")
	}
	b.WriteString(fmt.Sprintf(`"name":"%s",`, db.Instance.Name))
	if db.Instance.FlavorRef == "" {
		return nil, errors.New("Flavor is required")
	}
	b.WriteString(fmt.Sprintf(`"flavorRef":"%s",`,
		db.Instance.FlavorRef))
	if db.Instance.Port == 0 {
		b.WriteString(`"port":"3306",`)
	} else {
		b.WriteString(fmt.Sprintf(`"port":"%s",`, db.Instance.Port))
	}
	b.WriteString(`"dbtype":{`)
	b.WriteString(`"name":"mysql",`)
	b.WriteString(`"version":"5.5"}}}`)

	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package syslog

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"log/syslog"
	"net"
	"os"
	"text/template"
	"time"

	"github.com/gliderlabs/logspout/router"
)

var hostname string

func init() {
	hostname, _ = os.Hostname()
	router.AdapterFactories.Register(NewSyslogAdapter, "syslog")
}

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

func NewSyslogAdapter(route *router.Route) (router.LogAdapter, error) {
	transport, found := router.AdapterTransports.Lookup(route.AdapterTransport("udp"))
	if !found {
		return nil, errors.New("bad transport: " + route.Adapter)
	}
	conn, err := transport.Dial(route.Address, route.Options)
	if err != nil {
		return nil, err
	}

	format := getopt("SYSLOG_FORMAT", "rfc5424")
	priority := getopt("SYSLOG_PRIORITY", "{{.Priority}}")
	hostname := getopt("SYSLOG_HOSTNAME", "{{.Container.Config.Hostname}}")
	pid := getopt("SYSLOG_PID", "{{.Container.State.Pid}}")
	tag := getopt("SYSLOG_TAG", "{{.ContainerName}}"+route.Options["append_tag"])
	structuredData := getopt("SYSLOG_STRUCTURED_DATA", "")
	if route.Options["structured_data"] != "" {
		structuredData = route.Options["structured_data"]
	}
	data := getopt("SYSLOG_DATA", "{{.Data}}")

	if structuredData == "" {
		structuredData = "-"
	} else {
		structuredData = fmt.Sprintf("[%s]", structuredData)
	}

	var tmplStr string
	switch format {
	case "rfc5424":
		tmplStr = fmt.Sprintf("<%s>1 {{.Timestamp}} %s %s %s - %s %s\n",
			priority, hostname, tag, pid, structuredData, data)
	case "rfc3164":
		tmplStr = fmt.Sprintf("<%s>{{.Timestamp}} %s %s[%s]: %s\n",
			priority, hostname, tag, pid, data)
	default:
		return nil, errors.New("unsupported syslog format: " + format)
	}
	tmpl, err := template.New("syslog").Parse(tmplStr)
	if err != nil {
		return nil, err
	}
	return &SyslogAdapter{
		route:     route,
		conn:      conn,
		tmpl:      tmpl,
		transport: transport,
	}, nil
}

type SyslogAdapter struct {
	conn      net.Conn
	route     *router.Route
	tmpl      *template.Template
	transport router.AdapterTransport
}

func (a *SyslogAdapter) Stream(logstream chan *router.Message) {
	for message := range logstream {
		m := &SyslogMessage{message}
		buf, err := m.Render(a.tmpl)
		if err != nil {
			log.Println("syslog:", err)
			return
		}
		_, err = a.conn.Write(buf)
		if err != nil {
			log.Println("syslog:", err)
			switch a.conn.(type) {
			case *net.UDPConn:
				continue
			default:
				err = a.retry(buf, err)
				if err != nil {
					log.Println("syslog:", err)
					return
				}
			}
		}
	}
}

func (a *SyslogAdapter) retry(buf []byte, err error) error {
	if opError, ok := err.(*net.OpError); ok {
		if opError.Temporary() || opError.Timeout() {
			retryErr := a.retryTemporary(buf)
			if retryErr == nil {
				return nil
			}
		}
	}

	return a.reconnect()
}

func (a *SyslogAdapter) retryTemporary(buf []byte) error {
	log.Println("syslog: retrying tcp up to 11 times")
	err := retryExp(func() error {
		_, err := a.conn.Write(buf)
		if err == nil {
			log.Println("syslog: retry successful")
			return nil
		}

		return err
	}, 11)

	if err != nil {
		log.Println("syslog: retry failed")
		return err
	}

	return nil
}

func (a *SyslogAdapter) reconnect() error {
	log.Println("syslog: reconnecting up to 11 times")
	err := retryExp(func() error {
		conn, err := a.transport.Dial(a.route.Address, a.route.Options)
		if err != nil {
			return err
		}

		a.conn = conn
		return nil
	}, 11)

	if err != nil {
		log.Println("syslog: reconnect failed")
		return err
	}

	return nil
}

func retryExp(fun func() error, tries uint) error {
	try := uint(0)
	for {
		err := fun()
		if err == nil {
			return nil
		}

		try++
		if try > tries {
			return err
		}

		time.Sleep((1 << try) * 10 * time.Millisecond)
	}
}

type SyslogMessage struct {
	*router.Message
}

func (m *SyslogMessage) Render(tmpl *template.Template) ([]byte, error) {
	buf := new(bytes.Buffer)
	err := tmpl.Execute(buf, m)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (m *SyslogMessage) Priority() syslog.Priority {
	switch m.Message.Source {
	case "stdout":
		return syslog.LOG_USER | syslog.LOG_INFO
	case "stderr":
		return syslog.LOG_USER | syslog.LOG_ERR
	default:
		return syslog.LOG_DAEMON | syslog.LOG_INFO
	}
}

func (m *SyslogMessage) Hostname() string {
	return hostname
}

func (m *SyslogMessage) Timestamp() string {
	return m.Message.Time.Format(time.RFC3339)
}

func (m *SyslogMessage) ContainerName() string {
	return m.Message.Container.Name[1:]
}
<commit_msg>Send timestamps down to the nanosecond<commit_after>package syslog

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"log/syslog"
	"net"
	"os"
	"text/template"
	"time"

	"github.com/gliderlabs/logspout/router"
)

var hostname string

func init() {
	hostname, _ = os.Hostname()
	router.AdapterFactories.Register(NewSyslogAdapter, "syslog")
}

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

func NewSyslogAdapter(route *router.Route) (router.LogAdapter, error) {
	transport, found := router.AdapterTransports.Lookup(route.AdapterTransport("udp"))
	if !found {
		return nil, errors.New("bad transport: " + route.Adapter)
	}
	conn, err := transport.Dial(route.Address, route.Options)
	if err != nil {
		return nil, err
	}

	format := getopt("SYSLOG_FORMAT", "rfc5424")
	priority := getopt("SYSLOG_PRIORITY", "{{.Priority}}")
	hostname := getopt("SYSLOG_HOSTNAME", "{{.Container.Config.Hostname}}")
	pid := getopt("SYSLOG_PID", "{{.Container.State.Pid}}")
	tag := getopt("SYSLOG_TAG", "{{.ContainerName}}"+route.Options["append_tag"])
	structuredData := getopt("SYSLOG_STRUCTURED_DATA", "")
	if route.Options["structured_data"] != "" {
		structuredData = route.Options["structured_data"]
	}
	data := getopt("SYSLOG_DATA", "{{.Data}}")

	if structuredData == "" {
		structuredData = "-"
	} else {
		structuredData = fmt.Sprintf("[%s]", structuredData)
	}

	var tmplStr string
	switch format {
	case "rfc5424":
		tmplStr = fmt.Sprintf("<%s>1 {{.Timestamp}} %s %s %s - %s %s\n",
			priority, hostname, tag, pid, structuredData, data)
	case "rfc3164":
		tmplStr = fmt.Sprintf("<%s>{{.Timestamp}} %s %s[%s]: %s\n",
			priority, hostname, tag, pid, data)
	default:
		return nil, errors.New("unsupported syslog format: " + format)
	}
	tmpl, err := template.New("syslog").Parse(tmplStr)
	if err != nil {
		return nil, err
	}
	return &SyslogAdapter{
		route:     route,
		conn:      conn,
		tmpl:      tmpl,
		transport: transport,
	}, nil
}

type SyslogAdapter struct {
	conn      net.Conn
	route     *router.Route
	tmpl      *template.Template
	transport router.AdapterTransport
}

func (a *SyslogAdapter) Stream(logstream chan *router.Message) {
	for message := range logstream {
		m := &SyslogMessage{message}
		buf, err := m.Render(a.tmpl)
		if err != nil {
			log.Println("syslog:", err)
			return
		}
		_, err = a.conn.Write(buf)
		if err != nil {
			log.Println("syslog:", err)
			switch a.conn.(type) {
			case *net.UDPConn:
				continue
			default:
				err = a.retry(buf, err)
				if err != nil {
					log.Println("syslog:", err)
					return
				}
			}
		}
	}
}

func (a *SyslogAdapter) retry(buf []byte, err error) error {
	if opError, ok := err.(*net.OpError); ok {
		if opError.Temporary() || opError.Timeout() {
			retryErr := a.retryTemporary(buf)
			if retryErr == nil {
				return nil
			}
		}
	}

	return a.reconnect()
}

func (a *SyslogAdapter) retryTemporary(buf []byte) error {
	log.Println("syslog: retrying tcp up to 11 times")
	err := retryExp(func() error {
		_, err := a.conn.Write(buf)
		if err == nil {
			log.Println("syslog: retry successful")
			return nil
		}

		return err
	}, 11)

	if err != nil {
		log.Println("syslog: retry failed")
		return err
	}

	return nil
}

func (a *SyslogAdapter) reconnect() error {
	log.Println("syslog: reconnecting up to 11 times")
	err := retryExp(func() error {
		conn, err := a.transport.Dial(a.route.Address, a.route.Options)
		if err != nil {
			return err
		}

		a.conn = conn
		return nil
	}, 11)

	if err != nil {
		log.Println("syslog: reconnect failed")
		return err
	}

	return nil
}

func retryExp(fun func() error, tries uint) error {
	try := uint(0)
	for {
		err := fun()
		if err == nil {
			return nil
		}

		try++
		if try > tries {
			return err
		}

		time.Sleep((1 << try) * 10 * time.Millisecond)
	}
}

type SyslogMessage struct {
	*router.Message
}

func (m *SyslogMessage) Render(tmpl *template.Template) ([]byte, error) {
	buf := new(bytes.Buffer)
	err := tmpl.Execute(buf, m)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (m *SyslogMessage) Priority() syslog.Priority {
	switch m.Message.Source {
	case "stdout":
		return syslog.LOG_USER | syslog.LOG_INFO
	case "stderr":
		return syslog.LOG_USER | syslog.LOG_ERR
	default:
		return syslog.LOG_DAEMON | syslog.LOG_INFO
	}
}

func (m *SyslogMessage) Hostname() string {
	return hostname
}

func (m *SyslogMessage) Timestamp() string {
	return m.Message.Time.Format(time.RFC3339Nano)
}

func (m *SyslogMessage) ContainerName() string {
	return m.Message.Container.Name[1:]
}
<|endoftext|>


<commit_before>package pgsql

import (
	"database/sql"
	"fmt"
	"strings"
)

type DB interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	Prepare(query string) (*sql.Stmt, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
	QueryRow(query string, args ...interface{}) *sql.Row
}

type Row struct {
	*Table
	DB        DB
	values    map[*Field]*TypedValue
	setErrors []error
}

func NewRow(db DB, table *Table) (ø *Row) {
	ø = &Row{Table: table, setErrors: []error{}}
	ø.SetDB(db)
	ø.clearValues()
	return
}

// the parameters should be given in pairs of
// *Field and *value
func (ø *Row) Get(o ...interface{}) {
	for i := 0; i < len(o); i = i + 2 {
		field := o[i].(*Field)
		res := o[i+1]
		err := Convert(ø.values[field], res)
		if err != nil {
			panic(
				"can't convert " +
					field.Name +
					" of table " +
					field.Table.Name +
					" to " +
					fmt.Sprintf("%#v", res) +
					": " +
					err.Error())
		}
	}
}

func (ø *Row) ValidateAll() (errs map[Sqler]error) {
	return ø.Table.Validate(ø.Values())
}

// the parameters should be given in pairs of
// *Field and value
func (ø *Row) Set(o ...interface{}) (err error) {
	for i := 0; i < len(o); i = i + 2 {
		field := o[i].(*Field)
		tv := &TypedValue{PgType: field.Type}
		err = Convert(o[i+1], tv)
		if err != nil {
			e := fmt.Errorf("error when setting field %s to value %#v: %s\n", field.Sql(), o[i+1], err.Error())
			ø.setErrors = append(ø.setErrors, e)
			return e
		}
		ø.values[field] = tv
	}
	err = ø.Validate()
	if err != nil {
		return err
	}
	return
}

func (ø *Row) Validate() (err error) {
	if len(ø.setErrors) > 0 {
		errString := []string{}
		for _, e := range ø.setErrors {
			errString = append(errString, fmt.Sprintf("\t%s", e.Error()))
		}
		return fmt.Errorf("%s\n", strings.Join(errString, "\n"))
	}
	errs := ø.ValidateAll()
	if len(errs) > 0 {
		errString := []string{}
		for k, e := range errs {
			errString = append(errString, fmt.Sprintf("\tValidation Error in %s: %s\n", k.Sql(), e.Error()))
		}
		return fmt.Errorf("%s\n", strings.Join(errString, "\n"))
	}
	return nil
}

func (ø *Row) Save() (err error) {
	err = ø.Validate()
	if err != nil {
		return fmt.Errorf("Can't save row of %s:\n%s\n", ø.Table.Sql(), err.Error())
	}
	ø.setErrors = []error{}
	if ø.HasId() {
		err = ø.Update()
	} else {
		err = ø.Insert()
	}
	return
}

func (ø *Row) HasId() bool {
	pkey := ø.PrimaryKey
	if ø.values[pkey].IsNil() {
		return false
	}
	return true
}

func (ø *Row) Fill(m map[string]interface{}) error {
	ø.values = map[*Field]*TypedValue{}
	for k, v := range m {
		e := ø.Set(ø.Table.Field(k), v)
		if e != nil {
			return e
		}
	}
	return nil
}

func (ø *Row) Properties() (m map[string]interface{}) {
	m = map[string]interface{}{}
	for field, val := range ø.values {
		m[field.Name] = val.Value
	}
	return
}

func (ø *Row) clearValues() {
	pkey := ø.PrimaryKey
	ø.values = map[*Field]*TypedValue{pkey: &TypedValue{PgType: pkey.Type}}
}

func (ø *Row) SetId(id int) (err error) {
	err = Convert(id, ø.values[ø.PrimaryKey])
	if err != nil {
		return
	}
	return
}

func (ø *Row) Id() SqlType {
	var idVal SqlType
	err := Convert(ø.values[ø.PrimaryKey], &idVal)
	if err != nil {
		panic("can't get id for table " + ø.Table.Name)
	}
	return idVal
}

func (ø *Row) Load(id int) (err error) {
	ø.clearValues()
	f := ø.Table.Fields
	err = ø.SetId(id)
	if err != nil {
		return
	}
	row, err := ø.Select(f, Where(Equals(ø.PrimaryKey, ø.Id())))
	if !row.Next() {
		return fmt.Errorf("no row for %v", id)
	}
	scanF := []interface{}{}
	for _, field := range f {
		// make default values and append them
		switch field.Type {
		case IntType:
			in := int(0)
			scanF = append(scanF, &in)
		case FloatType:
			fl := float32(0.0)
			scanF = append(scanF, &fl)
		default:
			s := ""
			scanF = append(scanF, &s)
		}
	}
	err = row.Scan(scanF...)
	if err != nil {
		return
	}
	for i, v := range scanF {
		tv := TypedValue{PgType: f[i].Type}
		e := Convert(v, &tv)
		if e != nil {
			err = e
			return
		}
	}
	return
}

func (ø *Row) Update() (err error) {
	vals := ø.typedValues()
	delete(vals, ø.PrimaryKey)
	u := Update(
		ø.Table,
		vals,
		Where(Equals(ø.PrimaryKey, ø.Id())))

	_, err = ø.Query(u)
	return
}

func (ø *Row) Values() (vals map[*Field]interface{}) {
	vals = map[*Field]interface{}{}
	for k, v := range ø.values {
		if !v.IsNil() {
			vals[k] = v.Value
		}
	}
	return
}

func (ø *Row) typedValues() (vals map[*Field]interface{}) {
	vals = map[*Field]interface{}{}
	for k, v := range ø.values {
		if !v.IsNil() {
			vals[k] = v
		}
	}
	return
}

func (ø *Row) Insert() (err error) {
	u := InsertMap(ø.Table, ø.typedValues())
	_, err = ø.Query(u)
	return
}

func (ø *Row) Delete() (err error) {
	u := Delete(ø.Table, Where(Equals(ø.PrimaryKey, ø.Id())))
	_, err = ø.Query(u)
	return
}

func (ø *Row) Select(objects ...interface{}) (r *sql.Rows, err error) {
	snew := make([]interface{}, len(objects)+1)
	snew[0] = ø.Table
	for i, o := range objects {
		snew[i+1] = o
	}
	s := Select(snew...)
	r, err = ø.Query(s)
	return
}

func (ø *Row) IsValid(f string, value interface{}) bool {
	field := ø.Table.Field(f)
	tv := &TypedValue{PgType: field.Type}
	err := Convert(value, tv)
	if err != nil {
		return false
	}
	err = field.Validate(tv)
	if err == nil {
		return true
	}
	return false
}

func (ø *Row) Exec(query Query, args ...interface{}) (r sql.Result, err error) {
	r, err = ø.DB.Exec(query.String(), args...)
	return
}

func (ø *Row) Prepare(query Query) (r *sql.Stmt, err error) {
	s := query.Sql()
	r, err = ø.DB.Prepare(s.String())
	return
}

func (ø *Row) Query(query Query, args ...interface{}) (r *sql.Rows, err error) {
	s := query.Sql()
	r, err = ø.DB.Query(s.String(), args...)
	return
}

func (ø *Row) QueryRow(query Query, args ...interface{}) (r *sql.Row) {
	s := query.Sql()
	r = ø.DB.QueryRow(s.String(), args...)
	return
}

func (ø *Row) SetDB(db DB) {
	ø.DB = db
}
<commit_msg>do validation after filling<commit_after>package pgsql

import (
	"database/sql"
	"fmt"
	"strings"
)

type DB interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	Prepare(query string) (*sql.Stmt, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
	QueryRow(query string, args ...interface{}) *sql.Row
}

type Row struct {
	*Table
	DB        DB
	values    map[*Field]*TypedValue
	setErrors []error
}

func NewRow(db DB, table *Table) (ø *Row) {
	ø = &Row{Table: table, setErrors: []error{}}
	ø.SetDB(db)
	ø.clearValues()
	return
}

// the parameters should be given in pairs of
// *Field and *value
func (ø *Row) Get(o ...interface{}) {
	for i := 0; i < len(o); i = i + 2 {
		field := o[i].(*Field)
		res := o[i+1]
		err := Convert(ø.values[field], res)
		if err != nil {
			panic(
				"can't convert " +
					field.Name +
					" of table " +
					field.Table.Name +
					" to " +
					fmt.Sprintf("%#v", res) +
					": " +
					err.Error())
		}
	}
}

func (ø *Row) ValidateAll() (errs map[Sqler]error) {
	return ø.Table.Validate(ø.Values())
}

// the parameters should be given in pairs of
// *Field and value
func (ø *Row) Set(o ...interface{}) (err error) {
	err = ø.set(o)
	if err != nil {
		return err
	}
	err = ø.Validate()
	if err != nil {
		return err
	}
	return
}

func (ø *Row) set(o ...interface{}) (err error) {
	for i := 0; i < len(o); i = i + 2 {
		field := o[i].(*Field)
		tv := &TypedValue{PgType: field.Type}
		err = Convert(o[i+1], tv)
		if err != nil {
			e := fmt.Errorf("error when setting field %s to value %#v: %s\n", field.Sql(), o[i+1], err.Error())
			ø.setErrors = append(ø.setErrors, e)
			return e
		}
		ø.values[field] = tv
	}
	return
}

func (ø *Row) Validate() (err error) {
	if len(ø.setErrors) > 0 {
		errString := []string{}
		for _, e := range ø.setErrors {
			errString = append(errString, fmt.Sprintf("\t%s", e.Error()))
		}
		return fmt.Errorf("%s\n", strings.Join(errString, "\n"))
	}
	errs := ø.ValidateAll()
	if len(errs) > 0 {
		errString := []string{}
		for k, e := range errs {
			errString = append(errString, fmt.Sprintf("\tValidation Error in %s: %s\n", k.Sql(), e.Error()))
		}
		return fmt.Errorf("%s\n", strings.Join(errString, "\n"))
	}
	return nil
}

func (ø *Row) Save() (err error) {
	err = ø.Validate()
	if err != nil {
		return fmt.Errorf("Can't save row of %s:\n%s\n", ø.Table.Sql(), err.Error())
	}
	ø.setErrors = []error{}
	if ø.HasId() {
		err = ø.Update()
	} else {
		err = ø.Insert()
	}
	return
}

func (ø *Row) HasId() bool {
	pkey := ø.PrimaryKey
	if ø.values[pkey].IsNil() {
		return false
	}
	return true
}

func (ø *Row) Fill(m map[string]interface{}) error {
	ø.values = map[*Field]*TypedValue{}
	for k, v := range m {
		e := ø.set(ø.Table.Field(k), v)

		if e != nil {
			fmt.Printf("error while filling %s with %v: %s\n", k, v, e.Error())
			return e
		}
	}
	err := ø.Validate()
	if err != nil {
		return err
	}
	return nil
}

func (ø *Row) Properties() (m map[string]interface{}) {
	m = map[string]interface{}{}
	for field, val := range ø.values {
		m[field.Name] = val.Value
	}
	return
}

func (ø *Row) clearValues() {
	pkey := ø.PrimaryKey
	ø.values = map[*Field]*TypedValue{pkey: &TypedValue{PgType: pkey.Type}}
}

func (ø *Row) SetId(id int) (err error) {
	err = Convert(id, ø.values[ø.PrimaryKey])
	if err != nil {
		return
	}
	return
}

func (ø *Row) Id() SqlType {
	var idVal SqlType
	err := Convert(ø.values[ø.PrimaryKey], &idVal)
	if err != nil {
		panic("can't get id for table " + ø.Table.Name)
	}
	return idVal
}

func (ø *Row) Load(id int) (err error) {
	ø.clearValues()
	f := ø.Table.Fields
	err = ø.SetId(id)
	if err != nil {
		return
	}
	row, err := ø.Select(f, Where(Equals(ø.PrimaryKey, ø.Id())))
	if !row.Next() {
		return fmt.Errorf("no row for %v", id)
	}
	scanF := []interface{}{}
	for _, field := range f {
		// make default values and append them
		switch field.Type {
		case IntType:
			in := int(0)
			scanF = append(scanF, &in)
		case FloatType:
			fl := float32(0.0)
			scanF = append(scanF, &fl)
		default:
			s := ""
			scanF = append(scanF, &s)
		}
	}
	err = row.Scan(scanF...)
	if err != nil {
		return
	}
	for i, v := range scanF {
		tv := TypedValue{PgType: f[i].Type}
		e := Convert(v, &tv)
		if e != nil {
			err = e
			return
		}
	}
	return
}

func (ø *Row) Update() (err error) {
	vals := ø.typedValues()
	delete(vals, ø.PrimaryKey)
	u := Update(
		ø.Table,
		vals,
		Where(Equals(ø.PrimaryKey, ø.Id())))

	_, err = ø.Query(u)
	return
}

func (ø *Row) Values() (vals map[*Field]interface{}) {
	vals = map[*Field]interface{}{}
	for k, v := range ø.values {
		if !v.IsNil() {
			vals[k] = v.Value
		}
	}
	return
}

func (ø *Row) typedValues() (vals map[*Field]interface{}) {
	vals = map[*Field]interface{}{}
	for k, v := range ø.values {
		if !v.IsNil() {
			vals[k] = v
		}
	}
	return
}

func (ø *Row) Insert() (err error) {
	u := InsertMap(ø.Table, ø.typedValues())
	_, err = ø.Query(u)
	return
}

func (ø *Row) Delete() (err error) {
	u := Delete(ø.Table, Where(Equals(ø.PrimaryKey, ø.Id())))
	_, err = ø.Query(u)
	return
}

func (ø *Row) Select(objects ...interface{}) (r *sql.Rows, err error) {
	snew := make([]interface{}, len(objects)+1)
	snew[0] = ø.Table
	for i, o := range objects {
		snew[i+1] = o
	}
	s := Select(snew...)
	r, err = ø.Query(s)
	return
}

func (ø *Row) IsValid(f string, value interface{}) bool {
	field := ø.Table.Field(f)
	tv := &TypedValue{PgType: field.Type}
	err := Convert(value, tv)
	if err != nil {
		return false
	}
	err = field.Validate(tv)
	if err == nil {
		return true
	}
	return false
}

func (ø *Row) Exec(query Query, args ...interface{}) (r sql.Result, err error) {
	r, err = ø.DB.Exec(query.String(), args...)
	return
}

func (ø *Row) Prepare(query Query) (r *sql.Stmt, err error) {
	s := query.Sql()
	r, err = ø.DB.Prepare(s.String())
	return
}

func (ø *Row) Query(query Query, args ...interface{}) (r *sql.Rows, err error) {
	s := query.Sql()
	r, err = ø.DB.Query(s.String(), args...)
	return
}

func (ø *Row) QueryRow(query Query, args ...interface{}) (r *sql.Row) {
	s := query.Sql()
	r = ø.DB.QueryRow(s.String(), args...)
	return
}

func (ø *Row) SetDB(db DB) {
	ø.DB = db
}
<|endoftext|>