<commit_before>package widget

import (
	"reflect"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/qor/admin"
	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/utils"
	"github.com/qor/roles"
	"github.com/qor/serializable_meta"
)

type QorWidgetSettingInterface interface {
	GetWidgetName() string
	SetWidgetName(string)
	GetGroupName() string
	SetGroupName(string)
	GetScope() string
	SetScope(string)
	GetTemplate() string
	SetTemplate(string)
	serializable_meta.SerializableMetaInterface
}

// QorWidgetSetting default qor widget setting struct
type QorWidgetSetting struct {
	Name        string `gorm:"primary_key"`
	WidgetType  string `gorm:"primary_key"`
	Scope       string `gorm:"primary_key;default:'default'"`
	GroupName   string
	ActivatedAt *time.Time
	Template    string
	serializable_meta.SerializableMeta
	CreatedAt time.Time
	UpdatedAt time.Time
}

func (widgetSetting *QorWidgetSetting) ResourceName() string {
	return "Widget Setting"
}

func (widgetSetting *QorWidgetSetting) BeforeCreate() {
	now := time.Now()
	widgetSetting.ActivatedAt = &now
}

func (widgetSetting *QorWidgetSetting) BeforeUpdate(scope *gorm.Scope) error {
	value := reflect.New(scope.GetModelStruct().ModelType).Interface()
	return scope.NewDB().Model(value).Where("name = ? AND scope = ?", widgetSetting.Name, widgetSetting.Scope).UpdateColumn("activated_at", gorm.Expr("NULL")).Error
}

func (widgetSetting *QorWidgetSetting) GetSerializableArgumentKind() string {
	if widgetSetting.WidgetType != "" {
		return widgetSetting.WidgetType
	}
	return widgetSetting.Kind
}

func (widgetSetting *QorWidgetSetting) SetSerializableArgumentKind(name string) {
	widgetSetting.WidgetType = name
	widgetSetting.Kind = name
}

// GetWidgetName get widget setting's group name
func (qorWidgetSetting QorWidgetSetting) GetWidgetName() string {
	return qorWidgetSetting.Name
}

// SetWidgetName set widget setting's group name
func (qorWidgetSetting *QorWidgetSetting) SetWidgetName(name string) {
	qorWidgetSetting.Name = name
}

// GetGroupName get widget setting's group name
func (qorWidgetSetting QorWidgetSetting) GetGroupName() string {
	return qorWidgetSetting.GroupName
}

// SetGroupName set widget setting's group name
func (qorWidgetSetting *QorWidgetSetting) SetGroupName(groupName string) {
	qorWidgetSetting.GroupName = groupName
}

// GetScope get widget's scope
func (qorWidgetSetting QorWidgetSetting) GetScope() string {
	return qorWidgetSetting.Scope
}

// SetScope set widget setting's scope
func (qorWidgetSetting *QorWidgetSetting) SetScope(scope string) {
	qorWidgetSetting.Scope = scope
}

// GetTemplate get used widget template
func (qorWidgetSetting QorWidgetSetting) GetTemplate() string {
	if widget := GetWidget(qorWidgetSetting.GetSerializableArgumentKind()); widget != nil {
		for _, value := range widget.Templates {
			if value == qorWidgetSetting.Template {
				return value
			}
		}

		// return first value of defined widget templates
		for _, value := range widget.Templates {
			return value
		}
	}
	return ""
}

// SetTemplate set used widget's template
func (qorWidgetSetting *QorWidgetSetting) SetTemplate(template string) {
	qorWidgetSetting.Template = template
}

// GetSerializableArgumentResource get setting's argument's resource
func (qorWidgetSetting *QorWidgetSetting) GetSerializableArgumentResource() *admin.Resource {
	widget := GetWidget(qorWidgetSetting.GetSerializableArgumentKind())
	if widget != nil {
		return widget.Setting
	}
	return nil
}

// ConfigureQorResource a method used to config Widget for qor admin
func (qorWidgetSetting *QorWidgetSetting) ConfigureQorResource(res resource.Resourcer) {
	if res, ok := res.(*admin.Resource); ok {
		res.Meta(&admin.Meta{Name: "Name", Permission: roles.Deny(roles.Update, roles.Anyone)})

		res.Meta(&admin.Meta{
			Name: "ActivatedAt",
			Type: "hidden",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				return time.Now()
			},
		})

		res.Meta(&admin.Meta{
			Name: "Scope",
			Type: "hidden",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				if scope := context.Request.URL.Query().Get("widget_scope"); scope != "" {
					return scope
				}

				if setting, ok := result.(QorWidgetSettingInterface); ok {
					if scope := setting.GetScope(); scope != "" {
						return scope
					}
				}

				return "default"
			},
			Setter: func(result interface{}, metaValue *resource.MetaValue, context *qor.Context) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					setting.SetScope(utils.ToString(metaValue.Value))
				}
			},
		})

		res.Meta(&admin.Meta{
			Name: "Widgets",
			Type: "select_one",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				if typ := context.Request.URL.Query().Get("widget_type"); typ != "" {
					return typ
				}

				if setting, ok := result.(QorWidgetSettingInterface); ok {
					return GetWidget(setting.GetSerializableArgumentKind()).Name
				}

				return ""
			},
			Collection: func(result interface{}, context *qor.Context) (results [][]string) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					groupName := setting.GetGroupName()
					for _, group := range registeredWidgetsGroup {
						if group.Name == groupName {
							for _, widget := range group.Widgets {
								results = append(results, []string{widget, widget})
							}
						}
					}

					if len(results) == 0 {
						results = append(results, []string{setting.GetSerializableArgumentKind(), setting.GetSerializableArgumentKind()})
					}
				}
				return
			},
			Setter: func(result interface{}, metaValue *resource.MetaValue, context *qor.Context) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					setting.SetSerializableArgumentKind(utils.ToString(metaValue.Value))
				}
			},
		})

		res.Meta(&admin.Meta{
			Name: "Template",
			Type: "select_one",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					return setting.GetTemplate()
				}
				return ""
			},
			Collection: func(result interface{}, context *qor.Context) (results [][]string) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					if widget := GetWidget(setting.GetSerializableArgumentKind()); widget != nil {
						for _, value := range widget.Templates {
							results = append(results, []string{value, value})
						}
					}
				}
				return
			},
			Setter: func(result interface{}, metaValue *resource.MetaValue, context *qor.Context) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					setting.SetTemplate(utils.ToString(metaValue.Value))
				}
			},
		})

		res.UseTheme("widget")

		res.IndexAttrs("Name", "CreatedAt", "UpdatedAt")
		res.ShowAttrs("Name", "Scope", "WidgetType", "Template", "Value", "CreatedAt", "UpdatedAt")
		res.EditAttrs(
			"Scope", "ActivatedAt", "Widgets", "Template",
			&admin.Section{
				Title: "Settings",
				Rows:  [][]string{{"Kind"}, {"SerializableMeta"}},
			},
		)
	}
}
<commit_msg>Update widget setting's resource name<commit_after>package widget

import (
	"reflect"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/qor/admin"
	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/utils"
	"github.com/qor/roles"
	"github.com/qor/serializable_meta"
)

type QorWidgetSettingInterface interface {
	GetWidgetName() string
	SetWidgetName(string)
	GetGroupName() string
	SetGroupName(string)
	GetScope() string
	SetScope(string)
	GetTemplate() string
	SetTemplate(string)
	serializable_meta.SerializableMetaInterface
}

// QorWidgetSetting default qor widget setting struct
type QorWidgetSetting struct {
	Name        string `gorm:"primary_key"`
	WidgetType  string `gorm:"primary_key"`
	Scope       string `gorm:"primary_key;default:'default'"`
	GroupName   string
	ActivatedAt *time.Time
	Template    string
	serializable_meta.SerializableMeta
	CreatedAt time.Time
	UpdatedAt time.Time
}

func (widgetSetting *QorWidgetSetting) ResourceName() string {
	return "Widget Content"
}

func (widgetSetting *QorWidgetSetting) BeforeCreate() {
	now := time.Now()
	widgetSetting.ActivatedAt = &now
}

func (widgetSetting *QorWidgetSetting) BeforeUpdate(scope *gorm.Scope) error {
	value := reflect.New(scope.GetModelStruct().ModelType).Interface()
	return scope.NewDB().Model(value).Where("name = ? AND scope = ?", widgetSetting.Name, widgetSetting.Scope).UpdateColumn("activated_at", gorm.Expr("NULL")).Error
}

func (widgetSetting *QorWidgetSetting) GetSerializableArgumentKind() string {
	if widgetSetting.WidgetType != "" {
		return widgetSetting.WidgetType
	}
	return widgetSetting.Kind
}

func (widgetSetting *QorWidgetSetting) SetSerializableArgumentKind(name string) {
	widgetSetting.WidgetType = name
	widgetSetting.Kind = name
}

// GetWidgetName get widget setting's group name
func (qorWidgetSetting QorWidgetSetting) GetWidgetName() string {
	return qorWidgetSetting.Name
}

// SetWidgetName set widget setting's group name
func (qorWidgetSetting *QorWidgetSetting) SetWidgetName(name string) {
	qorWidgetSetting.Name = name
}

// GetGroupName get widget setting's group name
func (qorWidgetSetting QorWidgetSetting) GetGroupName() string {
	return qorWidgetSetting.GroupName
}

// SetGroupName set widget setting's group name
func (qorWidgetSetting *QorWidgetSetting) SetGroupName(groupName string) {
	qorWidgetSetting.GroupName = groupName
}

// GetScope get widget's scope
func (qorWidgetSetting QorWidgetSetting) GetScope() string {
	return qorWidgetSetting.Scope
}

// SetScope set widget setting's scope
func (qorWidgetSetting *QorWidgetSetting) SetScope(scope string) {
	qorWidgetSetting.Scope = scope
}

// GetTemplate get used widget template
func (qorWidgetSetting QorWidgetSetting) GetTemplate() string {
	if widget := GetWidget(qorWidgetSetting.GetSerializableArgumentKind()); widget != nil {
		for _, value := range widget.Templates {
			if value == qorWidgetSetting.Template {
				return value
			}
		}

		// return first value of defined widget templates
		for _, value := range widget.Templates {
			return value
		}
	}
	return ""
}

// SetTemplate set used widget's template
func (qorWidgetSetting *QorWidgetSetting) SetTemplate(template string) {
	qorWidgetSetting.Template = template
}

// GetSerializableArgumentResource get setting's argument's resource
func (qorWidgetSetting *QorWidgetSetting) GetSerializableArgumentResource() *admin.Resource {
	widget := GetWidget(qorWidgetSetting.GetSerializableArgumentKind())
	if widget != nil {
		return widget.Setting
	}
	return nil
}

// ConfigureQorResource a method used to config Widget for qor admin
func (qorWidgetSetting *QorWidgetSetting) ConfigureQorResource(res resource.Resourcer) {
	if res, ok := res.(*admin.Resource); ok {
		res.Meta(&admin.Meta{Name: "Name", Permission: roles.Deny(roles.Update, roles.Anyone)})

		res.Meta(&admin.Meta{
			Name: "ActivatedAt",
			Type: "hidden",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				return time.Now()
			},
		})

		res.Meta(&admin.Meta{
			Name: "Scope",
			Type: "hidden",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				if scope := context.Request.URL.Query().Get("widget_scope"); scope != "" {
					return scope
				}

				if setting, ok := result.(QorWidgetSettingInterface); ok {
					if scope := setting.GetScope(); scope != "" {
						return scope
					}
				}

				return "default"
			},
			Setter: func(result interface{}, metaValue *resource.MetaValue, context *qor.Context) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					setting.SetScope(utils.ToString(metaValue.Value))
				}
			},
		})

		res.Meta(&admin.Meta{
			Name: "Widgets",
			Type: "select_one",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				if typ := context.Request.URL.Query().Get("widget_type"); typ != "" {
					return typ
				}

				if setting, ok := result.(QorWidgetSettingInterface); ok {
					return GetWidget(setting.GetSerializableArgumentKind()).Name
				}

				return ""
			},
			Collection: func(result interface{}, context *qor.Context) (results [][]string) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					groupName := setting.GetGroupName()
					for _, group := range registeredWidgetsGroup {
						if group.Name == groupName {
							for _, widget := range group.Widgets {
								results = append(results, []string{widget, widget})
							}
						}
					}

					if len(results) == 0 {
						results = append(results, []string{setting.GetSerializableArgumentKind(), setting.GetSerializableArgumentKind()})
					}
				}
				return
			},
			Setter: func(result interface{}, metaValue *resource.MetaValue, context *qor.Context) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					setting.SetSerializableArgumentKind(utils.ToString(metaValue.Value))
				}
			},
		})

		res.Meta(&admin.Meta{
			Name: "Template",
			Type: "select_one",
			Valuer: func(result interface{}, context *qor.Context) interface{} {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					return setting.GetTemplate()
				}
				return ""
			},
			Collection: func(result interface{}, context *qor.Context) (results [][]string) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					if widget := GetWidget(setting.GetSerializableArgumentKind()); widget != nil {
						for _, value := range widget.Templates {
							results = append(results, []string{value, value})
						}
					}
				}
				return
			},
			Setter: func(result interface{}, metaValue *resource.MetaValue, context *qor.Context) {
				if setting, ok := result.(QorWidgetSettingInterface); ok {
					setting.SetTemplate(utils.ToString(metaValue.Value))
				}
			},
		})

		res.UseTheme("widget")

		res.IndexAttrs("Name", "CreatedAt", "UpdatedAt")
		res.ShowAttrs("Name", "Scope", "WidgetType", "Template", "Value", "CreatedAt", "UpdatedAt")
		res.EditAttrs(
			"Scope", "ActivatedAt", "Widgets", "Template",
			&admin.Section{
				Title: "Settings",
				Rows:  [][]string{{"Kind"}, {"SerializableMeta"}},
			},
		)
	}
}
<|endoftext|>


