<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

// NodeVersion is the current node version
var NodeVersion = "?"

// RunScript runs some node code
func (p *Plugins) RunScript(script string) (cmd *exec.Cmd, done func()) {
	useTmpFile := true
	f, err := ioutil.TempFile("", "heroku-script-")
	if err != nil {
		useTmpFile = false
		LogIfError(err)
	}
	defer f.Close()
	if _, err := f.WriteString(script); err != nil {
		useTmpFile = false
		LogIfError(err)
	}
	if useTmpFile {
		cmd = exec.Command(p.nodeBinPath(), f.Name())
	} else {
		cmd = exec.Command(p.nodeBinPath(), "-e", script)
	}
	cmd.Env = append([]string{"NODE_PATH=" + p.modulesPath()}, os.Environ()...)
	if debugging {
		log.Printf("running node NODE_PATH=%s %s\n%s\n", p.modulesPath(), cmd.Path, script)
	}
	return cmd, func() {
		os.Remove(f.Name())
	}
}

func (p *Plugins) nodeBinPath() string {
	b := os.Getenv("HEROKU_NODE_PATH")
	if b == "" {
		b = filepath.Join(AppDir, "lib", "node-"+NodeVersion)
	}
	if runtime.GOOS == WINDOWS {
		b = b + ".exe"
	}
	if exists, _ := fileExists(b); !exists {
		var err error
		b, err = exec.LookPath("node")
		must(err)
	}
	return b
}

func (p *Plugins) modulesPath() string {
	return filepath.Join(p.Path, "node_modules")
}
<commit_msg>clean up debug output<commit_after>package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

// NodeVersion is the current node version
var NodeVersion = "?"

// RunScript runs some node code
func (p *Plugins) RunScript(script string) (cmd *exec.Cmd, done func()) {
	useTmpFile := true
	f, err := ioutil.TempFile("", "heroku-script-")
	if err != nil {
		useTmpFile = false
		LogIfError(err)
	}
	defer f.Close()
	if _, err := f.WriteString(script); err != nil {
		useTmpFile = false
		LogIfError(err)
	}
	if useTmpFile {
		cmd = exec.Command(p.nodeBinPath(), f.Name())
	} else {
		cmd = exec.Command(p.nodeBinPath(), "-e", script)
	}
	cmd.Env = append([]string{"NODE_PATH=" + p.modulesPath()}, os.Environ()...)
	return cmd, func() {
		os.Remove(f.Name())
	}
}

func (p *Plugins) nodeBinPath() string {
	b := os.Getenv("HEROKU_NODE_PATH")
	if b == "" {
		b = filepath.Join(AppDir, "lib", "node-"+NodeVersion)
	}
	if runtime.GOOS == WINDOWS {
		b = b + ".exe"
	}
	if exists, _ := fileExists(b); !exists {
		var err error
		b, err = exec.LookPath("node")
		must(err)
	}
	return b
}

func (p *Plugins) modulesPath() string {
	return filepath.Join(p.Path, "node_modules")
}
<|endoftext|>


<commit_before>package raftor

import "github.com/coreos/etcd/raft"

// RaftNode extends the etcd raft.Node
type RaftNode interface {
	raft.Node
	Starter

	// Cluster returns the cluster
	Cluster() Cluster
}
<commit_msg>Remove Cluster from RaftNode interface<commit_after>package raftor

import "github.com/coreos/etcd/raft"

// RaftNode extends the etcd raft.Node
type RaftNode interface {
	raft.Node
	Starter
}
<|endoftext|>


<commit_before>package resource

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
	"time"

	//  The fantastic ORM library for Golang, aims to be developer friendly.
	"github.com/jinzhu/gorm"

	"github.com/Sky-And-Hammer/TM_EC"
	"github.com/Sky-And-Hammer/TM_EC/utils"
	"github.com/Sky-And-Hammer/roles"
	"github.com/Sky-And-Hammer/validations"
)

//	'Metaor' interface
type Metaor interface {
	GetName() string
	GetFieldName() string
	GetSetter() func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context)
	GetFormattedValuer() func(interface{}, *TM_EC.Context) interface{}
	GetValuer() func(interface{}, *TM_EC.Context) interface{}
	GetResource() Resourcer
	GetMetas() []Metaor
	HasPermission(roles.PermissionMode, *TM_EC.Context) bool
}

//	'ConfigureMetaBeforeInitializeInterface' if a strust's field's type implemented this interface, it will be called when initializing a meta
type ConfigureMetaBeforeInitializeInterface interface {
	ConfigureECMetaBeforeInitialize(Metaor)
}

//	'ConfigureMetaInterface' if a struct's field's type implemented this interface, it will be called after configed
type ConfigureMetaInterface interface {
	ConfigureECMeta(Metaor)
}

//	'MetaConfigInterface' meta configuration interface
type MetaConfigInterface interface {
	ConfigureMetaInterface
}

//	'MetaConfig' base meta config struct
type MetaConfig struct{}

//	'ConfigureECMeta' implement the MetaConfigInterface
func (MetaConfig) ConfigureECMeta(Metaor) {}

//	'Meta' meta struct definition
type Meta struct {
	Name            string
	FieldName       string
	FieldStruct     *gorm.StructField
	Setter          func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context)
	Valuer          func(interface{}, *TM_EC.Context) interface{}
	FormattedValuer func(interface{}, *TM_EC.Context) interface{}
	Config          MetaConfigInterface
	Resource        Resourcer
	Permission      *roles.Permission
}

//	'GetBaseResource' get base resource from meta
func (meta Meta) GetBaseResource() Resourcer {
	return meta.Resource
}

//	'GetName' get meta's name
func (meta Meta) GetName() string {
	return meta.Name
}

//	'getFieldName' get meta's field name
func (meta Meta) getFieldName() string {
	return meta.FieldName
}

//	'SetFieldName' set meta's field name
func (meta *Meta) SetFieldName(name string) {
	meta.FieldName = name
}

//	'GetSetter' get meta's setter
func (meta Meta) GetSetter() func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context) {
	return meta.Setter
}

//	'SetSetter' set meta's setter
func (meta *Meta) SetSetter(fc func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context)) {
	meta.Setter = fc
}

//	'GetValuer' get meta's valuer
func (meta Meta) GetValuer() func(interface{}, *TM_EC.Context) interface{} {
	return meta.Valuer
}

//	'SetValuer' set meta's valuer
func (meta *Meta) SetValuer(fc func(interface{}, *TM_EC.Context) interface{}) {
	meta.Valuer = fc
}

//	'GetFormattedValuer' get formatted valuer form meta
func (meta *Meta) GetFormattedValuer() func(interface{}, *TM_EC.Context) interface{} {
	if meta.FormattedValuer != nil {
		return meta.FormattedValuer
	}
	return meta.Valuer
}

//	'SetFormattedValuer' set formatted valuer form meta
func (meta *Meta) SetFormattedValuer(fc func(interface{}, *TM_EC.Context) interface{}) {
	meta.FormattedValuer = fc
}

//	'HasPermission' check has permission or not
func (meta Meta) HasPermission(mode roles.PermissionMode, context *TM_EC.Context) bool {
	if meta.Permission == nil {
		return true
	}
	return meta.Permission.HasPermission(mode, context.Roles...)
}

//	'SetPermission' set permission for meta
func (meta *Meta) SetPermission(permission *roles.Permission) {
	meta.Permission = permission
}

//	'PerInitialize' when will be run beform initialize, used to fill some basic necessary information
func (meta *Meta) PerInitialize() error {
	if meta.Name == "" {
		utils.ExistWithMsg("Meta should have name: %v", reflect.TypeOf(meta))
	} else if meta.FieldName == "" {
		meta.FieldName = meta.Name
	}

	var parseNestedField = func(value reflect.Value, name string) (reflect.Value, string) {
		fields := strings.Split(name, ".")
		value = reflect.Indirect(value)
		for _, field := range fields[:len(fields)-1] {
			value = value.FieldByName(field)
		}
		return value, fields[len(fields)-1]
	}

	var getField = func(fields []*gorm.StructField, name string) *gorm.StructField {
		for _, field := range fields {
			if field.Name == name || field.DBName == name {
				return field
			}
		}
		return nil
	}

	var nestedField = strings.Contains(meta.FieldName, ".")
	var scope = &gorm.Scope{
		Value: meta.Resource.GetResource().Value,
	}
	if nestedField {
		subModel, name := parseNestedField(reflect.ValueOf(meta.Resource.GetResource().Validatiors), meta.FieldName)
		meta.FieldStruct = getField(scope.New(subModel.Interface()).GetStructFields(), name)
	} else {
		meta.FieldStruct = getField(scope.GetStructFields(), meta.FieldName)
	}
	return nil
}

//	'Initialize' initialize meta, will set valuer, setter if haven't configure it
func (meta *Meta) Initialize() error {
	var (
		nestedField = strings.Contains(meta.FieldName, ".")
		field       = meta.FieldStruct
		hasColumn   = meta.FieldStruct != nil
	)

	var fieldType reflect.Type
	if hasColumn {
		fieldType = field.Struct.Type
		for fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}
	}

	if meta.Valuer == nil {
		if hasColumn {
			meta.Valuer = func(value interface{}, context *TM_EC.Context) interface{} {
				scope := context.GetDB().NewScope(value)
				fieldName := meta.FieldName
				if nestedField {
					fileds := strings.Split(fieldName, ".")
					fieldName = fileds[len(fileds)-1]
				}

				if f, ok := scope.FieldByName(fieldName); ok {
					if f.Relationship != nil && f.Field.CanAddr() && !scope.PrimaryKeyZero() {
						context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.FieldName)
					}

					return f.Field.Interface()
				}

				return ""
			}
		} else {
			utils.ExistWithMsg("Meta %v is not supported for resource %v, no 'Valuer' configured for it", meta.FieldName, reflect.TypeOf(meta.Resource.GetResource().Value))
		}
	}

	if meta.Setter == nil && hasColumn {
		if relationship := field.Relationship; relationship != nil {
			if relationship.Kind == "belongs_to" || relationship.Kind == "many_to_many" {
				meta.Setter = func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context) {
					scope := &gorm.Scope{
						Value: resource,
					}
					reflectValue := reflect.Indirect(reflect.ValueOf(resource))
					field := reflectValue.FieldByName(meta.FieldName)
					if field.Kind() == reflect.Ptr {
						if field.IsNil() {
							field.Set(utils.NewValue(field.Type()).Elem())
						}

						for field.Kind() == reflect.Ptr {
							field = field.Elem()
						}
					}

					primaryKeys := utils.ToArray(metaValue.Value)
					if relationship.Kind == "belong_to" && len(relationship.ForeignFieldNames) == 1 {
						oldPrimaryKeys := utils.ToArray(reflectValue.FieldByName(relationship.ForeignFieldNames[0]).Interface())
						if fmt.Sprint(primaryKeys) == fmt.Sprint(oldPrimaryKeys) {
							return
						}

						if len(primaryKeys) == 0 {
							field := reflectValue.FieldByName(relationship.ForeignFieldNames[0])
							field.Set(reflect.Zero(field.Type()))
						}
					}

					if len(primaryKeys) > 0 {
						context.GetDB().Where(primaryKeys).Find(field.Addr().Interface())
					}

					if relationship.Kind == "many_to_many" {
						if !scope.PrimaryKeyZero() {
							context.GetDB().Model(resource).Association(meta.FieldName).Replace(field.Interface())
							field.Send(reflect.Zero(field.Type()))
						}
					}
				}
			}
		} else {
			meta.Setter = func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context) {
				if metaValue == nil {
					return
				}

				var (
					value     = metaValue.Value
					fieldName = meta.FieldName
				)

				defer func() {
					if r := recover(); r != nil {
						context.AddError(validations.NewError(resource, meta.Name, fmt.Sprintf("Can't set value %v", value)))
					}
				}()

				if nestedField {
					fields := strings.Split(fieldName, ".")
					fieldName = fields[len(fields)-1]
				}

				field := reflect.Indirect(reflect.ValueOf(resource)).FieldByName(fieldName)
				if field.Kind() == reflect.Ptr {
					if field.IsNil() && utils.ToString(value) != "" {
						field.Set(utils.NewValue(field.Type()).Elem())
					}

					if utils.ToString(value) == "" {
						field.Set(reflect.Zero(field.Type()))
						return
					}

					for field.Kind() == reflect.Ptr {
						field = field.Elem()
					}
				}

				if field.IsValid() && field.CanAddr() {
					switch field.Kind() {
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						field.SetInt(utils.ToInt(value))
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						field.SetUint(utils.ToUInt(value))
					case reflect.Float32, reflect.Float64:
						field.SetFloat(utils.ToFloat(value))
					case reflect.Bool:
						if utils.ToString(value) == "true" {
							field.SetBool(true)
						} else {
							field.SetBool(false)
						}
					default:
						if scanner, ok := field.Addr().Interface().(sql.Scanner); ok {
							if value == nil && len(metaValue.MetaValues.Values) > 0 {
								decodeMetaValuesToField(meta.Resource, field, metaValue, context)
								return
							}

							if scanner.Scan(value) != nil {
								scanner.Scan(utils.ToString(value))
							}
						} else if reflect.TypeOf("").ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToString(value)).Convert(field.Type()))
						} else if reflect.TypeOf([]string{}).ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToArray(value)).Convert(field.Type()))
						} else if rValue := reflect.ValueOf(value); reflect.TypeOf(rValue.Type()).ConvertibleTo(field.Type()) {
							field.Set(rValue.Convert(field.Type()))
						} else if _, ok := field.Addr().Interface().(*time.Time); ok {
							if str := utils.ToString(value); str != "" {
								if newTime, err := utils.ParseTime(str, context); err == nil {
									field.Set(reflect.ValueOf(newTime))
								}
							} else {
								field.Set(reflect.Zero(field.Type()))
							}
						} else {
							var buffer = bytes.NewBufferString("")
							json.NewEncoder(buffer).Encode(value)
							if err := json.NewDecoder(strings.NewReader(buffer.String())).Decode(field.Addr().Interface()); err != nil {
								utils.ExistWithMsg("Can't set value %v to %v [meta %v]", reflect.TypeOf(value), field.Type(), meta)
							}
						}
					}
				}
			}
		}
	}

	if nestedField {
		oldValue := meta.Valuer
		meta.Valuer = func(value interface{}, context *TM_EC.Context) interface{} {
			return oldValue(getNestedModel(value, meta.FieldName, context), context)
		}

		oldSetter := meta.Setter
		meta.Setter = func(resource interface{}, metaValu *MetaValue, context *TM_EC.Context) {
			oldSetter(getNestedModel(resource, meta.FieldName, context), metaValu, context)
		}
	}

	return nil
}

