<commit_before>// TODO：普通的表达式没有处理字符串转义，需要接受外部传入的数据的话，请一定参数化
// TODO: Stringer 接口应该改为exp接口，exp.evel接受engine参数
// 目前还没有对纯文本文法中的命名做映射，要享受转换的能力，请使用table和field类型
package exp

import (
	"fmt"
	"time"
	"strings"
	"regexp"
)

var argFinder,_ = regexp.Compile("([^\\$]\\$\\d)|(^\\$d)")
var dollar,_ = regexp.Compile("\\$\\$")

type Env interface {
	// Type Name to Table Name
	// NOTE: 需要注意的是当前使用type的Name()，其中包含packages名
	TynaToTana(typename string) string
	// Struct Field Name to Table Column Name
	FinaToCona(typename string, fieldname string) string
	Scope() Exp
	SetScope(Exp)
}

type Exp interface {
	Eval(Env) string
}

type equal struct{
	x, y Exp
}
func Equal(x, y Exp) Exp{
	return &equal{x, y}
}
func (e equal)Eval(env Env)string{
	return fmt.Sprintf("%s=%s", e.x.Eval(env), e.y.Eval(env))
}

type notequal struct{
	x, y Exp
}
func NotEqual(x, y Exp) Exp{
	return &notequal{x, y}
}
func (e notequal)Eval(env Env)string{
	return fmt.Sprintf("%s!=%s", e.x.Eval(env), e.y.Eval(env))
}

type great struct{
	x, y Exp
}
func Great(x, y Exp) Exp{
	return &great{x, y}
}
func (e great)Eval(env Env)string{
	return fmt.Sprintf("%s>%s", e.x.Eval(env), e.y.Eval(env))
}

type less struct{
	x, y Exp
}
func Less(x, y Exp) Exp{
	return &great{x, y}
}
func (e less)Eval(env Env)string{
	return fmt.Sprintf("%s<%s", e.x.Eval(env), e.y.Eval(env))
}

type and struct{
	x, y Exp
}
func And(x, y Exp) Exp{
	return &and{x, y}
}
func (a and)Eval(env Env)string{
	return fmt.Sprintf("(%s) and (%s)", a.x.Eval(env), a.y.Eval(env))
}

type or struct{
	x, y Exp
}
func Or(x, y Exp) Exp{
	return &or{x, y}
}
func (o or)Eval(env Env)string{
	return fmt.Sprintf("(%s) or (%s)", o.x.Eval(env), o.y.Eval(env))
}

// text 就是 PostgreSQL 的 text 类型。由于作者太懒，先用这个代替所有的文本和字符串类型用吧，
// 在 PG 里其实一般的规模好像也问题不大……
type text struct{
	data string
}
func Text(data string) Exp{
	return &text{data}
}
func(t *text)Eval(env Env)string{
	return fmt.Sprintf("'%s'", t.data)
}

type integer struct{
	data int
}
func Integer(data int) Exp{
	return &integer{data}
}
func(i *integer)Eval(env Env)string{
	return fmt.Sprintf("%d", i.data)
}

type timestamp struct{
	data time.Time
}
func TimeStamp(data time.Time) Exp {
	return &timestamp{data}
}
func(ts *timestamp)Eval(env Env) string{
	return fmt.Sprintf("'%v'::Timestamp", ts.data)
}

// 之所以用 arg 而不是 parameter ， 完全是为了少写几个字母……
type arg struct{
	Order int
}
// 我也觉得自动生成序列号比较省力气啊。不过想了半天， $%d 就是为了可以指定参数插入位置啊，
// 自动生成顺序就白瞎了啊……
// 将来可能会把这个变成支持命名的，order虽然更省事儿，但是命名相对来说更省心
func Arg(order int) *arg {
	return &arg{order}
}
func (a arg)Eval(env Env)string{
	return fmt.Sprintf("$%d", a.Order)
}
// 写到 Update 一个对象的时候发现需要一个方法，将引擎中的条件表达式的所有条件参数的
// order 增加一个整数。这种问题真是太暗黑了……
func IncOrder(e Exp, step int){
	switch ex := e.(type) {
	case *equal:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *notequal:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *and:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *or:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *great:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *less:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *not:
		IncOrder((*ex).exp, step)
	case *arg:
		ex.Order += step
	}
}

type function struct{
	name string
	args []Exp
}
func Func(name string, args... Exp) Exp{
	return &function{name, args}
}
func (f *function)Eval(env Env)string{
	var args = make([]string, len(f.args))
	for _, arg := range f.args{
		args = append(args, arg.Eval(env))
	}
	return fmt.Sprintf("%s(\"%s\")", f.name, strings.Join(args, ","))
}

type not struct{
	exp Exp
}
func Not(exp Exp) *not{
	return &not{exp}
}
func (n not)Eval(env Env) string{
	return fmt.Sprintf("not (%s)", n.exp.Eval(env))
}

type fieldIsNull struct{
	exp Exp
}
func FieldIsNull(field Exp) fieldIsNull{
	return fieldIsNull{field}
}
func (isnull *fieldIsNull)Eval(env Env) string{
	return fmt.Sprintf("%s is NULL", isnull.exp.Eval(env))
}

type isNullFunc struct{
	field Exp
	exp Exp
}
func IsNullFunc(field Exp, exp Exp) Exp{
	return isNullFunc{field, exp}
}
func (isnull isNullFunc)Eval(env Env) string{
	return fmt.Sprintf("isNull(%s, %s)", isnull.field.Eval(env),
		isnull.exp.Eval(env))
}

type nullif struct{
	field Exp
	exp Exp
}
func NullIf(field Exp, exp Exp) Exp{
	return nullif{field, exp}
}
func (nullif nullif)Eval(env Env) string{
	return fmt.Sprintf("nullif(%s, %s)", nullif.field.Eval(env),
		nullif.exp.Eval(env))
}

type fullTextSearch struct{
	field Exp
	query Exp
}
func FTS(field Exp, query Exp) *fullTextSearch{
	return &fullTextSearch{field, query}
}
func (fts fullTextSearch)Eval(env Env)string{
	return fmt.Sprintf("%s @@ %s", fts.field.Eval(env),
		fts.query.Eval(env))
}

// snippet 就是直接插入一段纯文本咯，不做任何检测咯，玩脱了是你活该咯……
type snippet struct {
	str *string
}
func Snippet(s string) *snippet{
	return &snippet{&s}
}
func (s *snippet)Eval(env Env) string {
	return *s.str
}
<commit_msg>add desc support<commit_after>// TODO：普通的表达式没有处理字符串转义，需要接受外部传入的数据的话，请一定参数化
// TODO: Stringer 接口应该改为exp接口，exp.evel接受engine参数
// 目前还没有对纯文本文法中的命名做映射，要享受转换的能力，请使用table和field类型
package exp

import (
	"fmt"
	"time"
	"strings"
	"regexp"
)

var argFinder,_ = regexp.Compile("([^\\$]\\$\\d)|(^\\$d)")
var dollar,_ = regexp.Compile("\\$\\$")

type Env interface {
	// Type Name to Table Name
	// NOTE: 需要注意的是当前使用type的Name()，其中包含packages名
	TynaToTana(typename string) string
	// Struct Field Name to Table Column Name
	FinaToCona(typename string, fieldname string) string
	Scope() Exp
	SetScope(Exp)
}

type Exp interface {
	Eval(Env) string
}

type equal struct{
	x, y Exp
}
func Equal(x, y Exp) Exp{
	return &equal{x, y}
}
func (e equal)Eval(env Env)string{
	return fmt.Sprintf("%s=%s", e.x.Eval(env), e.y.Eval(env))
}

type notequal struct{
	x, y Exp
}
func NotEqual(x, y Exp) Exp{
	return &notequal{x, y}
}
func (e notequal)Eval(env Env)string{
	return fmt.Sprintf("%s!=%s", e.x.Eval(env), e.y.Eval(env))
}

type great struct{
	x, y Exp
}
func Great(x, y Exp) Exp{
	return &great{x, y}
}
func (e great)Eval(env Env)string{
	return fmt.Sprintf("%s>%s", e.x.Eval(env), e.y.Eval(env))
}

type less struct{
	x, y Exp
}
func Less(x, y Exp) Exp{
	return &great{x, y}
}
func (e less)Eval(env Env)string{
	return fmt.Sprintf("%s<%s", e.x.Eval(env), e.y.Eval(env))
}

type and struct{
	x, y Exp
}
func And(x, y Exp) Exp{
	return &and{x, y}
}
func (a and)Eval(env Env)string{
	return fmt.Sprintf("(%s) and (%s)", a.x.Eval(env), a.y.Eval(env))
}

type or struct{
	x, y Exp
}
func Or(x, y Exp) Exp{
	return &or{x, y}
}
func (o or)Eval(env Env)string{
	return fmt.Sprintf("(%s) or (%s)", o.x.Eval(env), o.y.Eval(env))
}

// text 就是 PostgreSQL 的 text 类型。由于作者太懒，先用这个代替所有的文本和字符串类型用吧，
// 在 PG 里其实一般的规模好像也问题不大……
type text struct{
	data string
}
func Text(data string) Exp{
	return &text{data}
}
func(t *text)Eval(env Env)string{
	return fmt.Sprintf("'%s'", t.data)
}

type integer struct{
	data int
}
func Integer(data int) Exp{
	return &integer{data}
}
func(i *integer)Eval(env Env)string{
	return fmt.Sprintf("%d", i.data)
}

type timestamp struct{
	data time.Time
}
func TimeStamp(data time.Time) Exp {
	return &timestamp{data}
}
func(ts *timestamp)Eval(env Env) string{
	return fmt.Sprintf("'%v'::Timestamp", ts.data)
}

// 之所以用 arg 而不是 parameter ， 完全是为了少写几个字母……
type arg struct{
	Order int
}
// 我也觉得自动生成序列号比较省力气啊。不过想了半天， $%d 就是为了可以指定参数插入位置啊，
// 自动生成顺序就白瞎了啊……
// 将来可能会把这个变成支持命名的，order虽然更省事儿，但是命名相对来说更省心
func Arg(order int) *arg {
	return &arg{order}
}
func (a arg)Eval(env Env)string{
	return fmt.Sprintf("$%d", a.Order)
}
// 写到 Update 一个对象的时候发现需要一个方法，将引擎中的条件表达式的所有条件参数的
// order 增加一个整数。这种问题真是太暗黑了……
func IncOrder(e Exp, step int){
	switch ex := e.(type) {
	case *equal:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *notequal:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *and:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *or:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *great:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *less:
		IncOrder((*ex).x, step)
		IncOrder((*ex).y, step)
	case *not:
		IncOrder((*ex).exp, step)
	case *arg:
		ex.Order += step
	}
}

type function struct{
	name string
	args []Exp
}
func Func(name string, args... Exp) Exp{
	return &function{name, args}
}
func (f *function)Eval(env Env)string{
	var args = make([]string, len(f.args))
	for _, arg := range f.args{
		args = append(args, arg.Eval(env))
	}
	return fmt.Sprintf("%s(\"%s\")", f.name, strings.Join(args, ","))
}

type not struct{
	exp Exp
}
func Not(exp Exp) *not{
	return &not{exp}
}
func (n not)Eval(env Env) string{
	return fmt.Sprintf("not (%s)", n.exp.Eval(env))
}

type fieldIsNull struct{
	exp Exp
}
func FieldIsNull(field Exp) fieldIsNull{
	return fieldIsNull{field}
}
func (isnull *fieldIsNull)Eval(env Env) string{
	return fmt.Sprintf("%s is NULL", isnull.exp.Eval(env))
}

type isNullFunc struct{
	field Exp
	exp Exp
}
func IsNullFunc(field Exp, exp Exp) Exp{
	return isNullFunc{field, exp}
}
func (isnull isNullFunc)Eval(env Env) string{
	return fmt.Sprintf("isNull(%s, %s)", isnull.field.Eval(env),
		isnull.exp.Eval(env))
}

type nullif struct{
	field Exp
	exp Exp
}
func NullIf(field Exp, exp Exp) Exp{
	return nullif{field, exp}
}
func (nullif nullif)Eval(env Env) string{
	return fmt.Sprintf("nullif(%s, %s)", nullif.field.Eval(env),
		nullif.exp.Eval(env))
}

type fullTextSearch struct{
	field Exp
	query Exp
}
func FTS(field Exp, query Exp) *fullTextSearch{
	return &fullTextSearch{field, query}
}
func (fts fullTextSearch)Eval(env Env)string{
	return fmt.Sprintf("%s @@ %s", fts.field.Eval(env),
		fts.query.Eval(env))
}