<commit_before>package vault

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/vault/physical"
)

const (
	// aesgcmVersionByte is prefixed to a message to allow for
	// future versioning of barrier implementations.
	aesgcmVersionByte = 0x1
)

// barrierInit is the JSON encoded value stored
type barrierInit struct {
	Version int    // Version is the current format version
	Key     []byte // Key is the primary encryption key
}

// AESGCMBarrier is a SecurityBarrier implementation that
// uses a 128bit AES encryption cipher with the Galois Counter Mode.
// AES-GCM is high performance, and provides both confidentiality
// and integrity.
type AESGCMBarrier struct {
	backend physical.Backend

	l      sync.RWMutex
	sealed bool

	// primary is the AEAD keyed from the encryption key.
	// This is the cipher that should be used to encrypt/decrypt
	// all the underlying values. It will be available if the
	// barrier is unsealed.
	primary cipher.AEAD
}

// NewAESGCMBarrier is used to construct a new barrier that uses
// the provided physical backend for storage.
func NewAESGCMBarrier(physical physical.Backend) (*AESGCMBarrier, error) {
	b := &AESGCMBarrier{
		backend: physical,
		sealed:  true,
	}
	return b, nil
}

// Initialized checks if the barrier has been initialized
// and has a master key set.
func (b *AESGCMBarrier) Initialized() (bool, error) {
	// Read the init sentinel file
	out, err := b.backend.Get(barrierInitPath)
	if err != nil {
		return false, fmt.Errorf("failed to check for initialization: %v", err)
	}
	return out != nil, nil
}

// Initialize works only if the barrier has not been initialized
// and makes use of the given master key.
func (b *AESGCMBarrier) Initialize(key []byte) error {
	// Verify the key size
	min, max := b.KeyLength()
	if len(key) < min || len(key) > max {
		return fmt.Errorf("Key size must be between [%d, %d]", min, max)
	}

	// Check if already initialized
	if alreadyInit, err := b.Initialized(); err != nil {
		return err
	} else if alreadyInit {
		return ErrBarrierAlreadyInit
	}

	// Create the AES-GCM
	gcm, err := b.aeadFromKey(key)
	if err != nil {
		return err
	}

	// Generate encryption key
	encrypt, err := b.GenerateKey()
	if err != nil {
		return fmt.Errorf("failed to generate encryption key: %v", err)
	}
	defer memzero(encrypt)

	// Create the barrier init entry
	init := barrierInit{
		Version: 1,
		Key:     encrypt,
	}
	buf, err := json.Marshal(init)
	if err != nil {
		return fmt.Errorf("failed to create barrier entry: %v", err)
	}
	defer memzero(buf)

	// Encrypt the barrier init value
	value := b.encrypt(gcm, buf)

	// Create the barrierInitPath
	pe := &physical.Entry{
		Key:   barrierInitPath,
		Value: value,
	}
	if err := b.backend.Put(pe); err != nil {
		return fmt.Errorf("failed to create initialization key: %v", err)
	}
	return nil
}

// GenerateKey is used to generate a new key
func (b *AESGCMBarrier) GenerateKey() ([]byte, error) {
	buf := make([]byte, aes.BlockSize)
	_, err := rand.Read(buf)
	return buf, err
}

// KeyLength is used to sanity check a key
func (b *AESGCMBarrier) KeyLength() (int, int) {
	return aes.BlockSize, 2 * aes.BlockSize
}

// Sealed checks if the barrier has been unlocked yet. The Barrier
// is not expected to be able to perform any CRUD until it is unsealed.
func (b *AESGCMBarrier) Sealed() (bool, error) {
	b.l.RLock()
	defer b.l.RUnlock()
	return b.sealed, nil
}

// Unseal is used to provide the master key which permits the barrier
// to be unsealed. If the key is not correct, the barrier remains sealed.
func (b *AESGCMBarrier) Unseal(key []byte) error {
	b.l.Lock()
	defer b.l.Unlock()

	// Do nothing if already unsealed
	if !b.sealed {
		return nil
	}

	// Read the barrier initialization key
	out, err := b.backend.Get(barrierInitPath)
	if err != nil {
		return fmt.Errorf("failed to check for initialization: %v", err)
	}
	if out == nil {
		return ErrBarrierNotInit
	}

	// Create the AES-GCM
	gcm, err := b.aeadFromKey(key)
	if err != nil {
		return err
	}

	// Decrypt the barrier init key
	plain, err := b.decrypt(gcm, out.Value)
	if err != nil {
		if strings.Contains(err.Error(), "message authentication failed") {
			return ErrBarrierInvalidKey
		}
		return err
	}
	defer memzero(plain)

	// Unmarshal the barrier init
	var init barrierInit
	if err := json.Unmarshal(plain, &init); err != nil {
		return fmt.Errorf("failed to unmarshal barrier init file")
	}
	defer memzero(init.Key)

	// Initialize the master encryption key
	b.primary, err = b.aeadFromKey(init.Key)
	if err != nil {
		return err
	}

	// Set the vault as unsealed
	b.sealed = false
	return nil
}

// Seal is used to re-seal the barrier. This requires the barrier to
// be unsealed again to perform any further operations.
func (b *AESGCMBarrier) Seal() error {
	b.l.Lock()
	defer b.l.Unlock()

	// Remove the primary key, and seal the vault
	b.primary = nil
	b.sealed = true
	return nil
}