func getNestedModel(value interface{}, fieldName string, context *TM_EC.Context) interface{} {
	model := reflect.Indirect(reflect.ValueOf(value))
	fields := strings.Split(fieldName, ".")
	for _, field := range fields[:len(fields)-1] {
		subModel := model.FieldByName(field)
		if key := subModel.FieldByName("Id"); !key.IsValid() || key.Uint() == 0 {
			if subModel.CanAddr() {
				context.GetDB().Model(model.Addr().Interface()).Related(subModel.Addr().Interface())
				model = subModel
			} else {
				break
			}
		} else {
			model = subModel
		}
	}

	if model.CanAddr() {
		return model.Addr().Interface()
	}

	return nil
}
<commit_msg>fix func name<commit_after>package resource

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
	"time"

	//  The fantastic ORM library for Golang, aims to be developer friendly.
	"github.com/jinzhu/gorm"

	"github.com/Sky-And-Hammer/TM_EC"
	"github.com/Sky-And-Hammer/TM_EC/utils"
	"github.com/Sky-And-Hammer/roles"
	"github.com/Sky-And-Hammer/validations"
)

//	'Metaor' interface
type Metaor interface {
	GetName() string
	GetFieldName() string
	GetSetter() func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context)
	GetFormattedValuer() func(interface{}, *TM_EC.Context) interface{}
	GetValuer() func(interface{}, *TM_EC.Context) interface{}
	GetResource() Resourcer
	GetMetas() []Metaor
	HasPermission(roles.PermissionMode, *TM_EC.Context) bool
}

//	'ConfigureMetaBeforeInitializeInterface' if a strust's field's type implemented this interface, it will be called when initializing a meta
type ConfigureMetaBeforeInitializeInterface interface {
	ConfigureECMetaBeforeInitialize(Metaor)
}

//	'ConfigureMetaInterface' if a struct's field's type implemented this interface, it will be called after configed
type ConfigureMetaInterface interface {
	ConfigureECMeta(Metaor)
}

//	'MetaConfigInterface' meta configuration interface
type MetaConfigInterface interface {
	ConfigureMetaInterface
}

//	'MetaConfig' base meta config struct
type MetaConfig struct{}

//	'ConfigureECMeta' implement the MetaConfigInterface
func (MetaConfig) ConfigureECMeta(Metaor) {}

//	'Meta' meta struct definition
type Meta struct {
	Name            string
	FieldName       string
	FieldStruct     *gorm.StructField
	Setter          func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context)
	Valuer          func(interface{}, *TM_EC.Context) interface{}
	FormattedValuer func(interface{}, *TM_EC.Context) interface{}
	Config          MetaConfigInterface
	Resource        Resourcer
	Permission      *roles.Permission
}

//	'GetBaseResource' get base resource from meta
func (meta Meta) GetBaseResource() Resourcer {
	return meta.Resource
}

//	'GetName' get meta's name
func (meta Meta) GetName() string {
	return meta.Name
}

//	'getFieldName' get meta's field name
func (meta Meta) GetFieldName() string {
	return meta.FieldName
}

//	'SetFieldName' set meta's field name
func (meta *Meta) SetFieldName(name string) {
	meta.FieldName = name
}

//	'GetSetter' get meta's setter
func (meta Meta) GetSetter() func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context) {
	return meta.Setter
}

//	'SetSetter' set meta's setter
func (meta *Meta) SetSetter(fc func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context)) {
	meta.Setter = fc
}

//	'GetValuer' get meta's valuer
func (meta Meta) GetValuer() func(interface{}, *TM_EC.Context) interface{} {
	return meta.Valuer
}

//	'SetValuer' set meta's valuer
func (meta *Meta) SetValuer(fc func(interface{}, *TM_EC.Context) interface{}) {
	meta.Valuer = fc
}

//	'GetFormattedValuer' get formatted valuer form meta
func (meta *Meta) GetFormattedValuer() func(interface{}, *TM_EC.Context) interface{} {
	if meta.FormattedValuer != nil {
		return meta.FormattedValuer
	}
	return meta.Valuer
}

//	'SetFormattedValuer' set formatted valuer form meta
func (meta *Meta) SetFormattedValuer(fc func(interface{}, *TM_EC.Context) interface{}) {
	meta.FormattedValuer = fc
}

//	'HasPermission' check has permission or not
func (meta Meta) HasPermission(mode roles.PermissionMode, context *TM_EC.Context) bool {
	if meta.Permission == nil {
		return true
	}
	return meta.Permission.HasPermission(mode, context.Roles...)
}

//	'SetPermission' set permission for meta
func (meta *Meta) SetPermission(permission *roles.Permission) {
	meta.Permission = permission
}

//	'PerInitialize' when will be run beform initialize, used to fill some basic necessary information
func (meta *Meta) PerInitialize() error {
	if meta.Name == "" {
		utils.ExistWithMsg("Meta should have name: %v", reflect.TypeOf(meta))
	} else if meta.FieldName == "" {
		meta.FieldName = meta.Name
	}

	var parseNestedField = func(value reflect.Value, name string) (reflect.Value, string) {
		fields := strings.Split(name, ".")
		value = reflect.Indirect(value)
		for _, field := range fields[:len(fields)-1] {
			value = value.FieldByName(field)
		}
		return value, fields[len(fields)-1]
	}

	var getField = func(fields []*gorm.StructField, name string) *gorm.StructField {
		for _, field := range fields {
			if field.Name == name || field.DBName == name {
				return field
			}
		}
		return nil
	}

	var nestedField = strings.Contains(meta.FieldName, ".")
	var scope = &gorm.Scope{
		Value: meta.Resource.GetResource().Value,
	}
	if nestedField {
		subModel, name := parseNestedField(reflect.ValueOf(meta.Resource.GetResource().Validatiors), meta.FieldName)
		meta.FieldStruct = getField(scope.New(subModel.Interface()).GetStructFields(), name)
	} else {
		meta.FieldStruct = getField(scope.GetStructFields(), meta.FieldName)
	}
	return nil
}

//	'Initialize' initialize meta, will set valuer, setter if haven't configure it
func (meta *Meta) Initialize() error {
	var (
		nestedField = strings.Contains(meta.FieldName, ".")
		field       = meta.FieldStruct
		hasColumn   = meta.FieldStruct != nil
	)

	var fieldType reflect.Type
	if hasColumn {
		fieldType = field.Struct.Type
		for fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}
	}

	if meta.Valuer == nil {
		if hasColumn {
			meta.Valuer = func(value interface{}, context *TM_EC.Context) interface{} {
				scope := context.GetDB().NewScope(value)
				fieldName := meta.FieldName
				if nestedField {
					fileds := strings.Split(fieldName, ".")
					fieldName = fileds[len(fileds)-1]
				}

				if f, ok := scope.FieldByName(fieldName); ok {
					if f.Relationship != nil && f.Field.CanAddr() && !scope.PrimaryKeyZero() {
						context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.FieldName)
					}

					return f.Field.Interface()
				}

				return ""
			}
		} else {
			utils.ExistWithMsg("Meta %v is not supported for resource %v, no 'Valuer' configured for it", meta.FieldName, reflect.TypeOf(meta.Resource.GetResource().Value))
		}
	}

	if meta.Setter == nil && hasColumn {
		if relationship := field.Relationship; relationship != nil {
			if relationship.Kind == "belongs_to" || relationship.Kind == "many_to_many" {
				meta.Setter = func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context) {
					scope := &gorm.Scope{
						Value: resource,
					}
					reflectValue := reflect.Indirect(reflect.ValueOf(resource))
					field := reflectValue.FieldByName(meta.FieldName)
					if field.Kind() == reflect.Ptr {
						if field.IsNil() {
							field.Set(utils.NewValue(field.Type()).Elem())
						}

						for field.Kind() == reflect.Ptr {
							field = field.Elem()
						}
					}

					primaryKeys := utils.ToArray(metaValue.Value)
					if relationship.Kind == "belong_to" && len(relationship.ForeignFieldNames) == 1 {
						oldPrimaryKeys := utils.ToArray(reflectValue.FieldByName(relationship.ForeignFieldNames[0]).Interface())
						if fmt.Sprint(primaryKeys) == fmt.Sprint(oldPrimaryKeys) {
							return
						}

						if len(primaryKeys) == 0 {
							field := reflectValue.FieldByName(relationship.ForeignFieldNames[0])
							field.Set(reflect.Zero(field.Type()))
						}
					}

					if len(primaryKeys) > 0 {
						context.GetDB().Where(primaryKeys).Find(field.Addr().Interface())
					}

					if relationship.Kind == "many_to_many" {
						if !scope.PrimaryKeyZero() {
							context.GetDB().Model(resource).Association(meta.FieldName).Replace(field.Interface())
							field.Send(reflect.Zero(field.Type()))
						}
					}
				}
			}
		} else {
			meta.Setter = func(resource interface{}, metaValue *MetaValue, context *TM_EC.Context) {
				if metaValue == nil {
					return
				}

				var (
					value     = metaValue.Value
					fieldName = meta.FieldName
				)

				defer func() {
					if r := recover(); r != nil {
						context.AddError(validations.NewError(resource, meta.Name, fmt.Sprintf("Can't set value %v", value)))
					}
				}()

				if nestedField {
					fields := strings.Split(fieldName, ".")
					fieldName = fields[len(fields)-1]
				}

				field := reflect.Indirect(reflect.ValueOf(resource)).FieldByName(fieldName)
				if field.Kind() == reflect.Ptr {
					if field.IsNil() && utils.ToString(value) != "" {
						field.Set(utils.NewValue(field.Type()).Elem())
					}

					if utils.ToString(value) == "" {
						field.Set(reflect.Zero(field.Type()))
						return
					}

					for field.Kind() == reflect.Ptr {
						field = field.Elem()
					}
				}

				if field.IsValid() && field.CanAddr() {
					switch field.Kind() {
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						field.SetInt(utils.ToInt(value))
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						field.SetUint(utils.ToUInt(value))
					case reflect.Float32, reflect.Float64:
						field.SetFloat(utils.ToFloat(value))
					case reflect.Bool:
						if utils.ToString(value) == "true" {
							field.SetBool(true)
						} else {
							field.SetBool(false)
						}
					default:
						if scanner, ok := field.Addr().Interface().(sql.Scanner); ok {
							if value == nil && len(metaValue.MetaValues.Values) > 0 {
								decodeMetaValuesToField(meta.Resource, field, metaValue, context)
								return
							}

							if scanner.Scan(value) != nil {
								scanner.Scan(utils.ToString(value))
							}
						} else if reflect.TypeOf("").ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToString(value)).Convert(field.Type()))
						} else if reflect.TypeOf([]string{}).ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToArray(value)).Convert(field.Type()))
						} else if rValue := reflect.ValueOf(value); reflect.TypeOf(rValue.Type()).ConvertibleTo(field.Type()) {
							field.Set(rValue.Convert(field.Type()))
						} else if _, ok := field.Addr().Interface().(*time.Time); ok {
							if str := utils.ToString(value); str != "" {
								if newTime, err := utils.ParseTime(str, context); err == nil {
									field.Set(reflect.ValueOf(newTime))
								}
							} else {
								field.Set(reflect.Zero(field.Type()))
							}
						} else {
							var buffer = bytes.NewBufferString("")
							json.NewEncoder(buffer).Encode(value)
							if err := json.NewDecoder(strings.NewReader(buffer.String())).Decode(field.Addr().Interface()); err != nil {
								utils.ExistWithMsg("Can't set value %v to %v [meta %v]", reflect.TypeOf(value), field.Type(), meta)
							}
						}
					}
				}
			}
		}
	}

	if nestedField {
		oldValue := meta.Valuer
		meta.Valuer = func(value interface{}, context *TM_EC.Context) interface{} {
			return oldValue(getNestedModel(value, meta.FieldName, context), context)
		}

		oldSetter := meta.Setter
		meta.Setter = func(resource interface{}, metaValu *MetaValue, context *TM_EC.Context) {
			oldSetter(getNestedModel(resource, meta.FieldName, context), metaValu, context)
		}
	}

	return nil
}

