<commit_before>package controller

import (
	"strconv"
	"strings"

	"github.com/cuigh/auxo/data"
	"github.com/cuigh/auxo/errors"
	"github.com/cuigh/auxo/net/web"
	"github.com/cuigh/auxo/util/cast"
	"github.com/cuigh/swirl/biz"
	"github.com/cuigh/swirl/biz/docker"
	"github.com/cuigh/swirl/misc"
	"github.com/cuigh/swirl/model"
)

// ServiceController is a controller of docker service
type ServiceController struct {
	List       web.HandlerFunc `path:"/" name:"service.list" authorize:"!" desc:"service list page"`
	Detail     web.HandlerFunc `path:"/:name/detail" name:"service.detail" authorize:"!" perm:"read,service,name"`
	Raw        web.HandlerFunc `path:"/:name/raw" name:"service.raw" authorize:"!" perm:"read,service,name"`
	Logs       web.HandlerFunc `path:"/:name/logs" name:"service.logs" authorize:"!" perm:"read,service,name"`
	Delete     web.HandlerFunc `path:"/:name/delete" method:"post" name:"service.delete" authorize:"!" perm:"write,service,name"`
	Scale      web.HandlerFunc `path:"/:name/scale" method:"post" name:"service.scale" authorize:"!" perm:"write,service,name"`
	Rollback   web.HandlerFunc `path:"/:name/rollback" method:"post" name:"service.rollback" authorize:"!" perm:"write,service,name"`
	New        web.HandlerFunc `path:"/new" name:"service.new" authorize:"!" desc:"new service page"`
	Create     web.HandlerFunc `path:"/new" method:"post" name:"service.create" authorize:"!" desc:"create service"`
	Edit       web.HandlerFunc `path:"/:name/edit" name:"service.edit" authorize:"!" perm:"write,service,name"`
	Update     web.HandlerFunc `path:"/:name/edit" method:"post" name:"service.update" authorize:"!" perm:"write,service,name"`
	PermEdit   web.HandlerFunc `path:"/:name/perm" name:"service.perm.edit" authorize:"!" perm:"write,service,name"`
	PermUpdate web.HandlerFunc `path:"/:name/perm" method:"post" name:"service.perm.update" authorize:"!" perm:"write,service,name"`
}

// Service creates an instance of ServiceController
func Service() (c *ServiceController) {
	return &ServiceController{
		List:       serviceList,
		Detail:     serviceDetail,
		Raw:        serviceRaw,
		Logs:       serviceLogs,
		Delete:     serviceDelete,
		New:        serviceNew,
		Create:     serviceCreate,
		Edit:       serviceEdit,
		Update:     serviceUpdate,
		Scale:      serviceScale,
		Rollback:   serviceRollback,
		PermEdit:   servicePermEdit,
		PermUpdate: permUpdate("service", "name"),
	}
}

func serviceList(ctx web.Context) error {
	name := ctx.Q("name")
	page := cast.ToInt(ctx.Q("page"), 1)
	services, totalCount, err := docker.ServiceList(name, page, model.PageSize)
	if err != nil {
		return err
	}

	m := newPagerModel(ctx, totalCount, model.PageSize, page).
		Set("Name", name).
		Set("Services", services)
	return ctx.Render("service/list", m)
}

func serviceDetail(ctx web.Context) error {
	name := ctx.P("name")
	service, _, err := docker.ServiceInspect(name)
	if err != nil {
		return err
	}

	info := model.NewServiceDetailInfo(service)
	for _, vip := range service.Endpoint.VirtualIPs {
		n, e := docker.NetworkInspect(vip.NetworkID)
		if e != nil {
			return e
		}
		info.Networks = append(info.Networks, model.Network{ID: vip.NetworkID, Name: n.Name, Address: vip.Addr})
	}

	tasks, _, err := docker.TaskList(&model.TaskListArgs{Service: name})
	if err != nil {
		return err
	}

	cmd, err := docker.ServiceCommand(name)
	if err != nil {
		return err
	}

	m := newModel(ctx).Set("Service", info).Set("Tasks", tasks).Set("Command", cmd)
	return ctx.Render("service/detail", m)
}

func serviceRaw(ctx web.Context) error {
	name := ctx.P("name")
	_, raw, err := docker.ServiceInspect(name)
	if err != nil {
		return err
	}

	j, err := misc.JSONIndent(raw)
	if err != nil {
		return err
	}

	m := newModel(ctx).Set("Service", name).Set("Raw", j)
	return ctx.Render("service/raw", m)
}

func serviceLogs(ctx web.Context) error {
	name := ctx.P("name")
	line := cast.ToInt(ctx.Q("line"), 500)
	timestamps := cast.ToBool(ctx.Q("timestamps"), false)
	stdout, stderr, err := docker.ServiceLogs(name, line, timestamps)
	if err != nil {
		return err
	}

	m := newModel(ctx).Set("Service", name).Set("Line", line).Set("Timestamps", timestamps).
		Set("Stdout", stdout.String()).Set("Stderr", stderr.String())
	return ctx.Render("service/logs", m)
}

func serviceDelete(ctx web.Context) error {
	names := strings.Split(ctx.F("names"), ",")
	for _, name := range names {
		if err := docker.ServiceRemove(name); err != nil {
			return ajaxResult(ctx, err)
		}
		biz.Event.CreateService(model.EventActionDelete, name, ctx.User())
	}
	return ajaxSuccess(ctx, nil)
}

func serviceNew(ctx web.Context) error {
	info := &model.ServiceInfo{}
	tid := ctx.Q("template")
	if tid != "" {
		err := biz.Template.FillInfo(tid, info)
		if err != nil {
			return err
		}
	}

	networks, err := docker.NetworkList()
	if err != nil {
		return err
	}
	secrets, _, err := docker.SecretList("", 1, 100)
	if err != nil {
		return err
	}
	configs, _, err := docker.ConfigList("", 1, 100)
	if err != nil {
		return err
	}
	registries, err := biz.Registry.List()
	if err != nil {
		return err
	}

	checkedNetworks := data.NewSet()
	checkedNetworks.AddSlice(info.Networks, func(i int) interface{} {
		return info.Networks[i]
	})

	m := newModel(ctx).Set("Service", info).Set("Registries", registries).
		Set("Networks", networks).Set("CheckedNetworks", checkedNetworks).
		Set("Secrets", secrets).Set("Configs", configs)
	return ctx.Render("service/new", m)
}