// Put is used to insert or update an entry
func (b *AESGCMBarrier) Put(entry *Entry) error {
	defer metrics.MeasureSince([]string{"barrier", "put"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()

	primary := b.primary
	if primary == nil {
		return ErrBarrierSealed
	}

	pe := &physical.Entry{
		Key:   entry.Key,
		Value: b.encrypt(primary, entry.Value),
	}
	return b.backend.Put(pe)
}

// Get is used to fetch an entry
func (b *AESGCMBarrier) Get(key string) (*Entry, error) {
	defer metrics.MeasureSince([]string{"barrier", "get"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()

	primary := b.primary
	if primary == nil {
		return nil, ErrBarrierSealed
	}

	// Read the key from the backend
	pe, err := b.backend.Get(key)
	if err != nil {
		return nil, err
	} else if pe == nil {
		return nil, nil
	}

	// Decrypt the ciphertext
	plain, err := b.decrypt(primary, pe.Value)
	if err != nil {
		return nil, fmt.Errorf("decryption failed: %v", err)
	}

	// Wrap in a logical entry
	entry := &Entry{
		Key:   key,
		Value: plain,
	}
	return entry, nil
}

// Delete is used to permanently delete an entry
func (b *AESGCMBarrier) Delete(key string) error {
	defer metrics.MeasureSince([]string{"barrier", "delete"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()
	if b.sealed {
		return ErrBarrierSealed
	}

	return b.backend.Delete(key)
}

// List is used ot list all the keys under a given
// prefix, up to the next prefix.
func (b *AESGCMBarrier) List(prefix string) ([]string, error) {
	defer metrics.MeasureSince([]string{"barrier", "list"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()
	if b.sealed {
		return nil, ErrBarrierSealed
	}

	return b.backend.List(prefix)
}

// aeadFromKey returns an AES-GCM AEAD using the given key.
func (b *AESGCMBarrier) aeadFromKey(key []byte) (cipher.AEAD, error) {
	// Create the AES cipher
	aesCipher, err := aes.NewCipher(key)
	if err != nil {
		return nil, fmt.Errorf("failed to create cipher: %v", err)
	}

	// Create the GCM mode AEAD
	gcm, err := cipher.NewGCM(aesCipher)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize GCM mode")
	}
	return gcm, nil
}

// encrypt is used to encrypt a value
func (b *AESGCMBarrier) encrypt(gcm cipher.AEAD, plain []byte) []byte {
	// Allocate the output buffer with room for version byte,
	// nonce, GCM tag and the plaintext
	capacity := 1 + gcm.NonceSize() + gcm.Overhead() + len(plain)
	size := 1 + gcm.NonceSize()
	out := make([]byte, size, capacity)

	// Set the version byte
	out[0] = aesgcmVersionByte

	// Generate a random nonce
	nonce := out[1 : 1+gcm.NonceSize()]
	rand.Read(nonce)

	// Seal the output
	out = gcm.Seal(out, nonce, plain, nil)
	return out
}

// decrypt is used to decrypt a value
func (b *AESGCMBarrier) decrypt(gcm cipher.AEAD, cipher []byte) ([]byte, error) {
	// Verify the version byte
	if cipher[0] != aesgcmVersionByte {
		return nil, fmt.Errorf("version bytes mis-match")
	}

	// Capture the parts
	nonce := cipher[1 : 1+gcm.NonceSize()]
	raw := cipher[1+gcm.NonceSize():]
	out := make([]byte, 0, len(raw)-gcm.NonceSize())

	// Attempt to open
	return gcm.Open(out, nonce, raw, nil)
}
<commit_msg>vault: Default key size to 256bit.<commit_after>package vault

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/armon/go-metrics"
	"github.com/hashicorp/vault/physical"
)

const (
	// aesgcmVersionByte is prefixed to a message to allow for
	// future versioning of barrier implementations.
	aesgcmVersionByte = 0x1
)

// barrierInit is the JSON encoded value stored
type barrierInit struct {
	Version int    // Version is the current format version
	Key     []byte // Key is the primary encryption key
}

// AESGCMBarrier is a SecurityBarrier implementation that
// uses a 128bit AES encryption cipher with the Galois Counter Mode.
// AES-GCM is high performance, and provides both confidentiality
// and integrity.
type AESGCMBarrier struct {
	backend physical.Backend

	l      sync.RWMutex
	sealed bool

	// primary is the AEAD keyed from the encryption key.
	// This is the cipher that should be used to encrypt/decrypt
	// all the underlying values. It will be available if the
	// barrier is unsealed.
	primary cipher.AEAD
}

// NewAESGCMBarrier is used to construct a new barrier that uses
// the provided physical backend for storage.
func NewAESGCMBarrier(physical physical.Backend) (*AESGCMBarrier, error) {
	b := &AESGCMBarrier{
		backend: physical,
		sealed:  true,
	}
	return b, nil
}

// Initialized checks if the barrier has been initialized
// and has a master key set.
func (b *AESGCMBarrier) Initialized() (bool, error) {
	// Read the init sentinel file
	out, err := b.backend.Get(barrierInitPath)
	if err != nil {
		return false, fmt.Errorf("failed to check for initialization: %v", err)
	}
	return out != nil, nil
}

// Initialize works only if the barrier has not been initialized
// and makes use of the given master key.
func (b *AESGCMBarrier) Initialize(key []byte) error {
	// Verify the key size
	min, max := b.KeyLength()
	if len(key) < min || len(key) > max {
		return fmt.Errorf("Key size must be between [%d, %d]", min, max)
	}

	// Check if already initialized
	if alreadyInit, err := b.Initialized(); err != nil {
		return err
	} else if alreadyInit {
		return ErrBarrierAlreadyInit
	}

	// Create the AES-GCM
	gcm, err := b.aeadFromKey(key)
	if err != nil {
		return err
	}

	// Generate encryption key
	encrypt, err := b.GenerateKey()
	if err != nil {
		return fmt.Errorf("failed to generate encryption key: %v", err)
	}
	defer memzero(encrypt)

	// Create the barrier init entry
	init := barrierInit{
		Version: 1,
		Key:     encrypt,
	}
	buf, err := json.Marshal(init)
	if err != nil {
		return fmt.Errorf("failed to create barrier entry: %v", err)
	}
	defer memzero(buf)

	// Encrypt the barrier init value
	value := b.encrypt(gcm, buf)

	// Create the barrierInitPath
	pe := &physical.Entry{
		Key:   barrierInitPath,
		Value: value,
	}
	if err := b.backend.Put(pe); err != nil {
		return fmt.Errorf("failed to create initialization key: %v", err)
	}
	return nil
}

// GenerateKey is used to generate a new key
func (b *AESGCMBarrier) GenerateKey() ([]byte, error) {
	// Generate a 256bit key
	buf := make([]byte, 2*aes.BlockSize)
	_, err := rand.Read(buf)
	return buf, err
}

// KeyLength is used to sanity check a key
func (b *AESGCMBarrier) KeyLength() (int, int) {
	return aes.BlockSize, 2 * aes.BlockSize
}

// Sealed checks if the barrier has been unlocked yet. The Barrier
// is not expected to be able to perform any CRUD until it is unsealed.
func (b *AESGCMBarrier) Sealed() (bool, error) {
	b.l.RLock()
	defer b.l.RUnlock()
	return b.sealed, nil
}

// Unseal is used to provide the master key which permits the barrier
// to be unsealed. If the key is not correct, the barrier remains sealed.
func (b *AESGCMBarrier) Unseal(key []byte) error {
	b.l.Lock()
	defer b.l.Unlock()

	// Do nothing if already unsealed
	if !b.sealed {
		return nil
	}

	// Read the barrier initialization key
	out, err := b.backend.Get(barrierInitPath)
	if err != nil {
		return fmt.Errorf("failed to check for initialization: %v", err)
	}
	if out == nil {
		return ErrBarrierNotInit
	}

	// Create the AES-GCM
	gcm, err := b.aeadFromKey(key)
	if err != nil {
		return err
	}

	// Decrypt the barrier init key
	plain, err := b.decrypt(gcm, out.Value)
	if err != nil {
		if strings.Contains(err.Error(), "message authentication failed") {
			return ErrBarrierInvalidKey
		}
		return err
	}
	defer memzero(plain)

	// Unmarshal the barrier init
	var init barrierInit
	if err := json.Unmarshal(plain, &init); err != nil {
		return fmt.Errorf("failed to unmarshal barrier init file")
	}
	defer memzero(init.Key)

	// Initialize the master encryption key
	b.primary, err = b.aeadFromKey(init.Key)
	if err != nil {
		return err
	}

	// Set the vault as unsealed
	b.sealed = false
	return nil
}

// Seal is used to re-seal the barrier. This requires the barrier to
// be unsealed again to perform any further operations.
func (b *AESGCMBarrier) Seal() error {
	b.l.Lock()
	defer b.l.Unlock()

	// Remove the primary key, and seal the vault
	b.primary = nil
	b.sealed = true
	return nil
}

// Put is used to insert or update an entry
func (b *AESGCMBarrier) Put(entry *Entry) error {
	defer metrics.MeasureSince([]string{"barrier", "put"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()

	primary := b.primary
	if primary == nil {
		return ErrBarrierSealed
	}

	pe := &physical.Entry{
		Key:   entry.Key,
		Value: b.encrypt(primary, entry.Value),
	}
	return b.backend.Put(pe)
}

// Get is used to fetch an entry
func (b *AESGCMBarrier) Get(key string) (*Entry, error) {
	defer metrics.MeasureSince([]string{"barrier", "get"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()

	primary := b.primary
	if primary == nil {
		return nil, ErrBarrierSealed
	}

	// Read the key from the backend
	pe, err := b.backend.Get(key)
	if err != nil {
		return nil, err
	} else if pe == nil {
		return nil, nil
	}

	// Decrypt the ciphertext
	plain, err := b.decrypt(primary, pe.Value)
	if err != nil {
		return nil, fmt.Errorf("decryption failed: %v", err)
	}

	// Wrap in a logical entry
	entry := &Entry{
		Key:   key,
		Value: plain,
	}
	return entry, nil
}

// Delete is used to permanently delete an entry
func (b *AESGCMBarrier) Delete(key string) error {
	defer metrics.MeasureSince([]string{"barrier", "delete"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()
	if b.sealed {
		return ErrBarrierSealed
	}

	return b.backend.Delete(key)
}

// List is used ot list all the keys under a given
// prefix, up to the next prefix.
func (b *AESGCMBarrier) List(prefix string) ([]string, error) {
	defer metrics.MeasureSince([]string{"barrier", "list"}, time.Now())
	b.l.RLock()
	defer b.l.RUnlock()
	if b.sealed {
		return nil, ErrBarrierSealed
	}

	return b.backend.List(prefix)
}

// aeadFromKey returns an AES-GCM AEAD using the given key.
func (b *AESGCMBarrier) aeadFromKey(key []byte) (cipher.AEAD, error) {
	// Create the AES cipher
	aesCipher, err := aes.NewCipher(key)
	if err != nil {
		return nil, fmt.Errorf("failed to create cipher: %v", err)
	}

	// Create the GCM mode AEAD
	gcm, err := cipher.NewGCM(aesCipher)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize GCM mode")
	}
	return gcm, nil
}

// encrypt is used to encrypt a value
func (b *AESGCMBarrier) encrypt(gcm cipher.AEAD, plain []byte) []byte {
	// Allocate the output buffer with room for version byte,
	// nonce, GCM tag and the plaintext
	capacity := 1 + gcm.NonceSize() + gcm.Overhead() + len(plain)
	size := 1 + gcm.NonceSize()
	out := make([]byte, size, capacity)

	// Set the version byte
	out[0] = aesgcmVersionByte

	// Generate a random nonce
	nonce := out[1 : 1+gcm.NonceSize()]
	rand.Read(nonce)

	// Seal the output
	out = gcm.Seal(out, nonce, plain, nil)
	return out
}

// decrypt is used to decrypt a value
func (b *AESGCMBarrier) decrypt(gcm cipher.AEAD, cipher []byte) ([]byte, error) {
	// Verify the version byte
	if cipher[0] != aesgcmVersionByte {
		return nil, fmt.Errorf("version bytes mis-match")
	}

	// Capture the parts
	nonce := cipher[1 : 1+gcm.NonceSize()]
	raw := cipher[1+gcm.NonceSize():]
	out := make([]byte, 0, len(raw)-gcm.NonceSize())

	// Attempt to open
	return gcm.Open(out, nonce, raw, nil)
}
<|endoftext|>


<commit_before>package shimmie

import (
	"io"
	"strings"
	"time"
)

type Shimmie struct {
	ImagePath string
	ThumbPath string
	Store
}

func New(imgPath, thumbPath string, s Store) *Shimmie {
	return &Shimmie{ImagePath: imgPath, ThumbPath: thumbPath, Store: s}
}

// Store describes all the operations that need to access database storage.
type Store interface {
	// GetUser gets a user by unique username.
	GetUser(username string) (*User, error)

	// GetConfig gets shimmie config values.
	GetConfig(keys ...string) (map[string]string, error)

	// GetCommon gets common configuration values.
	GetCommon() (*Common, error)

	// GetSafeBustedImages returns all the images that have been rated as safe
	// ignoring the ones from username.
	GetRatedImages(username string) ([]RatedImage, error)
	// GetImage gets a shimmie Image metadata (not it's bytes).
	GetImage(id int) (*Image, error)
	// WriteImageFile reads a shimmie image file (image or thumb) which exists
	// under a path and has a hash and then writes to w.
	WriteImageFile(w io.Writer, path, hash string) error
}

// RatedImage represents a shimmie image that also carries information about
// who rated it and when.
type RatedImage struct {
	Image
	Rater    string
	RaterIP  string
	RateDate *time.Time
}

// User represents a shimmie image.
type Image struct {
	ID           int
	OwnerID      int
	OwnerIP      string
	Filename     string
	Filesize     int
	Hash         string
	Ext          string
	Source       string
	Width        int
	Height       int
	Posted       *time.Time
	Locked       string
	NumericScore int
	Rating       string
	Favorites    int
}

// User represents a shimmie user.
type User struct {
	ID       int
	Name     string
	Pass     string
	JoinDate *time.Time
	Admin    string
	Email    string
	Class    string
}

// CommonConf holds common configuration values.
type Common struct {
	Title       string
	AnalyticsID string
	Description string
	Keywords    string
}

// SiteTitle returns the Title capitalized.
func (c Common) SiteTitle() string {
	return strings.Title(c.Title)
}
<commit_msg>Add Shimmie struct and New func doc comments<commit_after>package shimmie

import (
	"io"
	"strings"
	"time"
)

// Shimmie represents an installed shimmie2 project.
type Shimmie struct {
	ImagePath string
	ThumbPath string
	Store
}

// New creates a new Shimmie by providing a store with the database
// configuration and the paths of the images and thumbs.
func New(imgPath, thumbPath string, s Store) *Shimmie {
	return &Shimmie{ImagePath: imgPath, ThumbPath: thumbPath, Store: s}
}

// Store describes all the operations that need to access database storage.
type Store interface {
	// GetUser gets a user by unique username.
	GetUser(username string) (*User, error)

	// GetConfig gets shimmie config values.
	GetConfig(keys ...string) (map[string]string, error)

	// GetCommon gets common configuration values.
	GetCommon() (*Common, error)

	// GetSafeBustedImages returns all the images that have been rated as safe
	// ignoring the ones from username.
	GetRatedImages(username string) ([]RatedImage, error)
	// GetImage gets a shimmie Image metadata (not it's bytes).
	GetImage(id int) (*Image, error)
	// WriteImageFile reads a shimmie image file (image or thumb) which exists
	// under a path and has a hash and then writes to w.
	WriteImageFile(w io.Writer, path, hash string) error
}

// RatedImage represents a shimmie image that also carries information about
// who rated it and when.
type RatedImage struct {
	Image
	Rater    string
	RaterIP  string
	RateDate *time.Time
}

// User represents a shimmie image.
type Image struct {
	ID           int
	OwnerID      int
	OwnerIP      string
	Filename     string
	Filesize     int
	Hash         string
	Ext          string
	Source       string
	Width        int
	Height       int
	Posted       *time.Time
	Locked       string
	NumericScore int
	Rating       string
	Favorites    int
}

// User represents a shimmie user.
type User struct {
	ID       int
	Name     string
	Pass     string
	JoinDate *time.Time
	Admin    string
	Email    string
	Class    string
}

// CommonConf holds common configuration values.
type Common struct {
	Title       string
	AnalyticsID string
	Description string
	Keywords    string
}

// SiteTitle returns the Title capitalized.
func (c Common) SiteTitle() string {
	return strings.Title(c.Title)
}
<|endoftext|>


<commit_before>// package commands ...
package commands

import (
	"fmt"
	"os"

	"github.com/nanobox-io/nanobox-golang-stylish"
	"github.com/spf13/cobra"

	"github.com/nanobox-io/nanobox/commands/box"
	"github.com/nanobox-io/nanobox/commands/engine"
	"github.com/nanobox-io/nanobox/commands/production"
	"github.com/nanobox-io/nanobox/config"
	"github.com/nanobox-io/nanobox/util"
)

//
var (

	//
	NanoboxCmd = &cobra.Command{
		Use:   "nanobox",
		Short: "",
		Long:  ``,

		//
		PersistentPreRun: func(ccmd *cobra.Command, args []string) {

			// ensures all dependencies are satisfied before running nanobox commands
			runnable(ccmd, args)

			// if the verbose flag is used, up the log level (this will cascade into
			// all subcommands since this is the root command)
			if config.Verbose {
				config.LogLevel = "debug"
			}
		},

		//
		Run: func(ccmd *cobra.Command, args []string) {

			// hijack the verbose flag (-v), and use it to display the version of the
			// CLI
			if version || config.Verbose {
				fmt.Printf("nanobox v%s\n", config.VERSION)
				os.Exit(0)
			}

			// fall back on default help if no args/flags are passed
			ccmd.HelpFunc()(ccmd, args)
		},
	}

	//
	version bool // display the version of nanobox
)

// init creates the list of available nanobox commands and sub commands
func init() {

	// internal flags
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Devmode, "dev", "", false, "")
	NanoboxCmd.PersistentFlags().MarkHidden("dev")

	// persistent flags
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Background, "background", "", false, "Stops nanobox from auto-suspending.")
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Force, "force", "f", false, "Forces a command to run (effects vary per command).")
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Verbose, "verbose", "v", false, "Increase command output from 'info' to 'debug'.")

	// local flags
	NanoboxCmd.Flags().BoolVarP(&version, "version", "", false, "Display the current version of this CLI")

	// 'hidden' commands
	NanoboxCmd.AddCommand(buildCmd)
	NanoboxCmd.AddCommand(createCmd)
	NanoboxCmd.AddCommand(deployCmd)
	NanoboxCmd.AddCommand(execCmd)
	NanoboxCmd.AddCommand(initCmd)
	NanoboxCmd.AddCommand(logCmd)
	NanoboxCmd.AddCommand(reloadCmd)
	NanoboxCmd.AddCommand(resumeCmd)
	NanoboxCmd.AddCommand(sshCmd)
	NanoboxCmd.AddCommand(watchCmd)

	// 'nanobox' commands
	NanoboxCmd.AddCommand(runCmd)
	NanoboxCmd.AddCommand(devCmd)
	NanoboxCmd.AddCommand(bootstrapCmd)
	NanoboxCmd.AddCommand(infoCmd)
	NanoboxCmd.AddCommand(consoleCmd)
	NanoboxCmd.AddCommand(destroyCmd)
	NanoboxCmd.AddCommand(publishCmd)
	NanoboxCmd.AddCommand(stopCmd)
	NanoboxCmd.AddCommand(updateCmd)
	NanoboxCmd.AddCommand(updateImagesCmd)

	// subcommands
	NanoboxCmd.AddCommand(box.BoxCmd)
	NanoboxCmd.AddCommand(engine.EngineCmd)
	NanoboxCmd.AddCommand(production.ProductionCmd)
}

// runnable ensures all dependencies are satisfied before running box commands
func runnable(ccmd *cobra.Command, args []string) {

	// ensure vagrant exists
	if exists := Vagrant.Exists(); !exists {
		fmt.Println("Missing dependency 'Vagrant'. Please download and install it to continue (https://www.vagrantup.com/).")
		os.Exit(1)
	}

	// ensure virtualbox exists
	if exists := util.VboxExists(); !exists {
		fmt.Println("Missing dependency 'Virtualbox'. Please download and install it to continue (https://www.virtualbox.org/wiki/Downloads).")
		os.Exit(1)
	}
}

// boot
func boot(ccmd *cobra.Command, args []string) {

	// ensure vagrant exists before trying to run any nanobox command
	if exists := Vagrant.Exists(); !exists {
		fmt.Println("Missing dependency 'Vagrant'. Please download and install it to continue (https://www.vagrantup.com/).")
		os.Exit(1)
	}

	// ensure virtualbox exists before trying to run any nanobox command
	if exists := util.VboxExists(); !exists {
		fmt.Println("Missing dependency 'Virtualbox'. Please download and install it to continue (https://www.virtualbox.org/wiki/Downloads).")
		os.Exit(1)
	}

	// ensure a Vagrantfile is available before attempting to boot the VM
	initialize(nil, args)

	// get the status to know what needs to happen with the VM
	status := Vagrant.Status()

	switch status {

	// vm is running - do nothing
	case "running":
		fmt.Printf(stylish.Bullet("Nanobox is already running"))
		break

	// vm is suspended - resume it
	case "saved":
		resume(nil, args)

	// vm is not created - create it
	case "not created":
		create(nil, args)

	// vm is in some unknown state - reload it
	default:
		fmt.Printf(stylish.Bullet("Nanobox is in an unknown state (%s). Reloading...", status))
		reload(nil, args)
	}

	//
	Server.Lock()

	// if the background flag is passed, set the mode to "background"
	if config.Background {
		config.VMfile.BackgroundIs(true)
	}
}

// halt
func halt(ccmd *cobra.Command, args []string) {

	//
	Server.Unlock()

	//

	if err := Server.Suspend(); err != nil {
		Config.Fatal("[commands/halt] server.Suspend() failed", err.Error())
	}

	//
	if err := Vagrant.Suspend(); err != nil {
		Config.Fatal("[commands/halt] vagrant.Suspend() failed", err.Error())
	}

	//
	// os.Exit(0)
}
<commit_msg>using runnable in boot rather than duplicating logic<commit_after>// package commands ...
package commands

import (
	"fmt"
	"os"

	"github.com/nanobox-io/nanobox-golang-stylish"
	"github.com/spf13/cobra"

	"github.com/nanobox-io/nanobox/commands/box"
	"github.com/nanobox-io/nanobox/commands/engine"
	"github.com/nanobox-io/nanobox/commands/production"
	"github.com/nanobox-io/nanobox/config"
	"github.com/nanobox-io/nanobox/util"
)

//
var (

	//
	NanoboxCmd = &cobra.Command{
		Use:   "nanobox",
		Short: "",
		Long:  ``,

		//
		PersistentPreRun: func(ccmd *cobra.Command, args []string) {

			// ensures all dependencies are satisfied before running nanobox commands
			runnable(ccmd, args)

			// if the verbose flag is used, up the log level (this will cascade into
			// all subcommands since this is the root command)
			if config.Verbose {
				config.LogLevel = "debug"
			}
		},

		//
		Run: func(ccmd *cobra.Command, args []string) {

			// hijack the verbose flag (-v), and use it to display the version of the
			// CLI
			if version || config.Verbose {
				fmt.Printf("nanobox v%s\n", config.VERSION)
				os.Exit(0)
			}

			// fall back on default help if no args/flags are passed
			ccmd.HelpFunc()(ccmd, args)
		},
	}

	//
	version bool // display the version of nanobox
)

// init creates the list of available nanobox commands and sub commands
func init() {

	// internal flags
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Devmode, "dev", "", false, "")
	NanoboxCmd.PersistentFlags().MarkHidden("dev")

	// persistent flags
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Background, "background", "", false, "Stops nanobox from auto-suspending.")
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Force, "force", "f", false, "Forces a command to run (effects vary per command).")
	NanoboxCmd.PersistentFlags().BoolVarP(&config.Verbose, "verbose", "v", false, "Increase command output from 'info' to 'debug'.")

	// local flags
	NanoboxCmd.Flags().BoolVarP(&version, "version", "", false, "Display the current version of this CLI")

	// 'hidden' commands
	NanoboxCmd.AddCommand(buildCmd)
	NanoboxCmd.AddCommand(createCmd)
	NanoboxCmd.AddCommand(deployCmd)
	NanoboxCmd.AddCommand(execCmd)
	NanoboxCmd.AddCommand(initCmd)
	NanoboxCmd.AddCommand(logCmd)
	NanoboxCmd.AddCommand(reloadCmd)
	NanoboxCmd.AddCommand(resumeCmd)
	NanoboxCmd.AddCommand(sshCmd)
	NanoboxCmd.AddCommand(watchCmd)

	// 'nanobox' commands
	NanoboxCmd.AddCommand(runCmd)
	NanoboxCmd.AddCommand(devCmd)
	NanoboxCmd.AddCommand(bootstrapCmd)
	NanoboxCmd.AddCommand(infoCmd)
	NanoboxCmd.AddCommand(consoleCmd)
	NanoboxCmd.AddCommand(destroyCmd)
	NanoboxCmd.AddCommand(publishCmd)
	NanoboxCmd.AddCommand(stopCmd)
	NanoboxCmd.AddCommand(updateCmd)
	NanoboxCmd.AddCommand(updateImagesCmd)

	// subcommands
	NanoboxCmd.AddCommand(box.BoxCmd)
	NanoboxCmd.AddCommand(engine.EngineCmd)
	NanoboxCmd.AddCommand(production.ProductionCmd)
}

// runnable ensures all dependencies are satisfied before running box commands
func runnable(ccmd *cobra.Command, args []string) {

	// ensure vagrant exists
	if exists := Vagrant.Exists(); !exists {
		fmt.Println("Missing dependency 'Vagrant'. Please download and install it to continue (https://www.vagrantup.com/).")
		os.Exit(1)
	}

	// ensure virtualbox exists
	if exists := util.VboxExists(); !exists {
		fmt.Println("Missing dependency 'Virtualbox'. Please download and install it to continue (https://www.virtualbox.org/wiki/Downloads).")
		os.Exit(1)
	}
}

// boot
func boot(ccmd *cobra.Command, args []string) {

	// ensure the cli can run before trying to boot vm
	runnable(ccmd, nil)

	// ensure a Vagrantfile is available before attempting to boot the VM
	initialize(nil, args)

	// get the status to know what needs to happen with the VM
	status := Vagrant.Status()

	switch status {

	// vm is running - do nothing
	case "running":
		fmt.Printf(stylish.Bullet("Nanobox is already running"))
		break

	// vm is suspended - resume it
	case "saved":
		resume(nil, args)

	// vm is not created - create it
	case "not created":
		create(nil, args)

	// vm is in some unknown state - reload it
	default:
		fmt.Printf(stylish.Bullet("Nanobox is in an unknown state (%s). Reloading...", status))
		reload(nil, args)
	}

	//
	Server.Lock()

	// if the background flag is passed, set the mode to "background"
	if config.Background {
		config.VMfile.BackgroundIs(true)
	}
}

// halt
func halt(ccmd *cobra.Command, args []string) {

	//
	Server.Unlock()

	//

	if err := Server.Suspend(); err != nil {
		Config.Fatal("[commands/halt] server.Suspend() failed", err.Error())
	}

	//
	if err := Vagrant.Suspend(); err != nil {
		Config.Fatal("[commands/halt] vagrant.Suspend() failed", err.Error())
	}

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


<commit_before>package commands

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"github.com/spf13/cobra"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/debug"
	"strings"
	"time"
)

var (
	Debugging    = false
	ErrorBuffer  = &bytes.Buffer{}
	ErrorWriter  = io.MultiWriter(os.Stderr, ErrorBuffer)
	OutputWriter = io.MultiWriter(os.Stdout, ErrorBuffer)
	commands     = make(map[string]func(*Command) RunnableCommand)
	RootCmd      = &cobra.Command{
		Use:   "git-media",
		Short: "Git Media provides large file support to Git.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Git Media, yo")
		},
	}
)

// Error prints a formatted message to Stderr.  It also gets printed to the
// panic log if one is created for this command.
func Error(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(ErrorWriter, line)
}

// Print prints a formatted message to Stdout.  It also gets printed to the
// panic log if one is created for this command.
func Print(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(OutputWriter, line)
}

// Exit prints a formatted message and exits.
func Exit(format string, args ...interface{}) {
	Error(format, args...)
	os.Exit(2)
}

// Debug prints a formatted message if debugging is enabled.  The formatted
// message also shows up in the panic log, if created.
func Debug(format string, args ...interface{}) {
	if !Debugging {
		return
	}
	log.Printf(format, args...)
}

// Panic prints a formatted message, and writes a stack trace for the error to
// a log file before exiting.
func Panic(err error, format string, args ...interface{}) {
	Error(format, args...)
	file := handlePanic(err)

	if len(file) > 0 {
		fmt.Fprintf(os.Stderr, "\nErrors logged to %s.\nUse `git media logs last` to view the log.\n", file)
	}
	os.Exit(2)
}

func Run() {
	RootCmd.Execute()
}

func NewCommand(name, subname string) *Command {
	var args []string
	if len(os.Args) > 1 {
		args = os.Args[2:]
	}

	fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	setupDebugging(fs)
	fs.SetOutput(ErrorWriter)

	return &Command{name, subname, fs, args, args}
}

func PipeMediaCommand(name string, args ...string) error {
	return PipeCommand("bin/"+name, args...)
}

func PipeCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

type RunnableCommand interface {
	Setup()
	Parse()
	Run()
	Usage()
}

type Command struct {
	Name        string
	SubCommand  string
	FlagSet     *flag.FlagSet
	Args        []string
	SubCommands []string
}

func (c *Command) Usage() {
	Print("usage: %s %s", c.Name, c.SubCommand)
	c.FlagSet.PrintDefaults()
}

func (c *Command) Parse() {
	c.FlagSet.Parse(c.Args)
	c.SubCommands = c.FlagSet.Args()
}

func (c *Command) Setup() {}
func (c *Command) Run()   {}

func registerCommand(name string, cmdcb func(*Command) RunnableCommand) {
	commands[name] = cmdcb
}

func missingCommand(cmd *Command, subname string) {
	Error("%s: '%s' is not a %s command.  See %s help.",
		cmd.Name, subname, cmd.Name, cmd.Name)
}

func setupDebugging(flagset *flag.FlagSet) {
	if flagset == nil {
		flag.BoolVar(&Debugging, "debug", false, "Turns debugging on")
	} else {
		flagset.BoolVar(&Debugging, "debug", false, "Turns debugging on")
	}
}

func handlePanic(err error) string {
	if err == nil {
		return ""
	}

	Debug(err.Error())
	logFile, logErr := logPanic(err)
	if logErr != nil {
		fmt.Fprintf(os.Stderr, "Unable to log panic to %s - %s\n\n", gitmedia.LocalLogDir, err)
		logEnv(os.Stderr)
	}

	return logFile
}

func logEnv(w io.Writer) {
	for _, env := range gitmedia.Environ() {
		fmt.Fprintln(w, env)
	}
}

func logPanic(loggedError error) (string, error) {
	if err := os.MkdirAll(gitmedia.LocalLogDir, 0744); err != nil {
		return "", err
	}

	now := time.Now()
	name := now.Format("2006-01-02T15:04:05.999999999")
	full := filepath.Join(gitmedia.LocalLogDir, name+".log")

	file, err := os.Create(full)
	if err != nil {
		return "", err
	}

	defer file.Close()

	fmt.Fprintf(file, "> %s", filepath.Base(os.Args[0]))
	if len(os.Args) > 0 {
		fmt.Fprintf(file, " %s", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprint(file, "\n")

	logEnv(file)
	fmt.Fprint(file, "\n")

	file.Write(ErrorBuffer.Bytes())
	fmt.Fprint(file, "\n")

	fmt.Fprintln(file, loggedError.Error())
	file.Write(debug.Stack())

	return full, nil
}

func init() {
	log.SetOutput(ErrorWriter)
}
<commit_msg>remove old command crap<commit_after>package commands

import (
	"bytes"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"github.com/spf13/cobra"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/debug"
	"strings"
	"time"
)

var (
	Debugging    = false
	ErrorBuffer  = &bytes.Buffer{}
	ErrorWriter  = io.MultiWriter(os.Stderr, ErrorBuffer)
	OutputWriter = io.MultiWriter(os.Stdout, ErrorBuffer)
	RootCmd      = &cobra.Command{
		Use:   "git-media",
		Short: "Git Media provides large file support to Git.",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Git Media, yo")
		},
	}
)

// Error prints a formatted message to Stderr.  It also gets printed to the
// panic log if one is created for this command.
func Error(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(ErrorWriter, line)
}

// Print prints a formatted message to Stdout.  It also gets printed to the
// panic log if one is created for this command.
func Print(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(OutputWriter, line)
}

// Exit prints a formatted message and exits.
func Exit(format string, args ...interface{}) {
	Error(format, args...)
	os.Exit(2)
}

// Debug prints a formatted message if debugging is enabled.  The formatted
// message also shows up in the panic log, if created.
func Debug(format string, args ...interface{}) {
	if !Debugging {
		return
	}
	log.Printf(format, args...)
}

// Panic prints a formatted message, and writes a stack trace for the error to
// a log file before exiting.
func Panic(err error, format string, args ...interface{}) {
	Error(format, args...)
	file := handlePanic(err)

	if len(file) > 0 {
		fmt.Fprintf(os.Stderr, "\nErrors logged to %s.\nUse `git media logs last` to view the log.\n", file)
	}
	os.Exit(2)
}

func Run() {
	RootCmd.Execute()
}

func PipeMediaCommand(name string, args ...string) error {
	return PipeCommand("bin/"+name, args...)
}

func PipeCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func handlePanic(err error) string {
	if err == nil {
		return ""
	}

	Debug(err.Error())
	logFile, logErr := logPanic(err)
	if logErr != nil {
		fmt.Fprintf(os.Stderr, "Unable to log panic to %s - %s\n\n", gitmedia.LocalLogDir, err)
		logEnv(os.Stderr)
	}

	return logFile
}

func logEnv(w io.Writer) {
	for _, env := range gitmedia.Environ() {
		fmt.Fprintln(w, env)
	}
}

func logPanic(loggedError error) (string, error) {
	if err := os.MkdirAll(gitmedia.LocalLogDir, 0744); err != nil {
		return "", err
	}

	now := time.Now()
	name := now.Format("2006-01-02T15:04:05.999999999")
	full := filepath.Join(gitmedia.LocalLogDir, name+".log")

	file, err := os.Create(full)
	if err != nil {
		return "", err
	}

	defer file.Close()

	fmt.Fprintf(file, "> %s", filepath.Base(os.Args[0]))
	if len(os.Args) > 0 {
		fmt.Fprintf(file, " %s", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprint(file, "\n")

	logEnv(file)
	fmt.Fprint(file, "\n")

	file.Write(ErrorBuffer.Bytes())
	fmt.Fprint(file, "\n")

	fmt.Fprintln(file, loggedError.Error())
	file.Write(debug.Stack())

	return full, nil
}

func init() {
	log.SetOutput(ErrorWriter)
}
<|endoftext|>


<commit_before>package method

import "github.com/qlova/ilang/src"
import "github.com/qlova/ilang/src/modules/function"

var Flag = ilang.NewFlag()
var New = ilang.NewFlag()

func init() {
	ilang.RegisterToken([]string{"method"}, ScanMethod)
	ilang.RegisterListener(New, NewEnd)

	ilang.RegisterDefault(func(ic *ilang.Compiler) bool {
		token := ic.LastToken

		if ic.TypeExists(token) {
			if ic.DefinedTypes[token].Empty() && ic.Peek() == "." {
				ic.Scan('.')
				ic.ExpressionType = function.Flag
				var name = ic.Scan(ilang.Name)
				ic.Shunt(name+"_m_"+token)
				ic.Scan('(') //BUG I don't know why this has to be here.
				return true
			}
		}

		if ic.GetFlag(Flag) && ic.LastDefinedType.Detail != nil {
			if _, ok := ic.LastDefinedType.Detail.Table[token]; ok {
				ic.NextToken = ic.LastDefinedType.Name
				ic.NextNextToken = "."
				ic.NextNextNextToken = token
				ic.ScanStatement()
				return true
			}
		}

		return false
	})

	ilang.RegisterExpression(func(ic *ilang.Compiler) string {
		token := ic.LastToken

		if ic.TypeExists(token) {
			if ic.DefinedTypes[token].Empty() && ic.Peek() == "." {
				ic.Scan('.')
				ic.ExpressionType = function.Flag
				var name = ic.Scan(ilang.Name)
				return ic.Shunt(name+"_m_"+ic.DefinedTypes[token].GetComplexName())
			}
		}

		if ic.GetFlag(Flag) {
			if ic.TypeExists(token) && ic.LastDefinedType.Super == token {
	 			ic.ExpressionType = ic.DefinedTypes[ic.LastDefinedType.Super]
				return ic.Shunt(ic.LastDefinedType.Name)
		 	}

			//Scope methods with multiple arguments inside the method.
			//eg. method Package.dosomething(22)
			// in a Package method, dosomething(22) should be local.
			if _, ok  := ic.DefinedFunctions[token+"_m_"+ic.LastDefinedType.Name]; ok {
				var f = token+"_m_"+ic.LastDefinedType.Name

				if !ic.LastDefinedType.Empty() {
					ic.Assembly(ic.LastDefinedType.Push," ", ic.LastDefinedType.Name)
				}

				ic.ExpressionType = function.Flag

				return ic.Shunt(f)
			}
		}

	 	return ""
	})

	ilang.RegisterVariable(func(ic *ilang.Compiler, name string) ilang.Type {
		//Allow table values to be indexed in a method.
		if ic.GetFlag(Flag) && ic.LastDefinedType.Detail != nil {
			if _, ok := ic.LastDefinedType.Detail.Table[name]; ok {
				ic.DisableOwnership = true
				var value = ic.IndexUserType(ic.LastDefinedType.Name, name)
				ic.DisableOwnership = false

				ic.AssembleVar(name, value)
				ic.SetVariable(name+"_use", ilang.Used)
				return ic.ExpressionType
			}
		}
		return ilang.Undefined
	})

	ilang.RegisterShunt(".", ShuntMethodCall)
}

func Sync(ic *ilang.Compiler, variables ...string) {
	if ic.GetFlag(Flag) && ic.LastDefinedType.Detail != nil {

		for _, variable := range variables {

			if _, ok := ic.LastDefinedType.Detail.Table[variable]; ok {
				ic.SetUserType(ic.LastDefinedType.Name, variable, variable)
			}
		}
	}
}

func ShuntMethodCall(ic *ilang.Compiler, name string) string {
	var index = ic.Scan(ilang.Name)

	if f, ok  := ic.DefinedFunctions[index+"_m_"+ic.ExpressionType.GetComplexName()]; ok && len(f.Args) > 0 {
		var f = index+"_m_"+ic.ExpressionType.GetComplexName()
		ic.Assembly(ic.ExpressionType.Push," ", name)
		ic.ExpressionType = function.Flag
		return ic.Shunt(f)
	}

	ic.NextToken = index
	return ""
}

func NewEnd(ic *ilang.Compiler) {
	ic.Assembly("SHARE ", ic.LastDefinedType.Name)
	ic.LoseScope()
}

func Call(ic *ilang.Compiler, name string, t ilang.Type) {
	ic.Assembly(ic.RunFunction(name+"_m_"+t.GetComplexName()))
}

func ScanMethod(ic *ilang.Compiler) {
	ic.Header = false

	var name string = ic.Scan(ilang.Name)

	f := ic.DefinedFunctions[name]
	f.Method = true
	ic.DefinedFunctions[name] = f

	/*if name == "new" {
		ic.Scan('(')
		ic.ScanNew()
		return
	}*/

	var MethodType = ic.LastDefinedType

	var token = ic.Scan(0)
	if token == "(" {
		token = ic.Scan(0)
		if token != ")" {
			if t, ok := ic.DefinedTypes[token]; ok {
				MethodType = t
			} else {
				ic.NextToken = token
			}
		}

		ic.LastDefinedType = MethodType

		if MethodType.Name == "Game" && name == "new" {
			ic.NewGame = true
		}
		if MethodType.Name == "Game" && name == "draw" {
			ic.DrawGame = true
		}
		if MethodType.Name == "Game" && name == "update" {
			ic.UpdateGame = true
		}

		name += "_m_"+MethodType.Name

		ic.Assembly("FUNCTION ", name)
		ic.GainScope()

		if name == "new_m_"+MethodType.Name {

			ic.Assembly("PUSH ", len(MethodType.Detail.Elements))
			ic.Assembly("MAKE")
			ic.Assembly("GRAB ", MethodType.Name)

			ic.SetVariable(MethodType.Name, MethodType)
			ic.SetVariable(MethodType.Name+"_use", ilang.Used)
			ic.SetVariable(MethodType.Name+".", ilang.Protected)

		} else if  MethodType.Detail != nil && len(MethodType.Detail.Elements) > 0 {
			ic.Assembly("%v %v", MethodType.Pop, MethodType.Name)
			ic.SetVariable(MethodType.Name, MethodType)
			ic.SetVariable(MethodType.Name+"_use", ilang.Used)
			ic.SetVariable(MethodType.Name+".", ilang.Protected)
		}

		function.CreateFromArguments(name, ic)
		ic.SetFlag(Flag)

		f = ic.DefinedFunctions[name]
		if name == "new_m_"+MethodType.Name {
			ic.GainScope()
			ic.SetFlag(New)
			f.Returns = []ilang.Type{MethodType}

		}

		f.Method = true
		ic.DefinedFunctions[name] = f

		ic.InsertPlugins(name)

	//Functional methods.
	} else if token == "." {

		if !ic.TypeExists(name) {
			ic.RaiseError("Undefined type: ", name)
		}

		t := ic.DefinedTypes[name]
		ic.LastDefinedType = t

		name = ic.Scan(ilang.Name)
		name += "_m_"+t.GetComplexName()

		ic.Assembly("FUNCTION ", name)
		ic.GainScope()
		ic.Scan('(')

		function.CreateFromArguments(name, ic)

		if t.Detail == nil || len(t.Detail.Elements) > 0 {
			ic.Assembly("%v %v", t.Pop, t.Name)
			ic.SetVariable(t.Name, t)
			ic.SetVariable(t.Name+"_use", ilang.Used)
		}

		f = ic.DefinedFunctions[name]
		ic.SetFlag(Flag)

		f.Method = true
		ic.DefinedFunctions[name] = f

		ic.InsertPlugins(name)

	} else {
		var symbol = token
		var other = ic.Scan(ilang.Name)
		ic.Scan('{')

		if t, ok := ic.DefinedTypes[name]; ok {
			MethodType = t
		}

		var a = MethodType

		MethodType = ic.DefinedTypes[other]

		ic.LastDefinedType = MethodType

		var b = MethodType

		ilang.NewOperator(a, symbol, b, "SHARE %a\n SHARE %b\nRUN "+a.Name+"_"+symbol+"_"+b.Name+"\nGRAB %c", true)

		ic.Assembly("FUNCTION %s_%s_%s\n", a.Name, symbol, b.Name)
		ic.GainScope()
		ic.Assembly("GRAB b\nGRAB a\nARRAY c\n")
		for range a.Detail.Elements {
			ic.Assembly("PUT 0\n")
		}
		ic.InOperatorFunction = true

		ic.SetFlag(function.Flag)

		ic.SetVariable("c", a)
		ic.SetVariable("a", a)
		ic.SetVariable("b", b)
	}
}

<commit_msg>Allow methods to be called by tail.<commit_after>package method

import "github.com/qlova/ilang/src"
import "github.com/qlova/ilang/src/modules/function"

var Flag = ilang.NewFlag()
var New = ilang.NewFlag()

func init() {
	ilang.RegisterToken([]string{"method"}, ScanMethod)
	ilang.RegisterListener(New, NewEnd)

	ilang.RegisterDefault(func(ic *ilang.Compiler) bool {
		token := ic.LastToken

		if ic.TypeExists(token) {
			if ic.DefinedTypes[token].Empty() && ic.Peek() == "." {
				ic.Scan('.')
				ic.ExpressionType = function.Flag
				var name = ic.Scan(ilang.Name)
				ic.Shunt(name+"_m_"+token)
				ic.Scan('(') //BUG I don't know why this has to be here.
				return true
			}
		}

		if ic.GetFlag(Flag) && ic.LastDefinedType.Detail != nil {
			if _, ok := ic.LastDefinedType.Detail.Table[token]; ok {
				ic.NextToken = ic.LastDefinedType.Name
				ic.NextNextToken = "."
				ic.NextNextNextToken = token
				ic.ScanStatement()
				return true
			}
		}

		return false
	})

	ilang.RegisterExpression(func(ic *ilang.Compiler) string {
		token := ic.LastToken

		if ic.TypeExists(token) {
			if ic.DefinedTypes[token].Empty() && ic.Peek() == "." {
				ic.Scan('.')
				ic.ExpressionType = function.Flag
				var name = ic.Scan(ilang.Name)
				return ic.Shunt(name+"_m_"+ic.DefinedTypes[token].GetComplexName())
			}
		}

		if ic.GetFlag(Flag) {
			if ic.TypeExists(token) && ic.LastDefinedType.Super == token {
	 			ic.ExpressionType = ic.DefinedTypes[ic.LastDefinedType.Super]
				return ic.Shunt(ic.LastDefinedType.Name)
		 	}

			//Scope methods with multiple arguments inside the method.
			//eg. method Package.dosomething(22)
			// in a Package method, dosomething(22) should be local.
			if _, ok  := ic.DefinedFunctions[token+"_m_"+ic.LastDefinedType.Name]; ok {
				var f = token+"_m_"+ic.LastDefinedType.Name

				if !ic.LastDefinedType.Empty() {
					ic.Assembly(ic.LastDefinedType.Push," ", ic.LastDefinedType.Name)
				}

				ic.ExpressionType = function.Flag

				return ic.Shunt(f)
			}
		}

	 	return ""
	})

	ilang.RegisterVariable(func(ic *ilang.Compiler, name string) ilang.Type {
		//Allow table values to be indexed in a method.
		if ic.GetFlag(Flag) && ic.LastDefinedType.Detail != nil {
			if _, ok := ic.LastDefinedType.Detail.Table[name]; ok {
				ic.DisableOwnership = true
				var value = ic.IndexUserType(ic.LastDefinedType.Name, name)
				ic.DisableOwnership = false

				ic.AssembleVar(name, value)
				ic.SetVariable(name+"_use", ilang.Used)
				return ic.ExpressionType
			}
		}
		return ilang.Undefined
	})

	ilang.RegisterShunt(".", ShuntMethodCall)
}

func Sync(ic *ilang.Compiler, variables ...string) {
	if ic.GetFlag(Flag) && ic.LastDefinedType.Detail != nil {

		for _, variable := range variables {

			if _, ok := ic.LastDefinedType.Detail.Table[variable]; ok {
				ic.SetUserType(ic.LastDefinedType.Name, variable, variable)
			}
		}
	}
}

func ShuntMethodCall(ic *ilang.Compiler, name string) string {
	var index = ic.Scan(ilang.Name)

	if _, ok  := ic.DefinedFunctions[index+"_m_"+ic.ExpressionType.GetComplexName()]; ok {
		var f = index+"_m_"+ic.ExpressionType.GetComplexName()
		ic.Assembly(ic.ExpressionType.Push," ", name)
		ic.ExpressionType = function.Flag
		return ic.Shunt(f)
	}

	ic.NextToken = index
	return ""
}

func NewEnd(ic *ilang.Compiler) {
	ic.Assembly("SHARE ", ic.LastDefinedType.Name)
	ic.LoseScope()
}

func Call(ic *ilang.Compiler, name string, t ilang.Type) {
	ic.Assembly(ic.RunFunction(name+"_m_"+t.GetComplexName()))
}

func ScanMethod(ic *ilang.Compiler) {
	ic.Header = false

	var name string = ic.Scan(ilang.Name)

	f := ic.DefinedFunctions[name]
	f.Method = true
	ic.DefinedFunctions[name] = f

	/*if name == "new" {
		ic.Scan('(')
		ic.ScanNew()
		return
	}*/

	var MethodType = ic.LastDefinedType

	var token = ic.Scan(0)
	if token == "(" {
		token = ic.Scan(0)
		if token != ")" {
			if t, ok := ic.DefinedTypes[token]; ok {
				MethodType = t
			} else {
				ic.NextToken = token
			}
		}

		ic.LastDefinedType = MethodType

		if MethodType.Name == "Game" && name == "new" {
			ic.NewGame = true
		}
		if MethodType.Name == "Game" && name == "draw" {
			ic.DrawGame = true
		}
		if MethodType.Name == "Game" && name == "update" {
			ic.UpdateGame = true
		}

		name += "_m_"+MethodType.Name

		ic.Assembly("FUNCTION ", name)
		ic.GainScope()

		if name == "new_m_"+MethodType.Name {

			ic.Assembly("PUSH ", len(MethodType.Detail.Elements))
			ic.Assembly("MAKE")
			ic.Assembly("GRAB ", MethodType.Name)

			ic.SetVariable(MethodType.Name, MethodType)
			ic.SetVariable(MethodType.Name+"_use", ilang.Used)
			ic.SetVariable(MethodType.Name+".", ilang.Protected)

		} else if  MethodType.Detail != nil && len(MethodType.Detail.Elements) > 0 {
			ic.Assembly("%v %v", MethodType.Pop, MethodType.Name)
			ic.SetVariable(MethodType.Name, MethodType)
			ic.SetVariable(MethodType.Name+"_use", ilang.Used)
			ic.SetVariable(MethodType.Name+".", ilang.Protected)
		}

		function.CreateFromArguments(name, ic)
		ic.SetFlag(Flag)

		f = ic.DefinedFunctions[name]
		if name == "new_m_"+MethodType.Name {
			ic.GainScope()
			ic.SetFlag(New)
			f.Returns = []ilang.Type{MethodType}

		}

		f.Method = true
		ic.DefinedFunctions[name] = f

		ic.InsertPlugins(name)

	//Functional methods.
	} else if token == "." {

		if !ic.TypeExists(name) {
			ic.RaiseError("Undefined type: ", name)
		}

		t := ic.DefinedTypes[name]
		ic.LastDefinedType = t

		name = ic.Scan(ilang.Name)
		name += "_m_"+t.GetComplexName()

		ic.Assembly("FUNCTION ", name)
		ic.GainScope()
		ic.Scan('(')

		function.CreateFromArguments(name, ic)

		if t.Detail == nil || len(t.Detail.Elements) > 0 {
			ic.Assembly("%v %v", t.Pop, t.Name)
			ic.SetVariable(t.Name, t)
			ic.SetVariable(t.Name+"_use", ilang.Used)
		}

		f = ic.DefinedFunctions[name]
		ic.SetFlag(Flag)

		f.Method = true
		ic.DefinedFunctions[name] = f

		ic.InsertPlugins(name)

	} else {
		var symbol = token
		var other = ic.Scan(ilang.Name)
		ic.Scan('{')

		if t, ok := ic.DefinedTypes[name]; ok {
			MethodType = t
		}

		var a = MethodType

		MethodType = ic.DefinedTypes[other]

		ic.LastDefinedType = MethodType

		var b = MethodType

		ilang.NewOperator(a, symbol, b, "SHARE %a\n SHARE %b\nRUN "+a.Name+"_"+symbol+"_"+b.Name+"\nGRAB %c", true)

		ic.Assembly("FUNCTION %s_%s_%s\n", a.Name, symbol, b.Name)
		ic.GainScope()
		ic.Assembly("GRAB b\nGRAB a\nARRAY c\n")
		for range a.Detail.Elements {
			ic.Assembly("PUT 0\n")
		}
		ic.InOperatorFunction = true

		ic.SetFlag(function.Flag)

		ic.SetVariable("c", a)
		ic.SetVariable("a", a)
		ic.SetVariable("b", b)
	}
}

<|endoftext|>


<commit_before>package buf

import (
	"io"

	"v2ray.com/core/common/errors"
)

// BufferToBytesWriter is a Writer that writes alloc.Buffer into underlying writer.
type BufferToBytesWriter struct {
	io.Writer
}

func NewBufferToBytesWriter(writer io.Writer) *BufferToBytesWriter {
	return &BufferToBytesWriter{
		Writer: writer,
	}
}

// WriteMultiBuffer implements Writer. This method takes ownership of the given buffer.
func (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {
	defer mb.Release()

	bs := mb.ToNetBuffers()
	_, err := bs.WriteTo(w)
	return err
}

func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
	if readerFrom, ok := w.Writer.(io.ReaderFrom); ok {
		return readerFrom.ReadFrom(reader)
	}

	var sc SizeCounter
	err := Copy(NewReader(reader), w, CountSize(&sc))
	return sc.Size, err
}

type BufferedWriter struct {
	writer       Writer
	legacyWriter io.Writer
	buffer       *Buffer
	buffered     bool
}

func NewBufferedWriter(writer Writer) *BufferedWriter {
	w := &BufferedWriter{
		writer:   writer,
		buffer:   New(),
		buffered: true,
	}
	if lw, ok := writer.(io.Writer); ok {
		w.legacyWriter = lw
	}
	return w
}

func (w *BufferedWriter) Write(b []byte) (int, error) {
	if !w.buffered && w.legacyWriter != nil {
		return w.legacyWriter.Write(b)
	}

	totalBytes := 0
	for len(b) > 0 {
		if w.buffer == nil {
			w.buffer = New()
		}

		nBytes, err := w.buffer.Write(b)
		totalBytes += nBytes
		if err != nil {
			return totalBytes, err
		}
		if !w.buffered || w.buffer.IsFull() {
			if err := w.Flush(); err != nil {
				return totalBytes, err
			}
		}
		b = b[nBytes:]
	}

	return totalBytes, nil
}

func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
	if !w.buffered {
		return w.writer.WriteMultiBuffer(b)
	}

	defer b.Release()

	for !b.IsEmpty() {
		if err := w.buffer.AppendSupplier(ReadFrom(&b)); err != nil {
			return err
		}
		if w.buffer.IsFull() {
			if err := w.Flush(); err != nil {
				return err
			}
		}
	}

	return nil
}

func (w *BufferedWriter) Flush() error {
	if !w.buffer.IsEmpty() {
		if err := w.writer.WriteMultiBuffer(NewMultiBufferValue(w.buffer)); err != nil {
			return err
		}

		if w.buffered {
			w.buffer = New()
		} else {
			w.buffer = nil
		}
	}
	return nil
}

func (w *BufferedWriter) SetBuffered(f bool) error {
	w.buffered = f
	if !f {
		return w.Flush()
	}
	return nil
}

// ReadFrom implements io.ReaderFrom.
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
	var sc SizeCounter
	if !w.buffer.IsEmpty() {
		sc.Size += int64(w.buffer.Len())
		if err := w.Flush(); err != nil {
			return sc.Size, err
		}
	}

	w.buffered = false
	err := Copy(NewReader(reader), w, CountSize(&sc))

	return sc.Size, err
}

type seqWriter struct {
	writer io.Writer
}

func (w *seqWriter) WriteMultiBuffer(mb MultiBuffer) error {
	defer mb.Release()

	for _, b := range mb {
		if b.IsEmpty() {
			continue
		}
		if _, err := w.writer.Write(b.Bytes()); err != nil {
			return err
		}
	}

	return nil
}

type noOpWriter struct{}

func (noOpWriter) WriteMultiBuffer(b MultiBuffer) error {
	b.Release()
	return nil
}

type noOpBytesWriter struct{}

func (noOpBytesWriter) Write(b []byte) (int, error) {
	return len(b), nil
}

func (noOpBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
	b := New()
	defer b.Release()

	totalBytes := int64(0)
	for {
		err := b.Reset(ReadFrom(reader))
		totalBytes += int64(b.Len())
		if err != nil {
			if errors.Cause(err) == io.EOF {
				return totalBytes, nil
			}
			return totalBytes, err
		}
	}
}

var (
	// Discard is a Writer that swallows all contents written in.
	Discard Writer = noOpWriter{}

	// DiscardBytes is an io.Writer that swallows all contents written in.
	DiscardBytes io.Writer = noOpBytesWriter{}
)
<commit_msg>cleanup<commit_after>package buf

import (
	"io"

	"v2ray.com/core/common/errors"
)

// BufferToBytesWriter is a Writer that writes alloc.Buffer into underlying writer.
type BufferToBytesWriter struct {
	io.Writer
}

func NewBufferToBytesWriter(writer io.Writer) *BufferToBytesWriter {
	return &BufferToBytesWriter{
		Writer: writer,
	}
}

// WriteMultiBuffer implements Writer. This method takes ownership of the given buffer.
func (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {
	defer mb.Release()

	bs := mb.ToNetBuffers()
	_, err := bs.WriteTo(w)
	return err
}

func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
	var sc SizeCounter
	err := Copy(NewReader(reader), w, CountSize(&sc))
	return sc.Size, err
}

type BufferedWriter struct {
	writer       Writer
	legacyWriter io.Writer
	buffer       *Buffer
	buffered     bool
}

func NewBufferedWriter(writer Writer) *BufferedWriter {
	w := &BufferedWriter{
		writer:   writer,
		buffer:   New(),
		buffered: true,
	}
	if lw, ok := writer.(io.Writer); ok {
		w.legacyWriter = lw
	}
	return w
}

func (w *BufferedWriter) Write(b []byte) (int, error) {
	if !w.buffered && w.legacyWriter != nil {
		return w.legacyWriter.Write(b)
	}

	totalBytes := 0
	for len(b) > 0 {
		if w.buffer == nil {
			w.buffer = New()
		}

		nBytes, err := w.buffer.Write(b)
		totalBytes += nBytes
		if err != nil {
			return totalBytes, err
		}
		if !w.buffered || w.buffer.IsFull() {
			if err := w.Flush(); err != nil {
				return totalBytes, err
			}
		}
		b = b[nBytes:]
	}

	return totalBytes, nil
}

func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
	if !w.buffered {
		return w.writer.WriteMultiBuffer(b)
	}

	defer b.Release()

	for !b.IsEmpty() {
		if err := w.buffer.AppendSupplier(ReadFrom(&b)); err != nil {
			return err
		}
		if w.buffer.IsFull() {
			if err := w.Flush(); err != nil {
				return err
			}
		}
	}

	return nil
}

func (w *BufferedWriter) Flush() error {
	if !w.buffer.IsEmpty() {
		if err := w.writer.WriteMultiBuffer(NewMultiBufferValue(w.buffer)); err != nil {
			return err
		}

		if w.buffered {
			w.buffer = New()
		} else {
			w.buffer = nil
		}
	}
	return nil
}

func (w *BufferedWriter) SetBuffered(f bool) error {
	w.buffered = f
	if !f {
		return w.Flush()
	}
	return nil
}

// ReadFrom implements io.ReaderFrom.
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
	var sc SizeCounter
	if !w.buffer.IsEmpty() {
		sc.Size += int64(w.buffer.Len())
		if err := w.Flush(); err != nil {
			return sc.Size, err
		}
	}

	w.buffered = false
	err := Copy(NewReader(reader), w, CountSize(&sc))

	return sc.Size, err
}

type seqWriter struct {
	writer io.Writer
}

func (w *seqWriter) WriteMultiBuffer(mb MultiBuffer) error {
	defer mb.Release()

	for _, b := range mb {
		if b.IsEmpty() {
			continue
		}
		if _, err := w.writer.Write(b.Bytes()); err != nil {
			return err
		}
	}

	return nil
}

type noOpWriter struct{}

func (noOpWriter) WriteMultiBuffer(b MultiBuffer) error {
	b.Release()
	return nil
}

type noOpBytesWriter struct{}

func (noOpBytesWriter) Write(b []byte) (int, error) {
	return len(b), nil
}

func (noOpBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
	b := New()
	defer b.Release()

	totalBytes := int64(0)
	for {
		err := b.Reset(ReadFrom(reader))
		totalBytes += int64(b.Len())
		if err != nil {
			if errors.Cause(err) == io.EOF {
				return totalBytes, nil
			}
			return totalBytes, err
		}
	}
}

var (
	// Discard is a Writer that swallows all contents written in.
	Discard Writer = noOpWriter{}

	// DiscardBytes is an io.Writer that swallows all contents written in.
	DiscardBytes io.Writer = noOpBytesWriter{}
)
<|endoftext|>


<commit_before>package etcd

import (
	"crypto/tls"
	"errors"
	"io/ioutil"
	"net"
	"net/http"
	"path"
	"strings"
	"time"
)

const (
	HTTP = iota
	HTTPS
)

type Cluster struct {
	Leader   string
	Machines []string
}

type Config struct {
	CertFile string
	KeyFile  string
	Scheme   string
	Timeout  time.Duration
}

type Client struct {
	cluster    Cluster
	config     Config
	httpClient *http.Client
}

// Setup a basic conf and cluster
func NewClient() *Client {

	// default leader and machines
	cluster := Cluster{
		Leader:   "0.0.0.0:4001",
		Machines: make([]string, 1),
	}
	cluster.Machines[0] = "0.0.0.0:4001"

	config := Config{
		// default use http
		Scheme: "http",
		// default timeout is one second
		Timeout: time.Second,
	}

	tr := &http.Transport{
		Dial: dialTimeout,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}

	return &Client{
		cluster:    cluster,
		config:     config,
		httpClient: &http.Client{Transport: tr},
	}

}

func (c *Client) SetCertAndKey(cert string, key string) (bool, error) {

	if cert != "" && key != "" {
		tlsCert, err := tls.LoadX509KeyPair(cert, key)

		if err != nil {
			return false, err
		}

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				Certificates:       []tls.Certificate{tlsCert},
				InsecureSkipVerify: true,
			},
			Dial: dialTimeout,
		}

		c.httpClient = &http.Client{Transport: tr}
		return true, nil
	}
	return false, errors.New("Require both cert and key path")
}