func getNestedModel(value interface{}, fieldName string, context *TM_EC.Context) interface{} {
	model := reflect.Indirect(reflect.ValueOf(value))
	fields := strings.Split(fieldName, ".")
	for _, field := range fields[:len(fields)-1] {
		subModel := model.FieldByName(field)
		if key := subModel.FieldByName("Id"); !key.IsValid() || key.Uint() == 0 {
			if subModel.CanAddr() {
				context.GetDB().Model(model.Addr().Interface()).Related(subModel.Addr().Interface())
				model = subModel
			} else {
				break
			}
		} else {
			model = subModel
		}
	}

	if model.CanAddr() {
		return model.Addr().Interface()
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/emccode/rexray/rexray/cli"

	// load REX-Ray
	_ "github.com/emccode/rexray"
)

func main() {
	cli.Execute()
}
<commit_msg>REX-Ray Production Profiling<commit_after>package main

import (
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime/pprof"
	"runtime/trace"

	"github.com/emccode/rexray/rexray/cli"

	// load REX-Ray
	_ "github.com/emccode/rexray"
)

func init() {
	if p := os.Getenv("REXRAY_TRACE_PROFILE"); p != "" {
		f, err := os.Create(p)
		if err != nil {
			panic(err)
		}
		if err := trace.Start(f); err != nil {
			panic(err)
		}
		defer trace.Stop()
	}

	if p := os.Getenv("REXRAY_CPU_PROFILE"); p != "" {
		f, err := os.Create(p)
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if p := os.Getenv("REXRAY_PROFILE_ADDR"); p != "" {
		go http.ListenAndServe(p, http.DefaultServeMux)
	}
}

func main() {
	cli.Execute()
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package image

import (
	"image/color"
)

var (
	// Black is an opaque black uniform image.
	Black = NewUniform(color.Black)
	// White is an opaque white uniform image.
	White = NewUniform(color.White)
	// Transparent is a fully transparent uniform image.
	Transparent = NewUniform(color.Transparent)
	// Opaque is a fully opaque uniform image.
	Opaque = NewUniform(color.Opaque)
)

// Uniform is an infinite-sized Image of uniform color.
// It implements the color.Color, color.Model, and Image interfaces.
type Uniform struct {
	C color.Color
}

func (c *Uniform) RGBA() (r, g, b, a uint32) {
	return c.C.RGBA()
}

func (c *Uniform) ColorModel() color.Model {
	return c
}

func (c *Uniform) Convert(color.Color) color.Color {
	return c.C
}

func (c *Uniform) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }

func (c *Uniform) At(x, y int) color.Color { return c.C }

// Opaque scans the entire image and reports whether it is fully opaque.
func (c *Uniform) Opaque() bool {
	_, _, _, a := c.C.RGBA()
	return a == 0xffff
}

func NewUniform(c color.Color) *Uniform {
	return &Uniform{c}
}
<commit_msg>image: add a NewUniform doc comment<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package image

import (
	"image/color"
)

var (
	// Black is an opaque black uniform image.
	Black = NewUniform(color.Black)
	// White is an opaque white uniform image.
	White = NewUniform(color.White)
	// Transparent is a fully transparent uniform image.
	Transparent = NewUniform(color.Transparent)
	// Opaque is a fully opaque uniform image.
	Opaque = NewUniform(color.Opaque)
)

// Uniform is an infinite-sized Image of uniform color.
// It implements the color.Color, color.Model, and Image interfaces.
type Uniform struct {
	C color.Color
}

func (c *Uniform) RGBA() (r, g, b, a uint32) {
	return c.C.RGBA()
}

func (c *Uniform) ColorModel() color.Model {
	return c
}

func (c *Uniform) Convert(color.Color) color.Color {
	return c.C
}

func (c *Uniform) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }

func (c *Uniform) At(x, y int) color.Color { return c.C }

// Opaque scans the entire image and reports whether it is fully opaque.
func (c *Uniform) Opaque() bool {
	_, _, _, a := c.C.RGBA()
	return a == 0xffff
}

// NewUniform returns a new Uniform image of the given color.
func NewUniform(c color.Color) *Uniform {
	return &Uniform{c}
}
<|endoftext|>


<commit_before>/**
 * @file main.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU AGPLv3
 * @date December, 2015
 * @brief contest checking system CLI
 *
 * Entry point for contest checking system CLI
 */

package main

import (
	"database/sql"
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"

	"github.com/jollheef/henhouse/config"
	"github.com/jollheef/henhouse/db"
	"github.com/jollheef/henhouse/game"
	"github.com/olekukonko/tablewriter"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	configPath = kingpin.Flag("config", "Path to configuration file.").String()

	// Task
	task = kingpin.Command("task", "Work with tasks.")

	taskList        = task.Command("list", "List tasks.")
	taskListWOFlags = taskList.Flag("without-flags", "Do not include flags in output.").Bool()

	taskAdd    = task.Command("add", "Add task.")
	taskAddXML = taskAdd.Arg("xml", "Path to xml.").Required().String()

	taskUpdate    = task.Command("update", "Update task.")
	taskUpdateID  = taskUpdate.Arg("id", "ID of task.").Required().Int()
	taskUpdateXML = taskUpdate.Arg("xml", "Path to xml.").Required().String()

	taskOpen   = task.Command("open", "Open task.")
	taskOpenID = taskOpen.Arg("id", "ID of task").Required().Int()

	taskClose   = task.Command("close", "Close task.")
	taskCloseID = taskClose.Arg("id", "ID of task").Required().Int()

	taskDump   = task.Command("dump", "Dump task to xml.")
	taskDumpID = taskDump.Arg("id", "ID of task").Required().Int()

	// Category
	category = kingpin.Command("category", "Work with categories.")

	categoryList = category.Command("list", "List categories.")

	categoryAdd  = category.Command("add", "Add category.")
	categoryName = categoryAdd.Arg("name", "Name.").Required().String()

	// Team
	team = kingpin.Command("team", "Work with teams.")

	teamList   = team.Command("list", "List teams.")
	teamInfo   = team.Command("info", "Information about team.")
	teamInfoID = teamInfo.Arg("id", "ID of task").Required().Int()

	// Export
	export = kingpin.Command("export", "Export scoreboard for ctftime.")
)

var (
	// CommitID fill in ./build.sh
	CommitID string
	// BuildDate fill in ./build.sh
	BuildDate string
	// BuildTime fill in ./build.sh
	BuildTime string
)

func getCategoryByID(categoryID int, categories []db.Category) string {
	for _, cat := range categories {
		if cat.ID == categoryID {
			return cat.Name
		}
	}
	return "Unknown"
}

func getCategoryByName(name string, categories []db.Category) (id int, err error) {
	for _, cat := range categories {
		if cat.Name == name {
			return cat.ID, nil
		}
	}

	return 0, errors.New("Category " + name + " not found")
}

type byID []db.Task

func (t byID) Len() int           { return len(t) }
func (t byID) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t byID) Less(i, j int) bool { return t[i].ID < t[j].ID }

func parseTask(path string, categories []db.Category) (t db.Task, err error) {

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return
	}

	task, err := config.ParseXMLTask(content)
	if err != nil {
		return
	}

	t.Name = task.Name
	t.Desc = task.Description
	t.NameEn = task.NameEn
	t.DescEn = task.DescriptionEn
	t.CategoryID, err = getCategoryByName(task.Category, categories)
	if err != nil {
		log.Println("Cant find category")
		return
	}

	t.Level = task.Level
	t.Flag = task.Flag
	t.Price = 500         // TODO support non-shared task
	t.Shared = true       // TODO support non-shared task
	t.MaxSharePrice = 500 // TODO support value from xml
	t.MinSharePrice = 100 // TODO support value from xml
	t.Opened = false      // by default task is closed
	t.Author = task.Author
	t.Tags = task.Tags
	t.ForceClosed = task.ForceClosed

	return
}

var cfgFiles = []string{"/etc/henhouse/cli.toml", "/etc/henhouse.toml",
	"cli.toml", "henhouse.toml"}

func taskUpdateCmd(database *sql.DB, categories []db.Category) (err error) {
	task, err := db.GetTask(database, *taskUpdateID)
	if err != nil {
		return
	}

	id := task.ID

	task, err = parseTask(*taskUpdateXML, categories)
	if err != nil {
		return
	}

	task.ID = id

	err = db.UpdateTask(database, &task)
	if err != nil {
		return
	}

	return
}

func taskAddCmd(database *sql.DB, categories []db.Category) (err error) {
	t, err := parseTask(*taskAddXML, categories)
	if err != nil {
		return
	}

	err = db.AddTask(database, &t)
	if err != nil {
		return
	}

	return
}

func taskListCmd(database *sql.DB, categories []db.Category) (err error) {
	tasks, err := db.GetTasks(database)
	if err != nil {
		return
	}

	sort.Sort(byID(tasks))

	table := tablewriter.NewWriter(os.Stdout)
	var header []string
	if *taskListWOFlags {
		header = []string{"ID", "Name", "Category", "Opened", "Solved by"}
	} else {
		header = []string{"ID", "Name", "Category", "Flag", "Opened", "Solved by"}
	}
	table.SetHeader(header)

	for _, task := range tasks {
		var solvedBy int
		solvedBy, err = db.GetSolvedCount(database, task.ID)
		if err != nil {
			return
		}

		var row []string

		row = append(row, fmt.Sprintf("%d", task.ID))
		row = append(row, task.Name)
		row = append(row, getCategoryByID(task.CategoryID, categories))
		if !*taskListWOFlags {
			row = append(row, task.Flag)
		}
		row = append(row, fmt.Sprintf("%v", task.Opened))
		row = append(row, fmt.Sprintf("%d", solvedBy))

		table.Append(row)
	}

	table.Render()

	return
}

func taskDumpCmd(database *sql.DB, categories []db.Category) (err error) {
	task, err := db.GetTask(database, *taskDumpID)
	if err != nil {
		return
	}

	xmlTask := config.Task{
		Name:          task.Name,
		NameEn:        task.NameEn,
		Description:   task.Desc,
		DescriptionEn: task.DescEn,
		Category:      getCategoryByID(task.CategoryID, categories),
		Level:         task.Level,
		Flag:          task.Flag,
		Author:        task.Author,
		ForceClosed:   task.ForceClosed,
		Tags:          task.Tags,
	}

	output, err := xml.MarshalIndent(xmlTask, "", "	")
	if err != nil {
		return

	}

	fmt.Fprintln(os.Stdout, string(output))

	return
}

func categoryListCmd(database *sql.DB) (err error) {
	categories, err := db.GetCategories(database)
	if err != nil {
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name"})

	for _, cat := range categories {
		row := []string{fmt.Sprintf("%d", cat.ID), cat.Name}
		table.Append(row)
	}

	table.Render()

	return
}

type byScore [][]string

func (t byScore) Len() int      { return len(t) }
func (t byScore) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t byScore) Less(i, j int) bool {
	var in, jn int
	fmt.Sscanf(t[i][2], "%d", &in)
	fmt.Sscanf(t[j][2], "%d", &jn)
	return in > jn
}