func serviceCreate(ctx web.Context) error {
	info := &model.ServiceInfo{}
	err := ctx.Bind(info)
	if err != nil {
		return err
	}

	if info.Registry != "" {
		var registry *model.Registry
		registry, err = biz.Registry.Get(info.Registry)
		if err != nil {
			return errors.Wrap(err, "load registry info failed")
		} else if registry == nil {
			return errors.New("can't load registry info")
		}

		info.Image = registry.URL + "/" + info.Image
		info.RegistryAuth = registry.GetEncodedAuth()
	}

	if err = docker.ServiceCreate(info); err == nil {
		biz.Event.CreateService(model.EventActionCreate, info.Name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func serviceEdit(ctx web.Context) error {
	name := ctx.P("name")
	service, _, err := docker.ServiceInspect(name)
	if err != nil {
		return err
	}

	networks, err := docker.NetworkList()
	if err != nil {
		return err
	}
	secrets, _, err := docker.SecretList("", 1, 100)
	if err != nil {
		return err
	}
	configs, _, err := docker.ConfigList("", 1, 100)
	if err != nil {
		return err
	}

	stack := service.Spec.Labels["com.docker.stack.namespace"]
	checkedNetworks := data.NewSet()
	checkedNetworks.AddSlice(service.Endpoint.VirtualIPs, func(i int) interface{} { return service.Endpoint.VirtualIPs[i].NetworkID })

	m := newModel(ctx).Set("Service", model.NewServiceInfo(service)).Set("Stack", stack).
		Set("Networks", networks).Set("CheckedNetworks", checkedNetworks).
		Set("Secrets", secrets).Set("Configs", configs)
	return ctx.Render("service/edit", m)
}

func serviceUpdate(ctx web.Context) error {
	info := &model.ServiceInfo{}
	err := ctx.Bind(info)
	if err == nil {
		info.Name = ctx.P("name")
		err = docker.ServiceUpdate(info)
	}

	if err == nil {
		biz.Event.CreateService(model.EventActionUpdate, info.Name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func serviceScale(ctx web.Context) error {
	name := ctx.F("name")
	count, err := strconv.Atoi(ctx.F("count"))
	if err != nil {
		return err
	}

	err = docker.ServiceScale(name, uint64(count))
	if err == nil {
		biz.Event.CreateService(model.EventActionScale, name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func serviceRollback(ctx web.Context) error {
	name := ctx.F("name")
	err := docker.ServiceRollback(name)
	if err == nil {
		biz.Event.CreateService(model.EventActionRollback, name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func servicePermEdit(ctx web.Context) error {
	name := ctx.P("name")
	m := newModel(ctx).Set("Name", name)
	return permEdit(ctx, "service", name, "service/perm", m)
}
<commit_msg>Fix issue of failed to modify configs & secrets<commit_after>package controller

import (
	"strconv"
	"strings"

	"github.com/cuigh/auxo/data"
	"github.com/cuigh/auxo/errors"
	"github.com/cuigh/auxo/net/web"
	"github.com/cuigh/auxo/util/cast"
	"github.com/cuigh/swirl/biz"
	"github.com/cuigh/swirl/biz/docker"
	"github.com/cuigh/swirl/misc"
	"github.com/cuigh/swirl/model"
)

// ServiceController is a controller of docker service
type ServiceController struct {
	List       web.HandlerFunc `path:"/" name:"service.list" authorize:"!" desc:"service list page"`
	Detail     web.HandlerFunc `path:"/:name/detail" name:"service.detail" authorize:"!" perm:"read,service,name"`
	Raw        web.HandlerFunc `path:"/:name/raw" name:"service.raw" authorize:"!" perm:"read,service,name"`
	Logs       web.HandlerFunc `path:"/:name/logs" name:"service.logs" authorize:"!" perm:"read,service,name"`
	Delete     web.HandlerFunc `path:"/:name/delete" method:"post" name:"service.delete" authorize:"!" perm:"write,service,name"`
	Scale      web.HandlerFunc `path:"/:name/scale" method:"post" name:"service.scale" authorize:"!" perm:"write,service,name"`
	Rollback   web.HandlerFunc `path:"/:name/rollback" method:"post" name:"service.rollback" authorize:"!" perm:"write,service,name"`
	New        web.HandlerFunc `path:"/new" name:"service.new" authorize:"!" desc:"new service page"`
	Create     web.HandlerFunc `path:"/new" method:"post" name:"service.create" authorize:"!" desc:"create service"`
	Edit       web.HandlerFunc `path:"/:name/edit" name:"service.edit" authorize:"!" perm:"write,service,name"`
	Update     web.HandlerFunc `path:"/:name/edit" method:"post" name:"service.update" authorize:"!" perm:"write,service,name"`
	PermEdit   web.HandlerFunc `path:"/:name/perm" name:"service.perm.edit" authorize:"!" perm:"write,service,name"`
	PermUpdate web.HandlerFunc `path:"/:name/perm" method:"post" name:"service.perm.update" authorize:"!" perm:"write,service,name"`
}

// Service creates an instance of ServiceController
func Service() (c *ServiceController) {
	return &ServiceController{
		List:       serviceList,
		Detail:     serviceDetail,
		Raw:        serviceRaw,
		Logs:       serviceLogs,
		Delete:     serviceDelete,
		New:        serviceNew,
		Create:     serviceCreate,
		Edit:       serviceEdit,
		Update:     serviceUpdate,
		Scale:      serviceScale,
		Rollback:   serviceRollback,
		PermEdit:   servicePermEdit,
		PermUpdate: permUpdate("service", "name"),
	}
}

func serviceList(ctx web.Context) error {
	name := ctx.Q("name")
	page := cast.ToInt(ctx.Q("page"), 1)
	services, totalCount, err := docker.ServiceList(name, page, model.PageSize)
	if err != nil {
		return err
	}

	m := newPagerModel(ctx, totalCount, model.PageSize, page).
		Set("Name", name).
		Set("Services", services)
	return ctx.Render("service/list", m)
}

func serviceDetail(ctx web.Context) error {
	name := ctx.P("name")
	service, _, err := docker.ServiceInspect(name)
	if err != nil {
		return err
	}

	info := model.NewServiceDetailInfo(service)
	for _, vip := range service.Endpoint.VirtualIPs {
		n, e := docker.NetworkInspect(vip.NetworkID)
		if e != nil {
			return e
		}
		info.Networks = append(info.Networks, model.Network{ID: vip.NetworkID, Name: n.Name, Address: vip.Addr})
	}

	tasks, _, err := docker.TaskList(&model.TaskListArgs{Service: name})
	if err != nil {
		return err
	}

	cmd, err := docker.ServiceCommand(name)
	if err != nil {
		return err
	}

	m := newModel(ctx).Set("Service", info).Set("Tasks", tasks).Set("Command", cmd)
	return ctx.Render("service/detail", m)
}

func serviceRaw(ctx web.Context) error {
	name := ctx.P("name")
	_, raw, err := docker.ServiceInspect(name)
	if err != nil {
		return err
	}

	j, err := misc.JSONIndent(raw)
	if err != nil {
		return err
	}

	m := newModel(ctx).Set("Service", name).Set("Raw", j)
	return ctx.Render("service/raw", m)
}

func serviceLogs(ctx web.Context) error {
	name := ctx.P("name")
	line := cast.ToInt(ctx.Q("line"), 500)
	timestamps := cast.ToBool(ctx.Q("timestamps"), false)
	stdout, stderr, err := docker.ServiceLogs(name, line, timestamps)
	if err != nil {
		return err
	}

	m := newModel(ctx).Set("Service", name).Set("Line", line).Set("Timestamps", timestamps).
		Set("Stdout", stdout.String()).Set("Stderr", stderr.String())
	return ctx.Render("service/logs", m)
}

func serviceDelete(ctx web.Context) error {
	names := strings.Split(ctx.F("names"), ",")
	for _, name := range names {
		if err := docker.ServiceRemove(name); err != nil {
			return ajaxResult(ctx, err)
		}
		biz.Event.CreateService(model.EventActionDelete, name, ctx.User())
	}
	return ajaxSuccess(ctx, nil)
}

func serviceNew(ctx web.Context) error {
	info := &model.ServiceInfo{}
	tid := ctx.Q("template")
	if tid != "" {
		err := biz.Template.FillInfo(tid, info)
		if err != nil {
			return err
		}
	}

	networks, err := docker.NetworkList()
	if err != nil {
		return err
	}
	secrets, _, err := docker.SecretList("", 1, 100)
	if err != nil {
		return err
	}
	configs, _, err := docker.ConfigList("", 1, 100)
	if err != nil {
		return err
	}
	registries, err := biz.Registry.List()
	if err != nil {
		return err
	}

	checkedNetworks := data.NewSet()
	checkedNetworks.AddSlice(info.Networks, func(i int) interface{} {
		return info.Networks[i]
	})

	m := newModel(ctx).Set("Service", info).Set("Registries", registries).
		Set("Networks", networks).Set("CheckedNetworks", checkedNetworks).
		Set("Secrets", secrets).Set("Configs", configs)
	return ctx.Render("service/new", m)
}

func serviceCreate(ctx web.Context) error {
	info := &model.ServiceInfo{}
	err := ctx.Bind(info)
	if err != nil {
		return err
	}
	info.Normalize()

	if info.Registry != "" {
		var registry *model.Registry
		registry, err = biz.Registry.Get(info.Registry)
		if err != nil {
			return errors.Wrap(err, "load registry info failed")
		} else if registry == nil {
			return errors.New("can't load registry info")
		}

		info.Image = registry.URL + "/" + info.Image
		info.RegistryAuth = registry.GetEncodedAuth()
	}

	if err = docker.ServiceCreate(info); err == nil {
		biz.Event.CreateService(model.EventActionCreate, info.Name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func serviceEdit(ctx web.Context) error {
	name := ctx.P("name")
	service, _, err := docker.ServiceInspect(name)
	if err != nil {
		return err
	}

	networks, err := docker.NetworkList()
	if err != nil {
		return err
	}
	secrets, _, err := docker.SecretList("", 1, 100)
	if err != nil {
		return err
	}
	configs, _, err := docker.ConfigList("", 1, 100)
	if err != nil {
		return err
	}

	stack := service.Spec.Labels["com.docker.stack.namespace"]
	checkedNetworks := data.NewSet()
	checkedNetworks.AddSlice(service.Endpoint.VirtualIPs, func(i int) interface{} { return service.Endpoint.VirtualIPs[i].NetworkID })

	m := newModel(ctx).Set("Service", model.NewServiceInfo(service)).Set("Stack", stack).
		Set("Networks", networks).Set("CheckedNetworks", checkedNetworks).
		Set("Secrets", secrets).Set("Configs", configs)
	return ctx.Render("service/edit", m)
}

func serviceUpdate(ctx web.Context) error {
	info := &model.ServiceInfo{}
	err := ctx.Bind(info)
	if err == nil {
		info.Name = ctx.P("name")
		info.Normalize()
		err = docker.ServiceUpdate(info)
	}

	if err == nil {
		biz.Event.CreateService(model.EventActionUpdate, info.Name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func serviceScale(ctx web.Context) error {
	name := ctx.F("name")
	count, err := strconv.Atoi(ctx.F("count"))
	if err != nil {
		return err
	}

	err = docker.ServiceScale(name, uint64(count))
	if err == nil {
		biz.Event.CreateService(model.EventActionScale, name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func serviceRollback(ctx web.Context) error {
	name := ctx.F("name")
	err := docker.ServiceRollback(name)
	if err == nil {
		biz.Event.CreateService(model.EventActionRollback, name, ctx.User())
	}
	return ajaxResult(ctx, err)
}

func servicePermEdit(ctx web.Context) error {
	name := ctx.P("name")
	m := newModel(ctx).Set("Name", name)
	return permEdit(ctx, "service", name, "service/perm", m)
}
<|endoftext|>


<commit_before>package otto

// _environment

type _environment interface {
	HasBinding(string) bool

	CreateMutableBinding(string, bool)
	SetMutableBinding(string, Value, bool)
	// SetMutableBinding with Lazy CreateMutableBinding(..., true)
	SetValue(string, Value, bool)

	GetBindingValue(string, bool) Value
	GetValue(string, bool) Value // GetBindingValue
	DeleteBinding(string) bool
	ImplicitThisValue() *_object

	Outer() _environment

	newReference(string, bool) _reference
}

// _functionEnvironment

type _functionEnvironment struct {
	_objectEnvironment
	arguments           *_object
	indexOfArgumentName map[string]string
}

func (runtime *_runtime) newFunctionEnvironment(outer _environment) *_functionEnvironment {
	return &_functionEnvironment{
		_objectEnvironment: _objectEnvironment{
			outer:  outer,
			Object: runtime.newObject(),
		},
	}
}

func (self *_functionEnvironment) newReference(name string, strict bool) _reference {
	index, exists := self.indexOfArgumentName[name]
	if !exists {
		return self._objectEnvironment.newReference(name, strict)
	}
	return newArgumentReference(self.arguments, index, strict)
}

func (self *_functionEnvironment) HasBinding(name string) bool {
	_, exists := self.indexOfArgumentName[name]
	if exists {
		return true
	}
	return self.Object.hasProperty(name)
}

// _objectEnvironment

type _objectEnvironment struct {
	runtime     *_runtime
	outer       _environment
	Object      *_object
	ProvideThis bool
}

func (runtime *_runtime) newObjectEnvironment(object *_object, outer _environment) *_objectEnvironment {
	if object == nil {
		object = runtime.newBaseObject()
	}
	return &_objectEnvironment{
		runtime: runtime,
		outer:   outer,
		Object:  object,
	}
}

func (self *_objectEnvironment) HasBinding(name string) bool {
	return self.Object.hasProperty(name)
}

func (self *_objectEnvironment) CreateMutableBinding(name string, deletable bool) {
	if self.Object.hasProperty(name) {
		panic(hereBeDragons())
	}
	mode := _propertyMode(0111)
	if !deletable {
		mode = _propertyMode(0110)
	}
	self.Object.stash.set(name, UndefinedValue(), mode)
}

func (self *_objectEnvironment) SetMutableBinding(name string, value Value, strict bool) {
	self.Object.set(name, value, strict)
}

func (self *_objectEnvironment) SetValue(name string, value Value, throw bool) {
	if !self.HasBinding(name) {
		self.CreateMutableBinding(name, true) // Configureable by default
	}
	self.SetMutableBinding(name, value, throw)
}

func (self *_objectEnvironment) GetBindingValue(name string, strict bool) Value {
	if self.Object.hasProperty(name) {
		return self.Object.get(name)
	}
	if strict {
		panic(newReferenceError("Not Defined", name))
	}
	return UndefinedValue()
}

func (self *_objectEnvironment) GetValue(name string, throw bool) Value {
	return self.GetBindingValue(name, throw)
}

func (self *_objectEnvironment) DeleteBinding(name string) bool {
	return self.Object.delete(name, false)
}

func (self *_objectEnvironment) ImplicitThisValue() *_object {
	if self.ProvideThis {
		return self.Object
	}
	return nil
}

func (self *_objectEnvironment) Outer() _environment {
	return self.outer
}

func (self *_objectEnvironment) newReference(name string, strict bool) _reference {
	return newPropertyReference(self.Object, name, strict, nil)
}

// _declarativeEnvironment

func (runtime *_runtime) newDeclarativeEnvironment(outer _environment) *_declarativeEnvironment {
	return &_declarativeEnvironment{
		runtime: runtime,
		outer:   outer,
		stash:   map[string]*_declarativeProperty{},
	}
}

type _declarativeProperty struct {
	value     Value
	mutable   bool
	deletable bool
}

type _declarativeEnvironment struct {
	runtime *_runtime
	outer   _environment
	stash   map[string]*_declarativeProperty
}

func (self *_declarativeEnvironment) HasBinding(name string) bool {
	_, exists := self.stash[name]
	return exists
}

func (self *_declarativeEnvironment) CreateMutableBinding(name string, deletable bool) {
	_, exists := self.stash[name]
	if exists {
		panic(hereBeDragons())
	}
	self.stash[name] = &_declarativeProperty{
		value:     UndefinedValue(),
		mutable:   true,
		deletable: deletable,
	}
}

func (self *_declarativeEnvironment) SetMutableBinding(name string, value Value, strict bool) {
	property := self.stash[name]
	if property == nil {
		panic(hereBeDragons())
	}
	if property.mutable {
		property.value = value
	} else {
		typeErrorResult(strict)
	}
}

func (self *_declarativeEnvironment) SetValue(name string, value Value, throw bool) {
	if !self.HasBinding(name) {
		self.CreateMutableBinding(name, true) // Deletable by default
	}
	self.SetMutableBinding(name, value, throw)
}

func (self *_declarativeEnvironment) GetBindingValue(name string, strict bool) Value {
	property := self.stash[name]
	if property == nil {
		panic(hereBeDragons())
	}
	if !property.mutable {
		// TODO If uninitialized...
	}
	return property.value
}

func (self *_declarativeEnvironment) GetValue(name string, throw bool) Value {
	return self.GetBindingValue(name, throw)
}

func (self *_declarativeEnvironment) DeleteBinding(name string) bool {
	property := self.stash[name]
	if property == nil {
		delete(self.stash, name)
		return false
	}
	if !property.deletable {
		return false
	}
	delete(self.stash, name)
	return true
}

func (self *_declarativeEnvironment) ImplicitThisValue() *_object {
	return nil
}

func (self *_declarativeEnvironment) Outer() _environment {
	return self.outer
}

func (self *_declarativeEnvironment) newReference(name string, strict bool) _reference {
	return newEnvironmentReference(self, name, strict, nil)
}
<commit_msg>Mutable bindings should not be deletable by default<commit_after>package otto

// _environment

type _environment interface {
	HasBinding(string) bool

	CreateMutableBinding(string, bool)
	SetMutableBinding(string, Value, bool)
	// SetMutableBinding with Lazy CreateMutableBinding(..., true)
	SetValue(string, Value, bool)

	GetBindingValue(string, bool) Value
	GetValue(string, bool) Value // GetBindingValue
	DeleteBinding(string) bool
	ImplicitThisValue() *_object

	Outer() _environment

	newReference(string, bool) _reference
}

// _functionEnvironment

type _functionEnvironment struct {
	_objectEnvironment
	arguments           *_object
	indexOfArgumentName map[string]string
}

func (runtime *_runtime) newFunctionEnvironment(outer _environment) *_functionEnvironment {
	return &_functionEnvironment{
		_objectEnvironment: _objectEnvironment{
			outer:  outer,
			Object: runtime.newObject(),
		},
	}
}

func (self *_functionEnvironment) newReference(name string, strict bool) _reference {
	index, exists := self.indexOfArgumentName[name]
	if !exists {
		return self._objectEnvironment.newReference(name, strict)
	}
	return newArgumentReference(self.arguments, index, strict)
}

func (self *_functionEnvironment) HasBinding(name string) bool {
	_, exists := self.indexOfArgumentName[name]
	if exists {
		return true
	}
	return self.Object.hasProperty(name)
}

// _objectEnvironment

type _objectEnvironment struct {
	runtime     *_runtime
	outer       _environment
	Object      *_object
	ProvideThis bool
}

func (runtime *_runtime) newObjectEnvironment(object *_object, outer _environment) *_objectEnvironment {
	if object == nil {
		object = runtime.newBaseObject()
	}
	return &_objectEnvironment{
		runtime: runtime,
		outer:   outer,
		Object:  object,
	}
}

func (self *_objectEnvironment) HasBinding(name string) bool {
	return self.Object.hasProperty(name)
}

func (self *_objectEnvironment) CreateMutableBinding(name string, deletable bool) {
	if self.Object.hasProperty(name) {
		panic(hereBeDragons())
	}
	mode := _propertyMode(0111)
	if !deletable {
		mode = _propertyMode(0110)
	}
	self.Object.stash.set(name, UndefinedValue(), mode)
}

func (self *_objectEnvironment) SetMutableBinding(name string, value Value, strict bool) {
	self.Object.set(name, value, strict)
}

func (self *_objectEnvironment) SetValue(name string, value Value, throw bool) {
	if !self.HasBinding(name) {
		self.CreateMutableBinding(name, true) // Configureable by default
	}
	self.SetMutableBinding(name, value, throw)
}

func (self *_objectEnvironment) GetBindingValue(name string, strict bool) Value {
	if self.Object.hasProperty(name) {
		return self.Object.get(name)
	}
	if strict {
		panic(newReferenceError("Not Defined", name))
	}
	return UndefinedValue()
}

func (self *_objectEnvironment) GetValue(name string, throw bool) Value {
	return self.GetBindingValue(name, throw)
}

func (self *_objectEnvironment) DeleteBinding(name string) bool {
	return self.Object.delete(name, false)
}

func (self *_objectEnvironment) ImplicitThisValue() *_object {
	if self.ProvideThis {
		return self.Object
	}
	return nil
}

func (self *_objectEnvironment) Outer() _environment {
	return self.outer
}

func (self *_objectEnvironment) newReference(name string, strict bool) _reference {
	return newPropertyReference(self.Object, name, strict, nil)
}

// _declarativeEnvironment

func (runtime *_runtime) newDeclarativeEnvironment(outer _environment) *_declarativeEnvironment {
	return &_declarativeEnvironment{
		runtime: runtime,
		outer:   outer,
		stash:   map[string]*_declarativeProperty{},
	}
}

type _declarativeProperty struct {
	value     Value
	mutable   bool
	deletable bool
}

type _declarativeEnvironment struct {
	runtime *_runtime
	outer   _environment
	stash   map[string]*_declarativeProperty
}

func (self *_declarativeEnvironment) HasBinding(name string) bool {
	_, exists := self.stash[name]
	return exists
}

func (self *_declarativeEnvironment) CreateMutableBinding(name string, deletable bool) {
	_, exists := self.stash[name]
	if exists {
		panic(hereBeDragons())
	}
	self.stash[name] = &_declarativeProperty{
		value:     UndefinedValue(),
		mutable:   true,
		deletable: deletable,
	}
}

func (self *_declarativeEnvironment) SetMutableBinding(name string, value Value, strict bool) {
	property := self.stash[name]
	if property == nil {
		panic(hereBeDragons())
	}
	if property.mutable {
		property.value = value
	} else {
		typeErrorResult(strict)
	}
}

func (self *_declarativeEnvironment) SetValue(name string, value Value, throw bool) {
	if !self.HasBinding(name) {
		self.CreateMutableBinding(name, false) // NOT deletable by default
	}
	self.SetMutableBinding(name, value, throw)
}

func (self *_declarativeEnvironment) GetBindingValue(name string, strict bool) Value {
	property := self.stash[name]
	if property == nil {
		panic(hereBeDragons())
	}
	if !property.mutable {
		// TODO If uninitialized...
	}
	return property.value
}

func (self *_declarativeEnvironment) GetValue(name string, throw bool) Value {
	return self.GetBindingValue(name, throw)
}

func (self *_declarativeEnvironment) DeleteBinding(name string) bool {
	property := self.stash[name]
	if property == nil {
		delete(self.stash, name)
		return false
	}
	if !property.deletable {
		return false
	}
	delete(self.stash, name)
	return true
}

func (self *_declarativeEnvironment) ImplicitThisValue() *_object {
	return nil
}

func (self *_declarativeEnvironment) Outer() _environment {
	return self.outer
}

func (self *_declarativeEnvironment) newReference(name string, strict bool) _reference {
	return newEnvironmentReference(self, name, strict, nil)
}
<|endoftext|>


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

/*

Package file provides a file-based implementation of the catalog
package.

*/
package file

import (
	"github.com/couchbaselabs/tuqtng/catalog"
	"github.com/couchbaselabs/tuqtng/query"
	"path/filepath"
	"strings"
)

// site is the root for the file-based Site.
type site struct {
	path      string
	pools     map[string]*pool
	poolNames []string
}

func (s *site) URL() string {
	return "file://" + s.path
}

func (s *site) PoolNames() ([]string, query.Error) {
	return s.poolNames, nil
}

func (s *site) Pool(name string) (p Pool, e query.Error) {
	p, ok := s.pools[strings.ToUpper(name)]
	if !ok {
		e = query.NewError("Pool " + name + " not found.")
	}
}

// NewSite creates a new file-based site for the given filepath.
func NewSite(path string) (s Site, e query.Error) {
	s = new(site)
	s.path = path

	e = s.loadPools()
	if e != nil {
		s = nil
	}
}

func (s *site) loadPools() (e query.Error) {
	f, err := os.Open(s.path)
	if err != nil {
		if f != nil {
			f.Close()
		}

		return query.NewError(err)
	}

	dirs, err := f.Readdirnames(0)
	f.Close()

	if err != nil {
		return query.NewError(err)
	}

	s.pools = make(map[string]*pool, len(dirs))
	s.poolNames = dirs

	for _, dir := range dirs {
		diru := strings.ToUpper(dir)
		if _, ok := s.pools[diru]; ok {
			return query.NewError("Duplicate pool name " + dir)
		}

		pool, e := newPool(s, dir)
		if e != nil {
			return
		}

		s.pools[diru] = pool
	}
}

// pool represents a file-based Pool.
type pool struct {
	site        *site
	name        string
	buckets     map[string]*bucket
	bucketNames []string
}

func (p *pool) Name() string {
	return p.name
}

func (p *pool) BucketNames() ([]string, query.Error) {
	return p.bucketNames, nil
}

func (p *pool) Bucket(name string) (b Bucket, e query.Error) {
	b, ok := p.buckets[strings.ToUpper(name)]
	if !ok {
		e = query.NewError("Bucket " + name + " not found.")
	}
}

func (p *pool) path() string {
	return filepath.Join(p.site.path, p.name)
}

// newPool creates a new pool.
func newPool(s *site, dir string) (p pool, e query.Error) {
	p = new(pool)
	p.site = s
	p.name = dir

	e = p.loadBuckets()
}

func (p *pool) loadBuckets() (e query.Error) {
	f, err := os.Open(p.path())
	if err != nil {
		if f != nil {
			f.Close()
		}

		return query.NewError(err)
	}

	dirs, err := f.Readdirnames(0)
	f.Close()

	if err != nil {
		return query.NewError(err)
	}

	p.buckets = make(map[string]*pool, len(dirs))
	s.bucketNames = dirs

	for _, dir := range dirs {
		diru := strings.ToUpper(dir)
		if _, ok := p.buckets[diru]; ok {
			return query.NewError("Duplicate bucket name " + dir)
		}

		bucket, e := newBucket(p, dir)
		if e != nil {
			return
		}

		p.buckets[diru] = bucket
	}
}

// bucket is a file-based bucket.
type bucket struct {
	pool      *pool
	name      string
	filenames []string
	scanners  []Scanner
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) Count() (int64, query.Error) {
	return len(b.filenames), nil
}

func (b *bucket) Scanners() ([]Scanner, query.Error) {
	return b.scanners, nil
}

func (b *bucket) Fetch(id string) (item query.Item, e query.Error) {
	path := filepath.Join(b.path(), id)
	fi, err := os.Stat(path)
	if err != nil {
		return nil, query.NewError(err)
	}

	f, err := os.Open(path)
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err)
	}

	bytes := make([]byte, fi.Size())
	n, err := f.Read(bytes)
	f.Close()
	if err != nil {
		return nil, query.NewError(err)
	}
}

func (b *bucket) path() string {
	return filepath.Join(b.pool.path(), b.name)
}

// newBucket creates a new bucket.
func newBucket(p *pool, dir string) (b bucket, e query.Error) {
	b = new(bucket)
	b.pool = p
	b.name = dir

	f, err := os.Open(b.path())
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err)
	}

	b.filenames, err = f.Readdirnames()
	f.Close()
	if err != nil {
		return nil, query.NewError(err)
	}

	b.scanners = make([]Scanner, 1)
	fs := new(fullScanner)
	fs.bucket = b
	b.scanners.append(fs)
}

// fullScanner performs full bucket scans.
type fullScanner struct {
	bucket *bucket
}

func (fs *fullScanner) ScanAll(ch query.ItemChannel) query.Error {
}
<commit_msg>Compile catalog/file.<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

/*

Package file provides a file-based implementation of the catalog
package.

*/
package file

import (
	"github.com/couchbaselabs/tuqtng/catalog"
	"github.com/couchbaselabs/tuqtng/query"
	"os"
	"path/filepath"
	"strings"
)

// site is the root for the file-based Site.
type site struct {
	path      string
	pools     map[string]*pool
	poolNames []string
}

func (s *site) URL() string {
	return "file://" + s.path
}

func (s *site) PoolNames() ([]string, query.Error) {
	return s.poolNames, nil
}

func (s *site) Pool(name string) (p catalog.Pool, e query.Error) {
	p, ok := s.pools[strings.ToUpper(name)]
	if !ok {
		e = query.NewError(nil, "Pool " + name + " not found.")
	}

	return
}

// NewSite creates a new file-based site for the given filepath.
func NewSite(path string) (s catalog.Site, e query.Error) {
	fs := &site{path: path}

	e = fs.loadPools()
	if e != nil {
		return
	}

	s = fs
	return
}

func (s *site) loadPools() (e query.Error) {
	f, err := os.Open(s.path)
	if err != nil {
		if f != nil {
			f.Close()
		}

		return query.NewError(err, "")
	}

	dirs, err := f.Readdirnames(0)
	f.Close()

	if err != nil {
		return query.NewError(err, "")
	}

	s.pools = make(map[string] *pool, len(dirs))
	s.poolNames = dirs

	var p *pool
	for _, dir := range dirs {
		diru := strings.ToUpper(dir)
		if _, ok := s.pools[diru]; ok {
			return query.NewError(nil, "Duplicate pool name " + dir)
		}

		p, e = newPool(s, dir)
		if e != nil {
			return
		}

		s.pools[diru] = p
	}

	return
}

// pool represents a file-based Pool.
type pool struct {
	site        *site
	name        string
	buckets     map[string]*bucket
	bucketNames []string
}

func (p *pool) Name() string {
	return p.name
}

func (p *pool) BucketNames() ([]string, query.Error) {
	return p.bucketNames, nil
}

func (p *pool) Bucket(name string) (b catalog.Bucket, e query.Error) {
	b, ok := p.buckets[strings.ToUpper(name)]
	if !ok {
		e = query.NewError(nil, "Bucket " + name + " not found.")
	}

	return
}

func (p *pool) path() string {
	return filepath.Join(p.site.path, p.name)
}

// newPool creates a new pool.
func newPool(s *site, dir string) (p *pool, e query.Error) {
	p = new(pool)
	p.site = s
	p.name = dir

	e = p.loadBuckets()
	return
}

func (p *pool) loadBuckets() (e query.Error) {
	f, err := os.Open(p.path())
	if err != nil {
		if f != nil {
			f.Close()
		}

		return query.NewError(err, "")
	}

	dirs, err := f.Readdirnames(0)
	f.Close()

	if err != nil {
		return query.NewError(err, "")
	}

	p.buckets = make(map[string] *bucket, len(dirs))
	p.bucketNames = dirs

	var b *bucket
	for _, dir := range dirs {
		diru := strings.ToUpper(dir)
		if _, ok := p.buckets[diru]; ok {
			return query.NewError(nil, "Duplicate bucket name " + dir)
		}

		b, e = newBucket(p, dir)
		if e != nil {
			return
		}

		p.buckets[diru] = b
	}

	return
}

// bucket is a file-based bucket.
type bucket struct {
	pool      *pool
	name      string
	filenames []string
	scanners  []catalog.Scanner
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) Count() (int64, query.Error) {
	return int64(len(b.filenames)), nil
}

func (b *bucket) Scanners() ([]catalog.Scanner, query.Error) {
	return b.scanners, nil
}

func (b *bucket) Fetch(id string) (item query.Item, e query.Error) {
	path := filepath.Join(b.path(), id)
	fi, err := os.Stat(path)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	f, err := os.Open(path)
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err, "")
	}

	bytes := make([]byte, fi.Size())
	_, err = f.Read(bytes)
	f.Close()
	if err != nil {
		return nil, query.NewError(err, "")
	}

	return
}

func (b *bucket) path() string {
	return filepath.Join(b.pool.path(), b.name)
}

// newBucket creates a new bucket.
func newBucket(p *pool, dir string) (b *bucket, e query.Error) {
	b = new(bucket)
	b.pool = p
	b.name = dir

	f, err := os.Open(b.path())
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err, "")
	}

	b.filenames, err = f.Readdirnames(0)
	f.Close()
	if err != nil {
		return nil, query.NewError(err, "")
	}

	b.scanners = make([]catalog.Scanner, 1)
	fs := new(fullScanner)
	fs.bucket = b
	b.scanners = append(b.scanners, fs)

	return
}

// fullScanner performs full bucket scans.
type fullScanner struct {
	bucket *bucket
}

func (fs *fullScanner) ScanAll(ch query.ItemChannel) (e query.Error) {
     return
}
<|endoftext|>


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

/*

Package file provides a file-based implementation of the catalog
package.

*/
package file

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/couchbaselabs/tuqtng/catalog"
	"github.com/couchbaselabs/tuqtng/query"
)

// site is the root for the file-based Site.
type site struct {
	path      string
	pools     map[string]*pool
	poolNames []string
}

func (s *site) URL() string {
	return "file://" + s.path
}

func (s *site) PoolNames() ([]string, query.Error) {
	return s.poolNames, nil
}

func (s *site) Pool(name string) (p catalog.Pool, e query.Error) {
	p, ok := s.pools[strings.ToUpper(name)]
	if !ok {
		e = query.NewError(nil, "Pool "+name+" not found.")
	}

	return
}

// NewSite creates a new file-based site for the given filepath.
func NewSite(path string) (s catalog.Site, e query.Error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	fs := &site{path: path}

	e = fs.loadPools()
	if e != nil {
		return
	}

	s = fs
	return
}

func (s *site) loadPools() (e query.Error) {
	dirEntries, err := ioutil.ReadDir(s.path)
	if err != nil {
		return query.NewError(err, "")
	}

	s.pools = make(map[string]*pool)
	s.poolNames = make([]string, 0)

	var p *pool
	for _, dirEntry := range dirEntries {
		if dirEntry.IsDir() {
			s.poolNames = append(s.poolNames, dirEntry.Name())
			diru := strings.ToUpper(dirEntry.Name())
			if _, ok := s.pools[diru]; ok {
				return query.NewError(nil, "Duplicate pool name "+dirEntry.Name())
			}

			p, e = newPool(s, dirEntry.Name())
			if e != nil {
				return
			}

			s.pools[diru] = p
		}
	}

	return
}

// pool represents a file-based Pool.
type pool struct {
	site        *site
	name        string
	buckets     map[string]*bucket
	bucketNames []string
}

func (p *pool) Name() string {
	return p.name
}

func (p *pool) BucketNames() ([]string, query.Error) {
	return p.bucketNames, nil
}

func (p *pool) Bucket(name string) (b catalog.Bucket, e query.Error) {
	b, ok := p.buckets[strings.ToUpper(name)]
	if !ok {
		e = query.NewError(nil, "Bucket "+name+" not found.")
	}

	return
}

func (p *pool) path() string {
	return filepath.Join(p.site.path, p.name)
}

// newPool creates a new pool.
func newPool(s *site, dir string) (p *pool, e query.Error) {
	p = new(pool)
	p.site = s
	p.name = dir

	e = p.loadBuckets()
	return
}

func (p *pool) loadBuckets() (e query.Error) {
	dirEntries, err := ioutil.ReadDir(p.path())
	if err != nil {
		return query.NewError(err, "")
	}

	p.buckets = make(map[string]*bucket)
	p.bucketNames = make([]string, 0)

	var b *bucket
	for _, dirEntry := range dirEntries {
		if dirEntry.IsDir() {
			diru := strings.ToUpper(dirEntry.Name())
			if _, ok := p.buckets[diru]; ok {
				return query.NewError(nil, "Duplicate bucket name "+dirEntry.Name())
			}

			b, e = newBucket(p, dirEntry.Name())
			if e != nil {
				return
			}

			p.buckets[diru] = b
		}
	}

	return
}

// bucket is a file-based bucket.
type bucket struct {
	pool      *pool
	name      string
	filenames []string
	scanners  []catalog.Scanner
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) Count() (int64, query.Error) {
	return int64(len(b.filenames)), nil
}

func (b *bucket) Scanners() ([]catalog.Scanner, query.Error) {
	return b.scanners, nil
}

func (b *bucket) Fetch(id string) (item query.Item, e query.Error) {
	path := filepath.Join(b.path(), id+".json")
	item, e = fetch(path)
	if e != nil {
		item = nil
	}

	return
}

func (b *bucket) path() string {
	return filepath.Join(b.pool.path(), b.name)
}

// newBucket creates a new bucket.
func newBucket(p *pool, dir string) (b *bucket, e query.Error) {
	b = new(bucket)
	b.pool = p
	b.name = dir

	f, err := os.Open(b.path())
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err, "")
	}

	b.filenames, err = f.Readdirnames(0)
	f.Close()
	if err != nil {
		return nil, query.NewError(err, "")
	}

	b.scanners = make([]catalog.Scanner, 0, 1)
	fs := new(fullScanner)
	fs.bucket = b
	b.scanners = append(b.scanners, fs)

	return
}

// fullScanner performs full bucket scans.
type fullScanner struct {
	bucket *bucket
}

func (fs *fullScanner) ScanAll(ch query.ItemChannel, errch query.ErrorChannel) {
	go fs.scanAll(ch, errch)
}

func (fs *fullScanner) scanAll(ch query.ItemChannel, errch query.ErrorChannel) {
	defer close(ch)
	defer close(errch)

	dirEntries, err := ioutil.ReadDir(fs.bucket.path())
	if err != nil {
		errch <- query.NewError(err, "")
		return
	}

	for _, dirEntry := range dirEntries {
		if !dirEntry.IsDir() {
			doc := map[string]query.Value{}
			meta := map[string]query.Value{"id": documentPathToId(dirEntry.Name())}
			ch <- query.NewMapItem(doc, meta)
		}
	}
}

func fetch(path string) (item query.Item, e query.Error) {
	fi, err := os.Stat(path)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	f, err := os.Open(path)
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err, "")
	}

	bytes := make([]byte, fi.Size())
	_, err = f.Read(bytes)
	f.Close()
	if err != nil {
		return nil, query.NewError(err, "")
	}

	// convert file bytes to json
	doc := map[string]query.Value{}
	err = json.Unmarshal(bytes, &doc)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	meta := map[string]query.Value{
		"id": documentPathToId(path),
	}

	item = query.NewMapItem(doc, meta)

	return
}

func documentPathToId(p string) string {
	_, file := path.Split(p)
	ext := path.Ext(file)
	return file[0 : len(file)-len(ext)]
}
<commit_msg>removed caching of bucket filenames<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

/*

Package file provides a file-based implementation of the catalog
package.

*/
package file

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/couchbaselabs/tuqtng/catalog"
	"github.com/couchbaselabs/tuqtng/query"
)

// site is the root for the file-based Site.
type site struct {
	path      string
	pools     map[string]*pool
	poolNames []string
}

func (s *site) URL() string {
	return "file://" + s.path
}

func (s *site) PoolNames() ([]string, query.Error) {
	return s.poolNames, nil
}

func (s *site) Pool(name string) (p catalog.Pool, e query.Error) {
	p, ok := s.pools[strings.ToUpper(name)]
	if !ok {
		e = query.NewError(nil, "Pool "+name+" not found.")
	}

	return
}

// NewSite creates a new file-based site for the given filepath.
func NewSite(path string) (s catalog.Site, e query.Error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	fs := &site{path: path}

	e = fs.loadPools()
	if e != nil {
		return
	}

	s = fs
	return
}

func (s *site) loadPools() (e query.Error) {
	dirEntries, err := ioutil.ReadDir(s.path)
	if err != nil {
		return query.NewError(err, "")
	}

	s.pools = make(map[string]*pool)
	s.poolNames = make([]string, 0)

	var p *pool
	for _, dirEntry := range dirEntries {
		if dirEntry.IsDir() {
			s.poolNames = append(s.poolNames, dirEntry.Name())
			diru := strings.ToUpper(dirEntry.Name())
			if _, ok := s.pools[diru]; ok {
				return query.NewError(nil, "Duplicate pool name "+dirEntry.Name())
			}

			p, e = newPool(s, dirEntry.Name())
			if e != nil {
				return
			}

			s.pools[diru] = p
		}
	}

	return
}

// pool represents a file-based Pool.
type pool struct {
	site        *site
	name        string
	buckets     map[string]*bucket
	bucketNames []string
}

func (p *pool) Name() string {
	return p.name
}

func (p *pool) BucketNames() ([]string, query.Error) {
	return p.bucketNames, nil
}

func (p *pool) Bucket(name string) (b catalog.Bucket, e query.Error) {
	b, ok := p.buckets[strings.ToUpper(name)]
	if !ok {
		e = query.NewError(nil, "Bucket "+name+" not found.")
	}

	return
}

func (p *pool) path() string {
	return filepath.Join(p.site.path, p.name)
}

// newPool creates a new pool.
func newPool(s *site, dir string) (p *pool, e query.Error) {
	p = new(pool)
	p.site = s
	p.name = dir

	e = p.loadBuckets()
	return
}

func (p *pool) loadBuckets() (e query.Error) {
	dirEntries, err := ioutil.ReadDir(p.path())
	if err != nil {
		return query.NewError(err, "")
	}

	p.buckets = make(map[string]*bucket)
	p.bucketNames = make([]string, 0)

	var b *bucket
	for _, dirEntry := range dirEntries {
		if dirEntry.IsDir() {
			diru := strings.ToUpper(dirEntry.Name())
			if _, ok := p.buckets[diru]; ok {
				return query.NewError(nil, "Duplicate bucket name "+dirEntry.Name())
			}

			b, e = newBucket(p, dirEntry.Name())
			if e != nil {
				return
			}

			p.buckets[diru] = b
		}
	}

	return
}

// bucket is a file-based bucket.
type bucket struct {
	pool     *pool
	name     string
	scanners []catalog.Scanner
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) Count() (int64, query.Error) {
	dirEntries, err := ioutil.ReadDir(b.path())
	if err != nil {
		return 0, query.NewError(err, "")
	}
	return int64(len(dirEntries)), nil
}

func (b *bucket) Scanners() ([]catalog.Scanner, query.Error) {
	return b.scanners, nil
}

func (b *bucket) Fetch(id string) (item query.Item, e query.Error) {
	path := filepath.Join(b.path(), id+".json")
	item, e = fetch(path)
	if e != nil {
		item = nil
	}

	return
}

func (b *bucket) path() string {
	return filepath.Join(b.pool.path(), b.name)
}

// newBucket creates a new bucket.
func newBucket(p *pool, dir string) (b *bucket, e query.Error) {
	b = new(bucket)
	b.pool = p
	b.name = dir

	f, err := os.Open(b.path())
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err, "")
	}

	b.scanners = make([]catalog.Scanner, 0, 1)
	fs := new(fullScanner)
	fs.bucket = b
	b.scanners = append(b.scanners, fs)

	return
}

// fullScanner performs full bucket scans.
type fullScanner struct {
	bucket *bucket
}

func (fs *fullScanner) ScanAll(ch query.ItemChannel, errch query.ErrorChannel) {
	go fs.scanAll(ch, errch)
}

func (fs *fullScanner) scanAll(ch query.ItemChannel, errch query.ErrorChannel) {
	defer close(ch)
	defer close(errch)

	dirEntries, err := ioutil.ReadDir(fs.bucket.path())
	if err != nil {
		errch <- query.NewError(err, "")
		return
	}

	for _, dirEntry := range dirEntries {
		if !dirEntry.IsDir() {
			doc := map[string]query.Value{}
			meta := map[string]query.Value{"id": documentPathToId(dirEntry.Name())}
			ch <- query.NewMapItem(doc, meta)
		}
	}
}

func fetch(path string) (item query.Item, e query.Error) {
	fi, err := os.Stat(path)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	f, err := os.Open(path)
	if err != nil {
		if f != nil {
			f.Close()
		}

		return nil, query.NewError(err, "")
	}

	bytes := make([]byte, fi.Size())
	_, err = f.Read(bytes)
	f.Close()
	if err != nil {
		return nil, query.NewError(err, "")
	}

	// convert file bytes to json
	doc := map[string]query.Value{}
	err = json.Unmarshal(bytes, &doc)
	if err != nil {
		return nil, query.NewError(err, "")
	}

	meta := map[string]query.Value{
		"id": documentPathToId(path),
	}

	item = query.NewMapItem(doc, meta)

	return
}

func documentPathToId(p string) string {
	_, file := path.Split(p)
	ext := path.Ext(file)
	return file[0 : len(file)-len(ext)]
}
<|endoftext|>


<commit_before>package core

import (
	"bytes"
	"fmt"
	"math/big"
	"sync"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/rlp"
	"github.com/ethereum/go-ethereum/state"
)

var chainlogger = logger.NewLogger("CHAIN")

type ChainEvent struct {
	Block *types.Block
	Td    *big.Int
}

type StateQuery interface {
	GetAccount(addr []byte) *state.StateObject
}

func CalcDifficulty(block, parent *types.Block) *big.Int {
	diff := new(big.Int)

	adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
	if block.Time() >= parent.Time()+8 {
		diff.Sub(parent.Difficulty(), adjust)
	} else {
		diff.Add(parent.Difficulty(), adjust)
	}

	return diff
}

func CalculateTD(block, parent *types.Block) *big.Int {
	uncleDiff := new(big.Int)
	for _, uncle := range block.Uncles() {
		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
	}

	// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
	td := new(big.Int)
	td = td.Add(parent.Td, uncleDiff)
	td = td.Add(td, block.Header().Difficulty)

	return td
}

func CalcGasLimit(parent, block *types.Block) *big.Int {
	if block.Number().Cmp(big.NewInt(0)) == 0 {
		return ethutil.BigPow(10, 6)
	}

	// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024

	previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
	current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
	curInt := new(big.Int).Div(current.Num(), current.Denom())

	result := new(big.Int).Add(previous, curInt)
	result.Div(result, big.NewInt(1024))

	min := big.NewInt(125000)

	return ethutil.BigMax(min, result)
}

type ChainManager struct {
	//eth          EthManager
	db           ethutil.Database
	processor    types.BlockProcessor
	eventMux     *event.TypeMux
	genesisBlock *types.Block
	// Last known total difficulty
	mu            sync.RWMutex
	tsmu          sync.RWMutex
	td            *big.Int
	currentBlock  *types.Block
	lastBlockHash []byte

	transState *state.StateDB
}

func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
	bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
	bc.setLastBlock()
	bc.transState = bc.State().Copy()

	return bc
}

func (self *ChainManager) Td() *big.Int {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.td
}

func (self *ChainManager) LastBlockHash() []byte {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.lastBlockHash
}

func (self *ChainManager) CurrentBlock() *types.Block {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.currentBlock
}

func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.td, self.currentBlock.Hash(), self.Genesis().Hash()
}

func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
	self.processor = proc
}

func (self *ChainManager) State() *state.StateDB {
	return state.New(self.CurrentBlock().Root(), self.db)
}

func (self *ChainManager) TransState() *state.StateDB {
	self.tsmu.RLock()
	defer self.tsmu.RUnlock()

	return self.transState
}

func (self *ChainManager) setTransState(statedb *state.StateDB) {
	self.transState = statedb
}

func (bc *ChainManager) setLastBlock() {
	data, _ := bc.db.Get([]byte("LastBlock"))
	if len(data) != 0 {
		var block types.Block
		rlp.Decode(bytes.NewReader(data), &block)
		bc.currentBlock = &block
		bc.lastBlockHash = block.Hash()

		// Set the last know difficulty (might be 0x0 as initial value, Genesis)
		bc.td = ethutil.BigD(bc.db.LastKnownTD())
	} else {
		bc.Reset()
	}

	chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
}

// Block creation & chain handling
func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
	bc.mu.RLock()
	defer bc.mu.RUnlock()

	var root []byte
	parentHash := ZeroHash256

	if bc.currentBlock != nil {
		root = bc.currentBlock.Header().Root
		parentHash = bc.lastBlockHash
	}

	block := types.NewBlock(
		parentHash,
		coinbase,
		root,
		ethutil.BigPow(2, 32),
		nil,
		"")
	block.SetUncles(nil)
	block.SetTransactions(nil)
	block.SetReceipts(nil)

	parent := bc.currentBlock
	if parent != nil {
		header := block.Header()
		header.Difficulty = CalcDifficulty(block, parent)
		header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
		header.GasLimit = CalcGasLimit(parent, block)

	}

	return block
}

func (bc *ChainManager) Reset() {
	bc.mu.Lock()
	defer bc.mu.Unlock()

	for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
		bc.db.Delete(block.Hash())
	}

	// Prepare the genesis block
	bc.write(bc.genesisBlock)
	bc.insert(bc.genesisBlock)
	bc.currentBlock = bc.genesisBlock

	bc.setTotalDifficulty(ethutil.Big("0"))
}