func (c *Client) SetScheme(scheme int) (bool, error) {
	if scheme == HTTP {
		c.config.Scheme = "http"
		return true, nil
	}
	if scheme == HTTPS {
		c.config.Scheme = "https"
		return true, nil
	}
	return false, errors.New("Unknown Scheme")
}

// Try to sync from the given machine
func (c *Client) SetCluster(machines []string) bool {
	success := c.internalSyncCluster(machines)
	return success
}

// sycn cluster information using the existing machine list
func (c *Client) SyncCluster() bool {
	success := c.internalSyncCluster(c.cluster.Machines)
	return success
}

// sync cluster information by providing machine list
func (c *Client) internalSyncCluster(machines []string) bool {
	for _, machine := range machines {
		httpPath := c.createHttpPath(machine, "machines")
		resp, err := c.httpClient.Get(httpPath)
		if err != nil {
			// try another machine in the cluster
			continue
		} else {
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				// try another machine in the cluster
				continue
			}
			// update Machines List
			c.cluster.Machines = strings.Split(string(b), ",")
			logger.Debug("sync.machines ", c.cluster.Machines)
			return true
		}
	}
	return false
}

// serverName should contain both hostName and port
func (c *Client) createHttpPath(serverName string, _path string) string {
	httpPath := path.Join(serverName, _path)
	httpPath = c.config.Scheme + "://" + httpPath
	return httpPath
}