// snippet 就是直接插入一段纯文本咯，不做任何检测咯，玩脱了是你活该咯……
type snippet struct {
	str *string
}
func Snippet(s string) *snippet{
	return &snippet{&s}
}
func (s *snippet)Eval(env Env) string {
	return *s.str
}

// 虽然理论上说这个内涵的 field 肯定会是field，但是这里姑且还是假定为 exp.Exp
type desc struct {
	field Exp
}
// Desc 生成一个用于orderby desc的表达式
func Desc(field Exp)Exp{
	return &{field}
}

func (f field)Eval(env Env) string{
	return field.Eval(env)+" desc"
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"fmt"
	"github.com/limetext/gopy/lib"
	"github.com/limetext/lime/backend"
	"github.com/limetext/lime/backend/log"
	"github.com/limetext/text"
)

var _ = log.Global.LogError

type Refcounted py.Object

func (v *View) Py_has_non_empty_selection_region() (py.Object, error) {
	for _, r := range v.data.Sel().Regions() {
		if !r.Empty() {
			return toPython(true)
		}
	}
	return toPython(false)
}

func (view *View) Py_show(tu *py.Tuple, kw *py.Dict) (py.Object, error) {
	var (
		arg1 text.Region
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*Region); !ok {
		if v2, ok := v.(*py.Long); !ok {
			return nil, fmt.Errorf("Expected type *Region or *Int for primitives.Buffer.Substr() arg1, not %s", v.Type())
		} else {
			arg1.A = int(v2.Int64())
			arg1.B = arg1.A + 1
		}
	} else {
		arg1 = v2.data
	}
	backend.GetEditor().Frontend().Show(view.data, arg1)
	return toPython(nil)
}

func (o *View) Py_substr(tu *py.Tuple) (py.Object, error) {
	var (
		arg1 text.Region
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*Region); !ok {
		if v2, ok := v.(*py.Long); !ok {
			return nil, fmt.Errorf("Expected type *Region or *Int for primitives.Buffer.Substr() arg1, not %s", v.Type())
		} else {
			arg1.A = int(v2.Int64())
			arg1.B = arg1.A + 1
		}
	} else {
		arg1 = v2.data
	}
	ret0 := o.data.Buffer().Substr(arg1)
	var pyret0 py.Object

	pyret0, err = py.NewUnicode(ret0)
	if err != nil {
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	return pyret0, err
}

func (o *View) Py_add_regions(tu *py.Tuple, kw *py.Dict) (py.Object, error) {
	var (
		arg1 string
		arg2 []text.Region
	)
	if tu.Size() < 2 {
		return nil, fmt.Errorf("Not the expected argument size: %d", tu.Size())
	}
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*py.Unicode); !ok {
		return nil, fmt.Errorf("Expected type *py.Unicode for backend.View.AddRegions() arg1, not %s", v.Type())
	} else {
		arg1 = v2.String()
	}
	v, err = tu.GetItem(1)
	if err != nil {
		return nil, err
	}
	v2, ok := v.(*py.List)
	if !ok {
		return nil, fmt.Errorf("Expected type *py.List for backend.View.AddRegions() arg2, not %s", v.Type())
	}
	d := v2.Slice()
	arg2 = make([]text.Region, len(d))
	for i, o := range d {
		if v, err := fromPython(o); err != nil {
			return nil, err
		} else if v2, ok := v.(text.Region); !ok {
			return nil, fmt.Errorf("Expected non-region item in list passed to backend.View.AddRegions(): %s", o.Type())
		} else {
			arg2[i] = v2
		}
	}
	o.data.AddRegions(arg1, arg2, "", "", 0) // TODO
	return toPython(nil)
}