func (self *ChainManager) Export() []byte {
	self.mu.RLock()
	defer self.mu.RUnlock()

	chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)

	blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
	for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
		blocks[block.NumberU64()] = block
	}

	return ethutil.Encode(blocks)
}

func (bc *ChainManager) insert(block *types.Block) {
	encodedBlock := ethutil.Encode(block)
	bc.db.Put([]byte("LastBlock"), encodedBlock)
	bc.currentBlock = block
	bc.lastBlockHash = block.Hash()
}

func (bc *ChainManager) write(block *types.Block) {
	encodedBlock := ethutil.Encode(block.RlpDataForStorage())
	bc.db.Put(block.Hash(), encodedBlock)
}

// Accessors
func (bc *ChainManager) Genesis() *types.Block {
	return bc.genesisBlock
}

// Block fetching methods
func (bc *ChainManager) HasBlock(hash []byte) bool {
	data, _ := bc.db.Get(hash)
	return len(data) != 0
}

func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
	block := self.GetBlock(hash)
	if block == nil {
		return
	}

	// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
	for i := uint64(0); i < max; i++ {
		parentHash := block.Header().ParentHash
		block = self.GetBlock(parentHash)
		if block == nil {
			chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash)
			break
		}

		chain = append(chain, block.Hash())
		if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
			break
		}
	}
	fmt.Printf("get hash %x (%d)\n", hash, len(chain))

	return
}