// Dial with timeout.
func dialTimeout(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, time.Second)
}

func (c *Client) getHttpPath(s ...string) string {
	httpPath := path.Join(c.cluster.Leader, version)

	for _, seg := range s {
		httpPath = path.Join(httpPath, seg)
	}

	httpPath = c.config.Scheme + "://" + httpPath
	return httpPath
}

func (c *Client) updateLeader(httpPath string) {
	// httpPath http://127.0.0.1:4001/v1...
	leader := strings.Split(httpPath, "://")[1]
	// we want to have 127.0.0.1:4001

	leader = strings.Split(leader, "/")[0]
	logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, leader)
	c.cluster.Leader = leader
}

// Wrap GET, POST and internal error handling
func (c *Client) sendRequest(method string, _path string, body string) (*http.Response, error) {

	var resp *http.Response
	var err error
	var req *http.Request

	retry := 0
	// if we connect to a follower, we will retry until we found a leader
	for {

		httpPath := c.getHttpPath(_path)
		logger.Debug("send.request.to ", httpPath)
		if body == "" {

			req, _ = http.NewRequest(method, httpPath, nil)

		} else {
			req, _ = http.NewRequest(method, httpPath, strings.NewReader(body))
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
		}

		resp, err = c.httpClient.Do(req)

		logger.Debug("recv.response.from ", httpPath)
		// network error, change a machine!
		if err != nil {
			retry++
			if retry > 2*len(c.cluster.Machines) {
				return nil, errors.New("Cannot reach servers")
			}
			num := retry % len(c.cluster.Machines)
			logger.Debug("update.leader[", c.cluster.Leader, ",", c.cluster.Machines[num], "]")
			c.cluster.Leader = c.cluster.Machines[num]
			time.Sleep(time.Millisecond * 200)
			continue
		}

		if resp != nil {
			if resp.StatusCode == http.StatusTemporaryRedirect {
				httpPath := resp.Header.Get("Location")

				resp.Body.Close()

				if httpPath == "" {
					return nil, errors.New("Cannot get redirection location")
				}

				c.updateLeader(httpPath)
				logger.Debug("send.redirect")
				// try to connect the leader
				continue
			} else if resp.StatusCode == http.StatusInternalServerError {
				retry++
				if retry > 2*len(c.cluster.Machines) {
					return nil, errors.New("Cannot reach servers")
				}
				resp.Body.Close()
				continue
			} else {
				logger.Debug("send.return.response ", httpPath)
				break
			}

		}
		logger.Debug("error.from ", httpPath, " ", err.Error())
		return nil, err
	}
	return resp, nil
}
<commit_msg>hack(go-etcd): stop appending schema to everything<commit_after>package etcd