func (o *View) Py_command_history(tu *py.Tuple) (py.Object, error) {
	var (
		arg1 int
		arg2 bool
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*py.Long); !ok {
		return nil, fmt.Errorf("Expected type *py.Long for backend.View.CommandHistory() arg1, not %s", v.Type())
	} else {
		arg1 = int(v2.Int64())
	}
	if v, err := tu.GetItem(1); err == nil {
		if v2, ok := v.(*py.Bool); !ok {
			return nil, fmt.Errorf("Expected type *py.Bool for backend.View.CommandHistory() arg2, not %s", v.Type())
		} else {
			arg2 = v2.Bool()
		}
	}
	ret0, ret1, ret2 := o.data.CommandHistory(arg1, arg2)
	var pyret0 py.Object

	pyret0, err = py.NewUnicode(ret0)
	if err != nil {
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	var pyret1 py.Object

	// Sublime compatibility
	if len(ret1) == 0 {
		pyret1, err = toPython(nil)
	} else {
		pyret1, err = toPython(ret1)
	}
	if err != nil {
		pyret0.Decref()
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	var pyret2 py.Object

	pyret2 = py.NewLong(int64(ret2))
	if err != nil {
		pyret0.Decref()
		pyret1.Decref()
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	return py.PackTuple(pyret0, pyret1, pyret2)
}

func (o *View) Py_run_command(tu *py.Tuple) (py.Object, error) {
	var (
		arg1 string
		arg2 backend.Args
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*py.Unicode); !ok {
		return nil, fmt.Errorf("Expected type *py.Unicode for backend.View.RunCommand() arg1, not %s", v.Type())
	} else {
		arg1 = v2.String()
	}
	arg2 = make(backend.Args)
	if v, err := tu.GetItem(1); err == nil {
		v2, ok := v.(*py.Dict)
		if !ok {
			return nil, fmt.Errorf("Expected type *py.Dict for backend.View.RunCommand() arg2, not %s", v.Type())
		}
		if v, err := fromPython(v2); err != nil {
			return nil, err
		} else {
			arg2 = v.(backend.Args)
		}
	}
	backend.GetEditor().CommandHandler().RunTextCommand(o.data, arg1, arg2)
	return toPython(nil)
}

func (o *View) Py_visible_region() (py.Object, error) {
	ret0 := backend.GetEditor().Frontend().VisibleRegion(o.data)
	var err error
	var pyret0 py.Object

	pyret0, err = _regionClass.Alloc(1)
	if err != nil {
		return nil, err
	} else if v2, ok := pyret0.(*Region); !ok {
		return nil, fmt.Errorf("Unable to convert return value to the right type?!: %s", pyret0.Type())
	} else {
		v2.data = ret0
	}
	if err != nil {
		return nil, err
	}
	return pyret0, err
}

func (o *View) Py_line(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if _, ok := v.(*Region); ok {
		return o.liner(tu)
	} else {
		return o.line(tu)
	}
}

func (o *View) Py_full_line(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if _, ok := v.(*Region); ok {
		return o.fullliner(tu)
	}
	return o.fullline(tu)
}

func (o *View) Py_word(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if _, ok := v.(*Region); ok {
		return o.wordr(tu)
	}
	return o.word(tu)
}

func (o *View) Py_set_syntax_file(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v, ok := v.(*py.Unicode); ok {
		o.data.Settings().Set("syntax", v.String())
	}
	return toPython(nil)
}

func (o *View) Py_expand_by_class(tu *py.Tuple, kw *py.Dict) (py.Object, error) {
	var (
		arg1 text.Region
		arg2 int
	)

	if v, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		if v2, ok := v.(*Region); !ok {
			if v2, ok := v.(*py.Long); !ok {
				return nil, fmt.Errorf("Expected type *Region or *Int for backend.View.ExpandByClass() arg1, not %s", v.Type())
			} else {
				arg1.A = int(v2.Int64())
				arg1.B = arg1.A + 1
			}
		} else {
			arg1 = v2.data
		}
	}

	if v, err := tu.GetItem(1); err != nil {
		return nil, err
	} else {
		if v3, err2 := fromPython(v); err2 != nil {
			return nil, err2
		} else {
			if v2, ok := v3.(int); !ok {
				return nil, fmt.Errorf("Expected type int for backend.View.ExpandByClass() arg2, not %s", v.Type())
			} else {
				arg2 = v2
			}
		}
	}

	ret := o.data.ExpandByClass(arg1, arg2)
	var err error
	var pyret py.Object

	pyret, err = toPython(ret)
	if err != nil {
		return nil, err
	}
	return pyret, err
}
<commit_msg>[backend] Remove unused log call.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"fmt"
	"github.com/limetext/gopy/lib"
	"github.com/limetext/lime/backend"
	"github.com/limetext/text"
)

type Refcounted py.Object

func (v *View) Py_has_non_empty_selection_region() (py.Object, error) {
	for _, r := range v.data.Sel().Regions() {
		if !r.Empty() {
			return toPython(true)
		}
	}
	return toPython(false)
}

func (view *View) Py_show(tu *py.Tuple, kw *py.Dict) (py.Object, error) {
	var (
		arg1 text.Region
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*Region); !ok {
		if v2, ok := v.(*py.Long); !ok {
			return nil, fmt.Errorf("Expected type *Region or *Int for primitives.Buffer.Substr() arg1, not %s", v.Type())
		} else {
			arg1.A = int(v2.Int64())
			arg1.B = arg1.A + 1
		}
	} else {
		arg1 = v2.data
	}
	backend.GetEditor().Frontend().Show(view.data, arg1)
	return toPython(nil)
}

func (o *View) Py_substr(tu *py.Tuple) (py.Object, error) {
	var (
		arg1 text.Region
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*Region); !ok {
		if v2, ok := v.(*py.Long); !ok {
			return nil, fmt.Errorf("Expected type *Region or *Int for primitives.Buffer.Substr() arg1, not %s", v.Type())
		} else {
			arg1.A = int(v2.Int64())
			arg1.B = arg1.A + 1
		}
	} else {
		arg1 = v2.data
	}
	ret0 := o.data.Buffer().Substr(arg1)
	var pyret0 py.Object

	pyret0, err = py.NewUnicode(ret0)
	if err != nil {
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	return pyret0, err
}

func (o *View) Py_add_regions(tu *py.Tuple, kw *py.Dict) (py.Object, error) {
	var (
		arg1 string
		arg2 []text.Region
	)
	if tu.Size() < 2 {
		return nil, fmt.Errorf("Not the expected argument size: %d", tu.Size())
	}
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*py.Unicode); !ok {
		return nil, fmt.Errorf("Expected type *py.Unicode for backend.View.AddRegions() arg1, not %s", v.Type())
	} else {
		arg1 = v2.String()
	}
	v, err = tu.GetItem(1)
	if err != nil {
		return nil, err
	}
	v2, ok := v.(*py.List)
	if !ok {
		return nil, fmt.Errorf("Expected type *py.List for backend.View.AddRegions() arg2, not %s", v.Type())
	}
	d := v2.Slice()
	arg2 = make([]text.Region, len(d))
	for i, o := range d {
		if v, err := fromPython(o); err != nil {
			return nil, err
		} else if v2, ok := v.(text.Region); !ok {
			return nil, fmt.Errorf("Expected non-region item in list passed to backend.View.AddRegions(): %s", o.Type())
		} else {
			arg2[i] = v2
		}
	}
	o.data.AddRegions(arg1, arg2, "", "", 0) // TODO
	return toPython(nil)
}

func (o *View) Py_command_history(tu *py.Tuple) (py.Object, error) {
	var (
		arg1 int
		arg2 bool
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*py.Long); !ok {
		return nil, fmt.Errorf("Expected type *py.Long for backend.View.CommandHistory() arg1, not %s", v.Type())
	} else {
		arg1 = int(v2.Int64())
	}
	if v, err := tu.GetItem(1); err == nil {
		if v2, ok := v.(*py.Bool); !ok {
			return nil, fmt.Errorf("Expected type *py.Bool for backend.View.CommandHistory() arg2, not %s", v.Type())
		} else {
			arg2 = v2.Bool()
		}
	}
	ret0, ret1, ret2 := o.data.CommandHistory(arg1, arg2)
	var pyret0 py.Object

	pyret0, err = py.NewUnicode(ret0)
	if err != nil {
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	var pyret1 py.Object

	// Sublime compatibility
	if len(ret1) == 0 {
		pyret1, err = toPython(nil)
	} else {
		pyret1, err = toPython(ret1)
	}
	if err != nil {
		pyret0.Decref()
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	var pyret2 py.Object

	pyret2 = py.NewLong(int64(ret2))
	if err != nil {
		pyret0.Decref()
		pyret1.Decref()
		// TODO: do the py objs need to be freed?
		return nil, err
	}

	return py.PackTuple(pyret0, pyret1, pyret2)
}

func (o *View) Py_run_command(tu *py.Tuple) (py.Object, error) {
	var (
		arg1 string
		arg2 backend.Args
	)
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v2, ok := v.(*py.Unicode); !ok {
		return nil, fmt.Errorf("Expected type *py.Unicode for backend.View.RunCommand() arg1, not %s", v.Type())
	} else {
		arg1 = v2.String()
	}
	arg2 = make(backend.Args)
	if v, err := tu.GetItem(1); err == nil {
		v2, ok := v.(*py.Dict)
		if !ok {
			return nil, fmt.Errorf("Expected type *py.Dict for backend.View.RunCommand() arg2, not %s", v.Type())
		}
		if v, err := fromPython(v2); err != nil {
			return nil, err
		} else {
			arg2 = v.(backend.Args)
		}
	}
	backend.GetEditor().CommandHandler().RunTextCommand(o.data, arg1, arg2)
	return toPython(nil)
}

func (o *View) Py_visible_region() (py.Object, error) {
	ret0 := backend.GetEditor().Frontend().VisibleRegion(o.data)
	var err error
	var pyret0 py.Object

	pyret0, err = _regionClass.Alloc(1)
	if err != nil {
		return nil, err
	} else if v2, ok := pyret0.(*Region); !ok {
		return nil, fmt.Errorf("Unable to convert return value to the right type?!: %s", pyret0.Type())
	} else {
		v2.data = ret0
	}
	if err != nil {
		return nil, err
	}
	return pyret0, err
}

func (o *View) Py_line(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if _, ok := v.(*Region); ok {
		return o.liner(tu)
	} else {
		return o.line(tu)
	}
}

func (o *View) Py_full_line(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if _, ok := v.(*Region); ok {
		return o.fullliner(tu)
	}
	return o.fullline(tu)
}

func (o *View) Py_word(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if _, ok := v.(*Region); ok {
		return o.wordr(tu)
	}
	return o.word(tu)
}

func (o *View) Py_set_syntax_file(tu *py.Tuple) (py.Object, error) {
	v, err := tu.GetItem(0)
	if err != nil {
		return nil, err
	}
	if v, ok := v.(*py.Unicode); ok {
		o.data.Settings().Set("syntax", v.String())
	}
	return toPython(nil)
}

func (o *View) Py_expand_by_class(tu *py.Tuple, kw *py.Dict) (py.Object, error) {
	var (
		arg1 text.Region
		arg2 int
	)

	if v, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		if v2, ok := v.(*Region); !ok {
			if v2, ok := v.(*py.Long); !ok {
				return nil, fmt.Errorf("Expected type *Region or *Int for backend.View.ExpandByClass() arg1, not %s", v.Type())
			} else {
				arg1.A = int(v2.Int64())
				arg1.B = arg1.A + 1
			}
		} else {
			arg1 = v2.data
		}
	}

	if v, err := tu.GetItem(1); err != nil {
		return nil, err
	} else {
		if v3, err2 := fromPython(v); err2 != nil {
			return nil, err2
		} else {
			if v2, ok := v3.(int); !ok {
				return nil, fmt.Errorf("Expected type int for backend.View.ExpandByClass() arg2, not %s", v.Type())
			} else {
				arg2 = v2
			}
		}
	}

	ret := o.data.ExpandByClass(arg1, arg2)
	var err error
	var pyret py.Object

	pyret, err = toPython(ret)
	if err != nil {
		return nil, err
	}
	return pyret, err
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"strings"
	"bytes"
	"bufio"
)

func main() {
	// Read Box file
	file, _ := ioutil.ReadFile("hello.xps")
	boxCode := string(file)

	// Compile Box to Go
	boxCode = strings.Replace(boxCode, "parcel", "package", -1)
	boxCode = strings.Replace(boxCode, "deploy", "import", -1)
	boxCode = strings.Replace(boxCode, "fun()", "func() {", -1)
	boxCode = strings.Replace(boxCode, "end", "}", -1)

	reader := bufio.NewReader(bytes.NewBuffer([]byte(boxCode)))

	var lines string

	for {
		ss, _, err := reader.ReadLine()
		ss_s := string(ss)

		if err == nil {
			if strings.HasPrefix(ss_s, "interface ") {
				ss_plit := strings.Split(ss_s, " ")
				ss_s = "type " + ss_plit[1] + " interface {"
			} else if strings.HasPrefix(ss_s, "struct ") {
				ss_s = "type " + strings.Split(ss_s, " ")[1] + " struct {"
			} else if strings.HasPrefix(ss_s, "fun ") {
				ss_s = strings.Replace(ss_s, "fun ", "func ", 1) + " {"
			}

			lines += ss_s + "\n"

		} else {
			break
		}
	}

	ioutil.WriteFile("hello.go", []byte(lines), 0664)
}<commit_msg>Remove unused replacements<commit_after>package main

import (
	"io/ioutil"
	"strings"
	"bytes"
	"bufio"
)

func main() {
	// Read Express file
	file, _ := ioutil.ReadFile("hello.xps")
	boxCode := string(file)

	// Compile Express to Go
	boxCode = strings.Replace(boxCode, "fun()", "func() {", -1)
	boxCode = strings.Replace(boxCode, "end", "}", -1)

	reader := bufio.NewReader(bytes.NewBuffer([]byte(boxCode)))

	var lines string

	for {
		ss, _, err := reader.ReadLine()
		ss_s := string(ss)

		if err == nil {
			if strings.HasPrefix(ss_s, "interface ") {
				ss_plit := strings.Split(ss_s, " ")
				ss_s = "type " + ss_plit[1] + " interface {"
			} else if strings.HasPrefix(ss_s, "struct ") {
				ss_s = "type " + strings.Split(ss_s, " ")[1] + " struct {"
			} else if strings.HasPrefix(ss_s, "fun ") {
				ss_s = strings.Replace(ss_s, "fun ", "func ", 1) + " {"
			}

			lines += ss_s + "\n"

		} else {
			break
		}
	}

	ioutil.WriteFile("hello.go", []byte(lines), 0664)
}<|endoftext|>


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

package dotpath

/*
type result struct {
	string
	bool
}
*/

// Parse returns a slice of pathname, bool
func Parse(args ...string) (recurlist []struct {
	string
	bool
}) {

	recurlist = make([]struct {
		string
		bool
	}, 0, len(args)*4) // initial cap: 4 per arg

	dotS := FilePathS(args...)
	for _, dotPath := range dotS {
		recurlist = append(recurlist, dotPathS(dotPath)...)
	}

	return recurlist
}

// dotPathS returns Recurse / NotDown folds from DotPath
func dotPathS(dotPath *DotPath) (recurlist []struct {
	string
	bool
}) {

	recurlist = make([]struct {
		string
		bool
	}, 0, 4) // initial cap: 4 per arg

	var waydown = make(map[string]bool)
	for _, p := range PathS() {
		waydown[p.String()] = false
	}

	var r struct {
		string
		bool
	}

	for _, p := range RecursePathS() {
		if _, ok := waydown[p]; ok {
			waydown[p.String()] = true
		} else {
			r = struct {
				string
				bool
			}{{string(p.String()), bool(true)}}
			recurlist = append(recurlist, r)
		}
	}

	for _, p := range dotPath.PathS() {
		if waydown[p.String()] {
			r = struct {
				string
				bool
			}{{p, true}}
			recurlist = append(recurlist, r)
		} else {
			r = struct {
				string
				bool
			}{{p, false}}
			recurlist = append(recurlist, r)
		}
	}
	return recurlist
}
<commit_msg>make `golint` more happy<commit_after><|endoftext|>


<commit_before>//
// Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package sysdb

import (
	"fmt"
	"time"
)

// The SysDB JSON time format.
const jsonTime = `"2006-01-02 15:04:05 -0700"`

// A Duration represents the elapsed time between two instants as a
// nanoseconds count.
//
// It supports marshaling to and unmarshaling from the SysDB JSON format (a
// sequence of decimal numbers with a unit suffix).
type Duration time.Duration

const (
	Second = Duration(1000000000)
	Minute = 60 * Second
	Hour   = 60 * Minute
	Day    = 24 * Hour
	Month  = Duration(30436875 * 24 * 60 * 60 * 1000)
	Year   = Duration(3652425 * 24 * 60 * 60 * 100000)
)

// MarshalJSON implements the json.Marshaler interface. The time is a quoted
// string in the SysDB JSON format.
func (d Duration) MarshalJSON() ([]byte, error) {
	if d == 0 {
		return []byte(`"0s"`), nil
	}

	s := `"`
	secs := false
	for _, spec := range []struct {
		interval Duration
		suffix   string
	}{{Year, "Y"}, {Month, "M"}, {Day, "D"}, {Hour, "h"}, {Minute, "m"}, {Second, ""}} {
		if d >= spec.interval {
			s += fmt.Sprintf("%d%s", d/spec.interval, spec.suffix)
			d %= spec.interval
			if spec.interval == Second {
				secs = true
			}
		}
	}

	if d > 0 {
		s += fmt.Sprintf(".%09d", d)
		for i := len(s) - 1; i > 0; i-- {
			if s[i] != '0' {
				break
			}
			s = s[:i]
		}
		secs = true
	}
	if secs {
		s += "s"
	}
	s += `"`
	return []byte(s), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface. The duration is
// expected to be a quoted string in the SysDB JSON format.
func (d *Duration) UnmarshalJSON(data []byte) error {
	m := map[string]Duration{
		"Y": Year,
		"M": Month,
		"D": Day,
		"h": Hour,
		"m": Minute,
		"s": Second,
	}

	if data[0] != '"' || data[len(data)-1] != '"' {
		return fmt.Errorf("unquoted duration %q", string(data))
	}
	data = data[1 : len(data)-1]

	orig := string(data)
	var res Duration
	for len(data) != 0 {
		// consume digits
		n := 0
		dec := 0
		frac := false
		for n < len(data) && '0' <= data[n] && data[n] <= '9' {
			dec = dec*10 + int(data[n]-'0')
			n++
		}
		if n < len(data) && data[n] == '.' {
			frac = true
			n++

			// consume fraction
			m := 1000000000
			for n < len(data) && '0' <= data[n] && data[n] <= '9' {
				if m > 1 { // cut of to nanoseconds
					dec = dec*10 + int(data[n]-'0')
					m /= 10
				}
				n++
			}
			dec *= m
		}
		if n >= len(data) {
			return fmt.Errorf("missing unit in duration %q", orig)
		}
		if n == 0 {
			// we found something which is not a number
			return fmt.Errorf("invalid duration %q", orig)
		}

		// consume unit
		u := n
		for u < len(data) && data[u] != '.' && (data[u] < '0' || '9' < data[u]) {
			u++
		}

		unit := string(data[n:u])
		data = data[u:]

		// convert to Duration
		d, ok := m[unit]
		if !ok {
			return fmt.Errorf("invalid unit %q in duration %q", unit, orig)
		}

		if d == Second {
			if frac {
				d = 1
			}
		} else if frac {
			return fmt.Errorf("invalid fraction %q%s in duration %q", dec, unit, orig)
		}

		res += Duration(dec) * d
	}
	*d = res
	return nil
}

// String returns the duration formatted using a predefined format string.
func (d Duration) String() string { return time.Duration(d).String() }

// A Time represents an instant in time with nanosecond precision.
//
// It supports marshaling to and unmarshaling from the SysDB JSON format
// (YYYY-MM-DD hh:mm:ss +-zzzz).
type Time time.Time

func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(time.Time(t).Format(jsonTime)), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface. The time is
// expected to be a quoted string in the SysDB JSON format.
func (t *Time) UnmarshalJSON(data []byte) error {
	parsed, err := time.Parse(jsonTime, string(data))
	if err == nil {
		*t = Time(parsed)
	}
	return err
}

// Equal reports whether t and u represent the same time instant.
func (t Time) Equal(u Time) bool {
	return time.Time(t).Equal(time.Time(u))
}

// String returns the time formatted using a predefined format string.
func (t Time) String() string { return time.Time(t).String() }

// An Attribute describes a host, metric, or service attribute.
type Attribute struct {
	Name           string   `json:"name"`
	Value          string   `json:"value"`
	LastUpdate     Time     `json:"last_update"`
	UpdateInterval Duration `json:"update_interval"`
}

// A Metric describes a metric known to SysDB.
type Metric struct {
	Name           string      `json:"name"`
	LastUpdate     Time        `json:"last_update"`
	UpdateInterval Duration    `json:"update_interval"`
	Attributes     []Attribute `json:"attributes"`
}

// A Service describes a service object stored in the SysDB store.
type Service struct {
	Name           string      `json:"name"`
	LastUpdate     Time        `json:"last_update"`
	UpdateInterval Duration    `json:"update_interval"`
	Attributes     []Attribute `json:"attributes"`
}

// A Host describes a host object stored in the SysDB store.
type Host struct {
	Name           string      `json:"name"`
	LastUpdate     Time        `json:"last_update"`
	UpdateInterval Duration    `json:"update_interval"`
	Attributes     []Attribute `json:"attributes"`
	Metrics        []Metric    `json:"metrics"`
	Services       []Service   `json:"services"`
}

// A DataPoint describes a datum at a certain point of time.
type DataPoint struct {
	Timestamp Time    `json:"timestamp"`
	Value     float64 `json:"value"`
}

// A Timeseries describes a sequence of data-points.
type Timeseries struct {
	Start Time `json:"start"`
	End   Time `json:"end"`
	Data  map[string][]DataPoint
}

// vim: set tw=78 sw=4 sw=4 noexpandtab :
<commit_msg>Add the 'Backends' field to all store object types.<commit_after>//
// Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package sysdb

import (
	"fmt"
	"time"
)

// The SysDB JSON time format.
const jsonTime = `"2006-01-02 15:04:05 -0700"`

// A Duration represents the elapsed time between two instants as a
// nanoseconds count.
//
// It supports marshaling to and unmarshaling from the SysDB JSON format (a
// sequence of decimal numbers with a unit suffix).
type Duration time.Duration

const (
	Second = Duration(1000000000)
	Minute = 60 * Second
	Hour   = 60 * Minute
	Day    = 24 * Hour
	Month  = Duration(30436875 * 24 * 60 * 60 * 1000)
	Year   = Duration(3652425 * 24 * 60 * 60 * 100000)
)

// MarshalJSON implements the json.Marshaler interface. The time is a quoted
// string in the SysDB JSON format.
func (d Duration) MarshalJSON() ([]byte, error) {
	if d == 0 {
		return []byte(`"0s"`), nil
	}

	s := `"`
	secs := false
	for _, spec := range []struct {
		interval Duration
		suffix   string
	}{{Year, "Y"}, {Month, "M"}, {Day, "D"}, {Hour, "h"}, {Minute, "m"}, {Second, ""}} {
		if d >= spec.interval {
			s += fmt.Sprintf("%d%s", d/spec.interval, spec.suffix)
			d %= spec.interval
			if spec.interval == Second {
				secs = true
			}
		}
	}

	if d > 0 {
		s += fmt.Sprintf(".%09d", d)
		for i := len(s) - 1; i > 0; i-- {
			if s[i] != '0' {
				break
			}
			s = s[:i]
		}
		secs = true
	}
	if secs {
		s += "s"
	}
	s += `"`
	return []byte(s), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface. The duration is
// expected to be a quoted string in the SysDB JSON format.
func (d *Duration) UnmarshalJSON(data []byte) error {
	m := map[string]Duration{
		"Y": Year,
		"M": Month,
		"D": Day,
		"h": Hour,
		"m": Minute,
		"s": Second,
	}

	if data[0] != '"' || data[len(data)-1] != '"' {
		return fmt.Errorf("unquoted duration %q", string(data))
	}
	data = data[1 : len(data)-1]

	orig := string(data)
	var res Duration
	for len(data) != 0 {
		// consume digits
		n := 0
		dec := 0
		frac := false
		for n < len(data) && '0' <= data[n] && data[n] <= '9' {
			dec = dec*10 + int(data[n]-'0')
			n++
		}
		if n < len(data) && data[n] == '.' {
			frac = true
			n++

			// consume fraction
			m := 1000000000
			for n < len(data) && '0' <= data[n] && data[n] <= '9' {
				if m > 1 { // cut of to nanoseconds
					dec = dec*10 + int(data[n]-'0')
					m /= 10
				}
				n++
			}
			dec *= m
		}
		if n >= len(data) {
			return fmt.Errorf("missing unit in duration %q", orig)
		}
		if n == 0 {
			// we found something which is not a number
			return fmt.Errorf("invalid duration %q", orig)
		}

		// consume unit
		u := n
		for u < len(data) && data[u] != '.' && (data[u] < '0' || '9' < data[u]) {
			u++
		}

		unit := string(data[n:u])
		data = data[u:]

		// convert to Duration
		d, ok := m[unit]
		if !ok {
			return fmt.Errorf("invalid unit %q in duration %q", unit, orig)
		}

		if d == Second {
			if frac {
				d = 1
			}
		} else if frac {
			return fmt.Errorf("invalid fraction %q%s in duration %q", dec, unit, orig)
		}

		res += Duration(dec) * d
	}
	*d = res
	return nil
}

// String returns the duration formatted using a predefined format string.
func (d Duration) String() string { return time.Duration(d).String() }

// A Time represents an instant in time with nanosecond precision.
//
// It supports marshaling to and unmarshaling from the SysDB JSON format
// (YYYY-MM-DD hh:mm:ss +-zzzz).
type Time time.Time

func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(time.Time(t).Format(jsonTime)), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface. The time is
// expected to be a quoted string in the SysDB JSON format.
func (t *Time) UnmarshalJSON(data []byte) error {
	parsed, err := time.Parse(jsonTime, string(data))
	if err == nil {
		*t = Time(parsed)
	}
	return err
}

// Equal reports whether t and u represent the same time instant.
func (t Time) Equal(u Time) bool {
	return time.Time(t).Equal(time.Time(u))
}

// String returns the time formatted using a predefined format string.
func (t Time) String() string { return time.Time(t).String() }

// An Attribute describes a host, metric, or service attribute.
type Attribute struct {
	Name           string   `json:"name"`
	Value          string   `json:"value"`
	LastUpdate     Time     `json:"last_update"`
	UpdateInterval Duration `json:"update_interval"`
	Backends       []string `json:"backends"`
}

// A Metric describes a metric known to SysDB.
type Metric struct {
	Name           string      `json:"name"`
	LastUpdate     Time        `json:"last_update"`
	UpdateInterval Duration    `json:"update_interval"`
	Backends       []string    `json:"backends"`
	Attributes     []Attribute `json:"attributes"`
}

// A Service describes a service object stored in the SysDB store.
type Service struct {
	Name           string      `json:"name"`
	LastUpdate     Time        `json:"last_update"`
	UpdateInterval Duration    `json:"update_interval"`
	Backends       []string    `json:"backends"`
	Attributes     []Attribute `json:"attributes"`
}

// A Host describes a host object stored in the SysDB store.
type Host struct {
	Name           string      `json:"name"`
	LastUpdate     Time        `json:"last_update"`
	UpdateInterval Duration    `json:"update_interval"`
	Backends       []string    `json:"backends"`
	Attributes     []Attribute `json:"attributes"`
	Metrics        []Metric    `json:"metrics"`
	Services       []Service   `json:"services"`
}

// A DataPoint describes a datum at a certain point of time.
type DataPoint struct {
	Timestamp Time    `json:"timestamp"`
	Value     float64 `json:"value"`
}

// A Timeseries describes a sequence of data-points.
type Timeseries struct {
	Start Time `json:"start"`
	End   Time `json:"end"`
	Data  map[string][]DataPoint
}

// vim: set tw=78 sw=4 sw=4 noexpandtab :
<|endoftext|>


<commit_before>package ghostrace

import (
	"fmt"
	"runtime"
	"syscall"

	"./memio"
	"./process"
	"./sys"
)

func TraceSpawn(cmd string, args ...string) (chan *Event, error) {
	pid, err := syscall.ForkExec(cmd, args, &syscall.ProcAttr{
		Sys:   &syscall.SysProcAttr{Ptrace: true},
		Files: []uintptr{0, 1, 2},
	})
	if err != nil {
		return nil, err
	}
	proc, err := process.FindPid(pid)
	if err != nil {
		return nil, err
	}
	return traceProcess(proc, false)
}

func TracePid(pid int) (chan *Event, error) {
	proc, err := process.FindPid(pid)
	if err != nil {
		return nil, err
	}
	return traceProcess(proc, true)
}

func traceProcess(proc process.Process, attach bool) (chan *Event, error) {
	pid := proc.Pid()
	if attach {
		if err := syscall.PtraceAttach(pid); err != nil {
			return nil, err
		}
	}
	var status syscall.WaitStatus
	if _, err := syscall.Wait4(pid, &status, 0, nil); err != nil {
		return nil, err
	}
	// TODO: set options for following children?
	if err := syscall.PtraceSetOptions(pid, syscall.PTRACE_O_TRACESYSGOOD); err != nil {
		return nil, err
	}
	var readMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePeekData(pid, uintptr(addr), p)
	}
	var writeMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePokeData(pid, uintptr(addr), p)
	}
	codec, err := sys.NewCodec(sys.ARCH_X86_64, sys.OS_LINUX, memio.NewMemIO(readMem, writeMem))
	if err != nil {
		return nil, err
	}
	ret := make(chan *Event)
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		var savedRegs, regs syscall.PtraceRegs
		newSyscall := true
	Outer:
		for {
			for {
				// wait for syscall entry
				if err := syscall.PtraceSyscall(pid, 0); err != nil {
					fmt.Println("DEBUG: " + err.Error())
					break Outer
				}
				if _, err := syscall.Wait4(pid, &status, 0, nil); err != nil {
					fmt.Println("DEBUG: " + err.Error())
					break Outer
				}
				if status.Exited() {
					fmt.Println("DEBUG: process exited")
					break Outer
				}
				if status.StopSignal() != 0 {
					break
				}
			}
			signal := status.StopSignal()
			switch signal {
			case syscall.SIGTRAP | 0x80:
				if err := syscall.PtraceGetRegs(pid, &regs); err != nil {
					break
				}
				if newSyscall {
					newSyscall = false
					savedRegs = regs
				} else {
					newSyscall = true
					args := []uint64{regs.Rdi, regs.Rsi, regs.Rdx, regs.R10, regs.R8, regs.R9}
					call, err := codec.DecodeRet(int(savedRegs.Orig_rax), args, regs.Rax)
					if err != nil {
						fmt.Println(err)
					} else {
						ret <- &Event{
							Process: proc,
							Syscall: call,
						}
					}
				}
				// TODO: do something with these?
			case syscall.PTRACE_EVENT_VFORK:
			case syscall.PTRACE_EVENT_FORK:
			case syscall.PTRACE_EVENT_CLONE:
			case syscall.PTRACE_EVENT_VFORK_DONE:
			case syscall.PTRACE_EVENT_EXEC:
			case syscall.PTRACE_EVENT_EXIT:
			}
		}
		close(ret)
	}()
	return ret, nil
}
<commit_msg>improve behavior with signals (fix #7)<commit_after>package ghostrace

import (
	"fmt"
	"runtime"
	"syscall"
	"time"

	"./memio"
	"./process"
	"./sys"
)

func TraceSpawn(cmd string, args ...string) (chan *Event, error) {
	pid, err := syscall.ForkExec(cmd, args, &syscall.ProcAttr{
		Sys:   &syscall.SysProcAttr{Ptrace: true},
		Files: []uintptr{0, 1, 2},
	})
	if err != nil {
		return nil, err
	}
	proc, err := process.FindPid(pid)
	if err != nil {
		return nil, err
	}
	return traceProcess(proc, false)
}

func TracePid(pid int) (chan *Event, error) {
	proc, err := process.FindPid(pid)
	if err != nil {
		return nil, err
	}
	return traceProcess(proc, true)
}

func traceProcess(proc process.Process, attach bool) (chan *Event, error) {
	pid := proc.Pid()
	if attach {
		if err := syscall.PtraceAttach(pid); err != nil {
			return nil, err
		}
	}
	var status syscall.WaitStatus
	if _, err := syscall.Wait4(pid, &status, 0, nil); err != nil {
		return nil, err
	}
	options := syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEFORK | syscall.PTRACE_O_TRACEVFORK | syscall.PTRACE_O_TRACESYSGOOD
	if err := syscall.PtraceSetOptions(pid, options); err != nil {
		return nil, err
	}
	var readMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePeekData(pid, uintptr(addr), p)
	}
	var writeMem = func(p []byte, addr uint64) (int, error) {
		return syscall.PtracePokeData(pid, uintptr(addr), p)
	}
	codec, err := sys.NewCodec(sys.ARCH_X86_64, sys.OS_LINUX, memio.NewMemIO(readMem, writeMem))
	if err != nil {
		return nil, err
	}
	ret := make(chan *Event)
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		var savedRegs, regs syscall.PtraceRegs
		var stopSig syscall.Signal
		newSyscall := true
	Outer:
		for {
			// wait for syscall entry
			if err := syscall.PtraceSyscall(pid, int(stopSig)); err != nil {
				fmt.Println("DEBUG: " + err.Error())
				break
			}
			if _, err := syscall.Wait4(pid, &status, syscall.WALL, nil); err != nil {
				fmt.Println("DEBUG: " + err.Error())
				break
			}
			if status.Exited() {
				fmt.Println("DEBUG: process exited")
				break
			}
			stopSig = status.StopSignal()
			// are we blocking on a sigstop?
			// TODO: send events upstream for signals
			wasStopped := false
			for stopSig == syscall.SIGSTOP ||
				stopSig == syscall.SIGTTIN || stopSig == syscall.SIGTTOU || stopSig == syscall.SIGTSTP {
				wasStopped = true
				if err := syscall.PtraceCont(pid, int(stopSig)); err != nil {
					fmt.Println("DEBUG: " + err.Error())
					break Outer
				}
				if _, err := syscall.Wait4(pid, &status, syscall.WALL, nil); err != nil {
					fmt.Println("DEBUG: " + err.Error())
					break Outer
				}
				stopSig = status.StopSignal()
				time.Sleep(50 * time.Millisecond)
			}
			// did we get a ptrace event?
			if !wasStopped && (stopSig&syscall.SIGTRAP) != 0 {
				stopSig = syscall.Signal(0)
				switch status.StopSignal() & ^syscall.SIGTRAP {
				case 0x80: // SYSCALL
					if err := syscall.PtraceGetRegs(pid, &regs); err != nil {
						break
					}
					if newSyscall {
						newSyscall = false
						savedRegs = regs
					} else {
						newSyscall = true
						args := []uint64{regs.Rdi, regs.Rsi, regs.Rdx, regs.R10, regs.R8, regs.R9}
						call, err := codec.DecodeRet(int(savedRegs.Orig_rax), args, regs.Rax)
						if err != nil {
							fmt.Println(err)
						} else {
							ret <- &Event{
								Process: proc,
								Syscall: call,
							}
						}
					}
					// TODO: do something with these?
				case syscall.PTRACE_EVENT_VFORK << 8:
				case syscall.PTRACE_EVENT_FORK << 8:
				case syscall.PTRACE_EVENT_CLONE << 8:
				case syscall.PTRACE_EVENT_VFORK_DONE << 8:
				case syscall.PTRACE_EVENT_EXEC << 8:
				case syscall.PTRACE_EVENT_EXIT << 8:
				}
			}
		}
		close(ret)
	}()
	return ret, nil
}
<|endoftext|>