func (self *ChainManager) GetBlock(hash []byte) *types.Block {
	data, _ := self.db.Get(hash)
	if len(data) == 0 {
		return nil
	}
	var block types.Block
	if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
		fmt.Println(err)
		return nil
	}

	return &block
}

func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
	for i := 0; block != nil && i < length; i++ {
		uncles = append(uncles, block.Uncles()...)
		block = self.GetBlock(block.ParentHash())
	}

	return
}

func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) {
	for i := 0; i < length; i++ {
		block = self.GetBlock(block.ParentHash())
		if block == nil {
			break
		}

		blocks = append(blocks, block)
	}

	return
}

func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
	self.mu.RLock()
	defer self.mu.RUnlock()

	var block *types.Block

	if num <= self.currentBlock.Number().Uint64() {
		block = self.currentBlock
		for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
			if block.Header().Number.Uint64() == num {
				break
			}
		}
	}

	return block
}

func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
	bc.db.Put([]byte("LTD"), td.Bytes())
	bc.td = td
}

func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
	parent := self.GetBlock(block.Header().ParentHash)
	if parent == nil {
		return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash)
	}

	parentTd := parent.Td

	uncleDiff := new(big.Int)
	for _, uncle := range block.Uncles() {
		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
	}

	td := new(big.Int)
	td = td.Add(parentTd, uncleDiff)
	td = td.Add(td, block.Header().Difficulty)

	return td, nil
}