import (
	"crypto/tls"
	"errors"
	"io/ioutil"
	"net"
	"net/http"
	"path"
	"strings"
	"time"
)

const (
	HTTP = iota
	HTTPS
)

type Cluster struct {
	Leader   string
	Machines []string
}

type Config struct {
	CertFile string
	KeyFile  string
	Scheme   string
	Timeout  time.Duration
}

type Client struct {
	cluster    Cluster
	config     Config
	httpClient *http.Client
}

// Setup a basic conf and cluster
func NewClient() *Client {

	// default leader and machines
	cluster := Cluster{
		Leader:   "0.0.0.0:4001",
		Machines: make([]string, 1),
	}
	cluster.Machines[0] = "0.0.0.0:4001"

	config := Config{
		// default use http
		Scheme: "http",
		// default timeout is one second
		Timeout: time.Second,
	}

	tr := &http.Transport{
		Dial: dialTimeout,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}

	return &Client{
		cluster:    cluster,
		config:     config,
		httpClient: &http.Client{Transport: tr},
	}

}

func (c *Client) SetCertAndKey(cert string, key string) (bool, error) {

	if cert != "" && key != "" {
		tlsCert, err := tls.LoadX509KeyPair(cert, key)

		if err != nil {
			return false, err
		}

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				Certificates:       []tls.Certificate{tlsCert},
				InsecureSkipVerify: true,
			},
			Dial: dialTimeout,
		}

		c.httpClient = &http.Client{Transport: tr}
		return true, nil
	}
	return false, errors.New("Require both cert and key path")
}

