<commit_before>package filesystem

import (
	"io/ioutil"
	"os"
	"runtime"
	"testing"
	"unicode/utf8"
)

// TestPathSeparatorSingleByte verifies that the platform path separator rune is
// encoded as a single byte in UTF-8. We rely on this assumption for high
// performance in ensureValidName.
func TestPathSeparatorSingleByte(t *testing.T) {
	if utf8.RuneLen(os.PathSeparator) != 1 {
		t.Fatal("OS path separator does not have single-byte UTF-8 encoding")
	}
}

func TestDirectoryContentsNotExist(t *testing.T) {
	if _, err := DirectoryContentsByPath("/does/not/exist"); err == nil {
		t.Error("directory listing succeedeed for non-existent path")
	}
}

func TestDirectoryContentsFile(t *testing.T) {
	// Create an empty temporary file and defer its cleanup.
	file, err := ioutil.TempFile("", "mutagen_filesystem")
	if err != nil {
		t.Fatal("unable to create temporary file:", err)
	} else if err = file.Close(); err != nil {
		t.Error("unable to close temporary file:", err)
	}
	defer os.Remove(file.Name())

	// Ensure that directory listing fails.
	if _, err := DirectoryContentsByPath(file.Name()); err == nil {
		t.Error("directory listing succeedeed for non-directory path")
	}
}

func TestDirectoryContentsGOROOT(t *testing.T) {
	if contents, err := DirectoryContentsByPath(runtime.GOROOT()); err != nil {
		t.Fatal("directory listing failed for GOROOT:", err)
	} else if contents == nil {
		t.Fatal("directory contents nil for GOROOT")
	}
}
<commit_msg>Added test of directory symbolic link removal<commit_after>package filesystem

import (
	"io/ioutil"
	"os"
	"runtime"
	"testing"
	"unicode/utf8"
)

// TestPathSeparatorSingleByte verifies that the platform path separator rune is
// encoded as a single byte in UTF-8. We rely on this assumption for high
// performance in ensureValidName.
func TestPathSeparatorSingleByte(t *testing.T) {
	if utf8.RuneLen(os.PathSeparator) != 1 {
		t.Fatal("OS path separator does not have single-byte UTF-8 encoding")
	}
}

func TestDirectoryContentsNotExist(t *testing.T) {
	if _, err := DirectoryContentsByPath("/does/not/exist"); err == nil {
		t.Error("directory listing succeedeed for non-existent path")
	}
}

func TestDirectoryContentsFile(t *testing.T) {
	// Create an empty temporary file and defer its cleanup.
	file, err := ioutil.TempFile("", "mutagen_filesystem")
	if err != nil {
		t.Fatal("unable to create temporary file:", err)
	} else if err = file.Close(); err != nil {
		t.Error("unable to close temporary file:", err)
	}
	defer os.Remove(file.Name())

	// Ensure that directory listing fails.
	if _, err := DirectoryContentsByPath(file.Name()); err == nil {
		t.Error("directory listing succeedeed for non-directory path")
	}
}

func TestDirectoryContentsGOROOT(t *testing.T) {
	if contents, err := DirectoryContentsByPath(runtime.GOROOT()); err != nil {
		t.Fatal("directory listing failed for GOROOT:", err)
	} else if contents == nil {
		t.Fatal("directory contents nil for GOROOT")
	}
}