func (bc *ChainManager) Stop() {
	if bc.CurrentBlock != nil {
		chainlogger.Infoln("Stopped")
	}
}

func (self *ChainManager) InsertChain(chain types.Blocks) error {
	self.tsmu.Lock()
	defer self.tsmu.Unlock()

	for _, block := range chain {
		td, err := self.processor.Process(block)
		if err != nil {
			if IsKnownBlockErr(err) {
				continue
			}

			h := block.Header()
			chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4])
			chainlogger.Infoln(block)
			chainlogger.Infoln(err)
			return err
		}
		block.Td = td

		var chain, split bool
		self.mu.Lock()
		{
			self.write(block)
			cblock := self.currentBlock
			if td.Cmp(self.td) > 0 {
				if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
					chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
					split = true
				}

				self.setTotalDifficulty(td)
				self.insert(block)

				chain = true
			}
		}
		self.mu.Unlock()

		if chain {
			self.eventMux.Post(ChainEvent{block, td})
		}

		if split {
			self.setTransState(state.New(block.Root(), self.db))
			self.eventMux.Post(ChainSplitEvent{block})
		}
	}

	return nil
}

// Satisfy state query interface
func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
	return self.State().GetAccount(addr)
}
<commit_msg>removed log<commit_after>package core

import (
	"bytes"
	"fmt"
	"math/big"
	"sync"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/rlp"
	"github.com/ethereum/go-ethereum/state"
)