func (c *Client) SetScheme(scheme int) (bool, error) {
	if scheme == HTTP {
		c.config.Scheme = "http"
		return true, nil
	}
	if scheme == HTTPS {
		c.config.Scheme = "https"
		return true, nil
	}
	return false, errors.New("Unknown Scheme")
}

// Try to sync from the given machine
func (c *Client) SetCluster(machines []string) bool {
	success := c.internalSyncCluster(machines)
	return success
}

// sycn cluster information using the existing machine list
func (c *Client) SyncCluster() bool {
	success := c.internalSyncCluster(c.cluster.Machines)
	return success
}

// sync cluster information by providing machine list
func (c *Client) internalSyncCluster(machines []string) bool {
	for _, machine := range machines {
		httpPath := c.createHttpPath(machine, "machines")
		resp, err := c.httpClient.Get(httpPath)
		if err != nil {
			// try another machine in the cluster
			continue
		} else {
			b, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				// try another machine in the cluster
				continue
			}
			// update Machines List
			c.cluster.Machines = strings.Split(string(b), ",")
			logger.Debug("sync.machines ", c.cluster.Machines)
			return true
		}
	}
	return false
}

// serverName should contain both hostName and port
func (c *Client) createHttpPath(serverName string, _path string) string {
	httpPath := path.Join(serverName, _path)
	return httpPath
}