func teamListCmd(database *sql.DB) (err error) {
	teams, err := db.GetTeams(database)
	if err != nil {
		return
	}

	flags, err := db.GetFlags(database)
	if err != nil {
		return
	}

	tasks, err := db.GetTasks(database)
	if err != nil {
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Score", "Solved"})

	rows := [][]string{}

	for _, t := range teams {
		row := []string{fmt.Sprintf("%d", t.ID), t.Name}

		var score db.Score
		score, err = db.GetLastScore(database, t.ID)
		if err != nil {
			continue
		}
		row = append(row, fmt.Sprintf("%d", score.Score))

		solvedCount := 0
		for _, f := range flags {
			if f.TeamID == t.ID {
				solvedCount++
			}
		}

		row = append(row, fmt.Sprintf("%d/%d", solvedCount, len(tasks)))

		rows = append(rows, row)
	}

	sort.Sort(byScore(rows))

	for _, row := range rows {
		table.Append(row)
	}

	table.Render()

	return
}

func teamInfoCmd(database *sql.DB) (err error) {
	teams, err := db.GetTeams(database)
	if err != nil {
		return
	}

	flags, err := db.GetFlags(database)
	if err != nil {
		return
	}

	tasks, err := db.GetTasks(database)
	if err != nil {
		return
	}

	for _, t := range teams {
		if t.ID == *teamInfoID {
			fmt.Println("ID:", t.ID)
			fmt.Println("Name:", t.Name)
			fmt.Println("Email:", t.Email)
			fmt.Println("Description:", t.Desc)
			fmt.Println("Token:", t.Token)
			fmt.Println("Test:", t.Test)
			fmt.Print("Solved: ")
			solvedCount := 0
			for _, f := range flags {
				if f.TeamID == t.ID {
					var task db.Task
					task, err = db.GetTask(database, f.TaskID)
					if err != nil {
						return
					}
					solvedCount++
					fmt.Printf("%s (%d), ", task.Name, task.ID)
				}
			}
			fmt.Println()
			fmt.Printf("Solved: %d/%d\n", solvedCount, len(tasks))
		}
	}

	return
}

func exportScoreboard(database *sql.DB) (err error) {

	scores := []game.TeamScoreInfo{}

	teams, err := db.GetTeams(database)
	if err != nil {
		return
	}

	flags, err := db.GetFlags(database)
	if err != nil {
		return
	}

	for _, team := range teams {

		if team.Test {
			continue
		}

		var s db.Score
		s, err = db.GetLastScore(database, team.ID)
		if err != nil {
			return
		}

		scoreInfo := game.TeamScoreInfo{
			ID:         team.ID,
			Name:       team.Name,
			Score:      s.Score,
			LastAccept: game.LastAccept(team.ID, flags),
		}

		scores = append(scores, scoreInfo)
	}

	sort.Sort(game.ByScoreAndLastAccept(scores))

	fmt.Println("{\n\t\"standings\": [")
	for i, s := range scores {
		fmt.Printf("\t\t{ \"pos\": %d, \"team\": \"%s\", \"score\": %d, \"lastAccept\" : %d }",
			i+1, s.Name, s.Score, s.LastAccept)
		if i != len(scores)-1 {
			fmt.Printf(",\n")
		} else {
			fmt.Printf("\n")
		}

	}
	fmt.Println("\t]\n}")

	return
}

func runCommandLine(database *sql.DB, categories []db.Category) (err error) {
	switch kingpin.Parse() {
	case "task add":
		err = taskAddCmd(database, categories)
	case "task update":
		err = taskUpdateCmd(database, categories)
	case "task list":
		err = taskListCmd(database, categories)
	case "task open":
		err = db.SetOpened(database, *taskOpenID, true)
	case "task close":
		err = db.SetOpened(database, *taskCloseID, false)
	case "task dump":
		err = taskDumpCmd(database, categories)
	case "category add":
		err = db.AddCategory(database, &db.Category{Name: *categoryName})
	case "category list":
		err = categoryListCmd(database)
	case "team list":
		err = teamListCmd(database)
	case "team info":
		err = teamInfoCmd(database)
	case "export":
		err = exportScoreboard(database)
	}

	return
}

func main() {

	if len(CommitID) > 7 {
		CommitID = CommitID[:7] // abbreviated commit hash
	}

	kingpin.Version(BuildDate + " " + CommitID +
		" (Mikhail Klementyev <jollheef@riseup.net>)")

	kingpin.Parse()

	var cfgPath string

	if *configPath != "" {
		cfgPath = *configPath
	} else {

		for _, cfgFile := range cfgFiles {
			_, err := os.Stat(cfgFile)
			if err == nil {
				cfgPath = cfgFile
				break
			}
		}
	}

	if cfgPath == "" {
		log.Fatalln("Config not found")
	}

	cfg, err := config.ReadConfig(cfgPath)
	if err != nil {
		log.Fatalln("Cannot open config:", err)
	}

	database, err := db.OpenDatabase(cfg.Database.Connection)
	if err != nil {
		log.Fatalln("Error:", err)
	}

	defer database.Close()

	database.SetMaxOpenConns(cfg.Database.MaxConnections)

	categories, err := db.GetCategories(database)
	if err != nil {
		log.Fatalln("Error:", err)
	}

	err = runCommandLine(database, categories)
	if err != nil {
		log.Fatalln("Error:", err)
	}
}
<commit_msg>Show last accept only if need<commit_after>/**
 * @file main.go
 * @author Mikhail Klementyev jollheef<AT>riseup.net
 * @license GNU AGPLv3
 * @date December, 2015
 * @brief contest checking system CLI
 *
 * Entry point for contest checking system CLI
 */

package main

import (
	"database/sql"
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"

	"github.com/jollheef/henhouse/config"
	"github.com/jollheef/henhouse/db"
	"github.com/jollheef/henhouse/game"
	"github.com/olekukonko/tablewriter"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	configPath = kingpin.Flag("config", "Path to configuration file.").String()

	// Task
	task = kingpin.Command("task", "Work with tasks.")

	taskList        = task.Command("list", "List tasks.")
	taskListWOFlags = taskList.Flag("without-flags", "Do not include flags in output.").Bool()

	taskAdd    = task.Command("add", "Add task.")
	taskAddXML = taskAdd.Arg("xml", "Path to xml.").Required().String()

	taskUpdate    = task.Command("update", "Update task.")
	taskUpdateID  = taskUpdate.Arg("id", "ID of task.").Required().Int()
	taskUpdateXML = taskUpdate.Arg("xml", "Path to xml.").Required().String()

	taskOpen   = task.Command("open", "Open task.")
	taskOpenID = taskOpen.Arg("id", "ID of task").Required().Int()

	taskClose   = task.Command("close", "Close task.")
	taskCloseID = taskClose.Arg("id", "ID of task").Required().Int()

	taskDump   = task.Command("dump", "Dump task to xml.")
	taskDumpID = taskDump.Arg("id", "ID of task").Required().Int()

	// Category
	category = kingpin.Command("category", "Work with categories.")

	categoryList = category.Command("list", "List categories.")

	categoryAdd  = category.Command("add", "Add category.")
	categoryName = categoryAdd.Arg("name", "Name.").Required().String()

	// Team
	team = kingpin.Command("team", "Work with teams.")

	teamList   = team.Command("list", "List teams.")
	teamInfo   = team.Command("info", "Information about team.")
	teamInfoID = teamInfo.Arg("id", "ID of task").Required().Int()

	// Export
	export               = kingpin.Command("export", "Export scoreboard for ctftime.")
	exportWithLastAccept = export.Flag("with-last-accept", "Add last-accept field.").Bool()
)

var (
	// CommitID fill in ./build.sh
	CommitID string
	// BuildDate fill in ./build.sh
	BuildDate string
	// BuildTime fill in ./build.sh
	BuildTime string
)

func getCategoryByID(categoryID int, categories []db.Category) string {
	for _, cat := range categories {
		if cat.ID == categoryID {
			return cat.Name
		}
	}
	return "Unknown"
}

func getCategoryByName(name string, categories []db.Category) (id int, err error) {
	for _, cat := range categories {
		if cat.Name == name {
			return cat.ID, nil
		}
	}

	return 0, errors.New("Category " + name + " not found")
}

type byID []db.Task

func (t byID) Len() int           { return len(t) }
func (t byID) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t byID) Less(i, j int) bool { return t[i].ID < t[j].ID }

func parseTask(path string, categories []db.Category) (t db.Task, err error) {

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return
	}

	task, err := config.ParseXMLTask(content)
	if err != nil {
		return
	}

	t.Name = task.Name
	t.Desc = task.Description
	t.NameEn = task.NameEn
	t.DescEn = task.DescriptionEn
	t.CategoryID, err = getCategoryByName(task.Category, categories)
	if err != nil {
		log.Println("Cant find category")
		return
	}

	t.Level = task.Level
	t.Flag = task.Flag
	t.Price = 500         // TODO support non-shared task
	t.Shared = true       // TODO support non-shared task
	t.MaxSharePrice = 500 // TODO support value from xml
	t.MinSharePrice = 100 // TODO support value from xml
	t.Opened = false      // by default task is closed
	t.Author = task.Author
	t.Tags = task.Tags
	t.ForceClosed = task.ForceClosed

	return
}

var cfgFiles = []string{"/etc/henhouse/cli.toml", "/etc/henhouse.toml",
	"cli.toml", "henhouse.toml"}

func taskUpdateCmd(database *sql.DB, categories []db.Category) (err error) {
	task, err := db.GetTask(database, *taskUpdateID)
	if err != nil {
		return
	}

	id := task.ID

	task, err = parseTask(*taskUpdateXML, categories)
	if err != nil {
		return
	}

	task.ID = id

	err = db.UpdateTask(database, &task)
	if err != nil {
		return
	}

	return
}

func taskAddCmd(database *sql.DB, categories []db.Category) (err error) {
	t, err := parseTask(*taskAddXML, categories)
	if err != nil {
		return
	}

	err = db.AddTask(database, &t)
	if err != nil {
		return
	}

	return
}

func taskListCmd(database *sql.DB, categories []db.Category) (err error) {
	tasks, err := db.GetTasks(database)
	if err != nil {
		return
	}

	sort.Sort(byID(tasks))

	table := tablewriter.NewWriter(os.Stdout)
	var header []string
	if *taskListWOFlags {
		header = []string{"ID", "Name", "Category", "Opened", "Solved by"}
	} else {
		header = []string{"ID", "Name", "Category", "Flag", "Opened", "Solved by"}
	}
	table.SetHeader(header)

	for _, task := range tasks {
		var solvedBy int
		solvedBy, err = db.GetSolvedCount(database, task.ID)
		if err != nil {
			return
		}

		var row []string

		row = append(row, fmt.Sprintf("%d", task.ID))
		row = append(row, task.Name)
		row = append(row, getCategoryByID(task.CategoryID, categories))
		if !*taskListWOFlags {
			row = append(row, task.Flag)
		}
		row = append(row, fmt.Sprintf("%v", task.Opened))
		row = append(row, fmt.Sprintf("%d", solvedBy))

		table.Append(row)
	}

	table.Render()

	return
}

func taskDumpCmd(database *sql.DB, categories []db.Category) (err error) {
	task, err := db.GetTask(database, *taskDumpID)
	if err != nil {
		return
	}

	xmlTask := config.Task{
		Name:          task.Name,
		NameEn:        task.NameEn,
		Description:   task.Desc,
		DescriptionEn: task.DescEn,
		Category:      getCategoryByID(task.CategoryID, categories),
		Level:         task.Level,
		Flag:          task.Flag,
		Author:        task.Author,
		ForceClosed:   task.ForceClosed,
		Tags:          task.Tags,
	}

	output, err := xml.MarshalIndent(xmlTask, "", "	")
	if err != nil {
		return

	}

	fmt.Fprintln(os.Stdout, string(output))

	return
}

func categoryListCmd(database *sql.DB) (err error) {
	categories, err := db.GetCategories(database)
	if err != nil {
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name"})

	for _, cat := range categories {
		row := []string{fmt.Sprintf("%d", cat.ID), cat.Name}
		table.Append(row)
	}

	table.Render()

	return
}

type byScore [][]string

func (t byScore) Len() int      { return len(t) }
func (t byScore) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t byScore) Less(i, j int) bool {
	var in, jn int
	fmt.Sscanf(t[i][2], "%d", &in)
	fmt.Sscanf(t[j][2], "%d", &jn)
	return in > jn
}