<commit_before>package properrandom

import (
	cryptrand "crypto/rand"
	"encoding/binary"
	"io"
	mathrand "math/rand"
)

var defaultSource cryptoSource
var globalRand *mathrand.Rand

func init() {
	defaultSource = cryptoSource{
		source: cryptrand.Reader,
	}

	globalRand = mathrand.New(defaultSource)
}

type cryptoSource struct {
	source io.Reader
}

func (c cryptoSource) Uint64() uint64 {
	buf := make([]byte, 8)
	n, err := io.ReadFull(c.source, buf)
	if err != nil {
		// Fall back on the default random reader
		_, err = io.ReadFull(cryptrand.Reader, buf[n:])
		if err != nil {
			panic(err)
		}
	}

	return binary.BigEndian.Uint64(buf)
}

func (c cryptoSource) Int63() int64 {
	return int64(c.Uint64() & 0x7fffffffffffffff)
}

func (c cryptoSource) Seed(seed int64) {
	// Don't.
}

// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
// from the default Source.
func Int63() int64 { return globalRand.Int63() }

// Uint32 returns a pseudo-random 32-bit value as a uint32
// from the default Source.
func Uint32() uint32 { return globalRand.Uint32() }

// Uint64 returns a pseudo-random 64-bit value as a uint64
// from the default Source.
func Uint64() uint64 { return defaultSource.Uint64() }

// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func Int31() int32 { return globalRand.Int31() }

// Int returns a non-negative pseudo-random int from the default Source.
func Int() int { return globalRand.Int() }

// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Int63n(n int64) int64 { return globalRand.Int63n(n) }

// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Int31n(n int32) int32 { return globalRand.Int31n(n) }

// Intn returns, as an int, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Intn(n int) int { return globalRand.Intn(n) }

// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0)
// from the default Source.
func Float64() float64 { return globalRand.Float64() }

// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0)
// from the default Source.
func Float32() float32 { return globalRand.Float32() }

// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n)
// from the default Source.
func Perm(n int) []int { return globalRand.Perm(n) }

// Read generates len(p) random bytes from the default Source and
// writes them into p. It always returns len(p) and a nil error.
// Read, unlike the Rand.Read method, is safe for concurrent use.
func Read(p []byte) (n int, err error) { return globalRand.Read(p) }

// NormFloat64 returns a normally distributed float64 in the range
// [-math.MaxFloat64, +math.MaxFloat64] with
// standard normal distribution (mean = 0, stddev = 1)
// from the default Source.
// To produce a different normal distribution, callers can
// adjust the output using:
//
//  sample = NormFloat64() * desiredStdDev + desiredMean
//
func NormFloat64() float64 { return globalRand.NormFloat64() }

// ExpFloat64 returns an exponentially distributed float64 in the range
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source.
// To produce a distribution with a different rate parameter,
// callers can adjust the output using:
//
//  sample = ExpFloat64() / desiredRateParameter
//
func ExpFloat64() float64 { return globalRand.ExpFloat64() }
<commit_msg>Add 'Shuffle()' in properrand<commit_after>package properrandom

import (
	cryptrand "crypto/rand"
	"encoding/binary"
	"io"
	mathrand "math/rand"
)

var defaultSource cryptoSource
var globalRand *mathrand.Rand

func init() {
	defaultSource = cryptoSource{
		source: cryptrand.Reader,
	}

	globalRand = mathrand.New(defaultSource)
}

type cryptoSource struct {
	source io.Reader
}

func (c cryptoSource) Uint64() uint64 {
	buf := make([]byte, 8)
	n, err := io.ReadFull(c.source, buf)
	if err != nil {
		// Fall back on the default random reader
		_, err = io.ReadFull(cryptrand.Reader, buf[n:])
		if err != nil {
			panic(err)
		}
	}

	return binary.BigEndian.Uint64(buf)
}

func (c cryptoSource) Int63() int64 {
	return int64(c.Uint64() & 0x7fffffffffffffff)
}

func (c cryptoSource) Seed(seed int64) {
	// Don't.
}

// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
// from the default Source.
func Int63() int64 { return globalRand.Int63() }

// Uint32 returns a pseudo-random 32-bit value as a uint32
// from the default Source.
func Uint32() uint32 { return globalRand.Uint32() }

// Uint64 returns a pseudo-random 64-bit value as a uint64
// from the default Source.
func Uint64() uint64 { return defaultSource.Uint64() }

// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func Int31() int32 { return globalRand.Int31() }

// Int returns a non-negative pseudo-random int from the default Source.
func Int() int { return globalRand.Int() }

// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Int63n(n int64) int64 { return globalRand.Int63n(n) }

// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Int31n(n int32) int32 { return globalRand.Int31n(n) }

// Intn returns, as an int, a non-negative pseudo-random number in [0,n)
// from the default Source.
// It panics if n <= 0.
func Intn(n int) int { return globalRand.Intn(n) }

// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0)
// from the default Source.
func Float64() float64 { return globalRand.Float64() }

// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0)
// from the default Source.
func Float32() float32 { return globalRand.Float32() }

// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n)
// from the default Source.
func Perm(n int) []int { return globalRand.Perm(n) }

// Shuffle pseudo-randomizes the order of elements using the default Source.
// n is the number of elements. Shuffle panics if n < 0.
// swap swaps the elements with indexes i and j.
func Shuffle(n int, swap func(i, j int)) { globalRand.Shuffle(n, swap) }

// Read generates len(p) random bytes from the default Source and
// writes them into p. It always returns len(p) and a nil error.
// Read, unlike the Rand.Read method, is safe for concurrent use.
func Read(p []byte) (n int, err error) { return globalRand.Read(p) }

// NormFloat64 returns a normally distributed float64 in the range
// [-math.MaxFloat64, +math.MaxFloat64] with
// standard normal distribution (mean = 0, stddev = 1)
// from the default Source.
// To produce a different normal distribution, callers can
// adjust the output using:
//
//  sample = NormFloat64() * desiredStdDev + desiredMean
//
func NormFloat64() float64 { return globalRand.NormFloat64() }

// ExpFloat64 returns an exponentially distributed float64 in the range
// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source.
// To produce a distribution with a different rate parameter,
// callers can adjust the output using:
//
//  sample = ExpFloat64() / desiredRateParameter
//
func ExpFloat64() float64 { return globalRand.ExpFloat64() }
<|endoftext|>


<commit_before>package bootkube

import (
	"text/template"
)

var (
	// CVOOverrides is the constant to represent contents of cvo-override.yaml file
	// This is a gate to prevent CVO from installing these operators which is conflicting
	// with already owned resources by tectonic-operators.
	// This files can be dropped when the overrides list becomes empty.
	// IMPORTANT: You must also edit LegacyCVOOverrides
	CVOOverrides = template.Must(template.New("cvo-override.yaml").Parse(`
apiVersion: config.openshift.io/v1
kind: ClusterVersion
metadata:
  namespace: openshift-cluster-version
  name: cluster-version-operator
spec:
  upstream: http://localhost:8080/graph
  channel: fast
  clusterID: {{.CVOClusterID}}
  overrides:
  - kind: Deployment                    # this conflicts with kube-core-operator
    namespace: openshift-cluster-network-operator
    name: cluster-network-operator
    unmanaged: true
  - kind: ServiceAccount                # missing run level 0 on the namespace and has 0000_08
    namespace: openshift-cluster-dns-operator
    name: cluster-dns-operator
    unmanaged: true
  - kind: Deployment                    # this conflicts with kube-core-operator
    namespace: openshift-cluster-dns-operator
    name: cluster-dns-operator
    unmanaged: true
  - kind: APIService                    # packages.apps.redhat.com fails to start properly
    name: v1alpha1.packages.apps.redhat.com
    unmanaged: true
`))

	// LegacyCVOOverrides is the constant to represent contents of legacy-cvo-override.yaml file
	// This is a gate to prevent CVO from installing these operators which is conflicting
	// with already owned resources by tectonic-operators.
	// This files can be dropped when the overrides list becomes empty.
	LegacyCVOOverrides = template.Must(template.New("cvo-override.yaml").Parse(`
apiVersion: clusterversion.openshift.io/v1
kind: CVOConfig
metadata:
  namespace: openshift-cluster-version
  name: cluster-version-operator
upstream: http://localhost:8080/graph
channel: fast
clusterID: {{.CVOClusterID}}
overrides:
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-network-operator
  name: cluster-network-operator
  unmanaged: true
- kind: ServiceAccount                # missing run level 0 on the namespace and has 0000_08
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: APIService                    # packages.apps.redhat.com fails to start properly
  name: v1alpha1.packages.apps.redhat.com
  unmanaged: true
`))
)
<commit_msg>assets: The CVO object name has changed<commit_after>package bootkube

import (
	"text/template"
)

var (
	// CVOOverrides is the constant to represent contents of cvo-override.yaml file
	// This is a gate to prevent CVO from installing these operators which is conflicting
	// with already owned resources by tectonic-operators.
	// This files can be dropped when the overrides list becomes empty.
	// IMPORTANT: You must also edit LegacyCVOOverrides
	CVOOverrides = template.Must(template.New("cvo-override.yaml").Parse(`
apiVersion: config.openshift.io/v1
kind: ClusterVersion
metadata:
  namespace: openshift-cluster-version
  name: version
spec:
  upstream: http://localhost:8080/graph
  channel: fast
  clusterID: {{.CVOClusterID}}
  overrides:
  - kind: Deployment                    # this conflicts with kube-core-operator
    namespace: openshift-cluster-network-operator
    name: cluster-network-operator
    unmanaged: true
  - kind: ServiceAccount                # missing run level 0 on the namespace and has 0000_08
    namespace: openshift-cluster-dns-operator
    name: cluster-dns-operator
    unmanaged: true
  - kind: Deployment                    # this conflicts with kube-core-operator
    namespace: openshift-cluster-dns-operator
    name: cluster-dns-operator
    unmanaged: true
  - kind: APIService                    # packages.apps.redhat.com fails to start properly
    name: v1alpha1.packages.apps.redhat.com
    unmanaged: true
`))

	// LegacyCVOOverrides is the constant to represent contents of legacy-cvo-override.yaml file
	// This is a gate to prevent CVO from installing these operators which is conflicting
	// with already owned resources by tectonic-operators.
	// This files can be dropped when the overrides list becomes empty.
	LegacyCVOOverrides = template.Must(template.New("cvo-override.yaml").Parse(`
apiVersion: clusterversion.openshift.io/v1
kind: CVOConfig
metadata:
  namespace: openshift-cluster-version
  name: cluster-version-operator
upstream: http://localhost:8080/graph
channel: fast
clusterID: {{.CVOClusterID}}
overrides:
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-network-operator
  name: cluster-network-operator
  unmanaged: true
- kind: ServiceAccount                # missing run level 0 on the namespace and has 0000_08
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: Deployment                    # this conflicts with kube-core-operator
  namespace: openshift-cluster-dns-operator
  name: cluster-dns-operator
  unmanaged: true
- kind: APIService                    # packages.apps.redhat.com fails to start properly
  name: v1alpha1.packages.apps.redhat.com
  unmanaged: true
`))
)
<|endoftext|>