var chainlogger = logger.NewLogger("CHAIN")

type ChainEvent struct {
	Block *types.Block
	Td    *big.Int
}

type StateQuery interface {
	GetAccount(addr []byte) *state.StateObject
}

func CalcDifficulty(block, parent *types.Block) *big.Int {
	diff := new(big.Int)

	adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
	if block.Time() >= parent.Time()+8 {
		diff.Sub(parent.Difficulty(), adjust)
	} else {
		diff.Add(parent.Difficulty(), adjust)
	}

	return diff
}

func CalculateTD(block, parent *types.Block) *big.Int {
	uncleDiff := new(big.Int)
	for _, uncle := range block.Uncles() {
		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
	}

	// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
	td := new(big.Int)
	td = td.Add(parent.Td, uncleDiff)
	td = td.Add(td, block.Header().Difficulty)

	return td
}

func CalcGasLimit(parent, block *types.Block) *big.Int {
	if block.Number().Cmp(big.NewInt(0)) == 0 {
		return ethutil.BigPow(10, 6)
	}

	// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024

	previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
	current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
	curInt := new(big.Int).Div(current.Num(), current.Denom())

	result := new(big.Int).Add(previous, curInt)
	result.Div(result, big.NewInt(1024))

	min := big.NewInt(125000)

	return ethutil.BigMax(min, result)
}

type ChainManager struct {
	//eth          EthManager
	db           ethutil.Database
	processor    types.BlockProcessor
	eventMux     *event.TypeMux
	genesisBlock *types.Block
	// Last known total difficulty
	mu            sync.RWMutex
	tsmu          sync.RWMutex
	td            *big.Int
	currentBlock  *types.Block
	lastBlockHash []byte

	transState *state.StateDB
}

func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
	bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
	bc.setLastBlock()
	bc.transState = bc.State().Copy()

	return bc
}

func (self *ChainManager) Td() *big.Int {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.td
}

func (self *ChainManager) LastBlockHash() []byte {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.lastBlockHash
}

func (self *ChainManager) CurrentBlock() *types.Block {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.currentBlock
}

func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
	self.mu.RLock()
	defer self.mu.RUnlock()

	return self.td, self.currentBlock.Hash(), self.Genesis().Hash()
}

func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
	self.processor = proc
}

func (self *ChainManager) State() *state.StateDB {
	return state.New(self.CurrentBlock().Root(), self.db)
}

func (self *ChainManager) TransState() *state.StateDB {
	self.tsmu.RLock()
	defer self.tsmu.RUnlock()

	return self.transState
}

func (self *ChainManager) setTransState(statedb *state.StateDB) {
	self.transState = statedb
}

func (bc *ChainManager) setLastBlock() {
	data, _ := bc.db.Get([]byte("LastBlock"))
	if len(data) != 0 {
		var block types.Block
		rlp.Decode(bytes.NewReader(data), &block)
		bc.currentBlock = &block
		bc.lastBlockHash = block.Hash()

		// Set the last know difficulty (might be 0x0 as initial value, Genesis)
		bc.td = ethutil.BigD(bc.db.LastKnownTD())
	} else {
		bc.Reset()
	}

	chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
}

// Block creation & chain handling
func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
	bc.mu.RLock()
	defer bc.mu.RUnlock()

	var root []byte
	parentHash := ZeroHash256

	if bc.currentBlock != nil {
		root = bc.currentBlock.Header().Root
		parentHash = bc.lastBlockHash
	}

	block := types.NewBlock(
		parentHash,
		coinbase,
		root,
		ethutil.BigPow(2, 32),
		nil,
		"")
	block.SetUncles(nil)
	block.SetTransactions(nil)
	block.SetReceipts(nil)

	parent := bc.currentBlock
	if parent != nil {
		header := block.Header()
		header.Difficulty = CalcDifficulty(block, parent)
		header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
		header.GasLimit = CalcGasLimit(parent, block)

	}

	return block
}

func (bc *ChainManager) Reset() {
	bc.mu.Lock()
	defer bc.mu.Unlock()

	for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
		bc.db.Delete(block.Hash())
	}

	// Prepare the genesis block
	bc.write(bc.genesisBlock)
	bc.insert(bc.genesisBlock)
	bc.currentBlock = bc.genesisBlock

	bc.setTotalDifficulty(ethutil.Big("0"))
}

func (self *ChainManager) Export() []byte {
	self.mu.RLock()
	defer self.mu.RUnlock()

	chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)

	blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
	for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
		blocks[block.NumberU64()] = block
	}

	return ethutil.Encode(blocks)
}

func (bc *ChainManager) insert(block *types.Block) {
	encodedBlock := ethutil.Encode(block)
	bc.db.Put([]byte("LastBlock"), encodedBlock)
	bc.currentBlock = block
	bc.lastBlockHash = block.Hash()
}

func (bc *ChainManager) write(block *types.Block) {
	encodedBlock := ethutil.Encode(block.RlpDataForStorage())
	bc.db.Put(block.Hash(), encodedBlock)
}

// Accessors
func (bc *ChainManager) Genesis() *types.Block {
	return bc.genesisBlock
}

// Block fetching methods
func (bc *ChainManager) HasBlock(hash []byte) bool {
	data, _ := bc.db.Get(hash)
	return len(data) != 0
}

func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
	block := self.GetBlock(hash)
	if block == nil {
		return
	}

	// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
	for i := uint64(0); i < max; i++ {
		parentHash := block.Header().ParentHash
		block = self.GetBlock(parentHash)
		if block == nil {
			chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash)
			break
		}

		chain = append(chain, block.Hash())
		if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
			break
		}
	}

	return
}

func (self *ChainManager) GetBlock(hash []byte) *types.Block {
	data, _ := self.db.Get(hash)
	if len(data) == 0 {
		return nil
	}
	var block types.Block
	if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
		fmt.Println(err)
		return nil
	}

	return &block
}

func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
	for i := 0; block != nil && i < length; i++ {
		uncles = append(uncles, block.Uncles()...)
		block = self.GetBlock(block.ParentHash())
	}

	return
}

func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) {
	for i := 0; i < length; i++ {
		block = self.GetBlock(block.ParentHash())
		if block == nil {
			break
		}

		blocks = append(blocks, block)
	}

	return
}

func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
	self.mu.RLock()
	defer self.mu.RUnlock()

	var block *types.Block

	if num <= self.currentBlock.Number().Uint64() {
		block = self.currentBlock
		for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
			if block.Header().Number.Uint64() == num {
				break
			}
		}
	}

	return block
}

func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
	bc.db.Put([]byte("LTD"), td.Bytes())
	bc.td = td
}

func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
	parent := self.GetBlock(block.Header().ParentHash)
	if parent == nil {
		return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash)
	}

	parentTd := parent.Td

	uncleDiff := new(big.Int)
	for _, uncle := range block.Uncles() {
		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
	}

	td := new(big.Int)
	td = td.Add(parentTd, uncleDiff)
	td = td.Add(td, block.Header().Difficulty)

	return td, nil
}

func (bc *ChainManager) Stop() {
	if bc.CurrentBlock != nil {
		chainlogger.Infoln("Stopped")
	}
}

func (self *ChainManager) InsertChain(chain types.Blocks) error {
	self.tsmu.Lock()
	defer self.tsmu.Unlock()

	for _, block := range chain {
		td, err := self.processor.Process(block)
		if err != nil {
			if IsKnownBlockErr(err) {
				continue
			}

			h := block.Header()
			chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4])
			chainlogger.Infoln(block)
			chainlogger.Infoln(err)
			return err
		}
		block.Td = td

		var chain, split bool
		self.mu.Lock()
		{
			self.write(block)
			cblock := self.currentBlock
			if td.Cmp(self.td) > 0 {
				if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
					chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
					split = true
				}

				self.setTotalDifficulty(td)
				self.insert(block)

				chain = true
			}
		}
		self.mu.Unlock()

		if chain {
			self.eventMux.Post(ChainEvent{block, td})
		}

		if split {
			self.setTransState(state.New(block.Root(), self.db))
			self.eventMux.Post(ChainSplitEvent{block})
		}
	}

	return nil
}

// Satisfy state query interface
func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
	return self.State().GetAccount(addr)
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"text/tabwriter"

	oldcmds "github.com/ipfs/go-ipfs/commands"
	lgc "github.com/ipfs/go-ipfs/commands/legacy"
	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
	e "github.com/ipfs/go-ipfs/core/commands/e"
	corerepo "github.com/ipfs/go-ipfs/core/corerepo"
	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"

	config "gx/ipfs/QmPEpj17FDRpc7K1aArKZp3RsHtzRMKykeK9GVgn4WQGPR/go-ipfs-config"
	cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
	cmds "gx/ipfs/QmSXUokcP4TJpFfqozT69AVAYRtzXVMUjzQVkYX41R9Svs/go-ipfs-cmds"
	bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
	cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)

type RepoVersion struct {
	Version string
}

var RepoCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Manipulate the IPFS repo.",
		ShortDescription: `
'ipfs repo' is a plumbing command used to manipulate the repo.
`,
	},

	Subcommands: map[string]*cmds.Command{
		"stat":    repoStatCmd,
		"gc":      repoGcCmd,
		"fsck":    RepoFsckCmd,
		"version": repoVersionCmd,
		"verify":  lgc.NewCommand(repoVerifyCmd),
	},
}

// GcResult is the result returned by "repo gc" command.
type GcResult struct {
	Key   cid.Cid
	Error string `json:",omitempty"`
}

const (
	repoStreamErrorsOptionName = "stream-errors"
	repoQuietOptionName        = "quiet"
)

var repoGcCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Perform a garbage collection sweep on the repo.",
		ShortDescription: `
'ipfs repo gc' is a plumbing command that will sweep the local
set of stored objects and remove ones that are not pinned in
order to reclaim hard disk space.
`,
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption(repoStreamErrorsOptionName, "Stream errors."),
		cmdkit.BoolOption(repoQuietOptionName, "q", "Write minimal output."),
	},
	Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
		n, err := cmdenv.GetNode(env)
		if err != nil {
			return err
		}

		streamErrors, _ := req.Options[repoStreamErrorsOptionName].(bool)

		gcOutChan := corerepo.GarbageCollectAsync(n, req.Context)

		if streamErrors {
			errs := false
			for res := range gcOutChan {
				if res.Error != nil {
					if err := re.Emit(&GcResult{Error: res.Error.Error()}); err != nil {
						return err
					}
					errs = true
				} else {
					if err := re.Emit(&GcResult{Key: res.KeyRemoved}); err != nil {
						return err
					}
				}
			}
			if errs {
				return errors.New("encountered errors during gc run")
			}
		} else {
			err := corerepo.CollectResult(req.Context, gcOutChan, func(k cid.Cid) {
				re.Emit(&GcResult{Key: k})
			})
			if err != nil {
				return err
			}
		}

		return nil
	},
	Type: GcResult{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			quiet, _ := req.Options[repoQuietOptionName].(bool)

			obj, ok := v.(*GcResult)
			if !ok {
				return e.TypeErr(obj, v)
			}

			if obj.Error != "" {
				_, err := fmt.Fprintf(w, "Error: %s\n", obj.Error)
				return err
			}

			prefix := "removed "
			if quiet {
				prefix = ""
			}

			_, err := fmt.Fprintf(w, "%s%s\n", prefix, obj.Key)
			return err
		}),
	},
}