func teamListCmd(database *sql.DB) (err error) {
	teams, err := db.GetTeams(database)
	if err != nil {
		return
	}

	flags, err := db.GetFlags(database)
	if err != nil {
		return
	}

	tasks, err := db.GetTasks(database)
	if err != nil {
		return
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ID", "Name", "Score", "Solved"})

	rows := [][]string{}

	for _, t := range teams {
		row := []string{fmt.Sprintf("%d", t.ID), t.Name}

		var score db.Score
		score, err = db.GetLastScore(database, t.ID)
		if err != nil {
			continue
		}
		row = append(row, fmt.Sprintf("%d", score.Score))

		solvedCount := 0
		for _, f := range flags {
			if f.TeamID == t.ID {
				solvedCount++
			}
		}

		row = append(row, fmt.Sprintf("%d/%d", solvedCount, len(tasks)))

		rows = append(rows, row)
	}

	sort.Sort(byScore(rows))

	for _, row := range rows {
		table.Append(row)
	}

	table.Render()

	return
}

func teamInfoCmd(database *sql.DB) (err error) {
	teams, err := db.GetTeams(database)
	if err != nil {
		return
	}

	flags, err := db.GetFlags(database)
	if err != nil {
		return
	}

	tasks, err := db.GetTasks(database)
	if err != nil {
		return
	}

	for _, t := range teams {
		if t.ID == *teamInfoID {
			fmt.Println("ID:", t.ID)
			fmt.Println("Name:", t.Name)
			fmt.Println("Email:", t.Email)
			fmt.Println("Description:", t.Desc)
			fmt.Println("Token:", t.Token)
			fmt.Println("Test:", t.Test)
			fmt.Print("Solved: ")
			solvedCount := 0
			for _, f := range flags {
				if f.TeamID == t.ID {
					var task db.Task
					task, err = db.GetTask(database, f.TaskID)
					if err != nil {
						return
					}
					solvedCount++
					fmt.Printf("%s (%d), ", task.Name, task.ID)
				}
			}
			fmt.Println()
			fmt.Printf("Solved: %d/%d\n", solvedCount, len(tasks))
		}
	}

	return
}

func exportScoreboard(database *sql.DB) (err error) {

	scores := []game.TeamScoreInfo{}

	teams, err := db.GetTeams(database)
	if err != nil {
		return
	}

	flags, err := db.GetFlags(database)
	if err != nil {
		return
	}

	for _, team := range teams {

		if team.Test {
			continue
		}

		var s db.Score
		s, err = db.GetLastScore(database, team.ID)
		if err != nil {
			return
		}

		scoreInfo := game.TeamScoreInfo{
			ID:         team.ID,
			Name:       team.Name,
			Score:      s.Score,
			LastAccept: game.LastAccept(team.ID, flags),
		}

		scores = append(scores, scoreInfo)
	}

	sort.Sort(game.ByScoreAndLastAccept(scores))

	fmt.Println("{\n\t\"standings\": [")
	for i, s := range scores {
		if *exportWithLastAccept {
			fmt.Printf("\t\t{ \"pos\": %d, \"team\": \"%s\","+
				" \"score\": %d, \"lastAccept\" : %d }",
				i+1, s.Name, s.Score, s.LastAccept)
		} else {
			fmt.Printf("\t\t{ \"pos\": %d, \"team\": \"%s\","+
				" \"score\": %d }", i+1, s.Name, s.Score)
		}
		if i != len(scores)-1 {
			fmt.Printf(",\n")
		} else {
			fmt.Printf("\n")
		}

	}
	fmt.Println("\t]\n}")

	return
}

func runCommandLine(database *sql.DB, categories []db.Category) (err error) {
	switch kingpin.Parse() {
	case "task add":
		err = taskAddCmd(database, categories)
	case "task update":
		err = taskUpdateCmd(database, categories)
	case "task list":
		err = taskListCmd(database, categories)
	case "task open":
		err = db.SetOpened(database, *taskOpenID, true)
	case "task close":
		err = db.SetOpened(database, *taskCloseID, false)
	case "task dump":
		err = taskDumpCmd(database, categories)
	case "category add":
		err = db.AddCategory(database, &db.Category{Name: *categoryName})
	case "category list":
		err = categoryListCmd(database)
	case "team list":
		err = teamListCmd(database)
	case "team info":
		err = teamInfoCmd(database)
	case "export":
		err = exportScoreboard(database)
	}

	return
}

func main() {

	if len(CommitID) > 7 {
		CommitID = CommitID[:7] // abbreviated commit hash
	}

	kingpin.Version(BuildDate + " " + CommitID +
		" (Mikhail Klementyev <jollheef@riseup.net>)")

	kingpin.Parse()

	var cfgPath string

	if *configPath != "" {
		cfgPath = *configPath
	} else {

		for _, cfgFile := range cfgFiles {
			_, err := os.Stat(cfgFile)
			if err == nil {
				cfgPath = cfgFile
				break
			}
		}
	}

	if cfgPath == "" {
		log.Fatalln("Config not found")
	}

	cfg, err := config.ReadConfig(cfgPath)
	if err != nil {
		log.Fatalln("Cannot open config:", err)
	}

	database, err := db.OpenDatabase(cfg.Database.Connection)
	if err != nil {
		log.Fatalln("Error:", err)
	}

	defer database.Close()

	database.SetMaxOpenConns(cfg.Database.MaxConnections)

	categories, err := db.GetCategories(database)
	if err != nil {
		log.Fatalln("Error:", err)
	}

	err = runCommandLine(database, categories)
	if err != nil {
		log.Fatalln("Error:", err)
	}
}
<|endoftext|>


<commit_before>package fs

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strconv"

	"github.com/docker/libcontainer/cgroups"
)

type MemoryGroup struct {
}

func (s *MemoryGroup) Set(d *data) error {
	dir, err := d.join("memory")
	// only return an error for memory if it was specified
	if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
		return err
	}
	defer func() {
		if err != nil {
			os.RemoveAll(dir)
		}
	}()

	// Only set values if some config was specified.
	if d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0 {
		if d.c.Memory != 0 {
			if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil {
				return err
			}
		}
		if d.c.MemoryReservation != 0 {
			if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.c.MemoryReservation, 10)); err != nil {
				return err
			}
		}
		// By default, MemorySwap is set to twice the size of RAM.
		// If you want to omit MemorySwap, set it to `-1'.
		if d.c.MemorySwap != -1 {
			if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil {
				return err
			}
		}
	}
	return nil
}

func (s *MemoryGroup) Remove(d *data) error {
	return removePath(d.path("memory"))
}

func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
	// Set stats from memory.stat.
	statsFile, err := os.Open(filepath.Join(path, "memory.stat"))
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	defer statsFile.Close()

	sc := bufio.NewScanner(statsFile)
	for sc.Scan() {
		t, v, err := getCgroupParamKeyValue(sc.Text())
		if err != nil {
			return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err)
		}
		stats.MemoryStats.Stats[t] = v
	}

	// Set memory usage and max historical usage.
	value, err := getCgroupParamUint(path, "memory.usage_in_bytes")
	if err != nil {
		return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err)
	}
	stats.MemoryStats.Usage = value
	value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes")
	if err != nil {
		return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err)
	}
	stats.MemoryStats.MaxUsage = value
	value, err = getCgroupParamUint(path, "memory.failcnt")
	if err != nil {
		return fmt.Errorf("failed to parse memory.failcnt - %v", err)
	}
	stats.MemoryStats.Failcnt = value

	return nil
}
<commit_msg>cgroup: add support to set MemorySwap<commit_after>package fs

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strconv"

	"github.com/docker/libcontainer/cgroups"
)

type MemoryGroup struct {
}

func (s *MemoryGroup) Set(d *data) error {
	dir, err := d.join("memory")
	// only return an error for memory if it was specified
	if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) {
		return err
	}
	defer func() {
		if err != nil {
			os.RemoveAll(dir)
		}
	}()

	// Only set values if some config was specified.
	if d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0 {
		if d.c.Memory != 0 {
			if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil {
				return err
			}
		}
		if d.c.MemoryReservation != 0 {
			if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.c.MemoryReservation, 10)); err != nil {
				return err
			}
		}
		// By default, MemorySwap is set to twice the size of RAM.
		// If you want to omit MemorySwap, set it to '-1'.
		if d.c.MemorySwap == 0 {
			if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil {
				return err
			}
		}
		if d.c.MemorySwap > 0 {
			if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.MemorySwap, 10)); err != nil {
				return err
			}
		}
	}
	return nil
}

func (s *MemoryGroup) Remove(d *data) error {
	return removePath(d.path("memory"))
}

func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
	// Set stats from memory.stat.
	statsFile, err := os.Open(filepath.Join(path, "memory.stat"))
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	defer statsFile.Close()

	sc := bufio.NewScanner(statsFile)
	for sc.Scan() {
		t, v, err := getCgroupParamKeyValue(sc.Text())
		if err != nil {
			return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err)
		}
		stats.MemoryStats.Stats[t] = v
	}

	// Set memory usage and max historical usage.
	value, err := getCgroupParamUint(path, "memory.usage_in_bytes")
	if err != nil {
		return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err)
	}
	stats.MemoryStats.Usage = value
	value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes")
	if err != nil {
		return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err)
	}
	stats.MemoryStats.MaxUsage = value
	value, err = getCgroupParamUint(path, "memory.failcnt")
	if err != nil {
		return fmt.Errorf("failed to parse memory.failcnt - %v", err)
	}
	stats.MemoryStats.Failcnt = value

	return nil
}
<|endoftext|>


<commit_before>package glubcms

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	bm "github.com/microcosm-cc/bluemonday"
	bf "github.com/russross/blackfriday"
)

type Entry interface {
	Active() bool
	Author() string
	Date() time.Time
	HTML() template.HTML
	IsArticle() bool
	Link() string
	Title() string
}

type Entries []Entry

func (e Entries) Len() int {
	return len(e)
}
func (e Entries) Less(i, j int) bool {
	return e[i].Date().After(e[j].Date())
}
func (e Entries) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}
func (e Entries) Split() (Menu, Articles Entries) {
	for _, v := range e {
		if v.IsArticle() {
			Articles = append(Articles, v)
		} else {
			Menu = append(Menu, v)
		}
	}

	return
}

type GCTime time.Time

const GCTimeLayout = "2006-01-02 15:04"

func (t *GCTime) UnmarshalJSON(b []byte) error {
	tmp, err := time.Parse(GCTimeLayout, strings.Trim(string(b), "\""))
	*t = GCTime(tmp)
	return err
}

func (t GCTime) String() string {
	return time.Time(t).Format(GCTimeLayout)
}
func (t GCTime) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.String() + `"`), nil
}

type Meta struct {
	Author string
	Date   GCTime
	Title  string
}

type entry struct {
	meta      Meta
	active    bool
	html      []byte
	isarticle bool
	link      url.URL
}

func (e entry) Active() bool {
	return e.active
}
func (a entry) Author() string {
	return a.meta.Author
}
func (e entry) Date() time.Time {
	return time.Time(e.meta.Date)
}
func (e entry) HTML() template.HTML {
	return template.HTML(e.html)
}
func (e entry) IsArticle() bool {
	return e.isarticle
}
func (e entry) Link() string {
	return e.link.String()
}
func (e entry) Title() string {
	return e.meta.Title
}

func entryFromMeta(path string) (*entry, error) {
	ret := entry{}
	f, err := os.Open(filepath.Join(path))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(&ret.meta)
	return &ret, err
}

func entryFromDir(prefix, path, activepath string) Entry {
	ret, err := entryFromMeta(filepath.Join(prefix, path, "meta.json"))
	if err != nil {
		log.Println(err)
		return nil
	}

	ret.link = url.URL{Path: path}
	if strings.HasPrefix(activepath, path) {
		ret.active = true
	}

	md, err := os.Open(filepath.Join(prefix, path, "article.md"))
	if err != nil {
		if !os.IsNotExist(err) {
			log.Println(err)
		}
		return ret
	}
	defer md.Close()

	// only attempt to convert the markdown if it's the active path
	if activepath == path {
		b, err := ioutil.ReadAll(md)
		if err != nil {
			log.Println(err)
			return ret
		}
		ret.html = bf.MarkdownBasic(b)
		ret.html = bm.UGCPolicy().SanitizeBytes(ret.html)
	}

	ret.isarticle = true

	return ret
}

func entriesFromDir(prefix, path, activepath string) Entries {
	var ret Entries

	dir, err := os.Open(filepath.Join(prefix, path))
	if err != nil {
		log.Println(err)
		return nil
	}

	dirlist, err := dir.Readdir(0)
	if err != nil {
		log.Println(err)
	}
	dir.Close()

	for _, fi := range dirlist {
		if !fi.IsDir() {
			continue
		}
		entry := entryFromDir(prefix, filepath.Join(path, fi.Name()), activepath)
		if entry != nil {
			ret = append(ret, entry)
		}
	}

	sort.Sort(ret)
	return ret
}

type Page struct {
	Menu     []Entries
	Articles Entries
	Content  Entry
}

func PageFromDir(prefix, path string) Page {
	var p Page
	path = filepath.Clean(path)
	activepath := path

	// look for an article in current path
	if c := entryFromDir(prefix, path, activepath); c != nil && c.IsArticle() {
		p.Content = c
	}

	for {
		menu, articles := entriesFromDir(prefix, path, activepath).Split()
		if len(menu) > 0 {
			sort.Sort(menu)
			p.Menu = append(p.Menu, menu)
		}
		if p.Articles == nil && len(articles) > 0 {
			sort.Sort(articles)
			p.Articles = articles
			if p.Content == nil {
				// Parse again with activepath set, to get the markdown
				cpath := p.Articles[0].Link()
				p.Content = entryFromDir(prefix, cpath, cpath)
				p.Articles[0] = p.Content
			}
		}
		if path == "." || path == "/" {
			break
		}
		path = filepath.Dir(path)
	}

	// building from deepest path to /, need to reverse
	for l, r := 0, len(p.Menu)-1; l < r; l, r = l+1, r-1 {
		p.Menu[l], p.Menu[r] = p.Menu[r], p.Menu[l]
	}

	return p
}