// TestDirectorySymbolicLinkRemoval tests that removal of symbolic links that
// point to directories works as expected.
func TestDirectorySymbolicLinkRemoval(t *testing.T) {
	// Create a temporary directory and defer its cleanup.
	temporaryDirectoryPath, err := ioutil.TempDir("", "mutagen_filesystem_test")
	if err != nil {
		t.Fatal("unable to create temporary directory:", err)
	}
	defer os.RemoveAll(temporaryDirectoryPath)

	// Create a directory handle for this temporary directory and defer its
	// closure.
	directory, _, err := OpenDirectory(temporaryDirectoryPath, false)
	if err != nil {
		t.Fatal("unable to open directory handle:", err)
	}
	defer directory.Close()

	// Create a directory that will serve as our target.
	if err := directory.CreateDirectory("target"); err != nil {
		t.Fatal("unable to create target directory:", err)
	}

	// Open the target directory and defer its closure.
	target, err := directory.OpenDirectory("target")
	if err != nil {
		t.Fatal("unable to open target directory:", err)
	}
	defer target.Close()

	// Create content within the target.
	if err := target.CreateDirectory("content"); err != nil {
		t.Fatal("unable to create content in target directory:", err)
	}

	// Create a symbolic link to the target.
	if err := directory.CreateSymbolicLink("link", "target"); err != nil {
		t.Fatal("unable to create symbolic link:", err)
	}

	// Remove the symbolic link.
	if err := directory.RemoveSymbolicLink("link"); err != nil {
		t.Fatal("unable to remove symbolic link:", err)
	}

	// Grab the target metadata to ensure that it still exists.
	if _, err := directory.ReadContentMetadata("target"); err != nil {
		t.Error("unable to read target metadata:", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package assets

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"os"
	"path"
	"time"

	"github.com/pkg/errors"

	"k8s.io/klog/v2"
)

// MemorySource is the source name used for in-memory copies
const MemorySource = "memory"

// CopyableFile is something that can be copied
type CopyableFile interface {
	io.Reader
	GetLength() int
	GetSourcePath() string

	GetTargetDir() string
	GetTargetName() string
	GetPermissions() string
	GetModTime() (time.Time, error)
	Seek(int64, int) (int64, error)
}

// BaseAsset is the base asset class
type BaseAsset struct {
	SourcePath  string
	TargetDir   string
	TargetName  string
	Permissions string
	Source      string
}

// GetSourcePath returns asset name
func (b *BaseAsset) GetSourcePath() string {
	return b.SourcePath
}

// GetTargetDir returns target dir
func (b *BaseAsset) GetTargetDir() string {
	return b.TargetDir
}

// GetTargetName returns target name
func (b *BaseAsset) GetTargetName() string {
	return b.TargetName
}

// GetPermissions returns permissions
func (b *BaseAsset) GetPermissions() string {
	return b.Permissions
}

// GetModTime returns mod time
func (b *BaseAsset) GetModTime() (time.Time, error) {
	return time.Time{}, nil
}

// FileAsset is an asset using a file
type FileAsset struct {
	BaseAsset
	reader io.ReadSeeker
}

// NewMemoryAssetTarget creates a new MemoryAsset, with target
func NewMemoryAssetTarget(d []byte, targetPath, permissions string) *MemoryAsset {
	return NewMemoryAsset(d, path.Dir(targetPath), path.Base(targetPath), permissions)
}

// NewFileAsset creates a new FileAsset
func NewFileAsset(src, targetDir, targetName, permissions string) (*FileAsset, error) {
	klog.V(4).Infof("NewFileAsset: %s -> %s", src, path.Join(targetDir, targetName))

	f, err := os.Open(src)
	if err != nil {
		return nil, errors.Wrap(err, "open")
	}

	info, err := os.Stat(src)
	if err != nil {
		return nil, errors.Wrapf(err, "stat")
	}

	if info.Size() == 0 {
		klog.Warningf("NewFileAsset: %s is an empty file!", src)
	}

	return &FileAsset{
		BaseAsset: BaseAsset{
			SourcePath:  src,
			TargetDir:   targetDir,
			TargetName:  targetName,
			Permissions: permissions,
		},
		reader: io.NewSectionReader(f, 0, info.Size()),
	}, nil
}

// GetLength returns the file length, or 0 (on error)
func (f *FileAsset) GetLength() (flen int) {
	fi, err := os.Stat(f.SourcePath)
	if err != nil {
		klog.Errorf("stat(%q) failed: %v", f.SourcePath, err)
		return 0
	}
	return int(fi.Size())
}

// GetModTime returns modification time of the file
func (f *FileAsset) GetModTime() (time.Time, error) {
	fi, err := os.Stat(f.SourcePath)
	if err != nil {
		klog.Errorf("stat(%q) failed: %v", f.SourcePath, err)
		return time.Time{}, err
	}
	return fi.ModTime(), nil
}

// Read reads the asset
func (f *FileAsset) Read(p []byte) (int, error) {
	if f.reader == nil {
		return 0, errors.New("Error attempting FileAsset.Read, FileAsset.reader uninitialized")
	}
	return f.reader.Read(p)
}

// Seek resets the reader to offset
func (f *FileAsset) Seek(offset int64, whence int) (int64, error) {
	return f.reader.Seek(offset, whence)
}

// MemoryAsset is a memory-based asset
type MemoryAsset struct {
	BaseAsset
	reader io.ReadSeeker
	length int
}

// GetLength returns length
func (m *MemoryAsset) GetLength() int {
	return m.length
}

// Read reads the asset
func (m *MemoryAsset) Read(p []byte) (int, error) {
	return m.reader.Read(p)
}

// Seek resets the reader to offset
func (m *MemoryAsset) Seek(offset int64, whence int) (int64, error) {
	return m.reader.Seek(offset, whence)
}

// NewMemoryAsset creates a new MemoryAsset
func NewMemoryAsset(d []byte, targetDir, targetName, permissions string) *MemoryAsset {
	return &MemoryAsset{
		BaseAsset: BaseAsset{
			TargetDir:   targetDir,
			TargetName:  targetName,
			Permissions: permissions,
			SourcePath:  MemorySource,
		},
		reader: bytes.NewReader(d),
		length: len(d),
	}
}

// BinAsset is a bindata (binary data) asset
type BinAsset struct {
	BaseAsset
	reader   io.ReadSeeker
	template *template.Template
	length   int
}

// MustBinAsset creates a new BinAsset, or panics if invalid
func MustBinAsset(name, targetDir, targetName, permissions string, isTemplate bool) *BinAsset {
	asset, err := NewBinAsset(name, targetDir, targetName, permissions, isTemplate)
	if err != nil {
		panic(fmt.Sprintf("Failed to define asset %s: %v", name, err))
	}
	return asset
}

// NewBinAsset creates a new BinAsset
func NewBinAsset(name, targetDir, targetName, permissions string, isTemplate bool) (*BinAsset, error) {
	m := &BinAsset{
		BaseAsset: BaseAsset{
			SourcePath:  name,
			TargetDir:   targetDir,
			TargetName:  targetName,
			Permissions: permissions,
		},
		template: nil,
	}
	err := m.loadData(isTemplate)
	return m, err
}

func defaultValue(defValue string, val interface{}) string {
	if val == nil {
		return defValue
	}
	strVal, ok := val.(string)
	if !ok || strVal == "" {
		return defValue
	}
	return strVal
}

func (m *BinAsset) loadData(isTemplate bool) error {
	contents, err := Asset(m.SourcePath)
	if err != nil {
		return err
	}

	if isTemplate {
		tpl, err := template.New(m.SourcePath).Funcs(template.FuncMap{"default": defaultValue}).Parse(string(contents))
		if err != nil {
			return err
		}

		m.template = tpl
	}

	m.length = len(contents)
	m.reader = bytes.NewReader(contents)
	klog.V(1).Infof("Created asset %s with %d bytes", m.SourcePath, m.length)
	if m.length == 0 {
		return fmt.Errorf("%s is an empty asset", m.SourcePath)
	}
	return nil
}

// IsTemplate returns if the asset is a template
func (m *BinAsset) IsTemplate() bool {
	return m.template != nil
}

// Evaluate evaluates the template to a new asset
func (m *BinAsset) Evaluate(data interface{}) (*MemoryAsset, error) {
	if !m.IsTemplate() {
		return nil, errors.Errorf("the asset %s is not a template", m.SourcePath)

	}

	var buf bytes.Buffer
	if err := m.template.Execute(&buf, data); err != nil {
		return nil, err
	}

	return NewMemoryAsset(buf.Bytes(), m.GetTargetDir(), m.GetTargetName(), m.GetPermissions()), nil
}

// GetLength returns length
func (m *BinAsset) GetLength() int {
	return m.length
}

// Read reads the asset
func (m *BinAsset) Read(p []byte) (int, error) {
	if m.GetLength() == 0 {
		return 0, fmt.Errorf("attempted read from a 0 length asset")
	}
	return m.reader.Read(p)
}

// Seek resets the reader to offset
func (m *BinAsset) Seek(offset int64, whence int) (int64, error) {
	return m.reader.Seek(offset, whence)
}
<commit_msg>remove boolean template dependency<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package assets

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"os"
	"path"
	"time"

	"github.com/pkg/errors"

	"k8s.io/klog/v2"
)

// MemorySource is the source name used for in-memory copies
const MemorySource = "memory"

// CopyableFile is something that can be copied
type CopyableFile interface {
	io.Reader
	GetLength() int
	GetSourcePath() string

	GetTargetDir() string
	GetTargetName() string
	GetPermissions() string
	GetModTime() (time.Time, error)
	Seek(int64, int) (int64, error)
}

// BaseAsset is the base asset class
type BaseAsset struct {
	SourcePath  string
	TargetDir   string
	TargetName  string
	Permissions string
	Source      string
}

// GetSourcePath returns asset name
func (b *BaseAsset) GetSourcePath() string {
	return b.SourcePath
}

// GetTargetDir returns target dir
func (b *BaseAsset) GetTargetDir() string {
	return b.TargetDir
}

// GetTargetName returns target name
func (b *BaseAsset) GetTargetName() string {
	return b.TargetName
}

// GetPermissions returns permissions
func (b *BaseAsset) GetPermissions() string {
	return b.Permissions
}

// GetModTime returns mod time
func (b *BaseAsset) GetModTime() (time.Time, error) {
	return time.Time{}, nil
}

// FileAsset is an asset using a file
type FileAsset struct {
	BaseAsset
	reader io.ReadSeeker
}

// NewMemoryAssetTarget creates a new MemoryAsset, with target
func NewMemoryAssetTarget(d []byte, targetPath, permissions string) *MemoryAsset {
	return NewMemoryAsset(d, path.Dir(targetPath), path.Base(targetPath), permissions)
}

// NewFileAsset creates a new FileAsset
func NewFileAsset(src, targetDir, targetName, permissions string) (*FileAsset, error) {
	klog.V(4).Infof("NewFileAsset: %s -> %s", src, path.Join(targetDir, targetName))

	f, err := os.Open(src)
	if err != nil {
		return nil, errors.Wrap(err, "open")
	}

	info, err := os.Stat(src)
	if err != nil {
		return nil, errors.Wrapf(err, "stat")
	}

	if info.Size() == 0 {
		klog.Warningf("NewFileAsset: %s is an empty file!", src)
	}

	return &FileAsset{
		BaseAsset: BaseAsset{
			SourcePath:  src,
			TargetDir:   targetDir,
			TargetName:  targetName,
			Permissions: permissions,
		},
		reader: io.NewSectionReader(f, 0, info.Size()),
	}, nil
}

// GetLength returns the file length, or 0 (on error)
func (f *FileAsset) GetLength() (flen int) {
	fi, err := os.Stat(f.SourcePath)
	if err != nil {
		klog.Errorf("stat(%q) failed: %v", f.SourcePath, err)
		return 0
	}
	return int(fi.Size())
}

// GetModTime returns modification time of the file
func (f *FileAsset) GetModTime() (time.Time, error) {
	fi, err := os.Stat(f.SourcePath)
	if err != nil {
		klog.Errorf("stat(%q) failed: %v", f.SourcePath, err)
		return time.Time{}, err
	}
	return fi.ModTime(), nil
}

// Read reads the asset
func (f *FileAsset) Read(p []byte) (int, error) {
	if f.reader == nil {
		return 0, errors.New("Error attempting FileAsset.Read, FileAsset.reader uninitialized")
	}
	return f.reader.Read(p)
}

// Seek resets the reader to offset
func (f *FileAsset) Seek(offset int64, whence int) (int64, error) {
	return f.reader.Seek(offset, whence)
}

// MemoryAsset is a memory-based asset
type MemoryAsset struct {
	BaseAsset
	reader io.ReadSeeker
	length int
}

// GetLength returns length
func (m *MemoryAsset) GetLength() int {
	return m.length
}

// Read reads the asset
func (m *MemoryAsset) Read(p []byte) (int, error) {
	return m.reader.Read(p)
}

// Seek resets the reader to offset
func (m *MemoryAsset) Seek(offset int64, whence int) (int64, error) {
	return m.reader.Seek(offset, whence)
}

// NewMemoryAsset creates a new MemoryAsset
func NewMemoryAsset(d []byte, targetDir, targetName, permissions string) *MemoryAsset {
	return &MemoryAsset{
		BaseAsset: BaseAsset{
			TargetDir:   targetDir,
			TargetName:  targetName,
			Permissions: permissions,
			SourcePath:  MemorySource,
		},
		reader: bytes.NewReader(d),
		length: len(d),
	}
}

// BinAsset is a bindata (binary data) asset
type BinAsset struct {
	BaseAsset
	reader   io.ReadSeeker
	template *template.Template
	length   int
}

// MustBinAsset creates a new BinAsset, or panics if invalid
func MustBinAsset(name, targetDir, targetName, permissions string) *BinAsset {
	asset, err := NewBinAsset(name, targetDir, targetName, permissions)
	if err != nil {
		panic(fmt.Sprintf("Failed to define asset %s: %v", name, err))
	}
	return asset
}

// NewBinAsset creates a new BinAsset
func NewBinAsset(name, targetDir, targetName, permissions string) (*BinAsset, error) {
	m := &BinAsset{
		BaseAsset: BaseAsset{
			SourcePath:  name,
			TargetDir:   targetDir,
			TargetName:  targetName,
			Permissions: permissions,
		},
		template: nil,
	}
	err := m.loadData()
	return m, err
}

func defaultValue(defValue string, val interface{}) string {
	if val == nil {
		return defValue
	}
	strVal, ok := val.(string)
	if !ok || strVal == "" {
		return defValue
	}
	return strVal
}

func (m *BinAsset) loadData() error {
	contents, err := Asset(m.SourcePath)
	if err != nil {
		return err
	}

	tpl, err := template.New(m.SourcePath).Funcs(template.FuncMap{"default": defaultValue}).Parse(string(contents))
	if err != nil {
		return err
	}

	m.template = tpl

	m.length = len(contents)
	m.reader = bytes.NewReader(contents)
	klog.V(1).Infof("Created asset %s with %d bytes", m.SourcePath, m.length)
	if m.length == 0 {
		return fmt.Errorf("%s is an empty asset", m.SourcePath)
	}
	return nil
}

// IsTemplate returns if the asset is a template
func (m *BinAsset) IsTemplate() bool {
	return m.template != nil
}

// Evaluate evaluates the template to a new asset
func (m *BinAsset) Evaluate(data interface{}) (*MemoryAsset, error) {
	if !m.IsTemplate() {
		return nil, errors.Errorf("the asset %s is not a template", m.SourcePath)

	}

	var buf bytes.Buffer
	if err := m.template.Execute(&buf, data); err != nil {
		return nil, err
	}

	return NewMemoryAsset(buf.Bytes(), m.GetTargetDir(), m.GetTargetName(), m.GetPermissions()), nil
}

// GetLength returns length
func (m *BinAsset) GetLength() int {
	return m.length
}

// Read reads the asset
func (m *BinAsset) Read(p []byte) (int, error) {
	if m.GetLength() == 0 {
		return 0, fmt.Errorf("attempted read from a 0 length asset")
	}
	return m.reader.Read(p)
}

// Seek resets the reader to offset
func (m *BinAsset) Seek(offset int64, whence int) (int64, error) {
	return m.reader.Seek(offset, whence)
}
<|endoftext|>


<commit_before>package imgo

import (
	"encoding/xml"
)

const (
	UploadURL = "http://api.imgur.com/2/upload.xml"
)

type ImgurImage struct {
	XMLName    xml.Name `xml:"image"`
	Name       string   `xml:"name"`
	Title      string   `xml:"title"`
	Caption    string   `xml:"caption"`
	Hash       string   `xml:"hash"`
	DeleteHash string   `xml:"deletehash"`
	DateTime   string   `xml:"datetime"`
	Type       string   `xml:"type"`
	Animated   bool     `xml:"animated"`
	Width      int64    `xml:"width"`
	Height     int64    `xml:"height"`
	Size       int64    `xml:"size"`
	Views      int64    `xml:"views"`
	Bandwidth  int64    `xml:"bandwidth"`
}

type ImgurLinks struct {
	XMLName     xml.Name `xml:"links"`
	Original    string   `xml:"original"`
	Page        string   `xml:"imgur_page"`
	Delete      string   `xml:"delete_page"`
	SmallSquare string   `xml:"small_square"`
	Thumbnail   string   `xml:"large_thumbnail"`
}

type Stats struct {
	XMLName     xml.Name `xml:"stats"`
	MostPopular []string `xml:"most_popular_images>image_hash"`
}

type Upload struct {
	XMLName xml.Name `xml:"upload"`
	Image   ImgurImage
	Links   ImgurLinks
}
<commit_msg>Finished up Stats struct<commit_after>package imgo

import (
	"encoding/xml"
)

const (
	UploadURL = "http://api.imgur.com/2/upload.xml"
)

type ImgurImage struct {
	XMLName    xml.Name `xml:"image"`
	Name       string   `xml:"name"`
	Title      string   `xml:"title"`
	Caption    string   `xml:"caption"`
	Hash       string   `xml:"hash"`
	DeleteHash string   `xml:"deletehash"`
	DateTime   string   `xml:"datetime"`
	Type       string   `xml:"type"`
	Animated   bool     `xml:"animated"`
	Width      int64    `xml:"width"`
	Height     int64    `xml:"height"`
	Size       int64    `xml:"size"`
	Views      int64    `xml:"views"`
	Bandwidth  int64    `xml:"bandwidth"`
}

type ImgurLinks struct {
	XMLName     xml.Name `xml:"links"`
	Original    string   `xml:"original"`
	Page        string   `xml:"imgur_page"`
	Delete      string   `xml:"delete_page"`
	SmallSquare string   `xml:"small_square"`
	Thumbnail   string   `xml:"large_thumbnail"`
}

type Stats struct {
	XMLName        xml.Name `xml:"stats"`
	MostPopular    []string `xml:"most_popular_images>image_hash"`
	ImagesUploaded int64    `xml:"images_uploaded"`
	ImagesViewed   int64    `xml:"images_viewed"`
	BandwidthUsed  string   `xml:"bandwidth_used"`
	AvgImgSize     string   `xml:"average_image_size"`
}

type Upload struct {
	XMLName xml.Name `xml:"upload"`
	Image   ImgurImage
	Links   ImgurLinks
}
<|endoftext|>


<commit_before>package orchestrator

import (
	"github.com/hashicorp/go-multierror"
	"github.com/vburenin/nsync"

	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/discovery"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/exchange"
	"nimona.io/pkg/log"
	"nimona.io/pkg/object"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/sqlobjectstore"
	"nimona.io/pkg/stream"
)

var (
	streamRequestType        = new(stream.Request).GetType()
	streamResponseType       = new(stream.Response).GetType()
	streamObjectRequestType  = new(stream.ObjectRequest).GetType()
	streamObjectResponseType = new(stream.ObjectResponse).GetType()
	streamAnnouncementType   = new(stream.Announcement).GetType()
)

type (
	// Orchestrator is responsible of keeping streams and their underlying
	// graphs up to date
	Orchestrator interface {
		Sync(
			ctx context.Context,
			stream object.Hash,
			recipients peer.LookupOption,
			options ...exchange.Option,
		) (*Graph, error)
		Put(object.Object) error
		Get(
			ctx context.Context,
			root object.Hash,
		) (*Graph, error)
	}
	orchestrator struct {
		store     *sqlobjectstore.Store
		exchange  exchange.Exchange
		discovery discovery.Discoverer
		syncLock  *nsync.NamedMutex
		localInfo *peer.LocalPeer
	}
	Graph struct {
		Objects []object.Object
	}
)

// New constructs a new orchestrator given an object store and exchange
func New(
	store *sqlobjectstore.Store,
	exchange exchange.Exchange,
	discovery discovery.Discoverer,
	localInfo *peer.LocalPeer,
) (Orchestrator, error) {
	ctx := context.Background()
	return NewWithContext(
		ctx,
		store,
		exchange,
		discovery,
		localInfo,
	)
}

// NewWithContext constructs a new orchestrator given an object store and exchange
func NewWithContext(
	ctx context.Context,
	store *sqlobjectstore.Store,
	exc exchange.Exchange,
	discovery discovery.Discoverer,
	localInfo *peer.LocalPeer,
) (Orchestrator, error) {
	logger := log.FromContext(ctx).Named("orchestrator")
	m := &orchestrator{
		store:     store,
		exchange:  exc,
		discovery: discovery,
		syncLock:  nsync.NewNamedMutex(),
		localInfo: localInfo,
	}
	sub := m.exchange.Subscribe(
		exchange.FilterByObjectType("**"),
	)
	go func() {
		if err := m.process(ctx, sub); err != nil {
			logger.Error("processing failed", log.Error(err))
		}
	}()

	// Get all the content types that the local peer supports
	// find all the objects and serve only those objects
	os, err := m.store.Filter()
	if err != nil {
		logger.Error("failed to get objects", log.Error(err))
		return m, nil
	}

	// hashes we serve
	hs := []object.Hash{}

	for i, o := range os {
		// ignore peers
		if o.GetType() == "nimona.io/peer.Peer" {
			continue
		}
		// if object is part of a stream, ignore children
		if o.GetStream() != "" && o.GetStream() != object.NewHash(o) {
			continue
		}
		hs[i] = object.NewHash(o)
	}

	logger.Info(
		"adding supported object hashes as content",
		log.Any("rootObjectHashes", hs),
	)
	m.localInfo.AddContentHash(hs...)

	return m, nil
}

// Process an object
func (m *orchestrator) process(ctx context.Context, sub exchange.EnvelopeSubscription) error {
	for {
		e, err := sub.Next()
		if err != nil {
			return err
		}
		ctx := context.FromContext(ctx)
		logger := log.FromContext(ctx).With(
			log.String("method", "orchestrator.Process"),
			log.String("object._hash", object.NewHash(e.Payload).String()),
			log.String("object.type", e.Payload.GetType()),
		)
		logger.Debug("handling object")

		o := e.Payload
		switch o.GetType() {
		case streamRequestType:
			v := &stream.Request{}
			if err := v.FromObject(o); err != nil {
				return err
			}
			if err := m.handleStreamRequest(
				ctx,
				e.Sender,
				v,
			); err != nil {
				logger.Warn(
					"could not handle graph request object",
					log.Error(err),
				)
			}
		case streamObjectRequestType:
			v := &stream.ObjectRequest{}
			if err := v.FromObject(o); err != nil {
				return err
			}
			if err := m.handleStreamObjectRequest(
				ctx,
				e.Sender,
				v,
			); err != nil {
				logger.Warn(
					"could not handle graph request object",
					log.Error(err),
				)
			}
		case streamAnnouncementType:
			v := &stream.Announcement{}
			if err := v.FromObject(o); err != nil {
				return err
			}
			if err := m.handleStreamAnnouncement(
				ctx,
				e.Sender,
				v,
			); err != nil {
				logger.Warn(
					"could not handle graph announcement object",
					log.Error(err),
				)
			}

		}
	}
}

// IsComplete checks if a graph is missing any nodes
func IsComplete(cs []object.Object) bool {
	ms := map[string]bool{}
	cm := map[string]object.Object{}
	for _, c := range cs {
		// k: hash v: object
		cm[object.NewHash(c).String()] = c
	}
	for _, c := range cs {
		// get all the parents of an object
		for _, p := range c.GetParents() {
			h := p.String()
			// check if that hash exists in the map
			if _, ok := cm[h]; ok {
				continue
			}
			// if missing add the entry to the map
			ms[h] = true
		}
	}
	return len(ms) == 0
}

// Put stores a given object
// TODO(geoah) what happend if the graph is not complete? Error or sync?
func (m *orchestrator) Put(o object.Object) error {
	// set parents
	streamHash := o.GetStream()
	if !streamHash.IsEmpty() {
		os, _ := m.store.Filter(
			sqlobjectstore.FilterByStreamHash(streamHash),
		)
		if len(os) > 0 {
			parents := stream.GetStreamLeaves(os)
			parentHashes := make([]string, len(parents))
			for i, p := range parents {
				parentHashes[i] = object.NewHash(p).String()
			}
			o.Set("@parents:as", parentHashes)
		}
	}
	o.Set("@owners:as", []interface{}{m.localInfo.GetIdentityPublicKey().String()})

	h := object.NewHash(o)

	// store the object
	if err := m.store.Put(o); err != nil {
		return err
	}

	// // get all the objects that are part of the same graph
	// os, err := m.store.Filter(
	// 	sqlobjectstore.FilterByStreamHash(h),
	// )
	// if err != nil {
	// 	return errors.Wrap(
	// 		errors.Error("could not retrieve graph"),
	// 		err,
	// 	)
	// }

	// if !IsComplete(os) {
	// 	return errors.Wrap(
	// 		errors.New("cannot store object"),
	// 		ErrIncompleteGraph,
	// 	)
	// }

	// start publishing new content hashes
	m.localInfo.AddContentHash(h)

	// find leaves
	os, err := m.store.Filter(
		sqlobjectstore.FilterByStreamHash(streamHash),
	)
	if err != nil {
		return err
	}
	leaves := stream.GetStreamLeaves(os)
	leafHashes := make([]object.Hash, len(leaves))
	for i, p := range leaves {
		leafHashes[i] = object.NewHash(p)
	}

	// send announcements about new hashes
	announcement := &stream.Announcement{
		Stream: streamHash,
		Leaves: leafHashes,
		Owners: []crypto.PublicKey{
			m.localInfo.GetIdentityPublicKey(),
		},
	}

	sig, err := object.NewSignature(
		m.localInfo.GetPeerPrivateKey(),
		announcement.ToObject(),
	)
	if err != nil {
		return err
	}

	announcement.Signatures = []object.Signature{sig}

	// figure out who to send it to
	recipients := stream.GetAllowsKeysFromPolicies(os...)

	// send announcement to all recipients
	errs := &multierror.Group{}
	for _, recipient := range recipients {
		recipient := recipient
		errs.Go(func() error {
			return m.exchange.Send(
				context.New(),
				announcement.ToObject(),
				peer.LookupByOwner(recipient),
				exchange.WithAsync(),
				exchange.WithLocalDiscoveryOnly(),
			)
		})
	}

	return errs.Wait().ErrorOrNil()
}

// Get returns a complete and ordered graph given any node of the graph.
func (m *orchestrator) Get(
	ctx context.Context,
	root object.Hash,
) (*Graph, error) {
	os, err := m.store.Filter(sqlobjectstore.FilterByStreamHash(root))
	if err != nil {
		return nil, errors.Wrap(
			errors.Error("could not retrieve graph"),
			err,
		)
	}

	if !IsComplete(os) {
		return nil, ErrIncompleteGraph
	}

	g := &Graph{
		Objects: os,
	}

	return g, nil
}

func (m *orchestrator) handleStreamAnnouncement(
	ctx context.Context,
	sender crypto.PublicKey,
	req *stream.Announcement,
) error {
	// first let's check if we care about this announcement
	_, err := m.store.Get(req.Stream)
	// if we don't have the root, we probably don't care about this
	if errors.CausedBy(err, sqlobjectstore.ErrNotFound) {
		return nil
	}
	if err != nil {
		return err
	}

	// then let's go through the leaves
	missingObjects := []object.Hash{}
	for _, leafHash := range req.Leaves {
		// see if we already have each of them
		_, err := m.store.Get(leafHash)
		// and if not, request them
		if errors.CausedBy(err, sqlobjectstore.ErrNotFound) {
			missingObjects = append(missingObjects, leafHash)
			continue
		}
		if err != nil {
			return err
		}
		// else we already have it
	}

	if len(missingObjects) == 0 {
		return nil
	}

	// if there are leaves missing, sync
	if _, err := m.Sync(
		ctx,
		req.Stream,
		peer.LookupByOwner(sender),
		exchange.WithLocalDiscoveryOnly(),
		exchange.WithAsync(),
	); err != nil {
		return err
	}

	return nil
}

func (m *orchestrator) handleStreamRequest(
	ctx context.Context,
	sender crypto.PublicKey,
	req *stream.Request,
) error {
	// TODO check if policy allows requested to retrieve the object
	logger := log.FromContext(ctx)

	// get the entire graph for this stream
	vs, err := m.store.Filter(
		sqlobjectstore.FilterByStreamHash(req.Stream),
	)
	if err != nil {
		return err
	}

	// get only the object hashes
	hs := []object.Hash{}
	for _, o := range vs {
		hs = append(hs, object.NewHash(o))
	}

	res := &stream.Response{
		Stream:   req.Stream,
		Nonce:    req.Nonce,
		Children: hs,
		Owners: []crypto.PublicKey{
			m.localInfo.GetIdentityPublicKey(),
		},
	}
	sig, err := object.NewSignature(
		m.localInfo.GetPeerPrivateKey(),
		req.ToObject(),
	)
	if err != nil {
		return err
	}
	res.Signatures = []object.Signature{sig}

	if err := m.exchange.Send(
		ctx,
		res.ToObject(),
		peer.LookupByOwner(sender),
		exchange.WithLocalDiscoveryOnly(),
		exchange.WithAsync(),
	); err != nil {
		logger.Warn(
			"orchestrator.handleStreamRequest could not send response",
			log.Error(err),
		)
		return err
	}

	return nil
}

func (m *orchestrator) handleStreamObjectRequest(
	ctx context.Context,
	sender crypto.PublicKey,
	req *stream.ObjectRequest,
) error {
	// TODO check if policy allows requested to retrieve the object
	logger := log.FromContext(ctx)

	// create filter to get all requested objects
	filters := []sqlobjectstore.LookupOption{}
	for _, hash := range req.Objects {
		filters = append(filters, sqlobjectstore.FilterByHash(hash))
	}

	// get the objects
	vs, err := m.store.Filter(filters...)
	if err != nil {
		return err
	}

	// construct object response
	res := &stream.ObjectResponse{
		Stream:  req.Stream,
		Nonce:   req.Nonce,
		Objects: make([]*object.Object, len(vs)),
		Owners: []crypto.PublicKey{
			m.localInfo.GetIdentityPublicKey(),
		},
	}
	for i, obj := range vs {
		obj := obj
		res.Objects[i] = &obj
	}
	sig, err := object.NewSignature(
		m.localInfo.GetPeerPrivateKey(),
		req.ToObject(),
	)
	if err != nil {
		return err
	}
	res.Signatures = []object.Signature{sig}

	if err := m.exchange.Send(
		ctx,
		res.ToObject(),
		peer.LookupByOwner(sender),
		exchange.WithLocalDiscoveryOnly(),
		exchange.WithAsync(),
	); err != nil {
		logger.Warn(
			"orchestrator.handleStreamObjectRequest could not send object response",
			log.Error(err),
		)
		return err
	}

	return nil
}
<commit_msg>fix(orchestrator): make bootstrap async<commit_after>package orchestrator

import (
	"github.com/hashicorp/go-multierror"
	"github.com/vburenin/nsync"

	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/discovery"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/exchange"
	"nimona.io/pkg/log"
	"nimona.io/pkg/object"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/sqlobjectstore"
	"nimona.io/pkg/stream"
)

var (
	streamRequestType        = new(stream.Request).GetType()
	streamResponseType       = new(stream.Response).GetType()
	streamObjectRequestType  = new(stream.ObjectRequest).GetType()
	streamObjectResponseType = new(stream.ObjectResponse).GetType()
	streamAnnouncementType   = new(stream.Announcement).GetType()
)

type (
	// Orchestrator is responsible of keeping streams and their underlying
	// graphs up to date
	Orchestrator interface {
		Sync(
			ctx context.Context,
			stream object.Hash,
			recipients peer.LookupOption,
			options ...exchange.Option,
		) (*Graph, error)
		Put(object.Object) error
		Get(
			ctx context.Context,
			root object.Hash,
		) (*Graph, error)
	}
	orchestrator struct {
		store     *sqlobjectstore.Store
		exchange  exchange.Exchange
		discovery discovery.Discoverer
		syncLock  *nsync.NamedMutex
		localInfo *peer.LocalPeer
	}
	Graph struct {
		Objects []object.Object
	}
)

// New constructs a new orchestrator given an object store and exchange
func New(
	store *sqlobjectstore.Store,
	exchange exchange.Exchange,
	discovery discovery.Discoverer,
	localInfo *peer.LocalPeer,
) (Orchestrator, error) {
	ctx := context.Background()
	return NewWithContext(
		ctx,
		store,
		exchange,
		discovery,
		localInfo,
	)
}

// NewWithContext constructs a new orchestrator given an object store and exchange
func NewWithContext(
	ctx context.Context,
	store *sqlobjectstore.Store,
	exc exchange.Exchange,
	discovery discovery.Discoverer,
	localInfo *peer.LocalPeer,
) (Orchestrator, error) {
	logger := log.FromContext(ctx).Named("orchestrator")
	m := &orchestrator{
		store:     store,
		exchange:  exc,
		discovery: discovery,
		syncLock:  nsync.NewNamedMutex(),
		localInfo: localInfo,
	}
	sub := m.exchange.Subscribe(
		exchange.FilterByObjectType("**"),
	)
	go func() {
		if err := m.process(ctx, sub); err != nil {
			logger.Error("processing failed", log.Error(err))
		}
	}()

	go func() {
		// Get all the content types that the local peer supports
		// find all the objects and serve only those objects
		os, err := m.store.Filter()
		if err != nil {
			logger.Error("failed to get objects", log.Error(err))
			return
		}

		// hashes we serve
		hs := []object.Hash{}

		for _, o := range os {
			// ignore peers
			if o.GetType() == "nimona.io/peer.Peer" {
				continue
			}
			// if object is part of a stream, ignore children
			if o.GetStream() != "" && o.GetStream() != object.NewHash(o) {
				continue
			}
			hs = append(hs, object.NewHash(o))
		}

		logger.Info(
			"adding supported object hashes as content",
			log.Any("rootObjectHashes", hs),
		)
		m.localInfo.AddContentHash(hs...)
	}()

	return m, nil
}

// Process an object
func (m *orchestrator) process(ctx context.Context, sub exchange.EnvelopeSubscription) error {
	for {
		e, err := sub.Next()
		if err != nil {
			return err
		}
		ctx := context.FromContext(ctx)
		logger := log.FromContext(ctx).With(
			log.String("method", "orchestrator.Process"),
			log.String("object._hash", object.NewHash(e.Payload).String()),
			log.String("object.type", e.Payload.GetType()),
		)
		logger.Debug("handling object")

		o := e.Payload
		switch o.GetType() {
		case streamRequestType:
			v := &stream.Request{}
			if err := v.FromObject(o); err != nil {
				return err
			}
			if err := m.handleStreamRequest(
				ctx,
				e.Sender,
				v,
			); err != nil {
				logger.Warn(
					"could not handle graph request object",
					log.Error(err),
				)
			}
		case streamObjectRequestType:
			v := &stream.ObjectRequest{}
			if err := v.FromObject(o); err != nil {
				return err
			}
			if err := m.handleStreamObjectRequest(
				ctx,
				e.Sender,
				v,
			); err != nil {
				logger.Warn(
					"could not handle graph request object",
					log.Error(err),
				)
			}
		case streamAnnouncementType:
			v := &stream.Announcement{}
			if err := v.FromObject(o); err != nil {
				return err
			}
			if err := m.handleStreamAnnouncement(
				ctx,
				e.Sender,
				v,
			); err != nil {
				logger.Warn(
					"could not handle graph announcement object",
					log.Error(err),
				)
			}

		}
	}
}

// IsComplete checks if a graph is missing any nodes
func IsComplete(cs []object.Object) bool {
	ms := map[string]bool{}
	cm := map[string]object.Object{}
	for _, c := range cs {
		// k: hash v: object
		cm[object.NewHash(c).String()] = c
	}
	for _, c := range cs {
		// get all the parents of an object
		for _, p := range c.GetParents() {
			h := p.String()
			// check if that hash exists in the map
			if _, ok := cm[h]; ok {
				continue
			}
			// if missing add the entry to the map
			ms[h] = true
		}
	}
	return len(ms) == 0
}

// Put stores a given object
// TODO(geoah) what happend if the graph is not complete? Error or sync?
func (m *orchestrator) Put(o object.Object) error {
	// set parents
	streamHash := o.GetStream()
	if !streamHash.IsEmpty() {
		os, _ := m.store.Filter(
			sqlobjectstore.FilterByStreamHash(streamHash),
		)
		if len(os) > 0 {
			parents := stream.GetStreamLeaves(os)
			parentHashes := make([]string, len(parents))
			for i, p := range parents {
				parentHashes[i] = object.NewHash(p).String()
			}
			o.Set("@parents:as", parentHashes)
		}
	}
	o.Set("@owners:as", []interface{}{m.localInfo.GetIdentityPublicKey().String()})

	h := object.NewHash(o)

	// store the object
	if err := m.store.Put(o); err != nil {
		return err
	}

	// // get all the objects that are part of the same graph
	// os, err := m.store.Filter(
	// 	sqlobjectstore.FilterByStreamHash(h),
	// )
	// if err != nil {
	// 	return errors.Wrap(
	// 		errors.Error("could not retrieve graph"),
	// 		err,
	// 	)
	// }

	// if !IsComplete(os) {
	// 	return errors.Wrap(
	// 		errors.New("cannot store object"),
	// 		ErrIncompleteGraph,
	// 	)
	// }

	// start publishing new content hashes
	m.localInfo.AddContentHash(h)

	// find leaves
	os, err := m.store.Filter(
		sqlobjectstore.FilterByStreamHash(streamHash),
	)
	if err != nil {
		return err
	}
	leaves := stream.GetStreamLeaves(os)
	leafHashes := make([]object.Hash, len(leaves))
	for i, p := range leaves {
		leafHashes[i] = object.NewHash(p)
	}

	// send announcements about new hashes
	announcement := &stream.Announcement{
		Stream: streamHash,
		Leaves: leafHashes,
		Owners: []crypto.PublicKey{
			m.localInfo.GetIdentityPublicKey(),
		},
	}

	sig, err := object.NewSignature(
		m.localInfo.GetPeerPrivateKey(),
		announcement.ToObject(),
	)
	if err != nil {
		return err
	}

	announcement.Signatures = []object.Signature{sig}

	// figure out who to send it to
	recipients := stream.GetAllowsKeysFromPolicies(os...)

	// send announcement to all recipients
	errs := &multierror.Group{}
	for _, recipient := range recipients {
		recipient := recipient
		errs.Go(func() error {
			return m.exchange.Send(
				context.New(),
				announcement.ToObject(),
				peer.LookupByOwner(recipient),
				exchange.WithAsync(),
				exchange.WithLocalDiscoveryOnly(),
			)
		})
	}

	return errs.Wait().ErrorOrNil()
}

// Get returns a complete and ordered graph given any node of the graph.
func (m *orchestrator) Get(
	ctx context.Context,
	root object.Hash,
) (*Graph, error) {
	os, err := m.store.Filter(sqlobjectstore.FilterByStreamHash(root))
	if err != nil {
		return nil, errors.Wrap(
			errors.Error("could not retrieve graph"),
			err,
		)
	}

	if !IsComplete(os) {
		return nil, ErrIncompleteGraph
	}

	g := &Graph{
		Objects: os,
	}

	return g, nil
}

func (m *orchestrator) handleStreamAnnouncement(
	ctx context.Context,
	sender crypto.PublicKey,
	req *stream.Announcement,
) error {
	// first let's check if we care about this announcement
	_, err := m.store.Get(req.Stream)
	// if we don't have the root, we probably don't care about this
	if errors.CausedBy(err, sqlobjectstore.ErrNotFound) {
		return nil
	}
	if err != nil {
		return err
	}

	// then let's go through the leaves
	missingObjects := []object.Hash{}
	for _, leafHash := range req.Leaves {
		// see if we already have each of them
		_, err := m.store.Get(leafHash)
		// and if not, request them
		if errors.CausedBy(err, sqlobjectstore.ErrNotFound) {
			missingObjects = append(missingObjects, leafHash)
			continue
		}
		if err != nil {
			return err
		}
		// else we already have it
	}

	if len(missingObjects) == 0 {
		return nil
	}

	// if there are leaves missing, sync
	if _, err := m.Sync(
		ctx,
		req.Stream,
		peer.LookupByOwner(sender),
		exchange.WithLocalDiscoveryOnly(),
		exchange.WithAsync(),
	); err != nil {
		return err
	}

	return nil
}

func (m *orchestrator) handleStreamRequest(
	ctx context.Context,
	sender crypto.PublicKey,
	req *stream.Request,
) error {
	// TODO check if policy allows requested to retrieve the object
	logger := log.FromContext(ctx)

	// get the entire graph for this stream
	vs, err := m.store.Filter(
		sqlobjectstore.FilterByStreamHash(req.Stream),
	)
	if err != nil {
		return err
	}

	// get only the object hashes
	hs := []object.Hash{}
	for _, o := range vs {
		hs = append(hs, object.NewHash(o))
	}

	res := &stream.Response{
		Stream:   req.Stream,
		Nonce:    req.Nonce,
		Children: hs,
		Owners: []crypto.PublicKey{
			m.localInfo.GetIdentityPublicKey(),
		},
	}
	sig, err := object.NewSignature(
		m.localInfo.GetPeerPrivateKey(),
		req.ToObject(),
	)
	if err != nil {
		return err
	}
	res.Signatures = []object.Signature{sig}

	if err := m.exchange.Send(
		ctx,
		res.ToObject(),
		peer.LookupByOwner(sender),
		exchange.WithLocalDiscoveryOnly(),
		exchange.WithAsync(),
	); err != nil {
		logger.Warn(
			"orchestrator.handleStreamRequest could not send response",
			log.Error(err),
		)
		return err
	}

	return nil
}

func (m *orchestrator) handleStreamObjectRequest(
	ctx context.Context,
	sender crypto.PublicKey,
	req *stream.ObjectRequest,
) error {
	// TODO check if policy allows requested to retrieve the object
	logger := log.FromContext(ctx)

	// create filter to get all requested objects
	filters := []sqlobjectstore.LookupOption{}
	for _, hash := range req.Objects {
		filters = append(filters, sqlobjectstore.FilterByHash(hash))
	}

	// get the objects
	vs, err := m.store.Filter(filters...)
	if err != nil {
		return err
	}

	// construct object response
	res := &stream.ObjectResponse{
		Stream:  req.Stream,
		Nonce:   req.Nonce,
		Objects: make([]*object.Object, len(vs)),
		Owners: []crypto.PublicKey{
			m.localInfo.GetIdentityPublicKey(),
		},
	}
	for i, obj := range vs {
		obj := obj
		res.Objects[i] = &obj
	}
	sig, err := object.NewSignature(
		m.localInfo.GetPeerPrivateKey(),
		req.ToObject(),
	)
	if err != nil {
		return err
	}
	res.Signatures = []object.Signature{sig}

	if err := m.exchange.Send(
		ctx,
		res.ToObject(),
		peer.LookupByOwner(sender),
		exchange.WithLocalDiscoveryOnly(),
		exchange.WithAsync(),
	); err != nil {
		logger.Warn(
			"orchestrator.handleStreamObjectRequest could not send object response",
			log.Error(err),
		)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Skaffold Authors

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

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

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

package deploy

import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"os/exec"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha2"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/pkg/errors"
)

type KustomizeDeployer struct {
	*v1alpha2.KustomizeDeploy

	kubeContext string
}

func NewKustomizeDeployer(cfg *v1alpha2.KustomizeDeploy, kubeContext string) *KustomizeDeployer {
	return &KustomizeDeployer{
		KustomizeDeploy: cfg,
		kubeContext:     kubeContext,
	}
}

func (k *KustomizeDeployer) Labels() map[string]string {
	return map[string]string{
		constants.Labels.Deployer: "kustomize",
	}
}

func (k *KustomizeDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact) ([]Artifact, error) {
	manifests, err := buildManifests(k.KustomizePath)
	if err != nil {
		return nil, errors.Wrap(err, "kustomize")
	}
	manifestList, err := newManifestList(manifests)
	if err != nil {
		return nil, errors.Wrap(err, "getting manifest list")
	}
	manifestList, err = manifestList.replaceImages(builds)
	if err != nil {
		return nil, errors.Wrap(err, "replacing images")
	}
	if err := kubectl(manifestList.reader(), out, k.kubeContext, "apply", "-f", "-"); err != nil {
		return nil, errors.Wrap(err, "running kubectl")
	}
	return parseManifestsForDeploys(manifestList)
}

func newManifestList(r io.Reader) (manifestList, error) {
	var manifests manifestList
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, errors.Wrap(err, "reading manifests")
	}

	parts := bytes.Split(buf, []byte("\n---"))
	for _, part := range parts {
		manifests = append(manifests, part)
	}

	return manifests, nil
}

func (k *KustomizeDeployer) Cleanup(ctx context.Context, out io.Writer) error {
	manifests, err := buildManifests(constants.DefaultKustomizationPath)
	if err != nil {
		return errors.Wrap(err, "kustomize")
	}
	if err := kubectl(manifests, out, k.kubeContext, "delete", "-f", "-"); err != nil {
		return errors.Wrap(err, "kubectl delete")
	}
	return nil
}

func (k *KustomizeDeployer) Dependencies() ([]string, error) {
	// TODO(r2d4): parse kustomization yaml and add base and patches as dependencies
	return []string{k.KustomizePath}, nil
}

func buildManifests(kustomization string) (io.Reader, error) {
	cmd := exec.Command("kustomize", "build", kustomization)
	out, err := util.DefaultExecCommand.RunCmdOut(cmd)
	if err != nil {
		return nil, errors.Wrap(err, "running kustomize build")
	}
	return bytes.NewReader(out), nil
}
<commit_msg>kustomize: cleanup custom kustomize path<commit_after>/*
Copyright 2018 The Skaffold Authors

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

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

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

package deploy

import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"os/exec"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha2"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/pkg/errors"
)

type KustomizeDeployer struct {
	*v1alpha2.KustomizeDeploy

	kubeContext string
}

func NewKustomizeDeployer(cfg *v1alpha2.KustomizeDeploy, kubeContext string) *KustomizeDeployer {
	return &KustomizeDeployer{
		KustomizeDeploy: cfg,
		kubeContext:     kubeContext,
	}
}

func (k *KustomizeDeployer) Labels() map[string]string {
	return map[string]string{
		constants.Labels.Deployer: "kustomize",
	}
}

func (k *KustomizeDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact) ([]Artifact, error) {
	manifests, err := buildManifests(k.KustomizePath)
	if err != nil {
		return nil, errors.Wrap(err, "kustomize")
	}
	manifestList, err := newManifestList(manifests)
	if err != nil {
		return nil, errors.Wrap(err, "getting manifest list")
	}
	manifestList, err = manifestList.replaceImages(builds)
	if err != nil {
		return nil, errors.Wrap(err, "replacing images")
	}
	if err := kubectl(manifestList.reader(), out, k.kubeContext, "apply", "-f", "-"); err != nil {
		return nil, errors.Wrap(err, "running kubectl")
	}
	return parseManifestsForDeploys(manifestList)
}

func newManifestList(r io.Reader) (manifestList, error) {
	var manifests manifestList
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, errors.Wrap(err, "reading manifests")
	}

	parts := bytes.Split(buf, []byte("\n---"))
	for _, part := range parts {
		manifests = append(manifests, part)
	}

	return manifests, nil
}

func (k *KustomizeDeployer) Cleanup(ctx context.Context, out io.Writer) error {
	manifests, err := buildManifests(k.KustomizeDeploy.KustomizePath)
	if err != nil {
		return errors.Wrap(err, "kustomize")
	}
	if err := kubectl(manifests, out, k.kubeContext, "delete", "-f", "-"); err != nil {
		return errors.Wrap(err, "kubectl delete")
	}
	return nil
}

func (k *KustomizeDeployer) Dependencies() ([]string, error) {
	// TODO(r2d4): parse kustomization yaml and add base and patches as dependencies
	return []string{k.KustomizePath}, nil
}

func buildManifests(kustomization string) (io.Reader, error) {
	cmd := exec.Command("kustomize", "build", kustomization)
	out, err := util.DefaultExecCommand.RunCmdOut(cmd)
	if err != nil {
		return nil, errors.Wrap(err, "running kustomize build")
	}
	return bytes.NewReader(out), nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tamir Duberstein (tamird@gmail.com)

package storage

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/pkg/util/tracing"
)

func BenchmarkReplicaSnapshot(b *testing.B) {
	defer tracing.Disable()()
	storeCfg := TestStoreConfig(nil)
	storeCfg.TestingKnobs.DisableSplitQueue = true
	store, stopper := createTestStoreWithConfig(b, &storeCfg)
	defer stopper.Stop()
	// We want to manually control the size of the raft log.
	store.SetRaftLogQueueActive(false)

	rep, err := store.GetReplica(rangeID)
	if err != nil {
		b.Fatal(err)
	}

	snapSize := rep.GetMaxBytes()
	fillTestRange(b, rep, snapSize)
	b.SetBytes(snapSize)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := rep.GetSnapshot(context.Background()); err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>storage: call (*Replica).CloseOutSnap() after discarding snapshot<commit_after>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tamir Duberstein (tamird@gmail.com)

package storage

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/pkg/util/tracing"
)

func BenchmarkReplicaSnapshot(b *testing.B) {
	defer tracing.Disable()()
	storeCfg := TestStoreConfig(nil)
	storeCfg.TestingKnobs.DisableSplitQueue = true
	store, stopper := createTestStoreWithConfig(b, &storeCfg)
	defer stopper.Stop()
	// We want to manually control the size of the raft log.
	store.SetRaftLogQueueActive(false)

	rep, err := store.GetReplica(rangeID)
	if err != nil {
		b.Fatal(err)
	}

	snapSize := rep.GetMaxBytes()
	fillTestRange(b, rep, snapSize)
	b.SetBytes(snapSize)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := rep.GetSnapshot(context.Background()); err != nil {
			b.Fatal(err)
		}
		rep.CloseOutSnap()
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package openapi_test

import (
	"path/filepath"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/kube-openapi/pkg/util/proto"
	"k8s.io/kube-openapi/pkg/util/proto/testing"
	"k8s.io/kubectl/pkg/util/openapi"
)

var fakeSchema = testing.Fake{Path: filepath.Join("..", "..", "..", "testdata", "openapi", "swagger.json")}

var _ = Describe("Reading apps/v1/Deployment from openAPIData", func() {
	var resources openapi.Resources
	BeforeEach(func() {
		s, err := fakeSchema.OpenAPISchema()
		Expect(err).To(BeNil())
		resources, err = openapi.NewOpenAPIData(s)
		Expect(err).To(BeNil())
	})

	gvk := schema.GroupVersionKind{
		Kind:    "Deployment",
		Version: "v1",
		Group:   "apps",
	}

	var schema proto.Schema
	It("should lookup the Schema by its GroupVersionKind", func() {
		schema = resources.LookupResource(gvk)
		Expect(schema).ToNot(BeNil())
	})

	var deployment *proto.Kind
	It("should be a Kind", func() {
		deployment = schema.(*proto.Kind)
		Expect(deployment).ToNot(BeNil())
	})
})

var _ = Describe("Reading authorization.k8s.io/v1/SubjectAccessReview from openAPIData", func() {
	var resources openapi.Resources
	BeforeEach(func() {
		s, err := fakeSchema.OpenAPISchema()
		Expect(err).To(BeNil())
		resources, err = openapi.NewOpenAPIData(s)
		Expect(err).To(BeNil())
	})

	gvk := schema.GroupVersionKind{
		Kind:    "SubjectAccessReview",
		Version: "v1",
		Group:   "authorization.k8s.io",
	}

	var schema proto.Schema
	It("should lookup the Schema by its GroupVersionKind", func() {
		schema = resources.LookupResource(gvk)
		Expect(schema).ToNot(BeNil())
	})

	var sarspec *proto.Kind
	It("should be a Kind and have a spec", func() {
		sar := schema.(*proto.Kind)
		Expect(sar).ToNot(BeNil())
		Expect(sar.Fields).To(HaveKey("spec"))
		specRef := sar.Fields["spec"].(proto.Reference)
		Expect(specRef).ToNot(BeNil())
		Expect(specRef.Reference()).To(Equal("io.k8s.api.authorization.v1.SubjectAccessReviewSpec"))
		sarspec = specRef.SubSchema().(*proto.Kind)
		Expect(sarspec).ToNot(BeNil())
	})
})
<commit_msg>fix: combine assertion prevent npe<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package openapi_test

import (
	"path/filepath"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/kube-openapi/pkg/util/proto"
	"k8s.io/kube-openapi/pkg/util/proto/testing"
	"k8s.io/kubectl/pkg/util/openapi"
)

var fakeSchema = testing.Fake{Path: filepath.Join("..", "..", "..", "testdata", "openapi", "swagger.json")}

var _ = Describe("Reading apps/v1/Deployment from openAPIData", func() {
	var resources openapi.Resources
	BeforeEach(func() {
		s, err := fakeSchema.OpenAPISchema()
		Expect(err).To(BeNil())
		resources, err = openapi.NewOpenAPIData(s)
		Expect(err).To(BeNil())
	})

	gvk := schema.GroupVersionKind{
		Kind:    "Deployment",
		Version: "v1",
		Group:   "apps",
	}

	var schema proto.Schema
	It("should lookup the Schema by its GroupVersionKind", func() {
		schema = resources.LookupResource(gvk)
		Expect(schema).ToNot(BeNil())
		Expect(schema.(*proto.Kind)).ToNot(BeNil())
	})
})

var _ = Describe("Reading authorization.k8s.io/v1/SubjectAccessReview from openAPIData", func() {
	var resources openapi.Resources
	BeforeEach(func() {
		s, err := fakeSchema.OpenAPISchema()
		Expect(err).To(BeNil())
		resources, err = openapi.NewOpenAPIData(s)
		Expect(err).To(BeNil())
	})

	gvk := schema.GroupVersionKind{
		Kind:    "SubjectAccessReview",
		Version: "v1",
		Group:   "authorization.k8s.io",
	}

	var schema proto.Schema
	It("should lookup the Schema by its GroupVersionKind", func() {
		schema = resources.LookupResource(gvk)
		Expect(schema).ToNot(BeNil())
		sar := schema.(*proto.Kind)
		Expect(sar).ToNot(BeNil())
		Expect(sar.Fields).To(HaveKey("spec"))
		specRef := sar.Fields["spec"].(proto.Reference)
		Expect(specRef).ToNot(BeNil())
		Expect(specRef.Reference()).To(Equal("io.k8s.api.authorization.v1.SubjectAccessReviewSpec"))
		Expect(specRef.SubSchema().(*proto.Kind)).ToNot(BeNil())
	})
})
<|endoftext|>


<commit_before>package rest

import (
	"github.com/smancke/guble/protocol"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"

	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func TestServerHTTP(t *testing.T) {
	defer initCtrl(t)()
	a := assert.New(t)

	// given:  a rest api with a message sink
	routerMock := NewMockRouter(ctrl)
	api := NewRestMessageAPI(routerMock, "/api")

	url, _ := url.Parse("http://localhost/api/message/my/topic?userId=marvin&messageId=42")
	// and a http context
	req := &http.Request{
		URL:    url,
		Body:   ioutil.NopCloser(bytes.NewReader(testBytes)),
		Header: http.Header{},
	}
	w := &httptest.ResponseRecorder{}

	// then i expect
	routerMock.EXPECT().HandleMessage(gomock.Any()).Do(func(msg *protocol.Message) {
		a.Equal(testBytes, msg.Body)
		a.Equal("{}", msg.HeaderJSON)
		a.Equal("/my/topic", string(msg.Path))
		a.True(len(msg.ApplicationID) > 0)
		a.Equal("42", msg.MessageID)
		a.Equal("marvin", msg.UserID)
	})

	// when: I POST a message
	api.ServeHTTP(w, req)

}

func TestHeadersToJson(t *testing.T) {
	a := assert.New(t)

	// empty header
	a.Equal(`{}`, headersToJSON(http.Header{}))

	// simple head
	jsonString := headersToJSON(http.Header{
		X_HEADER_PREFIX + "a": []string{"b"},
		"foo": []string{"b"},
		X_HEADER_PREFIX + "x": []string{"y"},
		"bar": []string{"b"},
	})

	header := make(map[string]string)
	err := json.Unmarshal([]byte(jsonString), &header)
	a.NoError(err)

	a.Equal(2, len(header))
	a.Equal("b", header["a"])
	a.Equal("y", header["x"])
}

func TestRemoveTailingSlash(t *testing.T) {
	assert.Equal(t, "/foo", removeTrailingSlash("/foo/"))
	assert.Equal(t, "/foo", removeTrailingSlash("/foo"))
	assert.Equal(t, "/", removeTrailingSlash("/"))
}

func TestExtractTopic(t *testing.T) {
	a := assert.New(t)

	api := NewRestMessageAPI(nil, "/api")

	cases := []struct {
		path, topic string
		err         error
	}{
		{"/api/message/my/topic", "/my/topic", nil},
		{"/api/message/", "", errNotFound},
		{"/api/message", "", errNotFound},
		{"/api/invalid/request", "", errNotFound},
	}

	for _, c := range cases {
		topic, err := api.extractTopic(c.path)
		m := "Assertion failed for path: " + c.path

		if c.err == nil {
			a.Equal(c.topic, topic, m)
		} else {
			a.NotNil(err, m)
			a.Equal(c.err, err, m)
		}
	}
}
<commit_msg>Fix REST test to make a POST request<commit_after>package rest

import (
	"github.com/smancke/guble/protocol"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"

	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
)

func TestServerHTTP(t *testing.T) {
	defer initCtrl(t)()
	a := assert.New(t)

	// given:  a rest api with a message sink
	routerMock := NewMockRouter(ctrl)
	api := NewRestMessageAPI(routerMock, "/api")

	url, _ := url.Parse("http://localhost/api/message/my/topic?userId=marvin&messageId=42")
	// and a http context
	req := &http.Request{
		Method: http.MethodPost,
		URL:    url,
		Body:   ioutil.NopCloser(bytes.NewReader(testBytes)),
		Header: http.Header{},
	}
	w := &httptest.ResponseRecorder{}

	// then i expect
	routerMock.EXPECT().HandleMessage(gomock.Any()).Do(func(msg *protocol.Message) {
		a.Equal(testBytes, msg.Body)
		a.Equal("{}", msg.HeaderJSON)
		a.Equal("/my/topic", string(msg.Path))
		a.True(len(msg.ApplicationID) > 0)
		a.Equal("42", msg.MessageID)
		a.Equal("marvin", msg.UserID)
	})

	// when: I POST a message
	api.ServeHTTP(w, req)

}

func TestHeadersToJSON(t *testing.T) {
	a := assert.New(t)

	// empty header
	a.Equal(`{}`, headersToJSON(http.Header{}))

	// simple head
	jsonString := headersToJSON(http.Header{
		X_HEADER_PREFIX + "a": []string{"b"},
		"foo": []string{"b"},
		X_HEADER_PREFIX + "x": []string{"y"},
		"bar": []string{"b"},
	})

	header := make(map[string]string)
	err := json.Unmarshal([]byte(jsonString), &header)
	a.NoError(err)

	a.Equal(2, len(header))
	a.Equal("b", header["a"])
	a.Equal("y", header["x"])
}

func TestRemoveTailingSlash(t *testing.T) {
	assert.Equal(t, "/foo", removeTrailingSlash("/foo/"))
	assert.Equal(t, "/foo", removeTrailingSlash("/foo"))
	assert.Equal(t, "/", removeTrailingSlash("/"))
}

func TestExtractTopic(t *testing.T) {
	a := assert.New(t)

	api := NewRestMessageAPI(nil, "/api")

	cases := []struct {
		path, topic string
		err         error
	}{
		{"/api/message/my/topic", "/my/topic", nil},
		{"/api/message/", "", errNotFound},
		{"/api/message", "", errNotFound},
		{"/api/invalid/request", "", errNotFound},
	}

	for _, c := range cases {
		topic, err := api.extractTopic(c.path)
		m := "Assertion failed for path: " + c.path

		if c.err == nil {
			a.Equal(c.topic, topic, m)
		} else {
			a.NotNil(err, m)
			a.Equal(c.err, err, m)
		}
	}
}
<|endoftext|>


<commit_before>package physics

import (
	"buildblast/coords"
	"buildblast/mapgen"
)

type Box struct {
	xs float64
	xe float64
	ys float64
	ym float64
	ye float64
	zs float64
	ze float64
}

func NewBox(position coords.World, halfExtents coords.Vec3) *Box {
	return NewBoxOffset(position, halfExtents, coords.Vec3{X: 0, Y: 0, Z: 0})
}

func NewBoxOffset(position coords.World, halfExtents coords.Vec3, centerOffset coords.Vec3) *Box {
	p := position
	he := halfExtents
	co := centerOffset
	return &Box{
		xs: p.X - he.X + co.X,
		xe: p.X + he.X + co.X,
		ys: p.Y - he.Y + co.Y,
		ym: p.Y + co.Y,
		ye: p.Y + he.Y + co.Y,
		zs: p.Z - he.Z + co.Z,
		ze: p.Z + he.Z + co.Z,
	}
}

func (b *Box) AttemptMove(world mapgen.BlockSource, amount coords.Vec3) coords.Vec3 {
	if b.inSolid(world) {
		amount.X = 0
		amount.Y = 1
		amount.Z = 0
		return amount
	}

	b.xs += amount.X
	b.xe += amount.X
	if (b.inSolid(world)) {
		b.xs -= amount.X
		b.xe -= amount.X
		amount.X = 0
	}

	b.ys += amount.Y
	b.ym += amount.Y
	b.ye += amount.Y
	if (b.inSolid(world)) {
		b.ys -= amount.Y
		b.ym -= amount.Y
		b.ye -= amount.Y
		amount.Y = 0
	}

	b.zs += amount.Z
	b.ze += amount.Z
	if (b.inSolid(world)) {
		b.zs -= amount.Z
		b.ze -= amount.Z
		amount.Z = 0
	}

	return amount;
}

func (b *Box) Contains(position coords.World) bool {
	panic("Contains() not implemented!")
}

func (b *Box) inSolid(world mapgen.BlockSource) bool {
	solid := func (x, y, z float64) bool {
		block := world.Block(coords.World{x, y, z})
		return block.Solid()
	}

	xs := b.xs; xe := b.xe
	ys := b.ys; ym := b.ym; ye := b.ye
	zs := b.zs; ze := b.ze

	return solid(xs, ys, zs) || solid(xs, ys, ze) ||
		   solid(xs, ym, zs) || solid(xs, ym, ze) ||
		   solid(xs, ye, zs) || solid(xs, ye, ze) ||
		   solid(xe, ys, zs) || solid(xe, ys, ze) ||
		   solid(xe, ym, zs) || solid(xe, ym, ze) ||
		   solid(xe, ye, zs) || solid(xe, ye, ze)
}
<commit_msg>Implemented bounding box containment.<commit_after>package physics

import (
	"buildblast/coords"
	"buildblast/mapgen"
)

// xs means x start, xe means x end, etc.
// We have a middle value for y because otherwise
// players can impale themselves on blocks (since
// players are > 1 block high). Note that this means
// this implementation is not completely generic.
// Oh well, it also means that it's really fast!
type Box struct {
	xs float64
	xe float64
	ys float64
	ym float64
	ye float64
	zs float64
	ze float64
}

func NewBox(position coords.World, halfExtents coords.Vec3) *Box {
	return NewBoxOffset(position, halfExtents, coords.Vec3{X: 0, Y: 0, Z: 0})
}

func NewBoxOffset(position coords.World, halfExtents coords.Vec3, centerOffset coords.Vec3) *Box {
	p := position
	he := halfExtents
	co := centerOffset
	return &Box{
		xs: p.X - he.X + co.X,
		xe: p.X + he.X + co.X,
		ys: p.Y - he.Y + co.Y,
		ym: p.Y + co.Y,
		ye: p.Y + he.Y + co.Y,
		zs: p.Z - he.Z + co.Z,
		ze: p.Z + he.Z + co.Z,
	}
}

func (b *Box) AttemptMove(world mapgen.BlockSource, amount coords.Vec3) coords.Vec3 {
	if b.inSolid(world) {
		amount.X = 0
		amount.Y = 1
		amount.Z = 0
		return amount
	}

	b.xs += amount.X
	b.xe += amount.X
	if (b.inSolid(world)) {
		b.xs -= amount.X
		b.xe -= amount.X
		amount.X = 0
	}

	b.ys += amount.Y
	b.ym += amount.Y
	b.ye += amount.Y
	if (b.inSolid(world)) {
		b.ys -= amount.Y
		b.ym -= amount.Y
		b.ye -= amount.Y
		amount.Y = 0
	}

	b.zs += amount.Z
	b.ze += amount.Z
	if (b.inSolid(world)) {
		b.zs -= amount.Z
		b.ze -= amount.Z
		amount.Z = 0
	}

	return amount;
}

func (b *Box) Contains(position coords.World) bool {
	return b.xs < x && b.xe > x &&
		b.ys < y && b.ye > y &&
		b.zs < z && b.ze > z
}

func (b *Box) inSolid(world mapgen.BlockSource) bool {
	solid := func (x, y, z float64) bool {
		block := world.Block(coords.World{x, y, z})
		return block.Solid()
	}

	xs := b.xs; xe := b.xe
	ys := b.ys; ym := b.ym; ye := b.ye
	zs := b.zs; ze := b.ze

	return solid(xs, ys, zs) || solid(xs, ys, ze) ||
		   solid(xs, ym, zs) || solid(xs, ym, ze) ||
		   solid(xs, ye, zs) || solid(xs, ye, ze) ||
		   solid(xe, ys, zs) || solid(xe, ys, ze) ||
		   solid(xe, ym, zs) || solid(xe, ym, ze) ||
		   solid(xe, ye, zs) || solid(xe, ye, ze)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"reflect"
	"encoding/json"
	"code.google.com/p/go.net/websocket"
	"time"
)

type Conn struct {
	ws *websocket.Conn
}

func NewConn(ws *websocket.Conn) *Conn {
	c := new(Conn)
	c.ws = ws
	return c
}

func (c *Conn) Send(m Message) error {
	var err error

	cm := new(ClientMessage)
	cm.Kind = typeToKind(m)

	start := time.Now().UnixNano() / 1e6
	cm.Payload, err = json.Marshal(m)
	end := time.Now().UnixNano() / 1e6 - start
	if end > 10 {
		log.Println("That took", end, "ms to send")
	}
	if err != nil {
		log.Println("Marshalling websocket message:", err)
		return err
	}

	err = websocket.JSON.Send(c.ws, cm)
	if err != nil {
		log.Println("Sending websocket message:", err)
		return err
	}
	return nil
}

func (c *Conn) Recv() (Message, error) {
	cm := new(ClientMessage)
	err := websocket.JSON.Receive(c.ws, cm)
	if err != nil {
		if err != io.EOF {
			log.Println("Reading websocket message:", err)
		}
		return nil, err
	}

	m := kindToType(cm.Kind)
	err = json.Unmarshal(cm.Payload, &m)
	if err != nil {
		log.Println("Unmarshalling websocket message:", err)
		return nil, err
	}

	return m, nil
}

func kindToType(kind MessageKind) Message {
	switch kind {
		case MSG_ENTITY_CREATE:
			return &MsgEntityCreate{}
		case MSG_ENTITY_POSITION:
			return &MsgEntityPosition{}
		case MSG_ENTITY_REMOVE:
			return &MsgEntityRemove{}
		case MSG_BLOCK:
			return &MsgBlock{}
		case MSG_CONTROLS_STATE:
			return &MsgControlsState{}
		case MSG_CHAT:
			return &MsgChat{}
		case MSG_PLAYER_STATE:
			return &MsgPlayerState{}
		case MSG_DEBUG_RAY:
			return &MsgDebugRay{}
		case MSG_NTP_SYNC:
			return &MsgNtpSync{}
		case MSG_INVENTORY_STATE:
			return &MsgInventoryState{}
	}
	panic("Unknown message recieved from client: " + string(kind))
}

func typeToKind(m Message) MessageKind {
	switch m.(type) {
		case *MsgEntityCreate:
			return MSG_ENTITY_CREATE
		case *MsgEntityPosition:
			return MSG_ENTITY_POSITION
		case *MsgEntityRemove:
			return MSG_ENTITY_REMOVE
		case *MsgChunk:
			return MSG_CHUNK
		case *MsgBlock:
			return MSG_BLOCK
		case *MsgControlsState:
			return MSG_CONTROLS_STATE
		case *MsgChat:
			return MSG_CHAT
		case *MsgPlayerState:
			return MSG_PLAYER_STATE
		case *MsgDebugRay:
			return MSG_DEBUG_RAY
		case *MsgNtpSync:
			return MSG_NTP_SYNC
		case *MsgInventoryState:
			return MSG_INVENTORY_STATE
	}
	panic("Attempted to send unknown message to client: " + reflect.TypeOf(m).String())
}
<commit_msg>Don't print annoying error messages in conn.go, put debug timing statements around correct block of code.<commit_after>package main

import (
	"io"
	"log"
	"fmt"
	"time"
	"reflect"
	"encoding/json"

	"code.google.com/p/go.net/websocket"
)

type Conn struct {
	ws *websocket.Conn
}

func NewConn(ws *websocket.Conn) *Conn {
	c := new(Conn)
	c.ws = ws
	return c
}

func (c *Conn) Send(m Message) error {
	var err error

	cm := new(ClientMessage)
	cm.Kind = typeToKind(m)

	cm.Payload, err = json.Marshal(m)
	if err != nil {
		return fmt.Errorf("marshalling websocket message: %s", err)
	}

	start := time.Now().UnixNano() / 1e6

	err = websocket.JSON.Send(c.ws, cm)
	if err != nil {
		return fmt.Errorf("sending websocket message: %s", err)
	}

	end := time.Now().UnixNano() / 1e6 - start
	if end > 10 {
		log.Println("That took", end, "ms to send")
	}

	return nil
}

func (c *Conn) Recv() (Message, error) {
	cm := new(ClientMessage)
	err := websocket.JSON.Receive(c.ws, cm)
	if err != nil {
		if err != io.EOF {
			log.Println("Reading websocket message:", err)
		}
		return nil, err
	}

	m := kindToType(cm.Kind)
	err = json.Unmarshal(cm.Payload, &m)
	if err != nil {
		log.Println("Unmarshalling websocket message:", err)
		return nil, err
	}

	return m, nil
}

func kindToType(kind MessageKind) Message {
	switch kind {
		case MSG_ENTITY_CREATE:
			return &MsgEntityCreate{}
		case MSG_ENTITY_POSITION:
			return &MsgEntityPosition{}
		case MSG_ENTITY_REMOVE:
			return &MsgEntityRemove{}
		case MSG_BLOCK:
			return &MsgBlock{}
		case MSG_CONTROLS_STATE:
			return &MsgControlsState{}
		case MSG_CHAT:
			return &MsgChat{}
		case MSG_PLAYER_STATE:
			return &MsgPlayerState{}
		case MSG_DEBUG_RAY:
			return &MsgDebugRay{}
		case MSG_NTP_SYNC:
			return &MsgNtpSync{}
		case MSG_INVENTORY_STATE:
			return &MsgInventoryState{}
	}
	panic("Unknown message recieved from client: " + string(kind))
}

func typeToKind(m Message) MessageKind {
	switch m.(type) {
		case *MsgEntityCreate:
			return MSG_ENTITY_CREATE
		case *MsgEntityPosition:
			return MSG_ENTITY_POSITION
		case *MsgEntityRemove:
			return MSG_ENTITY_REMOVE
		case *MsgChunk:
			return MSG_CHUNK
		case *MsgBlock:
			return MSG_BLOCK
		case *MsgControlsState:
			return MSG_CONTROLS_STATE
		case *MsgChat:
			return MSG_CHAT
		case *MsgPlayerState:
			return MSG_PLAYER_STATE
		case *MsgDebugRay:
			return MSG_DEBUG_RAY
		case *MsgNtpSync:
			return MSG_NTP_SYNC
		case *MsgInventoryState:
			return MSG_INVENTORY_STATE
	}
	panic("Attempted to send unknown message to client: " + reflect.TypeOf(m).String())
}
<|endoftext|>


<commit_before>package main

import (
	//"flag"
	"os"
	"fmt"
	"io/ioutil"
	. "github.com/sebkl/gotojs"
)

func printUsage() {
	cmd:= os.Args[0]
	fmt.Printf(`
Usage:
	%s <command> [argument]

The Commands are:
	example <path_to_app_root>	Create a sample app.
	create 	<path_to_app_root>	Create a sample directory structure.
	export 	<path_to_template_dir>	Exports internally used templates.

Examples:
	%s create /var/www/helloworld
`,cmd,cmd)
}

const (
	fflag = os.FileMode(0644)
	dflag = os.FileMode(0755)
)

func check(e error) {
	if e != nil {
		printUsage()
		panic(e)
	}
}

func exportTemplates(path string) {
	fflag := os.FileMode(0644)

	temp := DefaultTemplates()
	err := ioutil.WriteFile(path + "/" + Template,[]byte(temp.Binding),fflag);
	check(err)
	err = ioutil.WriteFile(path + "/" + InterfaceTemplate,[]byte(temp.Interface),fflag);
	check(err)
	err = ioutil.WriteFile(path + "/" + MethodTemplate,[]byte(temp.Method),fflag);
	check(err)
}

func createBaseDirs(path string) {
	err := os.MkdirAll(path,dflag)
	check(err)
	err = os.MkdirAll(path + "/" + DefaultFileServerDir,dflag)
	check(err)
	err = os.MkdirAll(path + "/" + RelativePath,dflag)
	check(err)
	err = os.MkdirAll(path + "/" + RelativeLibPath,dflag)
	check(err)
}

func createSampleFiles(path string) {
	createBaseDirs(path)
	err := ioutil.WriteFile(path + "/" + DefaultFileServerDir + "/index.html",[]byte(`
<!DOCTYPE HTML>

  <title>gotojs example</title>
  <link type="text/css" href="css/main.css" rel="Stylesheet"/>

Hello World !

 `),fflag);
	check(err)
	err = os.MkdirAll(path + "/" + DefaultFileServerDir + "/css",dflag)
	check(err)
	err = os.MkdirAll(path + "/" + DefaultFileServerDir + "/js",dflag)
	check(err)
	err = ioutil.WriteFile(path + "/" + DefaultFileServerDir + "/css/main.css",[]byte(`
h1{ font-family: sans-serif; color: #AAAAAA; }
`),fflag);
	check(err)

	err = ioutil.WriteFile(path + "/app.go",[]byte(`
package main

import (
	"log"
	"fmt"
	"strings"
	. "github.com/sebkl/gotojs"
)

// Declare Service to be exposed.
type Service struct {}

// Methods of Service that will be exposed.
func (s *Service) UpperCase(mes string) string {
    return fmt.Sprintf("%s",strings.ToUpper(mes))
}

// Function that takes the HTTPContext as injection.
func AppendURL(context *HTTPContext, source string) string{
	return fmt.Sprintf("%s (%s)",source,context.Request.URL.String())
}

func main() {
	// Initialize the frontend.
	frontend := NewFrontend()

	// Setup the service object.
	service := Service{}

        // Declare some js code that is doing the calls. Usually this is done by a flat file in the public directory,
        // but in this case we would like to show how to use HandleStatic.
        myjs := "$(document).ready(function() {"
        myjs += "       var text = $('h1').html();"
        myjs += "       text = PROXY.Service.UpperCase(text);" // Make the title uppcase by the server side implementation
        myjs += "       text = PROXY.Service.AppendURL(text);" // Append the URL by the server side  implementation
        myjs += "       $('h1').html(text);"
        myjs += "});"

	// Expose the interface and setup the request routing.
	frontend.ExposeInterface(&service,"Service")
	frontend.ExposeFunction(AppendURL,"Service","AppendURL") // Name the function and expose it to existing interface.
	frontend.Redirect("/", "/public/index.html")
	frontend.HandleStatic("/my.js",myjs,"application/javascript")
	log.Fatal(frontend.Start(":8080","/gotojs"))
}
`),fflag);
	check(err)
}

func main() {
	al := len(os.Args)
	if al < 3 {
		printUsage()
		return
	}

	cmd := os.Args[1]
	arg := os.Args[2]

	switch cmd {
		case "example":
			createSampleFiles(arg)
			exportTemplates(arg + "/" + RelativePath)
		case "create":
			createBaseDirs(arg)
			exportTemplates(arg + "/" + RelativePath)
		case "export":
			exportTemplates(arg)
		default:
			fmt.Printf("Unknown command: %s\n\n",cmd)
			printUsage()
	}

}
<commit_msg>Fixed Fileserver changes in example.<commit_after>package main

import (
	//"flag"
	"os"
	"fmt"
	"io/ioutil"
	. "github.com/sebkl/gotojs"
)

func printUsage() {
	cmd:= os.Args[0]
	fmt.Printf(`
Usage:
	%s <command> [argument]

The Commands are:
	example <path_to_app_root>	Create a sample app.
	create 	<path_to_app_root>	Create a sample directory structure.
	export 	<path_to_template_dir>	Exports internally used templates.

Examples:
	%s create /var/www/helloworld
`,cmd,cmd)
}

const (
	fflag = os.FileMode(0644)
	dflag = os.FileMode(0755)
)

func check(e error) {
	if e != nil {
		printUsage()
		panic(e)
	}
}

func exportTemplates(path string) {
	fflag := os.FileMode(0644)

	temp := DefaultTemplates()
	err := ioutil.WriteFile(path + "/" + Template,[]byte(temp.Binding),fflag);
	check(err)
	err = ioutil.WriteFile(path + "/" + InterfaceTemplate,[]byte(temp.Interface),fflag);
	check(err)
	err = ioutil.WriteFile(path + "/" + MethodTemplate,[]byte(temp.Method),fflag);
	check(err)
}

func createBaseDirs(path string) {
	err := os.MkdirAll(path,dflag)
	check(err)
	err = os.MkdirAll(path + "/" + DefaultFileServerDir,dflag)
	check(err)
	err = os.MkdirAll(path + "/" + RelativePath,dflag)
	check(err)
	err = os.MkdirAll(path + "/" + RelativeLibPath,dflag)
	check(err)
}

func createSampleFiles(path string) {
	createBaseDirs(path)
	err := ioutil.WriteFile(path + "/" + DefaultFileServerDir + "/index.html",[]byte(`
<!DOCTYPE HTML>

  <title>gotojs example</title>
  <link type="text/css" href="css/main.css" rel="Stylesheet"/>

Hello World !

 `),fflag);
	check(err)
	err = os.MkdirAll(path + "/" + DefaultFileServerDir + "/css",dflag)
	check(err)
	err = os.MkdirAll(path + "/" + DefaultFileServerDir + "/js",dflag)
	check(err)
	err = ioutil.WriteFile(path + "/" + DefaultFileServerDir + "/css/main.css",[]byte(`
h1{ font-family: sans-serif; color: #AAAAAA; }
`),fflag);
	check(err)

	err = ioutil.WriteFile(path + "/app.go",[]byte(`
package main

import (
	"log"
	"fmt"
	"strings"
	. "github.com/sebkl/gotojs"
)

// Declare Service to be exposed.
type Service struct {}

// Methods of Service that will be exposed.
func (s *Service) UpperCase(mes string) string {
    return fmt.Sprintf("%s",strings.ToUpper(mes))
}

// Function that takes the HTTPContext as injection.
func AppendURL(context *HTTPContext, source string) string{
	return fmt.Sprintf("%s (%s)",source,context.Request.URL.String())
}

func main() {
	// Initialize the frontend.
	frontend := NewFrontend()

	// Setup the service object.
	service := Service{}

        // Declare some js code that is doing the calls. Usually this is done by a flat file in the public directory,
        // but in this case we would like to show how to use HandleStatic.
        myjs := "$(document).ready(function() {"
        myjs += "       var text = $('h1').html();"
        myjs += "       text = GOTOJS.Service.UpperCase(text);" // Make the title uppcase by the server side implementation
        myjs += "       text = GOTOJS.Service.AppendURL(text);" // Append the URL by the server side  implementation
        myjs += "       $('h1').html(text);"
        myjs += "});"

	// Expose the interface and setup the request routing.
	frontend.ExposeInterface(&service,"Service")
	frontend.ExposeFunction(AppendURL,"Service","AppendURL") // Name the function and expose it to existing interface.
	frontend.EnableFileServer("public","p")
	frontend.Redirect("/","/p/")
	frontend.HandleStatic("/my.js",myjs,"application/javascript")
	log.Fatal(frontend.Start(":8080","/gotojs"))
}
`),fflag);
	check(err)
}

func main() {
	al := len(os.Args)
	if al < 3 {
		printUsage()
		return
	}

	cmd := os.Args[1]
	arg := os.Args[2]

	switch cmd {
		case "example":
			createSampleFiles(arg)
			exportTemplates(arg + "/" + RelativePath)
		case "create":
			createBaseDirs(arg)
			exportTemplates(arg + "/" + RelativePath)
		case "export":
			exportTemplates(arg)
		default:
			fmt.Printf("Unknown command: %s\n\n",cmd)
			printUsage()
	}

}
<|endoftext|>


<commit_before>package utils

import (
	"net/http"
	"fmt"

	"github.com/jinzhu/gorm"
)

//TODO MOVE TO ERROR PACKAGE

type HttpError struct {
	Error string
	Code int
	InternalError string
}

func AssociationError(db *gorm.Association) *HttpError {
	return InternalServerError(db.Error.Error())
}

func DatabaseError(db *gorm.DB) *HttpError {
	if db.RecordNotFound() {
		return &HttpError { http.StatusText(http.StatusNotFound), http.StatusNotFound, db.Error.Error() }
	}
	return InternalServerError(db.Error.Error())
}

func BadRequest(error string) *HttpError {
	return &HttpError { http.StatusText(http.StatusBadRequest), http.StatusBadRequest, error }
}

func InternalServerError(error string) *HttpError {
	return &HttpError { http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError, error }
}

func NotFound(id uint) *HttpError {
	return &HttpError { http.StatusText(http.StatusNotFound), http.StatusNotFound, fmt.Sprintf("No object with id: %d was found", id) }
}<commit_msg>Print the stackstrace on error<commit_after>package utils

import (
	"net/http"
	"runtime/debug"

	"github.com/jinzhu/gorm"
)

//TODO MOVE TO ERROR PACKAGE

type HttpError struct {
	Error string
	Code int
	InternalError string
}

func AssociationError(db *gorm.Association) *HttpError {
	return InternalServerError(db.Error.Error())
}

func DatabaseError(db *gorm.DB) *HttpError {
	if db.RecordNotFound() {
		return NotFound(db.Error.Error())
	}
	return InternalServerError(db.Error.Error())
}

func BadRequest(error string) *HttpError {
	debug.PrintStack()
	return &HttpError { http.StatusText(http.StatusBadRequest), http.StatusBadRequest, error }
}

func InternalServerError(error string) *HttpError {
	debug.PrintStack()
	return &HttpError { http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError, error }
}

func NotFound(error string) *HttpError {
	debug.PrintStack()
	return &HttpError { http.StatusText(http.StatusNotFound), http.StatusNotFound, error }
}<|endoftext|>