// Dial with timeout.
func dialTimeout(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, time.Second)
}

func (c *Client) getHttpPath(s ...string) string {
	httpPath := path.Join(c.cluster.Leader, version)

	for _, seg := range s {
		httpPath = path.Join(httpPath, seg)
	}

	httpPath = c.config.Scheme + "://" + httpPath
	return httpPath
}

func (c *Client) updateLeader(httpPath string) {
	// httpPath http://127.0.0.1:4001/v1...
	leader := strings.Split(httpPath, "://")[1]
	// we want to have 127.0.0.1:4001

	leader = strings.Split(leader, "/")[0]
	logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, leader)
	c.cluster.Leader = leader
}

// Wrap GET, POST and internal error handling
func (c *Client) sendRequest(method string, _path string, body string) (*http.Response, error) {

	var resp *http.Response
	var err error
	var req *http.Request

	retry := 0
	// if we connect to a follower, we will retry until we found a leader
	for {

		httpPath := c.getHttpPath(_path)
		logger.Debug("send.request.to ", httpPath)
		if body == "" {

			req, _ = http.NewRequest(method, httpPath, nil)

		} else {
			req, _ = http.NewRequest(method, httpPath, strings.NewReader(body))
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
		}

		resp, err = c.httpClient.Do(req)

		logger.Debug("recv.response.from ", httpPath)
		// network error, change a machine!
		if err != nil {
			retry++
			if retry > 2*len(c.cluster.Machines) {
				return nil, errors.New("Cannot reach servers")
			}
			num := retry % len(c.cluster.Machines)
			logger.Debug("update.leader[", c.cluster.Leader, ",", c.cluster.Machines[num], "]")
			c.cluster.Leader = c.cluster.Machines[num]
			time.Sleep(time.Millisecond * 200)
			continue
		}

		if resp != nil {
			if resp.StatusCode == http.StatusTemporaryRedirect {
				httpPath := resp.Header.Get("Location")

				resp.Body.Close()

				if httpPath == "" {
					return nil, errors.New("Cannot get redirection location")
				}

				c.updateLeader(httpPath)
				logger.Debug("send.redirect")
				// try to connect the leader
				continue
			} else if resp.StatusCode == http.StatusInternalServerError {
				retry++
				if retry > 2*len(c.cluster.Machines) {
					return nil, errors.New("Cannot reach servers")
				}
				resp.Body.Close()
				continue
			} else {
				logger.Debug("send.return.response ", httpPath)
				break
			}

		}
		logger.Debug("error.from ", httpPath, " ", err.Error())
		return nil, err
	}
	return resp, nil
}
<|endoftext|>


<commit_before>package taskqueue

import (
	"encoding/base64"
	"net/url"
	"testing"

	"github.com/morikuni/chat/src/domain/event"
	"github.com/stretchr/testify/assert"
)

func TestCreateTask(t *testing.T) {

	type Input struct {
		Event event.Event
	}
	type Expect struct {
	}

	assert := assert.New(t)

	e := event.AccountCreated{
		UserID: 12345,
		Email:  "hoge@email.com",
	}

	task, err := createTask(e)

	assert.NoError(err)
	assert.Equal("POST", task.Method)

	values, err := url.ParseQuery(string(task.Payload))
	assert.NoError(err)
	assert.Equal("account_created", values.Get("name"))
	payload, err := base64.StdEncoding.DecodeString(values.Get("payload"))
	assert.NoError(err)
	assert.JSONEq(`{"user_id": 12345, "email": "hoge@email.com"}`, string(payload))
}
<commit_msg>Remove test of serialization<commit_after><|endoftext|>


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

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/pkg/errors"
	"golang.org/x/perf/benchstat"
)

// TODO: Add unit test.
type Benchmarker struct {
	logger Logger

	benchmarkArgs  []string
	benchFunc      string
	resultCacheDir string

	c    *commander
	repo *git.Repository
}

func newBenchmarker(logger Logger, env Environment, c *commander, benchTime time.Duration, benchTimeout time.Duration, resultCacheDir, packagePath string) *Benchmarker {
	return &Benchmarker{
		logger:    logger,
		benchFunc: env.BenchFunc(),
		benchmarkArgs: []string{
			// TODO(bwplotka): Allow memprofiles.
			// 'go test' flags: https://golang.org/cmd/go/#hdr-Testing_flags
			"go test",
			"-mod", "vendor",
			"-run", `"^$"`,
			"-bench", fmt.Sprintf(`"^%s$"`, env.BenchFunc()),
			"-benchmem",
			"-benchtime", benchTime.String(),
			"-timeout", benchTimeout.String(),
			packagePath,
		},
		c:              c,
		repo:           env.Repo(),
		resultCacheDir: resultCacheDir,
	}
}

func (b *Benchmarker) benchOutFileName(commit plumbing.Hash) (string, error) {
	// Sanitize bench func.
	bb := bytes.Buffer{}
	e := base64.NewEncoder(base64.StdEncoding, &bb)
	if _, err := e.Write([]byte(b.benchFunc)); err != nil {
		return "", err
	}
	if err := e.Close(); err != nil {
		return "", err
	}

	return fmt.Sprintf("%s-%s.out", bb.String(), commit.String()), nil
}

func (b *Benchmarker) exec(pkgRoot string, commit plumbing.Hash) (string, error) {
	fileName, err := b.benchOutFileName(commit)
	if err != nil {
		return "", err
	}

	if _, err := ioutil.ReadFile(filepath.Join(b.resultCacheDir, fileName)); err == nil {
		fmt.Println("Found previous results for ", fileName, b.benchFunc, "Reusing.")
		return filepath.Join(b.resultCacheDir, fileName), nil
	}

	// TODO Switch working directory before entering this function.
	benchCmd := []string{"sh", "-c", strings.Join(append([]string{"cd", pkgRoot, "&&"}, b.benchmarkArgs...), " ")}

	b.logger.Println("Executing benchmark command for", commit.String(), "\n", benchCmd)
	out, err := b.c.exec(benchCmd...)
	if err != nil {
		return "", errors.Wrap(err, "benchmark ended with an error.")
	}

	fn := filepath.Join(b.resultCacheDir, fileName)
	if b.resultCacheDir != "" {
		if err := os.MkdirAll(b.resultCacheDir, os.ModePerm); err != nil {
			return "", err
		}
	}
	if err := ioutil.WriteFile(fn, []byte(out), os.ModePerm); err != nil {
		return "", err
	}
	return fn, nil
}

func (b *Benchmarker) compareSubBenchmarks(string) ([]*benchstat.Table, error) {
	// TODO(bwplotka): Implement.
	return nil, errors.New("not implemented")
}

func compareBenchmarks(files ...string) ([]*benchstat.Table, error) {
	c := &benchstat.Collection{}

	for _, file := range files {
		f, err := os.Open(file)
		if err != nil {
			return nil, err
		}
		defer f.Close()

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

	tables := c.Tables()
	if tables == nil {
		return nil, errors.New("didn't match any existing benchmarks")
	}

	return tables, nil
}
<commit_msg>Make -delta-test=none by default for benchstat (#430)<commit_after>// Copyright 2020 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/pkg/errors"
	"golang.org/x/perf/benchstat"
)

// TODO: Add unit test.
type Benchmarker struct {
	logger Logger

	benchmarkArgs  []string
	benchFunc      string
	resultCacheDir string

	c    *commander
	repo *git.Repository
}

func newBenchmarker(logger Logger, env Environment, c *commander, benchTime time.Duration, benchTimeout time.Duration, resultCacheDir, packagePath string) *Benchmarker {
	return &Benchmarker{
		logger:    logger,
		benchFunc: env.BenchFunc(),
		benchmarkArgs: []string{
			// TODO(bwplotka): Allow memprofiles.
			// 'go test' flags: https://golang.org/cmd/go/#hdr-Testing_flags
			"go test",
			"-mod", "vendor",
			"-run", `"^$"`,
			"-bench", fmt.Sprintf(`"^%s$"`, env.BenchFunc()),
			"-benchmem",
			"-benchtime", benchTime.String(),
			"-timeout", benchTimeout.String(),
			packagePath,
		},
		c:              c,
		repo:           env.Repo(),
		resultCacheDir: resultCacheDir,
	}
}

func (b *Benchmarker) benchOutFileName(commit plumbing.Hash) (string, error) {
	// Sanitize bench func.
	bb := bytes.Buffer{}
	e := base64.NewEncoder(base64.StdEncoding, &bb)
	if _, err := e.Write([]byte(b.benchFunc)); err != nil {
		return "", err
	}
	if err := e.Close(); err != nil {
		return "", err
	}

	return fmt.Sprintf("%s-%s.out", bb.String(), commit.String()), nil
}

func (b *Benchmarker) exec(pkgRoot string, commit plumbing.Hash) (string, error) {
	fileName, err := b.benchOutFileName(commit)
	if err != nil {
		return "", err
	}

	if _, err := ioutil.ReadFile(filepath.Join(b.resultCacheDir, fileName)); err == nil {
		fmt.Println("Found previous results for ", fileName, b.benchFunc, "Reusing.")
		return filepath.Join(b.resultCacheDir, fileName), nil
	}

	// TODO Switch working directory before entering this function.
	benchCmd := []string{"sh", "-c", strings.Join(append([]string{"cd", pkgRoot, "&&"}, b.benchmarkArgs...), " ")}

	b.logger.Println("Executing benchmark command for", commit.String(), "\n", benchCmd)
	out, err := b.c.exec(benchCmd...)
	if err != nil {
		return "", errors.Wrap(err, "benchmark ended with an error.")
	}

	fn := filepath.Join(b.resultCacheDir, fileName)
	if b.resultCacheDir != "" {
		if err := os.MkdirAll(b.resultCacheDir, os.ModePerm); err != nil {
			return "", err
		}
	}
	if err := ioutil.WriteFile(fn, []byte(out), os.ModePerm); err != nil {
		return "", err
	}
	return fn, nil
}

func (b *Benchmarker) compareSubBenchmarks(string) ([]*benchstat.Table, error) {
	// TODO(bwplotka): Implement.
	return nil, errors.New("not implemented")
}

func compareBenchmarks(files ...string) ([]*benchstat.Table, error) {
	c := &benchstat.Collection{
		DeltaTest: benchstat.NoDeltaTest,
	}

	for _, file := range files {
		f, err := os.Open(file)
		if err != nil {
			return nil, err
		}
		defer f.Close()

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

	tables := c.Tables()
	if tables == nil {
		return nil, errors.New("didn't match any existing benchmarks")
	}

	return tables, nil
}
<|endoftext|>