// For debugging
func (p Page) Outline() string {
	buf := bytes.Buffer{}

	fmt.Fprintln(&buf, "Menu:")
	for level, ms := range p.Menu {
		for _, m := range ms {
			fmt.Fprintf(&buf, "%s%q", strings.Repeat("\t", level), m.Title())
			if m.Active() {
				fmt.Fprintf(&buf, " (active)")
			}
			fmt.Fprintln(&buf)
		}
	}

	fmt.Fprintln(&buf, "Articles:")
	for _, a := range p.Articles {
		fmt.Fprintf(&buf, "%q", a.Title())
		if a.Active() {
			fmt.Fprintf(&buf, " (active)")
		}
		fmt.Fprintln(&buf)
	}
	fmt.Fprintln(&buf, "Content:")
	if p.Content != nil {
		fmt.Fprint(&buf, p.Content.Title())
	}

	return buf.String()
}

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}
<commit_msg>better logging for parse errors<commit_after>package glubcms

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"

	bm "github.com/microcosm-cc/bluemonday"
	bf "github.com/russross/blackfriday"
)

type Entry interface {
	Active() bool
	Author() string
	Date() time.Time
	HTML() template.HTML
	IsArticle() bool
	Link() string
	Title() string
}

type Entries []Entry

func (e Entries) Len() int {
	return len(e)
}
func (e Entries) Less(i, j int) bool {
	return e[i].Date().After(e[j].Date())
}
func (e Entries) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}
func (e Entries) Split() (Menu, Articles Entries) {
	for _, v := range e {
		if v.IsArticle() {
			Articles = append(Articles, v)
		} else {
			Menu = append(Menu, v)
		}
	}

	return
}

type GCTime time.Time

const GCTimeLayout = "2006-01-02 15:04"

func (t *GCTime) UnmarshalJSON(b []byte) error {
	tmp, err := time.Parse(GCTimeLayout, strings.Trim(string(b), "\""))
	*t = GCTime(tmp)
	return err
}

func (t GCTime) String() string {
	return time.Time(t).Format(GCTimeLayout)
}
func (t GCTime) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.String() + `"`), nil
}

type Meta struct {
	Author string
	Date   GCTime
	Title  string
}

type entry struct {
	meta      Meta
	active    bool
	html      []byte
	isarticle bool
	link      url.URL
}

func (e entry) Active() bool {
	return e.active
}
func (a entry) Author() string {
	return a.meta.Author
}
func (e entry) Date() time.Time {
	return time.Time(e.meta.Date)
}
func (e entry) HTML() template.HTML {
	return template.HTML(e.html)
}
func (e entry) IsArticle() bool {
	return e.isarticle
}
func (e entry) Link() string {
	return e.link.String()
}
func (e entry) Title() string {
	return e.meta.Title
}

func entryFromMeta(path string) (*entry, error) {
	ret := entry{}
	f, err := os.Open(filepath.Join(path))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(&ret.meta)
	if err != nil {
		err = &os.PathError{
			Op:   "Parsing json in",
			Path: path,
			Err:  err,
		}
	}
	return &ret, err
}

func entryFromDir(prefix, path, activepath string) Entry {
	ret, err := entryFromMeta(filepath.Join(prefix, path, "meta.json"))
	if err != nil {
		log.Println(err)
		return nil
	}

	ret.link = url.URL{Path: path}
	if strings.HasPrefix(activepath, path) {
		ret.active = true
	}

	md, err := os.Open(filepath.Join(prefix, path, "article.md"))
	if err != nil {
		if !os.IsNotExist(err) {
			log.Println(err)
		}
		return ret
	}
	defer md.Close()

	// only attempt to convert the markdown if it's the active path
	if activepath == path {
		b, err := ioutil.ReadAll(md)
		if err != nil {
			log.Println(err)
			return ret
		}
		ret.html = bf.MarkdownBasic(b)
		ret.html = bm.UGCPolicy().SanitizeBytes(ret.html)
	}

	ret.isarticle = true

	return ret
}

func entriesFromDir(prefix, path, activepath string) Entries {
	var ret Entries

	dir, err := os.Open(filepath.Join(prefix, path))
	if err != nil {
		log.Println(err)
		return nil
	}

	dirlist, err := dir.Readdir(0)
	if err != nil {
		log.Println(err)
	}
	dir.Close()

	for _, fi := range dirlist {
		if !fi.IsDir() {
			continue
		}
		entry := entryFromDir(prefix, filepath.Join(path, fi.Name()), activepath)
		if entry != nil {
			ret = append(ret, entry)
		}
	}

	sort.Sort(ret)
	return ret
}

type Page struct {
	Menu     []Entries
	Articles Entries
	Content  Entry
}

func PageFromDir(prefix, path string) Page {
	var p Page
	path = filepath.Clean(path)
	activepath := path

	// look for an article in current path
	if c := entryFromDir(prefix, path, activepath); c != nil && c.IsArticle() {
		p.Content = c
	}

	for {
		menu, articles := entriesFromDir(prefix, path, activepath).Split()
		if len(menu) > 0 {
			sort.Sort(menu)
			p.Menu = append(p.Menu, menu)
		}
		if p.Articles == nil && len(articles) > 0 {
			sort.Sort(articles)
			p.Articles = articles
			if p.Content == nil {
				// Parse again with activepath set, to get the markdown
				cpath := p.Articles[0].Link()
				p.Content = entryFromDir(prefix, cpath, cpath)
				p.Articles[0] = p.Content
			}
		}
		if path == "." || path == "/" {
			break
		}
		path = filepath.Dir(path)
	}

	// building from deepest path to /, need to reverse
	for l, r := 0, len(p.Menu)-1; l < r; l, r = l+1, r-1 {
		p.Menu[l], p.Menu[r] = p.Menu[r], p.Menu[l]
	}

	return p
}

// For debugging
func (p Page) Outline() string {
	buf := bytes.Buffer{}

	fmt.Fprintln(&buf, "Menu:")
	for level, ms := range p.Menu {
		for _, m := range ms {
			fmt.Fprintf(&buf, "%s%q", strings.Repeat("\t", level), m.Title())
			if m.Active() {
				fmt.Fprintf(&buf, " (active)")
			}
			fmt.Fprintln(&buf)
		}
	}

	fmt.Fprintln(&buf, "Articles:")
	for _, a := range p.Articles {
		fmt.Fprintf(&buf, "%q", a.Title())
		if a.Active() {
			fmt.Fprintf(&buf, " (active)")
		}
		fmt.Fprintln(&buf)
	}
	fmt.Fprintln(&buf, "Content:")
	if p.Content != nil {
		fmt.Fprint(&buf, p.Content.Title())
	}

	return buf.String()
}

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}
<|endoftext|>


<commit_before>package glubcms

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"

	bm "github.com/microcosm-cc/bluemonday"
	bf "github.com/russross/blackfriday"
)

const (
	PSep = string(os.PathSeparator)
)

var (
	ErrHidden = errors.New("Hidden")
)

type Entry interface {
	Active() bool
	Author() string
	Date() time.Time
	HTML() template.HTML
	IsArticle() bool
	Link() string
	Priority() int
	Title() string
	Next() Entry
	Prev() Entry
}

type entries []entry

func (e entries) Len() int {
	return len(e)
}
func (e entries) Less(i, j int) bool {
	switch {
	case e[i].meta.IsIndex && !e[j].meta.IsIndex:
		return false
	case !e[i].meta.IsIndex && e[j].meta.IsIndex:
		return true
	case e[i].Priority() != e[j].Priority():
		return e[i].Priority() > e[j].Priority()
	}
	return e[i].Date().After(e[j].Date())
}
func (e entries) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}
func (e entries) Split() (Menu, Articles entries) {
	for _, v := range e {
		if v.IsArticle() {
			Articles = append(Articles, v)
		} else {
			Menu = append(Menu, v)
		}
	}

	return
}

type GCTime time.Time

const GCTimeLayout = "2006-01-02 15:04"

func (t *GCTime) UnmarshalJSON(b []byte) error {
	tmp, err := time.Parse(GCTimeLayout, strings.Trim(string(b), "\""))
	if err != nil {
		err = errors.Wrapf(err, "time.Parse failed on %q", b)
	}
	*t = GCTime(tmp)
	return err
}

func (t GCTime) String() string {
	return time.Time(t).Format(GCTimeLayout)
}
func (t GCTime) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.String() + `"`), nil
}

type Meta struct {
	Author   string
	Date     GCTime
	Title    string
	Priority int
	Hidden   bool `json:",omitempty"`
	Unsafe   bool `json:",omitempty"`
	IsIndex  bool `json:",omitempty"`
}

type ContentRenderer interface {
	Render() ([]byte, error)
}

type entry struct {
	meta       Meta
	active     bool
	html       []byte
	isarticle  bool
	link       url.URL
	next       *entry
	prev       *entry
	fs         http.FileSystem
	md_path    string
	once       sync.Once
	renderHTML ContentRenderer
}

func (e entry) Active() bool {
	return e.active
}
func (a entry) Author() string {
	return a.meta.Author
}
func (e entry) Date() time.Time {
	return time.Time(e.meta.Date)
}
func (e *entry) HTML() template.HTML {
	e.once.Do(func() {
		var err error
		e.html, err = e.renderHTML.Render()
		if err != nil {
			//TODO make errorpage
			log.Println(err)
		}
	})
	return template.HTML(e.html)
}
func (e entry) IsArticle() bool {
	return e.isarticle
}
func (e entry) Link() string {
	return e.link.String()
}
func (e entry) Priority() int {
	return e.meta.Priority
}
func (e entry) Title() string {
	return e.meta.Title
}
func (e entry) Next() Entry {
	if e.next != nil {
		return e.next
	}
	return nil
}
func (e entry) Prev() Entry {
	if e.prev != nil {
		return e.prev
	}
	return nil
}
func (e entry) IsIndex() bool {
	return e.meta.IsIndex
}
func (e *entry) Context(c int) entries {
	next := e
	prev := e
	n := 1

	for {
		moved := false

		if n < c && next.next != nil {
			moved = true
			next = next.next
			n++
		}
		if n < c && prev.prev != nil {
			moved = true
			prev = prev.prev
			n++
		}

		if n == c || moved == false {
			break
		}
	}

	ret := make(entries, 0, n)
	t := next
	for n > 0 {
		ret = append(ret, *t)
		t = t.prev
		n--
	}
	return ret
}

func entryFromMeta(fs http.FileSystem, path string) (entry, error) {
	ret := entry{}
	f, err := fs.Open(filepath.Join(path))
	if err != nil {
		return ret, errors.Wrapf(err, "file open failed: %q", path)
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(&ret.meta)
	if err != nil {
		err = errors.Wrapf(err, "Parsing json in: %q", path)
	}
	return ret, err
}

func entryFromDir(fs http.FileSystem, path, activepath string) (ret entry, err error) {
	ret, err = entryFromMeta(fs, filepath.Join(path, "meta.json"))
	if err != nil {
		err = errors.Wrapf(err, "Cannot open meta.json in: %q", path)
		return ret, err
	}

	// skip hidden folders, unless directly asked for
	if ret.meta.Hidden && activepath != path {
		return ret, ErrHidden
	}

	ret.link = url.URL{Path: path}
	// .Dir() removes trailing slashes, this prevents
	// /a/b/ beeing seen as prefix from /a/bc/
	if strings.HasPrefix(activepath+PSep, path+PSep) {
		ret.active = true
	}

	md_path := filepath.Join(path, "article.md")
	md, err := fs.Open(md_path)
	// Decide wether this is menu or article
	// TODO add entry to metadata and remove implicit menus
	if err != nil {
		if !os.IsNotExist(err) {
			return ret, errors.Wrapf(err, "Cannot open article.md in: %q", path)
		}
		return ret, nil
	}
	md.Close()

	ret.isarticle = true
	ret.renderHTML = articleRenderer{
		fs:      fs,
		md_path: md_path,
		unsafe:  ret.meta.Unsafe,
	}

	return ret, nil
}

type articleRenderer struct {
	fs      http.FileSystem
	md_path string
	unsafe  bool
}

func (a articleRenderer) Render() ([]byte, error) {
	md, err := a.fs.Open(a.md_path)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot open markdown file: %q", a.md_path)
	}
	defer md.Close()

	b, err := ioutil.ReadAll(md)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot read markdown file: %q", a.md_path)
	}
	html := bf.Markdown(b, bf.HtmlRenderer(bf.HTML_USE_XHTML, "", ""), bf.EXTENSION_TABLES)
	if !a.unsafe {
		html = bm.UGCPolicy().SanitizeBytes(html)
	}
	return html, nil
}