<commit_before>package nodesyncer

import (
	"fmt"

	"strings"

	"context"

	"sync"

	"github.com/rancher/norman/types/convert"
	"github.com/rancher/rancher/pkg/kubectl"
	nodehelper "github.com/rancher/rancher/pkg/node"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/runtime"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

const (
	drainTokenPrefix = "drain-node-"
	description      = "token for drain"
)

var nodeMapLock = sync.Mutex{}

func (m *NodesSyncer) syncCordonFields(key string, obj *v3.Node) error {
	if obj == nil || obj.DeletionTimestamp != nil || obj.Spec.DesiredNodeUnschedulable == "" {
		return nil
	}

	if obj.Spec.DesiredNodeUnschedulable != "true" && obj.Spec.DesiredNodeUnschedulable != "false" {
		return nil
	}

	node, err := nodehelper.GetNodeForMachine(obj, m.nodeLister)
	if err != nil {
		return err
	}
	desiredValue := convert.ToBool(obj.Spec.DesiredNodeUnschedulable)
	if node.Spec.Unschedulable != desiredValue {
		toUpdate := node.DeepCopy()
		toUpdate.Spec.Unschedulable = desiredValue
		if _, err := m.nodeClient.Update(toUpdate); err != nil {
			return err
		}
	}
	nodeCopy := obj.DeepCopy()
	if !desiredValue {
		removeDrainCondition(nodeCopy)
	}
	nodeCopy.Spec.DesiredNodeUnschedulable = ""
	_, err = m.machines.Update(nodeCopy)
	if err != nil {
		return err
	}
	return nil
}

func (d *NodeDrain) drainNode(key string, obj *v3.Node) error {
	if obj == nil || obj.DeletionTimestamp != nil || obj.Spec.DesiredNodeUnschedulable == "" {
		return nil
	}

	if obj.Spec.DesiredNodeUnschedulable != "drain" && obj.Spec.DesiredNodeUnschedulable != "stopDrain" {
		return nil
	}

	defer nodeMapLock.Unlock()
	if obj.Spec.DesiredNodeUnschedulable == "drain" {
		nodeMapLock.Lock()
		if _, ok := d.nodesToContext[obj.Name]; ok {
			return nil
		}
		ctx, cancel := context.WithCancel(d.ctx)
		d.nodesToContext[obj.Name] = cancel
		go d.drain(ctx, obj, cancel)

	} else if obj.Spec.DesiredNodeUnschedulable == "stopDrain" {
		nodeMapLock.Lock()
		cancelFunc, ok := d.nodesToContext[obj.Name]
		nodeMapLock.Unlock()
		if ok {
			cancelFunc()
		}
		return d.resetDesiredNodeUnschedulable(obj)
	}
	return nil
}

func (d *NodeDrain) drain(ctx context.Context, obj *v3.Node, cancel context.CancelFunc) {
	defer deleteFromContextMap(d.nodesToContext, obj.Name)

	for {
		select {
		case <-ctx.Done():
			return
		default:
		}

		stopped := false
		nodeName := obj.Spec.RequestedHostname
		updatedObj, err := v3.NodeConditionDrained.DoUntilTrue(obj, func() (runtime.Object, error) {
			kubeConfig, err := d.getKubeConfig()
			if err != nil {
				if err == context.Canceled {
					stopped = true
					logrus.Infof(fmt.Sprintf("Stopped draining %s in %s", obj.Name, obj.ClusterName))
				}
				logrus.Errorf("nodeDrain: error getting kubeConfig for node %s", obj.Name)
				return obj, fmt.Errorf("error getting kubeConfig for node %s", obj.Name)
			}
			_, msg, err := kubectl.Drain(ctx, kubeConfig, nodeName, getFlags(obj.Spec.NodeDrainInput))
			if err != nil {
				errMsg := filterErrorMsg(msg, nodeName)
				return obj, fmt.Errorf("%s", errMsg)
			}
			return obj, nil
		})
		if !stopped {
			nodeCopy := updatedObj.(*v3.Node).DeepCopy()
			if err == nil {
				nodeCopy.Spec.DesiredNodeUnschedulable = ""
			}
			_, updateErr := d.machines.Update(nodeCopy)
			if err != nil || updateErr != nil {
				logrus.Errorf("nodeDrain: [%s] in cluster [%s] : %v %v", nodeName, d.clusterName, err, updateErr)
				d.machines.Controller().Enqueue("", fmt.Sprintf("%s/%s", d.clusterName, obj.Name))
			}
		}
		cancel()
	}
}

func (d *NodeDrain) resetDesiredNodeUnschedulable(obj *v3.Node) error {
	nodeCopy := obj.DeepCopy()
	removeDrainCondition(nodeCopy)
	nodeCopy.Spec.DesiredNodeUnschedulable = ""
	if _, err := d.machines.Update(nodeCopy); err != nil {
		return err
	}
	return nil
}

func (d *NodeDrain) getKubeConfig() (*clientcmdapi.Config, error) {
	cluster, err := d.clusterLister.Get("", d.clusterName)
	if err != nil {
		return nil, err
	}
	user, err := d.systemAccountManager.GetSystemUser(cluster)
	if err != nil {
		return nil, err
	}
	token, err := d.userManager.EnsureToken(drainTokenPrefix+user.Name, description, user.Name)
	if err != nil {
		return nil, err
	}
	kubeConfig := d.kubeConfigGetter.KubeConfig(d.clusterName, token)
	for k := range kubeConfig.Clusters {
		kubeConfig.Clusters[k].InsecureSkipTLSVerify = true
	}
	return kubeConfig, nil
}

func getFlags(input *v3.NodeDrainInput) []string {
	return []string{
		fmt.Sprintf("--delete-local-data=%v", input.DeleteLocalData),
		fmt.Sprintf("--force=%v", input.Force),
		fmt.Sprintf("--grace-period=%v", input.GracePeriod),
		fmt.Sprintf("--ignore-daemonsets=%v", input.IgnoreDaemonSets),
		fmt.Sprintf("--timeout=%s", convert.ToString(input.Timeout)+"s")}
}

func filterErrorMsg(msg string, nodeName string) string {
	upd := []string{}
	lines := strings.Split(msg, "\n")
	for _, line := range lines[1:] {
		if strings.HasPrefix(line, "WARNING") || strings.HasPrefix(line, nodeName) {
			continue
		}
		if strings.Contains(line, "aborting") {
			continue
		}
		if strings.HasPrefix(line, "There are pending nodes ") {
			// for only one node in our case
			continue
		}
		if strings.HasPrefix(line, "There are pending pods ") {
			// already considered error
			continue
		}
		if strings.HasPrefix(line, "error") && strings.Contains(line, "unable to drain node") {
			// actual reason at end
			continue
		}
		if strings.HasPrefix(line, "pod") && strings.Contains(line, "evicted") {
			// evicted successfully
			continue
		}
		upd = append(upd, line)
	}
	return strings.Join(upd, "\n")
}

func removeDrainCondition(obj *v3.Node) {
	exists := false
	for _, condition := range obj.Status.Conditions {
		if condition.Type == "Drained" {
			exists = true
			break
		}
	}
	if exists {
		var conditions []v3.NodeCondition
		for _, condition := range obj.Status.Conditions {
			if condition.Type == "Drained" {
				continue
			}
			conditions = append(conditions, condition)
		}
		obj.Status.Conditions = conditions
	}
}

func deleteFromContextMap(data map[string]context.CancelFunc, id string) {
	nodeMapLock.Lock()
	delete(data, id)
	nodeMapLock.Unlock()
}
<commit_msg>Panic fix in cordonsync<commit_after>package nodesyncer

import (
	"fmt"

	"strings"

	"context"

	"sync"

	"github.com/rancher/norman/types/convert"
	"github.com/rancher/rancher/pkg/kubectl"
	nodehelper "github.com/rancher/rancher/pkg/node"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/runtime"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

const (
	drainTokenPrefix = "drain-node-"
	description      = "token for drain"
)

var nodeMapLock = sync.Mutex{}

func (m *NodesSyncer) syncCordonFields(key string, obj *v3.Node) error {
	if obj == nil || obj.DeletionTimestamp != nil || obj.Spec.DesiredNodeUnschedulable == "" {
		return nil
	}

	if obj.Spec.DesiredNodeUnschedulable != "true" && obj.Spec.DesiredNodeUnschedulable != "false" {
		return nil
	}

	node, err := nodehelper.GetNodeForMachine(obj, m.nodeLister)
	if err != nil || node == nil || node.DeletionTimestamp != nil {
		return err
	}
	desiredValue := convert.ToBool(obj.Spec.DesiredNodeUnschedulable)
	if node.Spec.Unschedulable != desiredValue {
		toUpdate := node.DeepCopy()
		toUpdate.Spec.Unschedulable = desiredValue
		if _, err := m.nodeClient.Update(toUpdate); err != nil {
			return err
		}
	}
	nodeCopy := obj.DeepCopy()
	if !desiredValue {
		removeDrainCondition(nodeCopy)
	}
	nodeCopy.Spec.DesiredNodeUnschedulable = ""
	_, err = m.machines.Update(nodeCopy)
	if err != nil {
		return err
	}
	return nil
}

func (d *NodeDrain) drainNode(key string, obj *v3.Node) error {
	if obj == nil || obj.DeletionTimestamp != nil || obj.Spec.DesiredNodeUnschedulable == "" {
		return nil
	}

	if obj.Spec.DesiredNodeUnschedulable != "drain" && obj.Spec.DesiredNodeUnschedulable != "stopDrain" {
		return nil
	}

	defer nodeMapLock.Unlock()
	if obj.Spec.DesiredNodeUnschedulable == "drain" {
		nodeMapLock.Lock()
		if _, ok := d.nodesToContext[obj.Name]; ok {
			return nil
		}
		ctx, cancel := context.WithCancel(d.ctx)
		d.nodesToContext[obj.Name] = cancel
		go d.drain(ctx, obj, cancel)

	} else if obj.Spec.DesiredNodeUnschedulable == "stopDrain" {
		nodeMapLock.Lock()
		cancelFunc, ok := d.nodesToContext[obj.Name]
		nodeMapLock.Unlock()
		if ok {
			cancelFunc()
		}
		return d.resetDesiredNodeUnschedulable(obj)
	}
	return nil
}

func (d *NodeDrain) drain(ctx context.Context, obj *v3.Node, cancel context.CancelFunc) {
	defer deleteFromContextMap(d.nodesToContext, obj.Name)

	for {
		select {
		case <-ctx.Done():
			return
		default:
		}

		stopped := false
		nodeName := obj.Spec.RequestedHostname
		updatedObj, err := v3.NodeConditionDrained.DoUntilTrue(obj, func() (runtime.Object, error) {
			kubeConfig, err := d.getKubeConfig()
			if err != nil {
				if err == context.Canceled {
					stopped = true
					logrus.Infof(fmt.Sprintf("Stopped draining %s in %s", obj.Name, obj.ClusterName))
				}
				logrus.Errorf("nodeDrain: error getting kubeConfig for node %s", obj.Name)
				return obj, fmt.Errorf("error getting kubeConfig for node %s", obj.Name)
			}
			_, msg, err := kubectl.Drain(ctx, kubeConfig, nodeName, getFlags(obj.Spec.NodeDrainInput))
			if err != nil {
				errMsg := filterErrorMsg(msg, nodeName)
				return obj, fmt.Errorf("%s", errMsg)
			}
			return obj, nil
		})
		if !stopped {
			nodeCopy := updatedObj.(*v3.Node).DeepCopy()
			if err == nil {
				nodeCopy.Spec.DesiredNodeUnschedulable = ""
			}
			_, updateErr := d.machines.Update(nodeCopy)
			if err != nil || updateErr != nil {
				logrus.Errorf("nodeDrain: [%s] in cluster [%s] : %v %v", nodeName, d.clusterName, err, updateErr)
				d.machines.Controller().Enqueue("", fmt.Sprintf("%s/%s", d.clusterName, obj.Name))
			}
		}
		cancel()
	}
}

func (d *NodeDrain) resetDesiredNodeUnschedulable(obj *v3.Node) error {
	nodeCopy := obj.DeepCopy()
	removeDrainCondition(nodeCopy)
	nodeCopy.Spec.DesiredNodeUnschedulable = ""
	if _, err := d.machines.Update(nodeCopy); err != nil {
		return err
	}
	return nil
}

func (d *NodeDrain) getKubeConfig() (*clientcmdapi.Config, error) {
	cluster, err := d.clusterLister.Get("", d.clusterName)
	if err != nil {
		return nil, err
	}
	user, err := d.systemAccountManager.GetSystemUser(cluster)
	if err != nil {
		return nil, err
	}
	token, err := d.userManager.EnsureToken(drainTokenPrefix+user.Name, description, user.Name)
	if err != nil {
		return nil, err
	}
	kubeConfig := d.kubeConfigGetter.KubeConfig(d.clusterName, token)
	for k := range kubeConfig.Clusters {
		kubeConfig.Clusters[k].InsecureSkipTLSVerify = true
	}
	return kubeConfig, nil
}

func getFlags(input *v3.NodeDrainInput) []string {
	return []string{
		fmt.Sprintf("--delete-local-data=%v", input.DeleteLocalData),
		fmt.Sprintf("--force=%v", input.Force),
		fmt.Sprintf("--grace-period=%v", input.GracePeriod),
		fmt.Sprintf("--ignore-daemonsets=%v", input.IgnoreDaemonSets),
		fmt.Sprintf("--timeout=%s", convert.ToString(input.Timeout)+"s")}
}

func filterErrorMsg(msg string, nodeName string) string {
	upd := []string{}
	lines := strings.Split(msg, "\n")
	for _, line := range lines[1:] {
		if strings.HasPrefix(line, "WARNING") || strings.HasPrefix(line, nodeName) {
			continue
		}
		if strings.Contains(line, "aborting") {
			continue
		}
		if strings.HasPrefix(line, "There are pending nodes ") {
			// for only one node in our case
			continue
		}
		if strings.HasPrefix(line, "There are pending pods ") {
			// already considered error
			continue
		}
		if strings.HasPrefix(line, "error") && strings.Contains(line, "unable to drain node") {
			// actual reason at end
			continue
		}
		if strings.HasPrefix(line, "pod") && strings.Contains(line, "evicted") {
			// evicted successfully
			continue
		}
		upd = append(upd, line)
	}
	return strings.Join(upd, "\n")
}

func removeDrainCondition(obj *v3.Node) {
	exists := false
	for _, condition := range obj.Status.Conditions {
		if condition.Type == "Drained" {
			exists = true
			break
		}
	}
	if exists {
		var conditions []v3.NodeCondition
		for _, condition := range obj.Status.Conditions {
			if condition.Type == "Drained" {
				continue
			}
			conditions = append(conditions, condition)
		}
		obj.Status.Conditions = conditions
	}
}

func deleteFromContextMap(data map[string]context.CancelFunc, id string) {
	nodeMapLock.Lock()
	delete(data, id)
	nodeMapLock.Unlock()
}
<|endoftext|>


<commit_before>package tfjson

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

// Parts of this package have been taken from, or inspired by
// Terraform's underlying type system, which can be found at:
//   https://godoc.org/github.com/zclconf/go-cty
//
// The attribute type system is largely slimmed down from cty and
// only serves to facilitate the correct marshaling/unmarshaling of
// the external JSON data. It is not designed to be 1-1 compatible
// with cty itself.

// MarshalJSON is an implementation of json.Marshaler that allows
// SchemaAttributeType instances to be serialized as JSON.
func (t SchemaAttributeType) MarshalJSON() ([]byte, error) {
	switch impl := t.attributeTypeImpl.(type) {
	case primitiveAttributeType:
		return []byte(fmt.Sprintf("%q", impl.kind)), nil

	case SchemaAttributeTypeCollection:
		buf := &bytes.Buffer{}
		etyJSON, err := t.ElementType().MarshalJSON()
		if err != nil {
			return nil, err
		}
		buf.WriteRune('[')
		fmt.Fprintf(buf, "%q", impl.kind)
		buf.WriteRune(',')
		buf.Write(etyJSON)
		buf.WriteRune(']')
		return buf.Bytes(), nil

	default:
		// should never happen
		panic("unknown type implementation")
	}
}

// UnmarshalJSON is the opposite of MarshalJSON for
// SchemaAttributeType.
func (t *SchemaAttributeType) UnmarshalJSON(buf []byte) error {
	r := bytes.NewReader(buf)
	dec := json.NewDecoder(r)

	tok, err := dec.Token()
	if err != nil {
		return err
	}

	switch v := tok.(type) {
	case string:
		switch v {
		case string(primitiveAttributeTypeBool):
			*t = SchemaAttributeTypeBool

		case string(primitiveAttributeTypeNumber):
			*t = SchemaAttributeTypeNumber

		case string(primitiveAttributeTypeString):
			*t = SchemaAttributeTypeString

		default:
			return fmt.Errorf("invalid primitive type name %q", v)
		}

		if dec.More() {
			return fmt.Errorf("extraneous data after type description")
		}

		return nil

	case json.Delim:
		if rune(v) != '[' {
			return fmt.Errorf("invalid complex type description")
		}

		tok, err = dec.Token()
		if err != nil {
			return err
		}

		kind, ok := tok.(string)
		if !ok {
			return fmt.Errorf("invalid complex type kind name")
		}

		switch kind {
		case string(collectionAttributeTypeList),
			string(collectionAttributeTypeSet),
			string(collectionAttributeTypeMap):
			var ety SchemaAttributeType
			err = dec.Decode(&ety)
			if err != nil {
				return err
			}

			*t = SchemaAttributeType{
				SchemaAttributeTypeCollection{
					kind:        collectionAttributeTypeKind(kind),
					elementType: ety,
				},
			}

		default:
			return fmt.Errorf("invalid complex type kind name")
		}

		tok, err = dec.Token()
		if err != nil {
			return err
		}

		if delim, ok := tok.(json.Delim); !ok || rune(delim) != ']' || dec.More() {
			return fmt.Errorf("unexpected extra data in type description")
		}

		return nil

	default:
		return fmt.Errorf("invalid type description")
	}
}
<commit_msg>show more information in unmarshal errors.<commit_after>package tfjson

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

// Parts of this package have been taken from, or inspired by
// Terraform's underlying type system, which can be found at:
//   https://godoc.org/github.com/zclconf/go-cty
//
// The attribute type system is largely slimmed down from cty and
// only serves to facilitate the correct marshaling/unmarshaling of
// the external JSON data. It is not designed to be 1-1 compatible
// with cty itself.

// MarshalJSON is an implementation of json.Marshaler that allows
// SchemaAttributeType instances to be serialized as JSON.
func (t SchemaAttributeType) MarshalJSON() ([]byte, error) {
	switch impl := t.attributeTypeImpl.(type) {
	case primitiveAttributeType:
		return []byte(fmt.Sprintf("%q", impl.kind)), nil

	case SchemaAttributeTypeCollection:
		buf := &bytes.Buffer{}
		etyJSON, err := t.ElementType().MarshalJSON()
		if err != nil {
			return nil, err
		}
		buf.WriteRune('[')
		fmt.Fprintf(buf, "%q", impl.kind)
		buf.WriteRune(',')
		buf.Write(etyJSON)
		buf.WriteRune(']')
		return buf.Bytes(), nil

	default:
		// should never happen
		panic("unknown type implementation")
	}
}

// UnmarshalJSON is the opposite of MarshalJSON for
// SchemaAttributeType.
func (t *SchemaAttributeType) UnmarshalJSON(buf []byte) error {
	r := bytes.NewReader(buf)
	dec := json.NewDecoder(r)

	tok, err := dec.Token()
	if err != nil {
		return err
	}

	switch v := tok.(type) {
	case string:
		switch v {
		case string(primitiveAttributeTypeBool):
			*t = SchemaAttributeTypeBool

		case string(primitiveAttributeTypeNumber):
			*t = SchemaAttributeTypeNumber

		case string(primitiveAttributeTypeString):
			*t = SchemaAttributeTypeString

		default:
			return fmt.Errorf("invalid primitive type name %q", v)
		}

		if dec.More() {
			return fmt.Errorf("extraneous data after type description")
		}

		return nil

	case json.Delim:
		if rune(v) != '[' {
			return fmt.Errorf("invalid complex type description")
		}

		tok, err = dec.Token()
		if err != nil {
			return err
		}

		kind, ok := tok.(string)
		if !ok {
			return fmt.Errorf("invalid complex type kind name: %T", tok)
		}

		switch kind {
		case string(collectionAttributeTypeList),
			string(collectionAttributeTypeSet),
			string(collectionAttributeTypeMap):
			var ety SchemaAttributeType
			err = dec.Decode(&ety)
			if err != nil {
				return err
			}

			*t = SchemaAttributeType{
				SchemaAttributeTypeCollection{
					kind:        collectionAttributeTypeKind(kind),
					elementType: ety,
				},
			}

		default:
			return fmt.Errorf("invalid complex type kind name: %s", kind)
		}

		tok, err = dec.Token()
		if err != nil {
			return err
		}

		if delim, ok := tok.(json.Delim); !ok || rune(delim) != ']' || dec.More() {
			return fmt.Errorf("unexpected extra data in type description")
		}

		return nil

	default:
		return fmt.Errorf("invalid type description")
	}
}
<|endoftext|>


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

// cgo invokes "go tool cgo" after filtering souces, and then process the output
// into a normalised form. It is invoked by the Go rules as an action.
package main

import (
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"unicode"
)

func testCgo(src string, data []byte) (bool, string, error) {
	fset := token.NewFileSet()
	parsed, err := parser.ParseFile(fset, src, data, parser.ImportsOnly)
	if err != nil {
		return false, "", err
	}
	for _, decl := range parsed.Decls {
		d, ok := decl.(*ast.GenDecl)
		if !ok {
			continue
		}
		for _, dspec := range d.Specs {
			spec, ok := dspec.(*ast.ImportSpec)
			if !ok {
				continue
			}
			imp, err := strconv.Unquote(spec.Path.Value)
			if err != nil {
				log.Panicf("%s: invalid string `%s`", src, spec.Path.Value)
			}
			if imp == "C" {
				return true, parsed.Name.String(), nil
			}
		}
	}
	return false, parsed.Name.String(), nil
}

func run(args []string) error {
	sources := multiFlag{}
	cc := ""
	objdir := ""
	dynout := ""
	dynimport := ""
	flags := flag.NewFlagSet("cgo", flag.ContinueOnError)
	goenv := envFlags(flags)
	flags.Var(&sources, "src", "A source file to be filtered and compiled")
	flags.StringVar(&cc, "cc", "", "Sets the c compiler to use")
	flags.StringVar(&objdir, "objdir", "", "The output directory")
	flags.StringVar(&dynout, "dynout", "", "The output directory")
	flags.StringVar(&dynimport, "dynimport", "", "The output directory")
	// process the args
	if err := flags.Parse(args); err != nil {
		return err
	}

	if len(dynout) > 0 {
		dynpackage, err := extractPackage(sources[0])
		if err != nil {
			return err
		}
		goargs := []string{
			"tool", "cgo",
			"-dynout", dynout,
			"-dynimport", dynimport,
			"-dynpackage", dynpackage,
		}
		cmd := exec.Command(goenv.Go, goargs...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("error running cgo: %v", err)
		}
		return nil
	}

	// apply build constraints to the source list
	// also pick out the cgo sources
	bctx := goenv.BuildContext()
	cgoSrcs := []string{}
	pkgName := ""
	for _, s := range sources {
		bits := strings.SplitN(s, "=", 2)
		if len(bits) != 2 {
			return fmt.Errorf("Invalid source arg, expected output=input got %s", s)
		}
		out := bits[0]
		in := bits[1]
		// Check if the file is filtered first
		data, err := ioutil.ReadFile(in)
		if err != nil {
			return err
		}
		match, err := matchFile(bctx, in)
		if err != nil {
			return err
		}
		// if this is not a go file, it cannot be cgo, so just check the filter
		if !strings.HasSuffix(in, ".go") {
			// Not a go file, just filter, assume C or C-like
			if match {
				// not filtered, copy over
				if err := ioutil.WriteFile(out, data, 0644); err != nil {
					return err
				}
			} else {
				// filtered, make empty file
				if err := ioutil.WriteFile(out, []byte(""), 0644); err != nil {
					return err
				}
			}
			continue
		}

		// Go source, must produce both c and go outputs
		cOut := strings.TrimSuffix(out, ".cgo1.go") + ".cgo2.c"
		isCgo, pkg, err := testCgo(in, data)
		if err != nil {
			return err
		}
		if pkg == "" {
			return fmt.Errorf("%s: error: could not parse package name", in)
		}

		if !match {
			// filtered file, fake both the go and the c
			if err := ioutil.WriteFile(out, []byte("package "+pkg), 0644); err != nil {
				return err
			}
			if err := ioutil.WriteFile(cOut, []byte(""), 0644); err != nil {
				return err
			}
			continue
		}

		if pkgName != "" && pkg != pkgName {
			return fmt.Errorf("multiple packages found: %s and %s", pkgName, pkg)
		}
		pkgName = pkg

		if isCgo {
			// add to cgo file list
			cgoSrcs = append(cgoSrcs, in)
		} else {
			// Non cgo file, copy the go and fake the c
			if err := ioutil.WriteFile(out, data, 0644); err != nil {
				return err
			}
			if err := ioutil.WriteFile(cOut, []byte(""), 0644); err != nil {
				return err
			}
		}
	}
	if pkgName == "" {
		return fmt.Errorf("no buildable Go source files found")
	}

	if len(cgoSrcs) == 0 {
		// If there were no cgo sources present, generate a minimal cgo input
		// This is so we can still run the cgo tool to build all the other outputs
		nullCgo := filepath.Join(objdir, "_cgo_empty.go")
		cgoSrcs = append(cgoSrcs, nullCgo)
		if err := ioutil.WriteFile(nullCgo, []byte("package "+pkgName+"\n/*\n*/\nimport \"C\"\n"), 0644); err != nil {
			return err
		}
	}

	// Tokenize copts. cc_library does this automatically, but cgo does not,
	// so we need to do it here.
	var copts []string
	for _, arg := range flags.Args() {
		args, err := splitQuoted(arg)
		if err != nil {
			return err
		}
		copts = append(copts, args...)
	}

	// Add the absoulute path to the c compiler to the environment
	if abs, err := filepath.Abs(cc); err == nil {
		cc = abs
	}
	env := os.Environ()
	env = append(env, goenv.Env()...)
	env = append(env, fmt.Sprintf("CC=%s", cc))
	env = append(env, fmt.Sprintf("CXX=%s", cc))

	goargs := []string{"tool", "cgo", "-objdir", objdir}
	goargs = append(goargs, copts...)
	goargs = append(goargs, cgoSrcs...)
	cmd := exec.Command(goenv.Go, goargs...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = env
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("error running cgo: %v", err)
	}
	return nil
}

// Copied from go/build.splitQuoted. Also in Gazelle (where tests are).
func splitQuoted(s string) (r []string, err error) {
	var args []string
	arg := make([]rune, len(s))
	escaped := false
	quoted := false
	quote := '\x00'
	i := 0
	for _, rune := range s {
		switch {
		case escaped:
			escaped = false
		case rune == '\\':
			escaped = true
			continue
		case quote != '\x00':
			if rune == quote {
				quote = '\x00'
				continue
			}
		case rune == '"' || rune == '\'':
			quoted = true
			quote = rune
			continue
		case unicode.IsSpace(rune):
			if quoted || i > 0 {
				quoted = false
				args = append(args, string(arg[:i]))
				i = 0
			}
			continue
		}
		arg[i] = rune
		i++
	}
	if quoted || i > 0 {
		args = append(args, string(arg[:i]))
	}
	if quote != 0 {
		err = errors.New("unclosed quote")
	} else if escaped {
		err = errors.New("unfinished escaping")
	}
	return args, err
}

func main() {
	log.SetPrefix("CgoCodegen: ")
	log.SetFlags(0) // don't print timestamps
	if err := run(os.Args[1:]); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Run both forms of cgo inside the environment (#930)<commit_after>// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// cgo invokes "go tool cgo" after filtering souces, and then process the output
// into a normalised form. It is invoked by the Go rules as an action.
package main

import (
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"unicode"
)

func testCgo(src string, data []byte) (bool, string, error) {
	fset := token.NewFileSet()
	parsed, err := parser.ParseFile(fset, src, data, parser.ImportsOnly)
	if err != nil {
		return false, "", err
	}
	for _, decl := range parsed.Decls {
		d, ok := decl.(*ast.GenDecl)
		if !ok {
			continue
		}
		for _, dspec := range d.Specs {
			spec, ok := dspec.(*ast.ImportSpec)
			if !ok {
				continue
			}
			imp, err := strconv.Unquote(spec.Path.Value)
			if err != nil {
				log.Panicf("%s: invalid string `%s`", src, spec.Path.Value)
			}
			if imp == "C" {
				return true, parsed.Name.String(), nil
			}
		}
	}
	return false, parsed.Name.String(), nil
}

func run(args []string) error {
	sources := multiFlag{}
	cc := ""
	objdir := ""
	dynout := ""
	dynimport := ""
	flags := flag.NewFlagSet("cgo", flag.ContinueOnError)
	goenv := envFlags(flags)
	flags.Var(&sources, "src", "A source file to be filtered and compiled")
	flags.StringVar(&cc, "cc", "", "Sets the c compiler to use")
	flags.StringVar(&objdir, "objdir", "", "The output directory")
	flags.StringVar(&dynout, "dynout", "", "The output directory")
	flags.StringVar(&dynimport, "dynimport", "", "The output directory")
	// process the args
	if err := flags.Parse(args); err != nil {
		return err
	}
	env := os.Environ()
	env = append(env, goenv.Env()...)

	if len(dynout) > 0 {
		dynpackage, err := extractPackage(sources[0])
		if err != nil {
			return err
		}
		goargs := []string{
			"tool", "cgo",
			"-dynout", dynout,
			"-dynimport", dynimport,
			"-dynpackage", dynpackage,
		}
		cmd := exec.Command(goenv.Go, goargs...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Env = env
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("error running cgo: %v", err)
		}
		return nil
	}

	// apply build constraints to the source list
	// also pick out the cgo sources
	bctx := goenv.BuildContext()
	cgoSrcs := []string{}
	pkgName := ""
	for _, s := range sources {
		bits := strings.SplitN(s, "=", 2)
		if len(bits) != 2 {
			return fmt.Errorf("Invalid source arg, expected output=input got %s", s)
		}
		out := bits[0]
		in := bits[1]
		// Check if the file is filtered first
		data, err := ioutil.ReadFile(in)
		if err != nil {
			return err
		}
		match, err := matchFile(bctx, in)
		if err != nil {
			return err
		}
		// if this is not a go file, it cannot be cgo, so just check the filter
		if !strings.HasSuffix(in, ".go") {
			// Not a go file, just filter, assume C or C-like
			if match {
				// not filtered, copy over
				if err := ioutil.WriteFile(out, data, 0644); err != nil {
					return err
				}
			} else {
				// filtered, make empty file
				if err := ioutil.WriteFile(out, []byte(""), 0644); err != nil {
					return err
				}
			}
			continue
		}

		// Go source, must produce both c and go outputs
		cOut := strings.TrimSuffix(out, ".cgo1.go") + ".cgo2.c"
		isCgo, pkg, err := testCgo(in, data)
		if err != nil {
			return err
		}
		if pkg == "" {
			return fmt.Errorf("%s: error: could not parse package name", in)
		}

		if !match {
			// filtered file, fake both the go and the c
			if err := ioutil.WriteFile(out, []byte("package "+pkg), 0644); err != nil {
				return err
			}
			if err := ioutil.WriteFile(cOut, []byte(""), 0644); err != nil {
				return err
			}
			continue
		}

		if pkgName != "" && pkg != pkgName {
			return fmt.Errorf("multiple packages found: %s and %s", pkgName, pkg)
		}
		pkgName = pkg

		if isCgo {
			// add to cgo file list
			cgoSrcs = append(cgoSrcs, in)
		} else {
			// Non cgo file, copy the go and fake the c
			if err := ioutil.WriteFile(out, data, 0644); err != nil {
				return err
			}
			if err := ioutil.WriteFile(cOut, []byte(""), 0644); err != nil {
				return err
			}
		}
	}
	if pkgName == "" {
		return fmt.Errorf("no buildable Go source files found")
	}

	if len(cgoSrcs) == 0 {
		// If there were no cgo sources present, generate a minimal cgo input
		// This is so we can still run the cgo tool to build all the other outputs
		nullCgo := filepath.Join(objdir, "_cgo_empty.go")
		cgoSrcs = append(cgoSrcs, nullCgo)
		if err := ioutil.WriteFile(nullCgo, []byte("package "+pkgName+"\n/*\n*/\nimport \"C\"\n"), 0644); err != nil {
			return err
		}
	}

	// Tokenize copts. cc_library does this automatically, but cgo does not,
	// so we need to do it here.
	var copts []string
	for _, arg := range flags.Args() {
		args, err := splitQuoted(arg)
		if err != nil {
			return err
		}
		copts = append(copts, args...)
	}

	// Add the absoulute path to the c compiler to the environment
	if abs, err := filepath.Abs(cc); err == nil {
		cc = abs
	}
	env = append(env, fmt.Sprintf("CC=%s", cc))
	env = append(env, fmt.Sprintf("CXX=%s", cc))

	goargs := []string{"tool", "cgo", "-objdir", objdir}
	goargs = append(goargs, copts...)
	goargs = append(goargs, cgoSrcs...)
	cmd := exec.Command(goenv.Go, goargs...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = env
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("error running cgo: %v", err)
	}
	return nil
}

// Copied from go/build.splitQuoted. Also in Gazelle (where tests are).
func splitQuoted(s string) (r []string, err error) {
	var args []string
	arg := make([]rune, len(s))
	escaped := false
	quoted := false
	quote := '\x00'
	i := 0
	for _, rune := range s {
		switch {
		case escaped:
			escaped = false
		case rune == '\\':
			escaped = true
			continue
		case quote != '\x00':
			if rune == quote {
				quote = '\x00'
				continue
			}
		case rune == '"' || rune == '\'':
			quoted = true
			quote = rune
			continue
		case unicode.IsSpace(rune):
			if quoted || i > 0 {
				quoted = false
				args = append(args, string(arg[:i]))
				i = 0
			}
			continue
		}
		arg[i] = rune
		i++
	}
	if quoted || i > 0 {
		args = append(args, string(arg[:i]))
	}
	if quote != 0 {
		err = errors.New("unclosed quote")
	} else if escaped {
		err = errors.New("unfinished escaping")
	}
	return args, err
}

func main() {
	log.SetPrefix("CgoCodegen: ")
	log.SetFlags(0) // don't print timestamps
	if err := run(os.Args[1:]); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package task

import (
	"fmt"
	"github.com/ory-am/gitdeploy/sse"
	"github.com/ory-am/event"
)

type Command interface {
	Run() (WorkerLog, error)
}

type EventManagerWorker struct {
	EventManager *event.EventManager
	Channel      string
}

type WorkerLog []*workerLogEntry

type workerLogEntry struct {
	event   string
	message string
	err error
}

func (w *WorkerLog) Add(event, message string) {
	n := append(*w, &workerLogEntry{
		event:   event,
		message: message,
	})
	w = &n
}

func (w *WorkerLog) AddError(event string, err error) {
	n := append(*w, &workerLogEntry{
		event:   event,
		message: fmt.Sprintf("An error occured: %s", err.Error()),
		err: err,
	})
	w = &n
}

func (l *EventManagerWorker) Work(m []Command) error {
	for _, c := range m {
		events, err := c.Run()
		if err != nil {
			return err
		}
		for _, v := range events {
			l.EventManager.TriggerAndWait(v.event, sse.NewEvent(l.Channel, v.message))
		}
	}
	return nil
}
<commit_msg>task: worker runs tasks and log aggregation concurrently<commit_after>package task

import (
	"fmt"
	"github.com/ory-am/event"
	"github.com/ory-am/gitdeploy/sse"
	"time"
)

type Command interface {
	Run(w WorkerLog, e WorkerError)
}

type EventManagerWorker struct {
	EventManager *event.EventManager
	Channel      string
}

type WorkerLog chan *workerLogEntry
type WorkerError chan error

type workerLogEntry struct {
	event   string
	message string
	err     error
	timestamp time.Time
}

func (w *WorkerLog) Add(event, message string) {
	w <- &workerLogEntry{
		event:   event,
		message: message,
		timestamp: time.Now(),
	}
}

func (w *WorkerLog) AddError(event string, err error) {
	w <- &workerLogEntry{
		event:   event,
		message: fmt.Sprintf("An error occured: %s", err.Error()),
		err:     err,
		timestamp: time.Now(),
	}
}

func (l *EventManagerWorker) Work(m []Command) (err error) {
	w := make(WorkerLog, 10)
	e := make(WorkerError)

	// Run all jobs
	for _, c := range m {
		// Run next in line
		go func() {
			defer close(w)
			defer close(e)
			c.Run(w, e)
		}()

		// Forward output to the event manager
		go func() {
			for {
				select {
				case v, open := <-w:
					if !open {
						return
					}
					l.EventManager.TriggerAndWait(v.event, sse.NewEvent(l.Channel, v.message))
				}
			}
		}()

		// Catch errors if any occur
		for {
			select {
			case err := <-e:
				return err
			}
		}
	}
	return nil
}
<|endoftext|>