const (
	repoSizeOnlyOptionName = "size-only"
	repoHumanOptionName    = "human"
)

var repoStatCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Get stats for the currently used repo.",
		ShortDescription: `
'ipfs repo stat' provides information about the local set of
stored objects. It outputs:

RepoSize        int Size in bytes that the repo is currently taking.
StorageMax      string Maximum datastore size (from configuration)
NumObjects      int Number of objects in the local repo.
RepoPath        string The path to the repo being currently used.
Version         string The repo version.
`,
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption(repoSizeOnlyOptionName, "Only report RepoSize and StorageMax."),
		cmdkit.BoolOption(repoHumanOptionName, "Output sizes in MiB."),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		n, err := cmdenv.GetNode(env)
		if err != nil {
			return err
		}

		sizeOnly, _ := req.Options[repoSizeOnlyOptionName].(bool)
		if sizeOnly {
			sizeStat, err := corerepo.RepoSize(req.Context, n)
			if err != nil {
				return err
			}
			cmds.EmitOnce(res, &corerepo.Stat{
				SizeStat: sizeStat,
			})
			return nil
		}

		stat, err := corerepo.RepoStat(req.Context, n)
		if err != nil {
			return err
		}

		return cmds.EmitOnce(res, &stat)
	},
	Type: &corerepo.Stat{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			stat, ok := v.(*corerepo.Stat)
			if !ok {
				return e.TypeErr(stat, v)
			}

			wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
			defer wtr.Flush()

			human, _ := req.Options[repoHumanOptionName].(bool)
			sizeOnly, _ := req.Options[repoSizeOnlyOptionName].(bool)

			printSize := func(name string, size uint64) {
				sizeInMiB := size / (1024 * 1024)
				if human && sizeInMiB > 0 {
					fmt.Fprintf(wtr, "%s (MiB):\t%d\n", name, sizeInMiB)
				} else {
					fmt.Fprintf(wtr, "%s:\t%d\n", name, size)
				}
			}

			if !sizeOnly {
				fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
			}

			printSize("RepoSize", stat.RepoSize)
			printSize("StorageMax", stat.StorageMax)

			if !sizeOnly {
				fmt.Fprintf(wtr, "RepoPath:\t%s\n", stat.RepoPath)
				fmt.Fprintf(wtr, "Version:\t%s\n", stat.Version)
			}

			return nil
		}),
	},
}

var RepoFsckCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Remove repo lockfiles.",
		ShortDescription: `
'ipfs repo fsck' is a plumbing command that will remove repo and level db
lockfiles, as well as the api file. This command can only run when no ipfs
daemons are running.
`,
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		configRoot, err := cmdenv.GetConfigRoot(env)
		if err != nil {
			return err
		}

		dsPath, err := config.DataStorePath(configRoot)
		if err != nil {
			return err
		}

		dsLockFile := filepath.Join(dsPath, "LOCK") // TODO: get this lockfile programmatically
		repoLockFile := filepath.Join(configRoot, fsrepo.LockFile)
		apiFile := filepath.Join(configRoot, "api") // TODO: get this programmatically

		log.Infof("Removing repo lockfile: %s", repoLockFile)
		log.Infof("Removing datastore lockfile: %s", dsLockFile)
		log.Infof("Removing api file: %s", apiFile)

		err = os.Remove(repoLockFile)
		if err != nil && !os.IsNotExist(err) {
			return err
		}
		err = os.Remove(dsLockFile)
		if err != nil && !os.IsNotExist(err) {
			return err
		}
		err = os.Remove(apiFile)
		if err != nil && !os.IsNotExist(err) {
			return err
		}

		return cmds.EmitOnce(res, &MessageOutput{"Lockfiles have been removed.\n"})
	},
	Type: MessageOutput{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *MessageOutput) error {
			fmt.Fprintf(w, out.Message)
			return nil
		}),
	},
}

type VerifyProgress struct {
	Msg      string
	Progress int
}

func verifyWorkerRun(ctx context.Context, wg *sync.WaitGroup, keys <-chan cid.Cid, results chan<- string, bs bstore.Blockstore) {
	defer wg.Done()

	for k := range keys {
		_, err := bs.Get(k)
		if err != nil {
			select {
			case results <- fmt.Sprintf("block %s was corrupt (%s)", k, err):
			case <-ctx.Done():
				return
			}

			continue
		}

		select {
		case results <- "":
		case <-ctx.Done():
			return
		}
	}
}

func verifyResultChan(ctx context.Context, keys <-chan cid.Cid, bs bstore.Blockstore) <-chan string {
	results := make(chan string)

	go func() {
		defer close(results)

		var wg sync.WaitGroup

		for i := 0; i < runtime.NumCPU()*2; i++ {
			wg.Add(1)
			go verifyWorkerRun(ctx, &wg, keys, results, bs)
		}

		wg.Wait()
	}()

	return results
}

var repoVerifyCmd = &oldcmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Verify all blocks in repo are not corrupted.",
	},
	Run: func(req oldcmds.Request, res oldcmds.Response) {
		nd, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		out := make(chan interface{})
		res.SetOutput((<-chan interface{})(out))
		defer close(out)

		bs := bstore.NewBlockstore(nd.Repo.Datastore())
		bs.HashOnRead(true)

		keys, err := bs.AllKeysChan(req.Context())
		if err != nil {
			log.Error(err)
			return
		}

		results := verifyResultChan(req.Context(), keys, bs)

		var fails int
		var i int
		for msg := range results {
			if msg != "" {
				select {
				case out <- &VerifyProgress{Msg: msg}:
				case <-req.Context().Done():
					return
				}
				fails++
			}
			i++
			select {
			case out <- &VerifyProgress{Progress: i}:
			case <-req.Context().Done():
				return
			}
		}

		if fails == 0 {
			select {
			case out <- &VerifyProgress{Msg: "verify complete, all blocks validated."}:
			case <-req.Context().Done():
				return
			}
		} else {
			res.SetError(fmt.Errorf("verify complete, some blocks were corrupt"), cmdkit.ErrNormal)
		}
	},
	Type: &VerifyProgress{},
	Marshalers: oldcmds.MarshalerMap{
		oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
			v, err := unwrapOutput(res.Output())
			if err != nil {
				return nil, err
			}

			obj, ok := v.(*VerifyProgress)
			if !ok {
				return nil, e.TypeErr(obj, v)
			}

			buf := new(bytes.Buffer)
			if strings.Contains(obj.Msg, "was corrupt") {
				fmt.Fprintln(os.Stdout, obj.Msg)
				return buf, nil
			}

			if obj.Msg != "" {
				if len(obj.Msg) < 20 {
					obj.Msg += "             "
				}
				fmt.Fprintln(buf, obj.Msg)
				return buf, nil
			}

			fmt.Fprintf(buf, "%d blocks processed.\r", obj.Progress)
			return buf, nil
		},
	},
}

var repoVersionCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Show the repo version.",
		ShortDescription: `
'ipfs repo version' returns the current repo version.
`,
	},

	Options: []cmdkit.Option{
		cmdkit.BoolOption(repoQuietOptionName, "q", "Write minimal output."),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		return cmds.EmitOnce(res, &RepoVersion{
			Version: fmt.Sprint(fsrepo.RepoVersion),
		})
	},
	Type: RepoVersion{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RepoVersion) error {
			quiet, _ := req.Options[repoQuietOptionName].(bool)

			if quiet {
				fmt.Fprintf(w, fmt.Sprintf("fs-repo@%s\n", out.Version))
			} else {
				fmt.Fprintf(w, fmt.Sprintf("ipfs repo version fs-repo@%s\n", out.Version))
			}
			return nil
		}),
	},
}
<commit_msg>refact(cmd/repo): repo verify uses new cmd lib<commit_after>package commands

import (
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"text/tabwriter"

	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
	e "github.com/ipfs/go-ipfs/core/commands/e"
	corerepo "github.com/ipfs/go-ipfs/core/corerepo"
	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"

	config "gx/ipfs/QmPEpj17FDRpc7K1aArKZp3RsHtzRMKykeK9GVgn4WQGPR/go-ipfs-config"
	cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
	cmds "gx/ipfs/QmSXUokcP4TJpFfqozT69AVAYRtzXVMUjzQVkYX41R9Svs/go-ipfs-cmds"
	bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
	cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)

type RepoVersion struct {
	Version string
}

var RepoCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Manipulate the IPFS repo.",
		ShortDescription: `
'ipfs repo' is a plumbing command used to manipulate the repo.
`,
	},

	Subcommands: map[string]*cmds.Command{
		"stat":    repoStatCmd,
		"gc":      repoGcCmd,
		"fsck":    RepoFsckCmd,
		"version": repoVersionCmd,
		"verify":  repoVerifyCmd,
	},
}

// GcResult is the result returned by "repo gc" command.
type GcResult struct {
	Key   cid.Cid
	Error string `json:",omitempty"`
}

const (
	repoStreamErrorsOptionName = "stream-errors"
	repoQuietOptionName        = "quiet"
)

var repoGcCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Perform a garbage collection sweep on the repo.",
		ShortDescription: `
'ipfs repo gc' is a plumbing command that will sweep the local
set of stored objects and remove ones that are not pinned in
order to reclaim hard disk space.
`,
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption(repoStreamErrorsOptionName, "Stream errors."),
		cmdkit.BoolOption(repoQuietOptionName, "q", "Write minimal output."),
	},
	Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
		n, err := cmdenv.GetNode(env)
		if err != nil {
			return err
		}

		streamErrors, _ := req.Options[repoStreamErrorsOptionName].(bool)

		gcOutChan := corerepo.GarbageCollectAsync(n, req.Context)

		if streamErrors {
			errs := false
			for res := range gcOutChan {
				if res.Error != nil {
					if err := re.Emit(&GcResult{Error: res.Error.Error()}); err != nil {
						return err
					}
					errs = true
				} else {
					if err := re.Emit(&GcResult{Key: res.KeyRemoved}); err != nil {
						return err
					}
				}
			}
			if errs {
				return errors.New("encountered errors during gc run")
			}
		} else {
			err := corerepo.CollectResult(req.Context, gcOutChan, func(k cid.Cid) {
				re.Emit(&GcResult{Key: k})
			})
			if err != nil {
				return err
			}
		}

		return nil
	},
	Type: GcResult{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			quiet, _ := req.Options[repoQuietOptionName].(bool)

			obj, ok := v.(*GcResult)
			if !ok {
				return e.TypeErr(obj, v)
			}

			if obj.Error != "" {
				_, err := fmt.Fprintf(w, "Error: %s\n", obj.Error)
				return err
			}

			prefix := "removed "
			if quiet {
				prefix = ""
			}

			_, err := fmt.Fprintf(w, "%s%s\n", prefix, obj.Key)
			return err
		}),
	},
}

const (
	repoSizeOnlyOptionName = "size-only"
	repoHumanOptionName    = "human"
)

var repoStatCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Get stats for the currently used repo.",
		ShortDescription: `
'ipfs repo stat' provides information about the local set of
stored objects. It outputs:

RepoSize        int Size in bytes that the repo is currently taking.
StorageMax      string Maximum datastore size (from configuration)
NumObjects      int Number of objects in the local repo.
RepoPath        string The path to the repo being currently used.
Version         string The repo version.
`,
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption(repoSizeOnlyOptionName, "Only report RepoSize and StorageMax."),
		cmdkit.BoolOption(repoHumanOptionName, "Output sizes in MiB."),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		n, err := cmdenv.GetNode(env)
		if err != nil {
			return err
		}

		sizeOnly, _ := req.Options[repoSizeOnlyOptionName].(bool)
		if sizeOnly {
			sizeStat, err := corerepo.RepoSize(req.Context, n)
			if err != nil {
				return err
			}
			cmds.EmitOnce(res, &corerepo.Stat{
				SizeStat: sizeStat,
			})
			return nil
		}

		stat, err := corerepo.RepoStat(req.Context, n)
		if err != nil {
			return err
		}

		return cmds.EmitOnce(res, &stat)
	},
	Type: &corerepo.Stat{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			stat, ok := v.(*corerepo.Stat)
			if !ok {
				return e.TypeErr(stat, v)
			}

			wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
			defer wtr.Flush()

			human, _ := req.Options[repoHumanOptionName].(bool)
			sizeOnly, _ := req.Options[repoSizeOnlyOptionName].(bool)

			printSize := func(name string, size uint64) {
				sizeInMiB := size / (1024 * 1024)
				if human && sizeInMiB > 0 {
					fmt.Fprintf(wtr, "%s (MiB):\t%d\n", name, sizeInMiB)
				} else {
					fmt.Fprintf(wtr, "%s:\t%d\n", name, size)
				}
			}

			if !sizeOnly {
				fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
			}

			printSize("RepoSize", stat.RepoSize)
			printSize("StorageMax", stat.StorageMax)

			if !sizeOnly {
				fmt.Fprintf(wtr, "RepoPath:\t%s\n", stat.RepoPath)
				fmt.Fprintf(wtr, "Version:\t%s\n", stat.Version)
			}

			return nil
		}),
	},
}

var RepoFsckCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Remove repo lockfiles.",
		ShortDescription: `
'ipfs repo fsck' is a plumbing command that will remove repo and level db
lockfiles, as well as the api file. This command can only run when no ipfs
daemons are running.
`,
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		configRoot, err := cmdenv.GetConfigRoot(env)
		if err != nil {
			return err
		}

		dsPath, err := config.DataStorePath(configRoot)
		if err != nil {
			return err
		}

		dsLockFile := filepath.Join(dsPath, "LOCK") // TODO: get this lockfile programmatically
		repoLockFile := filepath.Join(configRoot, fsrepo.LockFile)
		apiFile := filepath.Join(configRoot, "api") // TODO: get this programmatically

		log.Infof("Removing repo lockfile: %s", repoLockFile)
		log.Infof("Removing datastore lockfile: %s", dsLockFile)
		log.Infof("Removing api file: %s", apiFile)

		err = os.Remove(repoLockFile)
		if err != nil && !os.IsNotExist(err) {
			return err
		}
		err = os.Remove(dsLockFile)
		if err != nil && !os.IsNotExist(err) {
			return err
		}
		err = os.Remove(apiFile)
		if err != nil && !os.IsNotExist(err) {
			return err
		}

		return cmds.EmitOnce(res, &MessageOutput{"Lockfiles have been removed.\n"})
	},
	Type: MessageOutput{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *MessageOutput) error {
			fmt.Fprintf(w, out.Message)
			return nil
		}),
	},
}

type VerifyProgress struct {
	Msg      string
	Progress int
}

func verifyWorkerRun(ctx context.Context, wg *sync.WaitGroup, keys <-chan cid.Cid, results chan<- string, bs bstore.Blockstore) {
	defer wg.Done()

	for k := range keys {
		_, err := bs.Get(k)
		if err != nil {
			select {
			case results <- fmt.Sprintf("block %s was corrupt (%s)", k, err):
			case <-ctx.Done():
				return
			}

			continue
		}

		select {
		case results <- "":
		case <-ctx.Done():
			return
		}
	}
}

func verifyResultChan(ctx context.Context, keys <-chan cid.Cid, bs bstore.Blockstore) <-chan string {
	results := make(chan string)

	go func() {
		defer close(results)

		var wg sync.WaitGroup

		for i := 0; i < runtime.NumCPU()*2; i++ {
			wg.Add(1)
			go verifyWorkerRun(ctx, &wg, keys, results, bs)
		}

		wg.Wait()
	}()

	return results
}

var repoVerifyCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Verify all blocks in repo are not corrupted.",
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		nd, err := cmdenv.GetNode(env)
		if err != nil {
			return err
		}

		bs := bstore.NewBlockstore(nd.Repo.Datastore())
		bs.HashOnRead(true)

		keys, err := bs.AllKeysChan(req.Context)
		if err != nil {
			log.Error(err)
			return err
		}

		results := verifyResultChan(req.Context, keys, bs)

		var fails int
		var i int
		for msg := range results {
			if msg != "" {
				if err := res.Emit(&VerifyProgress{Msg: msg}); err != nil {
					return err
				}
				fails++
			}
			i++
			if err := res.Emit(&VerifyProgress{Progress: i}); err != nil {
				return err
			}
		}

		if fails != 0 {
			return errors.New("verify complete, some blocks were corrupt")
		}

		return res.Emit(&VerifyProgress{Msg: "verify complete, all blocks validated."})
	},
	Type: &VerifyProgress{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, obj *VerifyProgress) error {
			if strings.Contains(obj.Msg, "was corrupt") {
				fmt.Fprintln(os.Stdout, obj.Msg)
				return nil
			}

			if obj.Msg != "" {
				if len(obj.Msg) < 20 {
					obj.Msg += "             "
				}
				fmt.Fprintln(w, obj.Msg)
				return nil
			}

			fmt.Fprintf(w, "%d blocks processed.\r", obj.Progress)
			return nil
		}),
	},
}

var repoVersionCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Show the repo version.",
		ShortDescription: `
'ipfs repo version' returns the current repo version.
`,
	},

	Options: []cmdkit.Option{
		cmdkit.BoolOption(repoQuietOptionName, "q", "Write minimal output."),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
		return cmds.EmitOnce(res, &RepoVersion{
			Version: fmt.Sprint(fsrepo.RepoVersion),
		})
	},
	Type: RepoVersion{},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RepoVersion) error {
			quiet, _ := req.Options[repoQuietOptionName].(bool)

			if quiet {
				fmt.Fprintf(w, fmt.Sprintf("fs-repo@%s\n", out.Version))
			} else {
				fmt.Fprintf(w, fmt.Sprintf("ipfs repo version fs-repo@%s\n", out.Version))
			}
			return nil
		}),
	},
}
<|endoftext|>


<commit_before>// +build lambdabinary,noop

package cgo

import (
	"net/http"

	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	sparta "github.com/mweagle/Sparta"
)

////////////////////////////////////////////////////////////////////////////////
// cgoMain is the primary entrypoint for the library version
func cgoMain(callerFile string,
	serviceName string,
	serviceDescription string,
	lambdaAWSInfos []*sparta.LambdaAWSInfo,
	api *sparta.API,
	site *sparta.S3Site,
	workflowHooks *sparta.WorkflowHooks) error {
	// NOOP
	return nil
}

// LambdaHandler is the public handler that's called by the transformed
// CGO compliant userinput. Users should not need to call this function
// directly
func LambdaHandler(functionName string,
	eventJSON string,
	awsCredentials *credentials.Credentials) ([]byte, http.Header, error) {
	// NOOP
	return nil, nil, nil
}

// NewSession returns a CGO-aware AWS session that uses the Python
// credentials provided by the CGO interface.
func NewSession() *session.Session {
	// NOOP
	return nil
}
<commit_msg>Update signature for NOP codepath<commit_after>// +build lambdabinary,noop

package cgo

import (
	"net/http"

	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	sparta "github.com/mweagle/Sparta"
)

////////////////////////////////////////////////////////////////////////////////
// cgoMain is the primary entrypoint for the library version
func cgoMain(callerFile string,
	serviceName string,
	serviceDescription string,
	lambdaAWSInfos []*sparta.LambdaAWSInfo,
	api *sparta.API,
	site *sparta.S3Site,
	workflowHooks *sparta.WorkflowHooks) error {
	// NOOP
	return nil
}

// LambdaHandler is the public handler that's called by the transformed
// CGO compliant userinput. Users should not need to call this function
// directly
func LambdaHandler(functionName string,
	logLevel string,
	eventJSON string,
	awsCredentials *credentials.Credentials) ([]byte, http.Header, error) {
	// NOOP
	return nil, nil, nil
}

// NewSession returns a CGO-aware AWS session that uses the Python
// credentials provided by the CGO interface.
func NewSession() *session.Session {
	// NOOP
	return nil
}
<|endoftext|>


<commit_before>package hey

import "time"

// Manager represents storage methods
type Manager interface {
	// threads
	NewThread(*Thread) error
	GetThread(threadID string) (*Thread, error)
	UpdateThread(*Thread) error
	DeleteThread(threadID string) error

	// thread sources
	AddSource(dstThread, sourceThread string) error
	GetSources(threadID string, offset, limit uint32) ([]Thread, error)
	GetRefers(sourceThreadID string, offset, limit uint32) ([]Thread, error)
	RemoveSource(dstThread, sourceThread string) error

	// user subscriptions
	Observe(userID, threadID string) error
	Ignore(userID, threadID string) error
	Observers(threadID string, offset, limit uint32) ([]User, error)
	Observes(userID string, offset, limit uint32) ([]Thread, error)
	MarkAsDelivered(userID string, threadID string, times ...time.Time) error

	// threadline
	RecentActivityByLastTS(threadID string, limit uint32, lastts time.Time) ([]Event, error)
	RecentActivity(threadID string, limit, offset uint32) ([]Event, error)

	// events
	NewEvent(*Event) error
	GetEvent(id string) (*Event, error)
	GetEvents(ids ...string) ([]Event, error)
	UpdateEvent(ev *Event) error
	DeleteEvent(eventID string) error
}
<commit_msg>hide sources methods<commit_after>package hey

import "time"

// Manager represents storage methods
type Manager interface {
	// threads
	NewThread(*Thread) error
	GetThread(threadID string) (*Thread, error)
	UpdateThread(*Thread) error
	DeleteThread(threadID string) error

	// thread sources
	//AddSource(dstThread, sourceThread string) error
	//GetSources(threadID string, offset, limit uint32) ([]Thread, error)
	//GetRefers(sourceThreadID string, offset, limit uint32) ([]Thread, error)
	//RemoveSource(dstThread, sourceThread string) error

	// user subscriptions
	Observe(userID, threadID string) error
	Ignore(userID, threadID string) error
	Observers(threadID string, offset, limit uint32) ([]User, error)
	Observes(userID string, offset, limit uint32) ([]Thread, error)
	MarkAsDelivered(userID string, threadID string, times ...time.Time) error

	// threadline
	RecentActivityByLastTS(threadID string, limit uint32, lastts time.Time) ([]Event, error)
	RecentActivity(userID, threadID string, limit uint32) ([]Event, error)
	Activity(threadID string, offset, limit uint32) ([]Event, error)

	// events
	NewEvent(*Event) error
	GetEvent(id string) (*Event, error)
	GetEvents(ids ...string) ([]Event, error)
	UpdateEvent(ev *Event) error
	DeleteEvent(eventID string) error

	// related data
	SetRelatedData(*RelatedData) error
	GetRelatedDatas(userID string, events ...Event) ([]EventObserver, error)

	// users
	NewUser(*User) error
	GetUser(userID string) (*User, error)
}
<|endoftext|>