func entriesFromDir(fs http.FileSystem, path, activepath string) (entries, error) {
	var ret entries

	dir, err := fs.Open(path)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot open directory: %q", path)
	}

	dirlist, err := dir.Readdir(0)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot read directory: %q", path)
	}
	dir.Close()

	for _, fi := range dirlist {
		if !fi.IsDir() {
			continue
		}
		entry, err := entryFromDir(fs, filepath.Join(path, fi.Name()), activepath)
		if err == nil {
			ret = append(ret, entry)
		}
	}

	sort.Sort(ret)
	return ret, nil
}

type Page struct {
	Menu     []entries
	Articles entries
	Content  *entry
	Index    *entry
}

func PageFromDir(fs http.FileSystem, path string) (Page, error) {
	var p Page
	path = filepath.Clean(path)
	activepath := path

	for {
		es, err := entriesFromDir(fs, path, activepath)
		if err != nil {
			return Page{}, errors.Wrap(err, "entriesFromDir")
		}

		menu, articles := es.Split()
		if len(menu) > 0 {
			sort.Sort(menu)
			p.Menu = append(p.Menu, menu)
		}

		if p.Articles == nil && len(articles) > 0 {
			sort.Sort(articles)
			p.Articles = articles

			// don't list the index page as article
			for p.Articles[len(p.Articles)-1].meta.IsIndex {
				p.Index = &p.Articles[len(p.Articles)-1]
				p.Articles = p.Articles[:len(p.Articles)-1]
			}

			// link next/prev pointers
			for i := 1; i < len(p.Articles); i++ {
				p.Articles[i].next = &p.Articles[i-1]
				p.Articles[i-1].prev = &p.Articles[i]
			}

			// set the active article as content
			for i := range articles {
				if articles[i].link.Path == activepath {
					p.Content = &articles[i]
					break
				}
			}

			// if no exact match, default to first article
			if p.Content == nil {
				p.Content = &p.Articles[0]
				p.Content.active = true
			}
		}

		if path == "." || path == "/" {
			break
		}

		path = filepath.Dir(path)
	}

	// building from deepest path to /, need to reverse
	for l, r := 0, len(p.Menu)-1; l < r; l, r = l+1, r-1 {
		p.Menu[l], p.Menu[r] = p.Menu[r], p.Menu[l]
	}

	return p, nil
}

// For debugging
func (p Page) Outline() string {
	buf := bytes.Buffer{}

	fmt.Fprintln(&buf, "Menu:")
	for level, ms := range p.Menu {
		for _, m := range ms {
			fmt.Fprintf(&buf, "%s%q", strings.Repeat("\t", level), m.Title())
			if m.Active() {
				fmt.Fprintf(&buf, " (active)")
			}
			fmt.Fprintln(&buf)
		}
	}

	fmt.Fprintln(&buf, "Articles:")
	for _, a := range p.Articles {
		fmt.Fprintf(&buf, "%q", a.Title())
		if a.Active() {
			fmt.Fprintf(&buf, " (active)")
		}
		fmt.Fprintln(&buf)
	}
	fmt.Fprintln(&buf, "Content:")
	if p.Content != nil {
		fmt.Fprint(&buf, p.Content.Title())
	}

	return buf.String()
}

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}
<commit_msg>page.go: add ModTime as newest Date of all pages<commit_after>package glubcms

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"

	bm "github.com/microcosm-cc/bluemonday"
	bf "github.com/russross/blackfriday"
)

const (
	PSep = string(os.PathSeparator)
)

var (
	ErrHidden = errors.New("Hidden")
)

type Entry interface {
	Active() bool
	Author() string
	Date() time.Time
	HTML() template.HTML
	IsArticle() bool
	Link() string
	Priority() int
	Title() string
	Next() Entry
	Prev() Entry
}

type entries []entry

func (e entries) Len() int {
	return len(e)
}
func (e entries) Less(i, j int) bool {
	switch {
	case e[i].meta.IsIndex && !e[j].meta.IsIndex:
		return false
	case !e[i].meta.IsIndex && e[j].meta.IsIndex:
		return true
	case e[i].Priority() != e[j].Priority():
		return e[i].Priority() > e[j].Priority()
	}
	return e[i].Date().After(e[j].Date())
}
func (e entries) Swap(i, j int) {
	e[i], e[j] = e[j], e[i]
}
func (e entries) Split() (Menu, Articles entries) {
	for _, v := range e {
		if v.IsArticle() {
			Articles = append(Articles, v)
		} else {
			Menu = append(Menu, v)
		}
	}

	return
}

type GCTime time.Time

const GCTimeLayout = "2006-01-02 15:04"

func (t *GCTime) UnmarshalJSON(b []byte) error {
	tmp, err := time.Parse(GCTimeLayout, strings.Trim(string(b), "\""))
	if err != nil {
		err = errors.Wrapf(err, "time.Parse failed on %q", b)
	}
	*t = GCTime(tmp)
	return err
}

func (t GCTime) String() string {
	return time.Time(t).Format(GCTimeLayout)
}
func (t GCTime) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.String() + `"`), nil
}

type Meta struct {
	Author   string
	Date     GCTime
	Title    string
	Priority int
	Hidden   bool `json:",omitempty"`
	Unsafe   bool `json:",omitempty"`
	IsIndex  bool `json:",omitempty"`
}

type ContentRenderer interface {
	Render() ([]byte, error)
}

type entry struct {
	meta       Meta
	active     bool
	html       []byte
	isarticle  bool
	link       url.URL
	next       *entry
	prev       *entry
	fs         http.FileSystem
	md_path    string
	once       sync.Once
	renderHTML ContentRenderer
}

func (e entry) Active() bool {
	return e.active
}
func (a entry) Author() string {
	return a.meta.Author
}
func (e entry) Date() time.Time {
	return time.Time(e.meta.Date)
}
func (e *entry) HTML() template.HTML {
	e.once.Do(func() {
		var err error
		e.html, err = e.renderHTML.Render()
		if err != nil {
			//TODO make errorpage
			log.Println(err)
		}
	})
	return template.HTML(e.html)
}
func (e entry) IsArticle() bool {
	return e.isarticle
}
func (e entry) Link() string {
	return e.link.String()
}
func (e entry) Priority() int {
	return e.meta.Priority
}
func (e entry) Title() string {
	return e.meta.Title
}
func (e entry) Next() Entry {
	if e.next != nil {
		return e.next
	}
	return nil
}
func (e entry) Prev() Entry {
	if e.prev != nil {
		return e.prev
	}
	return nil
}
func (e entry) IsIndex() bool {
	return e.meta.IsIndex
}
func (e *entry) Context(c int) entries {
	next := e
	prev := e
	n := 1

	for {
		moved := false

		if n < c && next.next != nil {
			moved = true
			next = next.next
			n++
		}
		if n < c && prev.prev != nil {
			moved = true
			prev = prev.prev
			n++
		}

		if n == c || moved == false {
			break
		}
	}

	ret := make(entries, 0, n)
	t := next
	for n > 0 {
		ret = append(ret, *t)
		t = t.prev
		n--
	}
	return ret
}

func entryFromMeta(fs http.FileSystem, path string) (entry, error) {
	ret := entry{}
	f, err := fs.Open(filepath.Join(path))
	if err != nil {
		return ret, errors.Wrapf(err, "file open failed: %q", path)
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(&ret.meta)
	if err != nil {
		err = errors.Wrapf(err, "Parsing json in: %q", path)
	}
	return ret, err
}

func entryFromDir(fs http.FileSystem, path, activepath string) (ret entry, err error) {
	ret, err = entryFromMeta(fs, filepath.Join(path, "meta.json"))
	if err != nil {
		err = errors.Wrapf(err, "Cannot open meta.json in: %q", path)
		return ret, err
	}

	// skip hidden folders, unless directly asked for
	if ret.meta.Hidden && activepath != path {
		return ret, ErrHidden
	}

	ret.link = url.URL{Path: path}
	// .Dir() removes trailing slashes, this prevents
	// /a/b/ beeing seen as prefix from /a/bc/
	if strings.HasPrefix(activepath+PSep, path+PSep) {
		ret.active = true
	}

	md_path := filepath.Join(path, "article.md")
	md, err := fs.Open(md_path)
	// Decide wether this is menu or article
	// TODO add entry to metadata and remove implicit menus
	if err != nil {
		if !os.IsNotExist(err) {
			return ret, errors.Wrapf(err, "Cannot open article.md in: %q", path)
		}
		return ret, nil
	}
	md.Close()

	ret.isarticle = true
	ret.renderHTML = articleRenderer{
		fs:      fs,
		md_path: md_path,
		unsafe:  ret.meta.Unsafe,
	}

	return ret, nil
}

type articleRenderer struct {
	fs      http.FileSystem
	md_path string
	unsafe  bool
}

func (a articleRenderer) Render() ([]byte, error) {
	md, err := a.fs.Open(a.md_path)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot open markdown file: %q", a.md_path)
	}
	defer md.Close()

	b, err := ioutil.ReadAll(md)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot read markdown file: %q", a.md_path)
	}
	html := bf.Markdown(b, bf.HtmlRenderer(bf.HTML_USE_XHTML, "", ""), bf.EXTENSION_TABLES)
	if !a.unsafe {
		html = bm.UGCPolicy().SanitizeBytes(html)
	}
	return html, nil
}

func entriesFromDir(fs http.FileSystem, path, activepath string) (entries, error) {
	var ret entries

	dir, err := fs.Open(path)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot open directory: %q", path)
	}

	dirlist, err := dir.Readdir(0)
	if err != nil {
		return nil, errors.Wrapf(err, "Cannot read directory: %q", path)
	}
	dir.Close()

	for _, fi := range dirlist {
		if !fi.IsDir() {
			continue
		}
		entry, err := entryFromDir(fs, filepath.Join(path, fi.Name()), activepath)
		if err == nil {
			ret = append(ret, entry)
		}
	}

	sort.Sort(ret)
	return ret, nil
}

func latestOf(modtime time.Time, e *entry) time.Time {
	if e != nil && modtime.After(e.Date()) {
		return modtime
	}
	return modtime
}

type Page struct {
	Menu     []entries
	Articles entries
	Content  *entry
	Index    *entry
	ModTime  time.Time
}

func PageFromDir(fs http.FileSystem, path string) (Page, error) {
	var p Page
	path = filepath.Clean(path)
	activepath := path

	for {
		es, err := entriesFromDir(fs, path, activepath)
		if err != nil {
			return Page{}, errors.Wrap(err, "entriesFromDir")
		}

		menu, articles := es.Split()
		if len(menu) > 0 {
			sort.Sort(menu)
			p.Menu = append(p.Menu, menu)
		}

		if p.Articles == nil && len(articles) > 0 {
			sort.Sort(articles)
			p.Articles = articles

			// don't list the index page as article
			for p.Articles[len(p.Articles)-1].meta.IsIndex {
				p.Index = &p.Articles[len(p.Articles)-1]
				p.Articles = p.Articles[:len(p.Articles)-1]
			}

			// link next/prev pointers
			for i := 1; i < len(p.Articles); i++ {
				p.Articles[i].next = &p.Articles[i-1]
				p.Articles[i-1].prev = &p.Articles[i]
			}

			// set the active article as content
			for i := range articles {
				if articles[i].link.Path == activepath {
					p.Content = &articles[i]
					break
				}
			}

			// if no exact match, default to first article
			if p.Content == nil {
				p.Content = &p.Articles[0]
				p.Content.active = true
			}
		}

		if path == "." || path == "/" {
			break
		}

		path = filepath.Dir(path)
	}

	// building from deepest path to /, need to reverse
	for l, r := 0, len(p.Menu)-1; l < r; l, r = l+1, r-1 {
		p.Menu[l], p.Menu[r] = p.Menu[r], p.Menu[l]
	}

	// set ModTime to the latest of all values

	p.ModTime = latestOf(p.ModTime, p.Index)
	p.ModTime = latestOf(p.ModTime, p.Content)
	for _, es := range p.Menu {
		for i := range es {
			p.ModTime = latestOf(p.ModTime, &es[i])
		}
	}
	for i := range p.Articles {
		p.ModTime = latestOf(p.ModTime, &p.Articles[i])
	}

	return p, nil
}

// For debugging
func (p Page) Outline() string {
	buf := bytes.Buffer{}

	fmt.Fprintln(&buf, "Menu:")
	for level, ms := range p.Menu {
		for _, m := range ms {
			fmt.Fprintf(&buf, "%s%q", strings.Repeat("\t", level), m.Title())
			if m.Active() {
				fmt.Fprintf(&buf, " (active)")
			}
			fmt.Fprintln(&buf)
		}
	}

	fmt.Fprintln(&buf, "Articles:")
	for _, a := range p.Articles {
		fmt.Fprintf(&buf, "%q", a.Title())
		if a.Active() {
			fmt.Fprintf(&buf, " (active)")
		}
		fmt.Fprintln(&buf)
	}
	fmt.Fprintln(&buf, "Content:")
	if p.Content != nil {
		fmt.Fprint(&buf, p.Content.Title())
	}

	return buf.String()
}

func init() {
	log.SetFlags(log.Flags() | log.Lshortfile)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	"github.com/codegangsta/cli"

	"github.com/cafebazaar/kupak/pkg/pak"
	"github.com/cafebazaar/kupak/pkg/util"
)

func paks(c *cli.Context) error {
	repoAddresses := make([]string, 0)
	if c.GlobalIsSet("repo") {
		repoAddresses = append(repoAddresses, c.GlobalString("repo"))
	} else {
		reposFileCreateIfNotExist()
		for _, repoEntry := range reposFileEntries() {
			trimmed := strings.TrimSpace(repoEntry)
			if len(trimmed) > 0 {
				repoAddresses = append(repoAddresses, trimmed)
			}
		}
		if len(repoAddresses) == 0 {
			repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
		}
	}

	for _, repoAddress := range repoAddresses {
		repo, err := pak.RepoFromURL(repoAddress)
		if err != nil {
			return cli.NewExitError(fmt.Sprintf("can't fetch paks list: %v", err.Error()), -1)
		}
		fmt.Println("- Repository:", repoAddress)
		for i := range repo.Paks {
			fmt.Println("  - Name:", repo.Paks[i].Name)
			fmt.Println("    Version:", repo.Paks[i].Version)
			fmt.Println("    URL:", repo.Paks[i].URL)
			if len(repo.Paks[i].Tags) > 0 {
				fmt.Println("    Tags:", "["+strings.Join(repo.Paks[i].Tags, ", ")+"]")
			}
			fmt.Println("   ", strings.Trim(repo.Paks[i].Description, "\n"))
		}

	}
	return nil
}

func spec(c *cli.Context) error {
	pakURL := c.Args().First()
	if pakURL == "" {
		return cli.NewExitError("please specify the pak name", -1)
	}
	if strings.Index(pakURL, "/") == -1 &&
		!strings.HasSuffix(pakURL, ".json") &&
		!strings.HasSuffix(pakURL, ".yaml") {

		nameOfPakToCheck := pakURL
		repoAddr := c.GlobalString("repo")

		if len(repoAddr) > 0 {
			// TODO: change JoinURL
			repoPaks, err := pak.RepoFromURL(repoAddr)
			if err != nil {
				return cli.NewExitError(fmt.Sprintf("can't fetch the repo: %v", err.Error()), -1)
			}
			for _, pak := range repoPaks.Paks {
				if pak.Name == nameOfPakToCheck {
					pakURL = pak.URL
					if util.Relative(pakURL) {
						pakURL = util.JoinURL(repoAddr, pakURL)
					}
				}
			}
		}
	}
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("Name:", p.Name)
	fmt.Println("Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(strings.Trim(p.Description, "\n"))

	fmt.Println("\nProperties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println(" - Name:", property.Name)
		fmt.Println("   Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("   Type:", property.Type)
		if property.Default != nil {
			fmt.Println("   Default:", property.Default)
		}

	}
	return nil
}
<commit_msg>Added repos file functionality to spec sub-command<commit_after>package main

import (
	"fmt"
	"strings"

	"github.com/codegangsta/cli"

	"github.com/cafebazaar/kupak/pkg/pak"
	"github.com/cafebazaar/kupak/pkg/util"
)

func paks(c *cli.Context) error {
	repoAddresses := make([]string, 0)
	if c.GlobalIsSet("repo") {
		repoAddresses = append(repoAddresses, c.GlobalString("repo"))
	} else {
		reposFileCreateIfNotExist()
		for _, repoEntry := range reposFileEntries() {
			trimmed := strings.TrimSpace(repoEntry)
			if len(trimmed) > 0 {
				repoAddresses = append(repoAddresses, trimmed)
			}
		}
		if len(repoAddresses) == 0 {
			repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
		}
	}

	for _, repoAddress := range repoAddresses {
		repo, err := pak.RepoFromURL(repoAddress)
		if err != nil {
			return cli.NewExitError(fmt.Sprintf("can't fetch paks list: %v", err.Error()), -1)
		}
		fmt.Println("- Repository:", repoAddress)
		for i := range repo.Paks {
			fmt.Println("  - Name:", repo.Paks[i].Name)
			fmt.Println("    Version:", repo.Paks[i].Version)
			fmt.Println("    URL:", repo.Paks[i].URL)
			if len(repo.Paks[i].Tags) > 0 {
				fmt.Println("    Tags:", "["+strings.Join(repo.Paks[i].Tags, ", ")+"]")
			}
			fmt.Println("   ", strings.Trim(repo.Paks[i].Description, "\n"))
		}

	}
	return nil
}

func spec(c *cli.Context) error {
	pakURL := c.Args().First()
	if pakURL == "" {
		return cli.NewExitError("please specify the pak name", -1)
	}
	if strings.Index(pakURL, "/") == -1 &&
		!strings.HasSuffix(pakURL, ".json") &&
		!strings.HasSuffix(pakURL, ".yaml") {

		nameOfPakToCheck := pakURL

		repoAddresses := make([]string, 0)
		if c.GlobalIsSet("repo") {
			repoAddresses = append(repoAddresses, c.GlobalString("repo"))
		} else {
			reposFileCreateIfNotExist()
			for _, repoEntry := range reposFileEntries() {
				trimmed := strings.TrimSpace(repoEntry)
				if len(trimmed) > 0 {
					repoAddresses = append(repoAddresses, trimmed)
				}
			}
			if len(repoAddresses) == 0 {
				repoAddresses = append(repoAddresses, "github.com/cafebazaar/paks")
			}
		}

		for _, repoAddr := range repoAddresses {
			if len(repoAddr) > 0 {
				// TODO: change JoinURL
				repoPaks, err := pak.RepoFromURL(repoAddr)
				if err != nil {
					return cli.NewExitError(fmt.Sprintf("can't fetch the repo: %v", err.Error()), -1)
				}
				for _, pak := range repoPaks.Paks {
					if pak.Name == nameOfPakToCheck {
						pakURL = pak.URL
						if util.Relative(pakURL) {
							pakURL = util.JoinURL(repoAddr, pakURL)
						}
						specOfPakWithAbsoluteURLFromRepo(pakURL, repoAddr)
					}
				}
			}
		}
	} else {
		specOfPakWithAbsoluteURL(pakURL)
	}
	return nil
}

func specOfPakWithAbsoluteURLFromRepo(pakURL, repo string) error {
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("-Repository:", repo)
	fmt.Println("  Name:", p.Name)
	fmt.Println("  Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("  Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(" ", strings.Trim(p.Description, "\n"))

	fmt.Println("\n  Properties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println("   - Name:", property.Name)
		fmt.Println("     Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("     Type:", property.Type)
		if property.Default != nil {
			fmt.Println("     Default:", property.Default)
		}

	}
	return nil

}

func specOfPakWithAbsoluteURL(pakURL string) error {
	p, err := pak.FromURL(pakURL)
	if err != nil {
		return cli.NewExitError(fmt.Sprintf("can't fetch the specified pak: %v", err.Error()), -1)
	}
	fmt.Println("Name:", p.Name)
	fmt.Println("Version:", p.Version)
	if len(p.Tags) > 0 {
		fmt.Println("Tags:", "["+strings.Join(p.Tags, ", ")+"]")
	}
	fmt.Println(strings.Trim(p.Description, "\n"))

	fmt.Println("\nProperties:")
	for i := range p.Properties {
		property := p.Properties[i]
		fmt.Println(" - Name:", property.Name)
		fmt.Println("   Description:", strings.Trim(property.Description, "\n"))
		fmt.Println("   Type:", property.Type)
		if property.Default != nil {
			fmt.Println("   Default:", property.Default)
		}

	}
	return nil

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/bluele/slack"
)

var slackExpectedKeys = []string{"type", "check_url", "channel"}

// SlackNotifier represents notifier for Slack
type SlackNotifier struct {
	apiToken   string
	webhookURL string
	userName   string
	channel    string
}

// NewSlackNotifier create new SlackNotifier instance
func NewSlackNotifier(apiToken string, webhookURL string, userName string, channel string) *SlackNotifier {
	s := new(SlackNotifier)
	s.apiToken = apiToken
	s.webhookURL = webhookURL
	s.channel = channel

	if len(userName) == 0 {
		s.userName = "zatsu_monitor"
	} else {
		s.userName = userName
	}

	return s
}

// ExpectedKeys returns expected keys for SlackNotifier
func (s *SlackNotifier) ExpectedKeys() []string {
	return slackExpectedKeys
}

// PostStatus perform posting current status for URL
func (s *SlackNotifier) PostStatus(param *PostStatusParam) error {
	var statusText, iconEmoji, userName string

	successful := IsSuccessfulStatus(param.CurrentStatusCode)

	if successful {
		statusText = "ok"
		iconEmoji = ":green_heart:"
		userName = s.userName + " Successful"
	} else {
		statusText = "down"
		iconEmoji = ":broken_heart:"
		userName = s.userName + " Failure"
	}

	format := `%s is %s
statusCode: %d -> %d
responseTime: %f sec`
	message := fmt.Sprintf(format, param.CheckURL, statusText, param.BeforeStatusCode, param.CurrentStatusCode, param.ResponseTime)

	if param.HTTPError != nil {
		message += fmt.Sprintf("\nhttpError: %v", param.HTTPError)
	}

	if len(s.apiToken) > 0 {
		params := slack.ChatPostMessageOpt{
			Username:  userName,
			IconEmoji: iconEmoji,
		}

		api := slack.New(s.apiToken)

		return api.ChatPostMessage(s.channel, message, &params)

	} else if len(s.webhookURL) > 0 {
		hook := slack.NewWebHook(s.webhookURL)
		params := slack.WebHookPostPayload{
			Text:      message,
			Channel:   s.channel,
			Username:  userName,
			IconEmoji: iconEmoji,
		}
		return hook.PostMessage(&params)

	} else {
		return errors.New("Either `api_token` or `webhook_url` is required")
	}
}
<commit_msg>Use attachment text instead of plain text<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/bluele/slack"
)

var slackExpectedKeys = []string{"type", "check_url", "channel"}

// SlackNotifier represents notifier for Slack
type SlackNotifier struct {
	apiToken   string
	webhookURL string
	userName   string
	channel    string
}

// NewSlackNotifier create new SlackNotifier instance
func NewSlackNotifier(apiToken string, webhookURL string, userName string, channel string) *SlackNotifier {
	s := new(SlackNotifier)
	s.apiToken = apiToken
	s.webhookURL = webhookURL
	s.channel = channel

	if len(userName) == 0 {
		s.userName = "zatsu_monitor"
	} else {
		s.userName = userName
	}

	return s
}

// ExpectedKeys returns expected keys for SlackNotifier
func (s *SlackNotifier) ExpectedKeys() []string {
	return slackExpectedKeys
}

// PostStatus perform posting current status for URL
func (s *SlackNotifier) PostStatus(param *PostStatusParam) error {
	var statusText, iconEmoji, userName, attachmentColor string

	successful := IsSuccessfulStatus(param.CurrentStatusCode)

	if successful {
		statusText = "ok"
		iconEmoji = ":green_heart:"
		userName = s.userName + " Successful"
		attachmentColor = "good"
	} else {
		statusText = "down"
		iconEmoji = ":broken_heart:"
		userName = s.userName + " Failure"
		attachmentColor = "danger"
	}

	format := `%s is %s
statusCode: %d -> %d
responseTime: %f sec`
	message := fmt.Sprintf(format, param.CheckURL, statusText, param.BeforeStatusCode, param.CurrentStatusCode, param.ResponseTime)

	if param.HTTPError != nil {
		message += fmt.Sprintf("\nhttpError: %v", param.HTTPError)
	}

	if len(s.apiToken) > 0 {
		params := slack.ChatPostMessageOpt{
			Username:  userName,
			IconEmoji: iconEmoji,
			Attachments: []*slack.Attachment{
				{Fallback: message, Text: message, Color: attachmentColor},
			},
		}

		api := slack.New(s.apiToken)

		return api.ChatPostMessage(s.channel, "", &params)

	} else if len(s.webhookURL) > 0 {
		hook := slack.NewWebHook(s.webhookURL)
		params := slack.WebHookPostPayload{
			Channel:   s.channel,
			Username:  userName,
			IconEmoji: iconEmoji,
			Attachments: []*slack.Attachment{
				{Fallback: message, Text: message, Color: attachmentColor},
			},
		}
		return hook.PostMessage(&params)

	} else {
		return errors.New("Either `api_token` or `webhook_url` is required")
	}
}
<|endoftext|>