<commit_before>package main

import (
	pb "github.com/mediachain/concat/proto"
	"log"
	"strconv"
)

type Query struct {
	namespace string
	selector  QuerySelector
	criteria  QueryCriteria
	limit     int
}

type QuerySelector interface {
	SelectorType() string
}

type SimpleSelector string
type CompoundSelector []SimpleSelector
type FunctionSelector struct {
	op  string
	sel SimpleSelector
}

func (s SimpleSelector) SelectorType() string {
	return "simple"
}

func (s CompoundSelector) SelectorType() string {
	return "compound"
}

func (s *FunctionSelector) SelectorType() string {
	return "function"
}

type QueryCriteria interface {
	CriteriaType() string
}

type ValueCriteria struct {
	sel string
	val string
}

type TimeCriteria struct {
	op string
	ts int64
}

type CompoundCriteria struct {
	op          string
	left, right QueryCriteria
}

func (c *ValueCriteria) CriteriaType() string {
	return "value"
}

func (c *TimeCriteria) CriteriaType() string {
	return "time"
}

func (c *CompoundCriteria) CriteriaType() string {
	return "compound"
}

type ConsCell struct {
	car interface{}
	cdr *ConsCell
}

type ParseState struct {
	query *Query
	stack *ConsCell
	err   error
}

func (ps *ParseState) setSimpleSelector() {
	// stack: simple-selector
	sel := ps.pop().(string)
	ps.query.selector = SimpleSelector(sel)
}

func (ps *ParseState) setCompoundSelector() {
	// stack: simple-selector ...
	count := ps.sklen()
	sels := make([]SimpleSelector, count)
	for x := 0; x < count; x++ {
		sel := ps.pop().(string)
		sels[count-x-1] = SimpleSelector(sel)
	}
	ps.query.selector = CompoundSelector(sels)
}

func (ps *ParseState) setFunctionSelector() {
	// stack: simple-selector function
	sel := ps.pop().(string)
	op := ps.pop().(string)
	ps.query.selector = &FunctionSelector{op: op, sel: SimpleSelector(sel)}
}

func (ps *ParseState) setNamespace(ns string) {
	ps.query.namespace = ns
}

func (ps *ParseState) setCriteria() {
	// stack: criteria
	ps.query.criteria = ps.pop().(QueryCriteria)
}

func (ps *ParseState) addValueCriteria() {
	// stack: value value-selector ...
	val := ps.pop().(string)
	sel := ps.pop().(string)
	crit := &ValueCriteria{sel: sel, val: val}
	ps.push(crit)
}

func (ps *ParseState) addTimeCriteria() {
	// stack: time op ...
	tstr := ps.pop().(string)
	op := ps.pop().(string)
	ts, err := strconv.Atoi(tstr)
	if err != nil {
		ps.err = err
		ts = 0
	}
	crit := &TimeCriteria{op: op, ts: int64(ts)}
	ps.push(crit)
}

func (ps *ParseState) addCompoundCriteria() {
	// stack: criteria op criteria ...
	right := ps.pop().(QueryCriteria)
	op := ps.pop().(string)
	left := ps.pop().(QueryCriteria)
	crit := &CompoundCriteria{op: op, left: left, right: right}
	ps.push(crit)
}

func (ps *ParseState) setLimit(x string) {
	lim, err := strconv.Atoi(x)
	if err != nil {
		ps.err = err
		lim = 0
	}
	ps.query.limit = lim
}

func (ps *ParseState) push(val interface{}) {
	cell := &ConsCell{car: val, cdr: ps.stack}
	ps.stack = cell
}

func (ps *ParseState) pop() interface{} {
	top := ps.stack.car
	ps.stack = ps.stack.cdr
	return top
}

func (ps *ParseState) sklen() (x int) {
	for next := ps.stack; next != nil; next = next.cdr {
		x++
	}
	return x
}

// query parsing
func ParseQuery(qs string) (*Query, error) {
	ps := &ParseState{query: &Query{}}
	p := &QueryParser{Buffer: qs, ParseState: ps}
	p.Init()
	err := p.Parse()
	if err != nil {
		return nil, err
	}

	p.Execute()
	if ps.err != nil {
		return nil, ps.err
	}

	return ps.query, nil
}

// query evaluation: very primitive eval with only simple statements
// will have to do until we have an index and we can compile to sql.
func EvalQuery(query *Query, stmts []*pb.Statement) []interface{} {
	filter := makeCriteriaFilter(query)
	rs := makeResultSet(query)

	rs.begin(len(stmts))
	for _, stmt := range stmts {
		if filter(stmt) {
			rs.add(stmt)
		}
	}
	rs.end()

	return rs.result()
}

type QueryResultSet interface {
	begin(hint int)
	add(*pb.Statement)
	end()
	result() []interface{}
}

type CriteriaFilter func(*pb.Statement) bool
type ValueCriteriaFilter func(*pb.Statement, string) bool
type TimeCriteriaFilter func(*pb.Statement, int64) bool
type CompoundCriteriaFilter func(stmt *pb.Statement, left, right CriteriaFilter) bool

func idCriteriaFilter(stmt *pb.Statement, id string) bool {
	return stmt.Id == id
}

func publisherCriteriaFilter(stmt *pb.Statement, pub string) bool {
	return stmt.Publisher == pub
}

func sourceCriteriaFilter(stmt *pb.Statement, src string) bool {
	// only support simple statements for now, so src = publisher
	return stmt.Publisher == src
}

var valueCriteriaFilters = map[string]ValueCriteriaFilter{
	"id":        idCriteriaFilter,
	"publisher": publisherCriteriaFilter,
	"source":    sourceCriteriaFilter}

func timestampFilterLTEQ(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp <= ts
}

func timestampFilterLT(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp < ts
}

func timestampFilterEQ(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp == ts
}

func timestampFilterGTEQ(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp >= ts
}

func timestampFilterGT(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp >= ts
}

var timeCriteriaFilters = map[string]TimeCriteriaFilter{
	"<=": timestampFilterLTEQ,
	"<":  timestampFilterLT,
	"=":  timestampFilterEQ,
	">=": timestampFilterGTEQ,
	">":  timestampFilterGT}

func compoundCriteriaAND(stmt *pb.Statement, left, right CriteriaFilter) bool {
	return left(stmt) && right(stmt)
}

func compoundCriteriaOR(stmt *pb.Statement, left, right CriteriaFilter) bool {
	return left(stmt) || right(stmt)
}

var compoundCriteriaFilters = map[string]CompoundCriteriaFilter{
	"AND": compoundCriteriaAND,
	"OR":  compoundCriteriaOR}

func makeCriteriaFilter(query *Query) CriteriaFilter {
	c := query.criteria
	if c == nil {
		return func(*pb.Statement) bool { return true }
	}

	return makeCriteriaFilterF(c)
}

func makeCriteriaFilterF(c QueryCriteria) CriteriaFilter {
	switch c := c.(type) {
	case *ValueCriteria:
		filter, ok := valueCriteriaFilters[c.sel]
		if ok {
			return func(stmt *pb.Statement) bool {
				return filter(stmt, c.val)
			}
		} else {
			log.Fatalf("Unexpected criteria selector: %s", c.sel)
			return nil
		}

	case *TimeCriteria:
		filter, ok := timeCriteriaFilters[c.op]
		if ok {
			return func(stmt *pb.Statement) bool {
				return filter(stmt, c.ts)
			}
		} else {
			log.Fatalf("Unexpected criteria time op: %s", c.op)
			return nil
		}

	case *CompoundCriteria:
		filter, ok := compoundCriteriaFilters[c.op]
		if ok {
			left := makeCriteriaFilterF(c.left)
			right := makeCriteriaFilterF(c.right)
			return func(stmt *pb.Statement) bool {
				return filter(stmt, left, right)
			}
		} else {
			log.Fatalf("Unexpected criteria combinator: %s", c.op)
			return nil
		}

	default:
		log.Fatalf("Unexpected criteria type: %t", c)
		return nil
	}
}

func makeResultSet(query *Query) QueryResultSet {
	return nil
}
<commit_msg>query eval: namespace filter<commit_after>package main

import (
	pb "github.com/mediachain/concat/proto"
	"log"
	"strconv"
	"strings"
)

type Query struct {
	namespace string
	selector  QuerySelector
	criteria  QueryCriteria
	limit     int
}

type QuerySelector interface {
	SelectorType() string
}

type SimpleSelector string
type CompoundSelector []SimpleSelector
type FunctionSelector struct {
	op  string
	sel SimpleSelector
}

func (s SimpleSelector) SelectorType() string {
	return "simple"
}

func (s CompoundSelector) SelectorType() string {
	return "compound"
}

func (s *FunctionSelector) SelectorType() string {
	return "function"
}

type QueryCriteria interface {
	CriteriaType() string
}

type ValueCriteria struct {
	sel string
	val string
}

type TimeCriteria struct {
	op string
	ts int64
}

type CompoundCriteria struct {
	op          string
	left, right QueryCriteria
}

func (c *ValueCriteria) CriteriaType() string {
	return "value"
}

func (c *TimeCriteria) CriteriaType() string {
	return "time"
}

func (c *CompoundCriteria) CriteriaType() string {
	return "compound"
}

type ConsCell struct {
	car interface{}
	cdr *ConsCell
}

type ParseState struct {
	query *Query
	stack *ConsCell
	err   error
}

func (ps *ParseState) setSimpleSelector() {
	// stack: simple-selector
	sel := ps.pop().(string)
	ps.query.selector = SimpleSelector(sel)
}

func (ps *ParseState) setCompoundSelector() {
	// stack: simple-selector ...
	count := ps.sklen()
	sels := make([]SimpleSelector, count)
	for x := 0; x < count; x++ {
		sel := ps.pop().(string)
		sels[count-x-1] = SimpleSelector(sel)
	}
	ps.query.selector = CompoundSelector(sels)
}

func (ps *ParseState) setFunctionSelector() {
	// stack: simple-selector function
	sel := ps.pop().(string)
	op := ps.pop().(string)
	ps.query.selector = &FunctionSelector{op: op, sel: SimpleSelector(sel)}
}

func (ps *ParseState) setNamespace(ns string) {
	ps.query.namespace = ns
}

func (ps *ParseState) setCriteria() {
	// stack: criteria
	ps.query.criteria = ps.pop().(QueryCriteria)
}

func (ps *ParseState) addValueCriteria() {
	// stack: value value-selector ...
	val := ps.pop().(string)
	sel := ps.pop().(string)
	crit := &ValueCriteria{sel: sel, val: val}
	ps.push(crit)
}

func (ps *ParseState) addTimeCriteria() {
	// stack: time op ...
	tstr := ps.pop().(string)
	op := ps.pop().(string)
	ts, err := strconv.Atoi(tstr)
	if err != nil {
		ps.err = err
		ts = 0
	}
	crit := &TimeCriteria{op: op, ts: int64(ts)}
	ps.push(crit)
}

func (ps *ParseState) addCompoundCriteria() {
	// stack: criteria op criteria ...
	right := ps.pop().(QueryCriteria)
	op := ps.pop().(string)
	left := ps.pop().(QueryCriteria)
	crit := &CompoundCriteria{op: op, left: left, right: right}
	ps.push(crit)
}

func (ps *ParseState) setLimit(x string) {
	lim, err := strconv.Atoi(x)
	if err != nil {
		ps.err = err
		lim = 0
	}
	ps.query.limit = lim
}

func (ps *ParseState) push(val interface{}) {
	cell := &ConsCell{car: val, cdr: ps.stack}
	ps.stack = cell
}

func (ps *ParseState) pop() interface{} {
	top := ps.stack.car
	ps.stack = ps.stack.cdr
	return top
}

func (ps *ParseState) sklen() (x int) {
	for next := ps.stack; next != nil; next = next.cdr {
		x++
	}
	return x
}

// query parsing
func ParseQuery(qs string) (*Query, error) {
	ps := &ParseState{query: &Query{}}
	p := &QueryParser{Buffer: qs, ParseState: ps}
	p.Init()
	err := p.Parse()
	if err != nil {
		return nil, err
	}

	p.Execute()
	if ps.err != nil {
		return nil, ps.err
	}

	return ps.query, nil
}

// query evaluation: very primitive eval with only simple statements
// will have to do until we have an index and we can compile to sql.
func EvalQuery(query *Query, stmts []*pb.Statement) []interface{} {
	nsfilter := makeNamespaceFilter(query)
	cfilter := makeCriteriaFilter(query)
	rs := makeResultSet(query)

	rs.begin(len(stmts))
	for _, stmt := range stmts {
		if nsfilter(stmt) && cfilter(stmt) {
			rs.add(stmt)
		}
	}
	rs.end()

	return rs.result()
}

type QueryResultSet interface {
	begin(hint int)
	add(*pb.Statement)
	end()
	result() []interface{}
}

type StatementFilter func(*pb.Statement) bool
type ValueCriteriaFilter func(*pb.Statement, string) bool
type TimeCriteriaFilter func(*pb.Statement, int64) bool
type CompoundCriteriaFilter func(stmt *pb.Statement, left, right StatementFilter) bool

func idCriteriaFilter(stmt *pb.Statement, id string) bool {
	return stmt.Id == id
}

func publisherCriteriaFilter(stmt *pb.Statement, pub string) bool {
	return stmt.Publisher == pub
}

func sourceCriteriaFilter(stmt *pb.Statement, src string) bool {
	// only support simple statements for now, so src = publisher
	return stmt.Publisher == src
}

var valueCriteriaFilters = map[string]ValueCriteriaFilter{
	"id":        idCriteriaFilter,
	"publisher": publisherCriteriaFilter,
	"source":    sourceCriteriaFilter}

func timestampFilterLTEQ(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp <= ts
}

func timestampFilterLT(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp < ts
}

func timestampFilterEQ(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp == ts
}

func timestampFilterGTEQ(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp >= ts
}

func timestampFilterGT(stmt *pb.Statement, ts int64) bool {
	return stmt.Timestamp >= ts
}

var timeCriteriaFilters = map[string]TimeCriteriaFilter{
	"<=": timestampFilterLTEQ,
	"<":  timestampFilterLT,
	"=":  timestampFilterEQ,
	">=": timestampFilterGTEQ,
	">":  timestampFilterGT}

func compoundCriteriaAND(stmt *pb.Statement, left, right StatementFilter) bool {
	return left(stmt) && right(stmt)
}

func compoundCriteriaOR(stmt *pb.Statement, left, right StatementFilter) bool {
	return left(stmt) || right(stmt)
}

var compoundCriteriaFilters = map[string]CompoundCriteriaFilter{
	"AND": compoundCriteriaAND,
	"OR":  compoundCriteriaOR}

func emptyFilter(*pb.Statement) bool {
	return true
}

func makeNamespaceFilter(query *Query) StatementFilter {
	ns := query.namespace
	switch {
	case ns == "*":
		return emptyFilter

	case ns[len(ns)-1] == '*':
		prefix := ns[:len(ns)-2]
		return func(stmt *pb.Statement) bool {
			return strings.HasPrefix(stmt.Namespace, prefix)
		}

	default:
		return func(stmt *pb.Statement) bool {
			return stmt.Namespace == ns
		}
	}
}

func makeCriteriaFilter(query *Query) StatementFilter {
	c := query.criteria
	if c == nil {
		return emptyFilter
	}

	return makeCriteriaFilterF(c)
}

func makeCriteriaFilterF(c QueryCriteria) StatementFilter {
	switch c := c.(type) {
	case *ValueCriteria:
		filter, ok := valueCriteriaFilters[c.sel]
		if ok {
			return func(stmt *pb.Statement) bool {
				return filter(stmt, c.val)
			}
		} else {
			log.Fatalf("Unexpected criteria selector: %s", c.sel)
			return nil
		}

	case *TimeCriteria:
		filter, ok := timeCriteriaFilters[c.op]
		if ok {
			return func(stmt *pb.Statement) bool {
				return filter(stmt, c.ts)
			}
		} else {
			log.Fatalf("Unexpected criteria time op: %s", c.op)
			return nil
		}

	case *CompoundCriteria:
		filter, ok := compoundCriteriaFilters[c.op]
		if ok {
			left := makeCriteriaFilterF(c.left)
			right := makeCriteriaFilterF(c.right)
			return func(stmt *pb.Statement) bool {
				return filter(stmt, left, right)
			}
		} else {
			log.Fatalf("Unexpected criteria combinator: %s", c.op)
			return nil
		}

	default:
		log.Fatalf("Unexpected criteria type: %t", c)
		return nil
	}
}

func makeResultSet(query *Query) QueryResultSet {
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2013-2016 Pierre Neidhardt <ambrevar@gmail.com>
// Use of this file is governed by the license that can be found in LICENSE.

// Convert 'input' and 'output' from Go to Lua and from Lua to Go. Almost all
// scripting support is implemented in this file: in case of library change,
// this is the only file that would need some overhaul.

package main

import (
	"fmt"
	"log"
	"reflect"

	"bitbucket.org/ambrevar/demlo/golua/unicode"
	"github.com/aarzilli/golua/lua"
	"github.com/ambrevar/luar"
)

const (
	registryWhitelist = "_whitelist"
	registryScripts   = "_scripts"
)

// goToLua copies Go values to Lua and sets the result to name.
// Compound types are deep-copied.
// Functions are automatically converted to 'func (L *lua.State) int'.
func goToLua(L *lua.State, name string, val interface{}) {
	t := reflect.TypeOf(val)
	if t.Kind() == reflect.Func {
		L.PushGoFunction(luar.GoLuaFunc(L, val))
	} else {
		luar.GoToLua(L, t, reflect.ValueOf(val), true)
	}
	L.SetGlobal(name)
}

// Registers a Go function as a global variable and add it to the sandbox.
func sandboxRegister(L *lua.State, name string, f interface{}) {
	goToLua(L, name, f)

	L.PushString(registryWhitelist)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	L.GetGlobal(name)
	L.SetField(-2, name)
}

// The caller is responsible for closing the Lua state.
// Add a `defer L.Close()` to the calling code if there is no error.
func MakeSandbox(logPrint func(v ...interface{})) (*lua.State, error) {
	L := lua.NewState()
	L.OpenLibs()
	unicode.GoLuaReplaceFuncs(L)

	// Store the whitelist in registry to avoid tampering it.
	L.PushString(registryWhitelist)
	err := L.DoString(luaWhitelist)
	if err != nil {
		log.Fatal("Spurious sandbox", err)
	}
	L.SetTable(lua.LUA_REGISTRYINDEX)

	// Register before setting up the sandbox: these functions will be restored
	// together with the sandbox.
	// The closure allows access to the external logger.
	luaDebug := func(L *lua.State) int { return 0 }
	if logPrint != nil {
		luaDebug = func(L *lua.State) int {
			var arglist []interface{}
			nargs := L.GetTop()
			for i := 1; i <= nargs; i++ {
				if L.IsString(i) {
					arglist = append(arglist, L.ToString(i))
				}
			}
			logPrint(arglist...)
			return 0
		}
	}

	sandboxRegister(L, "debug", luaDebug)
	sandboxRegister(L, "stringnorm", stringNorm)
	sandboxRegister(L, "stringrel", stringRel)

	// Purge _G from everything but the content of the whitelist.
	err = L.DoString(luaSetSandbox)
	if err != nil {
		log.Fatal("Cannot load function to set sandbox", err)
	}
	L.PushString(registryWhitelist)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	err = L.Call(1, 0)
	if err != nil {
		log.Fatal("Failed to set sandbox", err)
	}

	return L, nil
}

// SandboxCompileScripts transfers the script buffer to the Lua state L and
// references them in LUA_REGISTRYINDEX.
func SandboxCompileScripts(L *lua.State, scripts []scriptBuffer) {
	L.PushString(registryScripts)
	L.NewTable()
	for _, script := range scripts {
		L.PushString(script.path)
		err := L.LoadString(script.buf)
		if err != 0 {
			log.Fatalf("%s: %s", script.path, L.ToString(-1))
			L.Pop(2)
		} else {
			L.SetTable(-3)
		}
	}
	L.SetTable(lua.LUA_REGISTRYINDEX)
}

func outputNumbersToStrings(L *lua.State) {
	L.GetGlobal("output")

	if !L.IsTable(-1) {
		L.NewTable()
		L.SetGlobal("output")
	}

	L.GetField(-1, "tags")
	if L.IsTable(-1) {
		// First key.
		L.PushNil()
		for L.Next(-2) != 0 {
			// Use 'key' at index -2 and 'value' at index -1.
			if L.IsString(-2) && L.IsString(-1) {
				// Convert numbers to strings.
				L.ToString(-1)
				L.SetField(-3, L.ToString(-2))
			} else {
				// Remove 'value' and keep 'key' for next iteration.
				L.Pop(1)
			}
		}
	}
	L.Pop(1)

	L.Pop(1)
}

// RunScript executes script named 'script' with 'input' and 'output' set as global variable.
// Any change made to 'input' is discarded. Change to 'output' are transfered
// back to Go on every script call to guarantee type consistency across script
// calls (Lua is dynamically typed).
func RunScript(L *lua.State, script string, input *inputInfo, output *outputInfo) error {
	// Restore the sandbox.
	err := L.DoString(luaRestoreSandbox)
	if err != nil {
		log.Fatal("Cannot load function to restore sandbox", err)
	}
	L.PushString(registryWhitelist)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	err = L.Call(1, 0)
	if err != nil {
		log.Fatal("Failed to restore sandbox", err)
	}

	goToLua(L, "input", *input)
	goToLua(L, "output", *output)

	// Shortcut (mostly for prescript and postscript).
	L.GetGlobal("input")
	L.GetField(-1, "tags")
	L.SetGlobal("i")
	L.Pop(1)
	L.GetGlobal("output")
	L.GetField(-1, "tags")
	L.SetGlobal("o")
	L.Pop(1)

	// Call the compiled script.
	L.PushString(registryScripts)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	L.PushString(script)
	if L.IsTable(-2) {
		L.GetTable(-2)
		if L.IsFunction(-1) {
			err := L.Call(0, 0)
			if err != nil {
				L.SetTop(0)
				return fmt.Errorf("%s", err)
			}
		} else {
			L.Pop(1)
		}
	} else {
		L.Pop(1)
	}
	L.Pop(1)

	// We allow tags to be numbers for convenience.
	outputNumbersToStrings(L)

	L.GetGlobal("output")
	r := luar.LuaToGo(L, reflect.TypeOf(*output), -1)
	L.Pop(1)

	*output = r.(outputInfo)

	return nil
}

func LoadConfig(config string, options interface{}) {
	L, err := MakeSandbox(log.Println)
	defer L.Close()

	err = L.DoFile(config)
	if err != nil {
		log.Fatalf("Error loading config: %s", err)
	}

	L.GetGlobal("_G")
	r := luar.LuaToGo(L, reflect.TypeOf(options), -1)
	L.Pop(1)

	v := reflect.ValueOf(options)
	v.Elem().Set(reflect.ValueOf(r).Elem())
}
<commit_msg>Use upstream luar<commit_after>// Copyright © 2013-2016 Pierre Neidhardt <ambrevar@gmail.com>
// Use of this file is governed by the license that can be found in LICENSE.

// Convert 'input' and 'output' from Go to Lua and from Lua to Go. Almost all
// scripting support is implemented in this file: in case of library change,
// this is the only file that would need some overhaul.

package main

import (
	"fmt"
	"log"
	"reflect"

	"bitbucket.org/ambrevar/demlo/golua/unicode"
	"github.com/aarzilli/golua/lua"
	"github.com/stevedonovan/luar"
)

const (
	registryWhitelist = "_whitelist"
	registryScripts   = "_scripts"
)

// goToLua copies Go values to Lua and sets the result to name.
// Compound types are deep-copied.
// Functions are automatically converted to 'func (L *lua.State) int'.
func goToLua(L *lua.State, name string, val interface{}) {
	t := reflect.TypeOf(val)
	if t.Kind() == reflect.Func {
		L.PushGoFunction(luar.GoLuaFunc(L, val))
	} else {
		luar.GoToLua(L, t, reflect.ValueOf(val), true)
	}
	L.SetGlobal(name)
}

// Registers a Go function as a global variable and add it to the sandbox.
func sandboxRegister(L *lua.State, name string, f interface{}) {
	goToLua(L, name, f)

	L.PushString(registryWhitelist)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	L.GetGlobal(name)
	L.SetField(-2, name)
}

// The caller is responsible for closing the Lua state.
// Add a `defer L.Close()` to the calling code if there is no error.
func MakeSandbox(logPrint func(v ...interface{})) (*lua.State, error) {
	L := lua.NewState()
	L.OpenLibs()
	unicode.GoLuaReplaceFuncs(L)

	// Store the whitelist in registry to avoid tampering it.
	L.PushString(registryWhitelist)
	err := L.DoString(luaWhitelist)
	if err != nil {
		log.Fatal("Spurious sandbox", err)
	}
	L.SetTable(lua.LUA_REGISTRYINDEX)

	// Register before setting up the sandbox: these functions will be restored
	// together with the sandbox.
	// The closure allows access to the external logger.
	luaDebug := func(L *lua.State) int { return 0 }
	if logPrint != nil {
		luaDebug = func(L *lua.State) int {
			var arglist []interface{}
			nargs := L.GetTop()
			for i := 1; i <= nargs; i++ {
				if L.IsString(i) {
					arglist = append(arglist, L.ToString(i))
				}
			}
			logPrint(arglist...)
			return 0
		}
	}

	sandboxRegister(L, "debug", luaDebug)
	sandboxRegister(L, "stringnorm", stringNorm)
	sandboxRegister(L, "stringrel", stringRel)

	// Purge _G from everything but the content of the whitelist.
	err = L.DoString(luaSetSandbox)
	if err != nil {
		log.Fatal("Cannot load function to set sandbox", err)
	}
	L.PushString(registryWhitelist)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	err = L.Call(1, 0)
	if err != nil {
		log.Fatal("Failed to set sandbox", err)
	}

	return L, nil
}

// SandboxCompileScripts transfers the script buffer to the Lua state L and
// references them in LUA_REGISTRYINDEX.
func SandboxCompileScripts(L *lua.State, scripts []scriptBuffer) {
	L.PushString(registryScripts)
	L.NewTable()
	for _, script := range scripts {
		L.PushString(script.path)
		err := L.LoadString(script.buf)
		if err != 0 {
			log.Fatalf("%s: %s", script.path, L.ToString(-1))
			L.Pop(2)
		} else {
			L.SetTable(-3)
		}
	}
	L.SetTable(lua.LUA_REGISTRYINDEX)
}

func outputNumbersToStrings(L *lua.State) {
	L.GetGlobal("output")

	if !L.IsTable(-1) {
		L.NewTable()
		L.SetGlobal("output")
	}

	L.GetField(-1, "tags")
	if L.IsTable(-1) {
		// First key.
		L.PushNil()
		for L.Next(-2) != 0 {
			// Use 'key' at index -2 and 'value' at index -1.
			if L.IsString(-2) && L.IsString(-1) {
				// Convert numbers to strings.
				L.ToString(-1)
				L.SetField(-3, L.ToString(-2))
			} else {
				// Remove 'value' and keep 'key' for next iteration.
				L.Pop(1)
			}
		}
	}
	L.Pop(1)

	L.Pop(1)
}

// RunScript executes script named 'script' with 'input' and 'output' set as global variable.
// Any change made to 'input' is discarded. Change to 'output' are transfered
// back to Go on every script call to guarantee type consistency across script
// calls (Lua is dynamically typed).
func RunScript(L *lua.State, script string, input *inputInfo, output *outputInfo) error {
	// Restore the sandbox.
	err := L.DoString(luaRestoreSandbox)
	if err != nil {
		log.Fatal("Cannot load function to restore sandbox", err)
	}
	L.PushString(registryWhitelist)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	err = L.Call(1, 0)
	if err != nil {
		log.Fatal("Failed to restore sandbox", err)
	}

	goToLua(L, "input", *input)
	goToLua(L, "output", *output)

	// Shortcut (mostly for prescript and postscript).
	L.GetGlobal("input")
	L.GetField(-1, "tags")
	L.SetGlobal("i")
	L.Pop(1)
	L.GetGlobal("output")
	L.GetField(-1, "tags")
	L.SetGlobal("o")
	L.Pop(1)

	// Call the compiled script.
	L.PushString(registryScripts)
	L.GetTable(lua.LUA_REGISTRYINDEX)
	L.PushString(script)
	if L.IsTable(-2) {
		L.GetTable(-2)
		if L.IsFunction(-1) {
			err := L.Call(0, 0)
			if err != nil {
				L.SetTop(0)
				return fmt.Errorf("%s", err)
			}
		} else {
			L.Pop(1)
		}
	} else {
		L.Pop(1)
	}
	L.Pop(1)

	// We allow tags to be numbers for convenience.
	outputNumbersToStrings(L)

	L.GetGlobal("output")
	r := luar.LuaToGo(L, reflect.TypeOf(*output), -1)
	L.Pop(1)

	*output = r.(outputInfo)

	return nil
}

func LoadConfig(config string, options interface{}) {
	L, err := MakeSandbox(log.Println)
	defer L.Close()

	err = L.DoFile(config)
	if err != nil {
		log.Fatalf("Error loading config: %s", err)
	}

	L.GetGlobal("_G")
	r := luar.LuaToGo(L, reflect.TypeOf(options), -1)
	L.Pop(1)

	v := reflect.ValueOf(options)
	v.Elem().Set(reflect.ValueOf(r).Elem())
}
<|endoftext|>


<commit_before>package nummethod

import "reflect"

type FooBar interface {
	foo()
	Bar()
}

type O struct {
	FooBar
}

func Num(o O) int {
	v := reflect.ValueOf(in)
	return v.Field(0).NumMethod()
}
<commit_msg>nummethod: fix tests<commit_after>package nummethod

import "reflect"

type FooBar interface {
	foo()
	Bar()
}

type O struct {
	FooBar
}

func Num(in interface{}) int {
	v := reflect.ValueOf(in)
	return v.Field(0).NumMethod()
}
<|endoftext|>


<commit_before>package virt

import (
	"errors"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"labix.org/v2/mgo/bson"
)

func (vm *VM) Start() error {
	if out, err := exec.Command("/usr/bin/lxc-start", "--name", vm.String(), "--daemon").CombinedOutput(); err != nil {
		return commandError("lxc-start failed.", err, out)
	}
	return vm.WaitForState("RUNNING", time.Second)
}

func (vm *VM) Stop() error {
	if out, err := exec.Command("/usr/bin/lxc-stop", "--name", vm.String()).CombinedOutput(); err != nil {
		return commandError("lxc-stop failed.", err, out)
	}
	return vm.WaitForState("STOPPED", time.Second)
}

func (vm *VM) Shutdown() error {
	if out, err := exec.Command("/usr/bin/lxc-shutdown", "--name", vm.String()).CombinedOutput(); err != nil {
		if vm.GetState() != "STOPPED" {
			return commandError("lxc-shutdown failed.", err, out)
		}
	}
	vm.WaitForState("STOPPED", 5*time.Second) // may time out, then vm is force stopped
	return vm.Stop()
}

func (vm *VM) AttachCommand(uid int, tty string, command ...string) *exec.Cmd {
	args := []string{"--name", vm.String()}
	if tty != "" {
		args = append(args, "--tty", tty)
	}
	args = append(args, "--", "/usr/bin/sudo", "-i", "-u", "#"+strconv.Itoa(uid), "--")
	args = append(args, command...)
	cmd := exec.Command("/usr/bin/lxc-attach", args...)
	cmd.Env = []string{"TERM=xterm-256color"}
	return cmd
}

func GetVMState(vmId bson.ObjectId) string {
	out, err := exec.Command("/usr/bin/lxc-info", "--name", VMName(vmId), "--state").CombinedOutput()
	if err != nil {
		lastError = commandError("lxc-info failed ", err, out)
		return "UNKNOWN"
	}
	return strings.TrimSpace(string(out)[6:])
}

func (vm *VM) GetState() string {
	return GetVMState(vm.Id)
}

func (vm *VM) WaitForState(state string, timeout time.Duration) error {
	tryUntil := time.Now().Add(timeout)
	for vm.GetState() != state {
		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM state.")
		}
		time.Sleep(time.Second / 10)
	}
	return nil
}

func (vm *VM) SendMessageToVMUsers(message string) error {
	cmd := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(), "--", "/usr/bin/wall", "--nobanner")
	cmd.Stdin = strings.NewReader(message)
	if out, err := cmd.CombinedOutput(); err != nil {
		return commandError("wall failed.", err, out)
	}
	return nil
}

func (vm *VM) WaitForNetwork() error {
	timeout := time.Second * 5
	isNetworkUp := func() bool {
		// neglect error because it's not important and we also going to timeout
		out, _ := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
			"--", "/bin/cat", "/sys/class/net/eth0/operstate").CombinedOutput()

		if strings.TrimSpace(string(out)) == "up" {
			return true
		}

		return false
	}

	tryUntil := time.Now().Add(timeout)
	for {
		if up := isNetworkUp(); up {
			return nil
		}

		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM Network state.")
		}

		time.Sleep(time.Millisecond * 100)
	}
}
<commit_msg>Ensure screen is also available before declaring the VM up<commit_after>package virt

import (
	"errors"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"labix.org/v2/mgo/bson"
)

func (vm *VM) Start() error {
	if out, err := exec.Command("/usr/bin/lxc-start", "--name", vm.String(), "--daemon").CombinedOutput(); err != nil {
		return commandError("lxc-start failed.", err, out)
	}
	return vm.WaitForState("RUNNING", time.Second)
}

func (vm *VM) Stop() error {
	if out, err := exec.Command("/usr/bin/lxc-stop", "--name", vm.String()).CombinedOutput(); err != nil {
		return commandError("lxc-stop failed.", err, out)
	}
	return vm.WaitForState("STOPPED", time.Second)
}

func (vm *VM) Shutdown() error {
	if out, err := exec.Command("/usr/bin/lxc-shutdown", "--name", vm.String()).CombinedOutput(); err != nil {
		if vm.GetState() != "STOPPED" {
			return commandError("lxc-shutdown failed.", err, out)
		}
	}
	vm.WaitForState("STOPPED", 5*time.Second) // may time out, then vm is force stopped
	return vm.Stop()
}

func (vm *VM) AttachCommand(uid int, tty string, command ...string) *exec.Cmd {
	args := []string{"--name", vm.String()}
	if tty != "" {
		args = append(args, "--tty", tty)
	}
	args = append(args, "--", "/usr/bin/sudo", "-i", "-u", "#"+strconv.Itoa(uid), "--")
	args = append(args, command...)
	cmd := exec.Command("/usr/bin/lxc-attach", args...)
	cmd.Env = []string{"TERM=xterm-256color"}
	return cmd
}

func GetVMState(vmId bson.ObjectId) string {
	out, err := exec.Command("/usr/bin/lxc-info", "--name", VMName(vmId), "--state").CombinedOutput()
	if err != nil {
		lastError = commandError("lxc-info failed ", err, out)
		return "UNKNOWN"
	}
	return strings.TrimSpace(string(out)[6:])
}

func (vm *VM) GetState() string {
	return GetVMState(vm.Id)
}

func (vm *VM) WaitForState(state string, timeout time.Duration) error {
	tryUntil := time.Now().Add(timeout)
	for vm.GetState() != state {
		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM state.")
		}
		time.Sleep(time.Second / 10)
	}
	return nil
}

func (vm *VM) SendMessageToVMUsers(message string) error {
	cmd := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(), "--", "/usr/bin/wall", "--nobanner")
	cmd.Stdin = strings.NewReader(message)
	if out, err := cmd.CombinedOutput(); err != nil {
		return commandError("wall failed.", err, out)
	}
	return nil
}

func (vm *VM) WaitForNetwork() error {
	timeout := time.Second * 5
	isNetworkUp := func() bool {
		// neglect error because it's not important and we also going to timeout
		out, _ := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
			"--", "/bin/cat", "/sys/class/net/eth0/operstate").CombinedOutput()

		if strings.TrimSpace(string(out)) == "up" {
			if out, err := exec.Command("/usr/bin/lxc-attach", "--name", vm.String(),
				"--", "/bin/stat", "/usr/bin/screen").CombinedOutput(); err != nil {
				return true
			} else {
				return false
			}
			return false
		}
	}
	tryUntil := time.Now().Add(timeout)
	for {
		if up := isNetworkUp(); up {
			return nil
		}

		if time.Now().After(tryUntil) {
			return errors.New("Timeout while waiting for VM Network state.")
		}

		time.Sleep(time.Millisecond * 100)
	}
}
<|endoftext|>


<commit_before>package hanoi

import (
	"container/list"
	"fmt"
)

// Tower ...
type Tower struct {
	*list.List

	name string
}

// New ...
func New(name string) *Tower {
	return &Tower{list.New(), name}
}

// Push ...
func (t *Tower) Push(value int) (e error) {
	if value == 0 {
		e = fmt.Errorf("attempted zero-value push")
	} else {
		t.PushBack(value)
	}
	return
}

// Pop ...
func (t *Tower) Pop() (int, error) {
	if lastElement := t.Back(); lastElement != nil {
		return t.Remove(lastElement).(int), nil
	}
	return 0, fmt.Errorf("cannot pop from empty stack")
}

// Peek ...
func (t *Tower) Peek() (int, error) {
	if lastElement := t.Back(); lastElement != nil {
		return lastElement.Value.(int), nil
	}
	return 0, fmt.Errorf("cannot peek into empty stack")
}

func (t *Tower) String() string {
	str := ""
	if len(t.name) > 0 {
		str = t.name + ": "
	}
	for le := t.Front(); le != nil; le = le.Next() {
		str += fmt.Sprintf("%v ", le.Value)
	}
	return str
}

func makeLegalMove(stepCount int, t1, t2 *Tower) {
	value1, _ := t1.Peek()
	value2, _ := t2.Peek()
	if value1 == value2 {
		panic(fmt.Sprintf("discs with size = %d found in %s and %s", value1, t1.name, t2.name))
	}

	switch {
	case value2 == 0:
		fallthrough
	case value1 != 0 && value1 < value2:
		fmt.Printf("%d. Move from %s to %s\n", stepCount, t1.name, t2.name)
		t1.Pop()
		t2.Push(value1)
	case value1 == 0:
		fallthrough
	case value2 != 0 && value2 < value1:
		fmt.Printf("%d. Move from %s to %s\n", stepCount, t2.name, t1.name)
		t2.Pop()
		t1.Push(value2)
	}
}

func recursiveSolution(discCount int, src, dst, aux *Tower, moveFn func(src, dst *Tower), dumpFn func()) {
	if discCount == 1 {
		moveFn(src, dst)
		dumpFn()
		return
	}
	recursiveSolution(discCount-1, src, aux, dst, moveFn, dumpFn)
	recursiveSolution(1, src, dst, aux, moveFn, dumpFn)
	recursiveSolution(discCount-1, aux, dst, src, moveFn, dumpFn)
}

// RecursiveSolution ...
func RecursiveSolution(src, dst, aux *Tower) {
	discCount := src.Len()
	if discCount <= 0 || dst.Len() != 0 || aux.Len() != 0 {
		panic("Illegal initial state of the Towers")
	}

	dumpFn := func() {
		dumpTowers("\t", src, aux, dst)
	}
	stepCount := 0
	moveFn := func(src, dst *Tower) {
		stepCount++
		srcLen := src.Len()
		makeLegalMove(stepCount, src, dst)
		if src.Len() > srcLen {
			panic("Unexpected move made")
		}
	}
	recursiveSolution(discCount, src, dst, aux, moveFn, dumpFn)
}

// IterativeSolution ...
func IterativeSolution(src, dst, aux *Tower) {
	if src == nil || aux == nil || dst == nil {
		return
	}
	discCount := src.Len()
	if discCount == 0 || dst.Len() != 0 || aux.Len() != 0 {
		panic("Illegal initial state of the Towers")
	}

	var t1, t2 *Tower
	if discCount%2 == 0 {
		t1, t2 = aux, dst
	} else {
		t1, t2 = dst, aux
	}
	moves := [][]*Tower{
		{src, t1},
		{src, t2},
		{aux, dst},
	}
	for i := 0; dst.Len() != discCount; i++ {
		m := i % 3
		makeLegalMove(i+1, moves[m][0], moves[m][1])
		dumpTowers("\t", src, aux, dst)
	}
}

func dumpTowers(padding string, towers ...*Tower) {
	for _, t := range towers {
		fmt.Printf("%s%s\n", padding, t)
	}
}

// Run ...
func Run() {
	towerA, towerB, towerC := New("Tower A"), New("Tower B"), New("Tower C")
	discCount := 5
	for i := 0; i < discCount; i++ {
		towerA.Push(discCount - i)
	}

	fmt.Println("Start ...")
	dumpTowers("", towerA, towerB, towerC)
	fmt.Println()

	fmt.Printf("Goal: to move all the discs from '%s' to '%s'\n", towerA, towerC)
	fmt.Println()

	// IterativeSolution(towerA, towerC, towerB)
	RecursiveSolution(towerA, towerC, towerB)

	fmt.Println("\n==== End ====")
}
<commit_msg>fixed a minor bug<commit_after>package hanoi

import (
	"container/list"
	"fmt"
)

// Tower ...
type Tower struct {
	*list.List

	name string
}

// New ...
func New(name string) *Tower {
	return &Tower{list.New(), name}
}

// Push ...
func (t *Tower) Push(value int) (e error) {
	if value == 0 {
		e = fmt.Errorf("attempted zero-value push")
	} else {
		t.PushBack(value)
	}
	return
}

// Pop ...
func (t *Tower) Pop() (int, error) {
	if lastElement := t.Back(); lastElement != nil {
		return t.Remove(lastElement).(int), nil
	}
	return 0, fmt.Errorf("cannot pop from empty stack")
}

// Peek ...
func (t *Tower) Peek() (int, error) {
	if lastElement := t.Back(); lastElement != nil {
		return lastElement.Value.(int), nil
	}
	return 0, fmt.Errorf("cannot peek into empty stack")
}

func (t *Tower) String() string {
	str := ""
	if len(t.name) > 0 {
		str = t.name + ": "
	}
	for le := t.Front(); le != nil; le = le.Next() {
		str += fmt.Sprintf("%v ", le.Value)
	}
	return str
}

func makeLegalMove(stepCount int, t1, t2 *Tower) {
	value1, _ := t1.Peek()
	value2, _ := t2.Peek()
	if value1 == value2 {
		panic(fmt.Sprintf("discs with size = %d found in %s and %s", value1, t1.name, t2.name))
	}

	switch {
	case value2 == 0:
		fallthrough
	case value1 != 0 && value1 < value2:
		fmt.Printf("%d. Move from %s to %s\n", stepCount, t1.name, t2.name)
		t1.Pop()
		t2.Push(value1)
	case value1 == 0:
		fallthrough
	case value2 != 0 && value2 < value1:
		fmt.Printf("%d. Move from %s to %s\n", stepCount, t2.name, t1.name)
		t2.Pop()
		t1.Push(value2)
	}
}

func recursiveSolution(discCount int, src, dst, aux *Tower, moveFn func(src, dst *Tower), dumpFn func()) {
	if discCount == 1 {
		moveFn(src, dst)
		dumpFn()
		return
	}
	recursiveSolution(discCount-1, src, aux, dst, moveFn, dumpFn)
	recursiveSolution(1, src, dst, aux, moveFn, dumpFn)
	recursiveSolution(discCount-1, aux, dst, src, moveFn, dumpFn)
}

// RecursiveSolution ...
func RecursiveSolution(src, dst, aux *Tower) {
	discCount := src.Len()
	if discCount <= 0 || dst.Len() != 0 || aux.Len() != 0 {
		panic("Illegal initial state of the Towers")
	}

	dumpFn := func() {
		dumpTowers("\t", src, aux, dst)
	}
	stepCount := 0
	moveFn := func(src, dst *Tower) {
		stepCount++
		srcLen := src.Len()
		makeLegalMove(stepCount, src, dst)
		if src.Len() > srcLen {
			panic("Unexpected move made")
		}
	}
	recursiveSolution(discCount, src, dst, aux, moveFn, dumpFn)
}

// IterativeSolution ...
func IterativeSolution(src, dst, aux *Tower) {
	if src == nil || aux == nil || dst == nil {
		return
	}
	discCount := src.Len()
	if discCount == 0 || dst.Len() != 0 || aux.Len() != 0 {
		panic("Illegal initial state of the Towers")
	}

	var t1, t2 *Tower
	if discCount%2 == 0 {
		t1, t2 = aux, dst
	} else {
		t1, t2 = dst, aux
	}
	moves := [][]*Tower{
		{src, t1},
		{src, t2},
		{aux, dst},
	}
	for i := 0; dst.Len() != discCount; i++ {
		m := i % 3
		makeLegalMove(i+1, moves[m][0], moves[m][1])
		dumpTowers("\t", src, aux, dst)
	}
}

func dumpTowers(padding string, towers ...*Tower) {
	for _, t := range towers {
		fmt.Printf("%s%s\n", padding, t)
	}
}

// Run ...
func Run() {
	towerA, towerB, towerC := New("Tower A"), New("Tower B"), New("Tower C")
	discCount := 3
	for i := 0; i < discCount; i++ {
		towerA.Push(discCount - i)
	}

	fmt.Println("Start ...")
	dumpTowers("", towerA, towerB, towerC)
	fmt.Println()

	fmt.Printf("Goal: to move all the discs from '%s' to '%s'\n", towerA.name, towerC.name)
	fmt.Println()

	// IterativeSolution(towerA, towerC, towerB)
	RecursiveSolution(towerA, towerC, towerB)

	fmt.Println("\n==== End ====")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcapgo"
	"golang.org/x/sync/errgroup"
	"os"
	"reflect"
	"regexp"
	"strconv"
)

// reconstructOptions represents all options for reconstruction
type reconstructOptions struct {
	BpP    int
	LimitX int
	LimitY int
	Scale  int
	Dtg    string
	Source string
	Filter string
}

// svgOptions represents various options for reconstruction
type svgOptions struct {
	regex             string
	reconstructOption string
}

func createPacket(ch chan<- []byte, packet []int, bpP int) error {
	var buf []byte
	var tmp int
	switch bpP {
	case 24:
		for _, i := range packet {
			buf = append(buf, byte(i))
		}
	case 3, 6, 9, 12, 15, 18, 21:
		var slice []int
		for i := 0; i < len(packet); i = i + 1 {
			if i%(bpP*8) == 0 && i != 0 {
				bytes := createBytes(slice, bpP/3)
				buf = append(buf, bytes...)
				slice = slice[:0]
			}
			slice = append(slice, packet[i])
		}
		bytes := createBytes(slice, bpP/3)
		buf = append(buf, bytes...)
	case 1:
		var j int
		for i := 0; i < len(packet); i = i + 3 {
			if j%8 == 0 && j != 0 {
				buf = append(buf, byte(tmp))
				tmp = 0
			}
			if packet[i] != 0 {
				tmp = tmp | (1 << uint8(7-j%8))
			}
			j = j + 1
		}
		if tmp != 0 {
			buf = append(buf, byte(tmp))
		}
	default:
		return fmt.Errorf("This format is not supported so far")
	}

	ch <- buf

	return nil
}

func checkVersion(parse *[]svgOptions, version string) (string, error) {

	scale := svgOptions{regex: "\\s+Scale=(\\d+)$", reconstructOption: "Scale"}
	*parse = append(*parse, scale)
	bpP := svgOptions{regex: "\\s+BitsPerPixel=(\\d+)$", reconstructOption: "BpP"}
	*parse = append(*parse, bpP)

	switch version {
	case "0.0.3":
		dtg := svgOptions{regex: "\\s+DTG=(\\w+)$", reconstructOption: "Dtg"}
		*parse = append(*parse, dtg)
		source := svgOptions{regex: "\\s+Source=(\\w+)$", reconstructOption: "Source"}
		*parse = append(*parse, source)
		filter := svgOptions{regex: "\\s+Filter=(\\w+)$", reconstructOption: "Filter"}
		*parse = append(*parse, filter)
		fallthrough
	case "0.0.4":
	default:
		return "", fmt.Errorf("Unrecognized version: %s", version)
	}
	return version, nil
}

func checkHeader(svg *bufio.Scanner) (reconstructOptions, error) {
	var options reconstructOptions
	var variant string
	var header bool = false
	var parseOptions []svgOptions
	var optionIndex int

	limits, err := regexp.Compile("^<svg width=\"(\\d+)\" height=\"(\\d+)\">$")
	if err != nil {
		return options, err
	}
	headerStart, err := regexp.Compile("^<!--$")
	if err != nil {
		return options, err
	}
	headerEnd, err := regexp.Compile("^-->$")
	if err != nil {
		return options, err
	}
	version, err := regexp.Compile("\\s+goNetViz \"([0-9.]+)\"$")
	if err != nil {
		return options, err
	}

	for svg.Scan() {
		switch {
		case options.LimitX == 0 && options.LimitY == 0 && header == false:
			matches := limits.FindStringSubmatch(svg.Text())
			if len(matches) == 3 {
				options.LimitX, _ = strconv.Atoi(matches[1])
				options.LimitY, _ = strconv.Atoi(matches[2])
			}
		case header == false:
			if headerStart.MatchString(svg.Text()) {
				header = true
			}
		case len(variant) == 0:
			matches := version.FindStringSubmatch(svg.Text())
			if len(matches) == 2 {
				variant, err = checkVersion(&parseOptions, matches[1])
				if err != nil {
					return options, fmt.Errorf("Unrecognized version: %s", matches[1])
				}
			}
		default:
			if optionIndex > len(parseOptions) {
				return options, fmt.Errorf("Option index is out of range")
			}
			regex, err := regexp.Compile(parseOptions[optionIndex].regex)
			if err != nil {
				return options, err
			}
			matches := regex.FindStringSubmatch(svg.Text())
			if len(matches) == 2 {
				option := reflect.ValueOf(&options).Elem().FieldByName(parseOptions[optionIndex].reconstructOption)

				switch option.Kind() {
				case reflect.Int:
					new, _ := strconv.Atoi(matches[1])
					option.SetInt(int64(new))
				case reflect.String:
					option.SetString(matches[1])
				default:
					return options, fmt.Errorf("Unhandeld option type")
				}
				optionIndex += 1
			} else {
				if headerEnd.MatchString(svg.Text()) {
					return options, nil
				}
			}
		}
	}
	return options, fmt.Errorf("No end of header found")
}

func extractInformation(g *errgroup.Group, ch chan []byte, cfg configs) error {
	inputfile, err := os.Open(cfg.file)
	if err != nil {
		return fmt.Errorf("Could not open file %s: %s\n", cfg.file, err.Error())
	}
	defer inputfile.Close()
	svg := bufio.NewScanner(inputfile)
	var yLast int
	var packet []int
	defer close(ch)

	opt, err := checkHeader(svg)
	if err != nil {
		return err
	}

	pixel, err := regexp.Compile("^<rect x=\"(\\d+)\" y=\"(\\d+)\" width=\"\\d+\" height=\"\\d+\" style=\"fill:rgb\\((\\d+),(\\d+),(\\d+)\\)\" />$")
	if err != nil {
		return err
	}
	svgEnd, err := regexp.Compile("</svg>")
	if err != nil {
		return err
	}

	for svg.Scan() {
		matches := pixel.FindStringSubmatch(svg.Text())
		if len(matches) == 6 {
			pixelX, _ := strconv.Atoi(matches[1])
			pixelY, _ := strconv.Atoi(matches[2])
			if pixelY != yLast {
				yLast = pixelY
				if err := createPacket(ch, packet, opt.BpP); err != nil {
					return err
				}
				packet = packet[:0]
			}
			if pixelX >= opt.LimitX {
				return fmt.Errorf("x-coordinate (%d) is bigger than the limit (%d)\n", pixelX, opt.LimitX)
			}
			r, _ := strconv.Atoi(matches[3])
			g, _ := strconv.Atoi(matches[4])
			b, _ := strconv.Atoi(matches[5])
			packet = append(packet, r, g, b)
		} else if svgEnd.MatchString(svg.Text()) {
			fmt.Println("End matches")
			if len(packet) != 0 {
				return createPacket(ch, packet, opt.BpP)
			}
		}
	}
	return nil
}

func createPcap(g *errgroup.Group, ch chan []byte, cfg configs) error {
	filename := cfg.prefix
	filename += ".pcap"
	output, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("Could not create file %s: %s\n", filename, err.Error())
	}
	defer output.Close()
	w := pcapgo.NewWriter(output)
	w.WriteFileHeader(65536, layers.LinkTypeEthernet)

	for i, ok := <-ch; ok; i, ok = <-ch {
		w.WritePacket(gopacket.CaptureInfo{CaptureLength: len(i), Length: len(i), InterfaceIndex: 0}, i)
	}

	return nil
}

func reconstruct(g *errgroup.Group, cfg configs) error {
	ch := make(chan []byte)

	go extractInformation(g, ch, cfg)

	g.Go(func() error {
		return createPcap(g, ch, cfg)
	})

	return g.Wait()
}
<commit_msg>Code refactoring<commit_after>package main

import (
	"bufio"
	"fmt"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcapgo"
	"golang.org/x/sync/errgroup"
	"os"
	"reflect"
	"regexp"
	"strconv"
)

// reconstructOptions represents all options for reconstruction
type reconstructOptions struct {
	BpP    int
	LimitX int
	LimitY int
	Scale  int
	Dtg    string
	Source string
	Filter string
}

// svgOptions represents various options for reconstruction
type svgOptions struct {
	regex             string
	reconstructOption string
}

func createPacket(ch chan<- []byte, packet []int, bpP int) error {
	var buf []byte
	var tmp int
	switch bpP {
	case 24:
		for _, i := range packet {
			buf = append(buf, byte(i))
		}
	case 3, 6, 9, 12, 15, 18, 21:
		var slice []int
		for i := 0; i < len(packet); i = i + 1 {
			if i%(bpP*8) == 0 && i != 0 {
				bytes := createBytes(slice, bpP/3)
				buf = append(buf, bytes...)
				slice = slice[:0]
			}
			slice = append(slice, packet[i])
		}
		bytes := createBytes(slice, bpP/3)
		buf = append(buf, bytes...)
	case 1:
		var j int
		for i := 0; i < len(packet); i = i + 3 {
			if j%8 == 0 && j != 0 {
				buf = append(buf, byte(tmp))
				tmp = 0
			}
			if packet[i] != 0 {
				tmp = tmp | (1 << uint8(7-j%8))
			}
			j = j + 1
		}
		if tmp != 0 {
			buf = append(buf, byte(tmp))
		}
	default:
		return fmt.Errorf("This format is not supported so far")
	}

	ch <- buf

	return nil
}

func checkVersion(parse *[]svgOptions, version string) (string, error) {

	scale := svgOptions{regex: "\\s+Scale=(\\d+)$", reconstructOption: "Scale"}
	*parse = append(*parse, scale)
	bpP := svgOptions{regex: "\\s+BitsPerPixel=(\\d+)$", reconstructOption: "BpP"}
	*parse = append(*parse, bpP)

	switch version {
	case "0.0.3":
		dtg := svgOptions{regex: "\\s+DTG=(\\w+)$", reconstructOption: "Dtg"}
		*parse = append(*parse, dtg)
		source := svgOptions{regex: "\\s+Source=(\\w+)$", reconstructOption: "Source"}
		*parse = append(*parse, source)
		filter := svgOptions{regex: "\\s+Filter=(\\w+)$", reconstructOption: "Filter"}
		*parse = append(*parse, filter)
		fallthrough
	case "0.0.4":
	default:
		return "", fmt.Errorf("Unrecognized version: %s", version)
	}
	return version, nil
}

func checkHeader(svg *bufio.Scanner) (reconstructOptions, error) {
	var options reconstructOptions
	var variant string
	var header bool = false
	var parseOptions []svgOptions
	var optionIndex int

	limits, err := regexp.Compile("^<svg width=\"(\\d+)\" height=\"(\\d+)\">$")
	if err != nil {
		return options, err
	}
	headerStart, err := regexp.Compile("^<!--$")
	if err != nil {
		return options, err
	}
	headerEnd, err := regexp.Compile("^-->$")
	if err != nil {
		return options, err
	}
	version, err := regexp.Compile("\\s+goNetViz \"([0-9.]+)\"$")
	if err != nil {
		return options, err
	}

	for svg.Scan() {
		line := svg.Text()
		switch {
		case options.LimitX == 0 && options.LimitY == 0 && header == false:
			matches := limits.FindStringSubmatch(line)
			if len(matches) == 3 {
				options.LimitX, _ = strconv.Atoi(matches[1])
				options.LimitY, _ = strconv.Atoi(matches[2])
			}
		case header == false:
			if headerStart.MatchString(line) {
				header = true
			}
		case len(variant) == 0:
			matches := version.FindStringSubmatch(line)
			if len(matches) == 2 {
				variant, err = checkVersion(&parseOptions, matches[1])
				if err != nil {
					return options, fmt.Errorf("Unrecognized version: %s", matches[1])
				}
			}
		default:
			if optionIndex > len(parseOptions) {
				return options, fmt.Errorf("Option index is out of range")
			}
			regex, err := regexp.Compile(parseOptions[optionIndex].regex)
			if err != nil {
				return options, err
			}
			matches := regex.FindStringSubmatch(line)
			if len(matches) == 2 {
				option := reflect.ValueOf(&options).Elem().FieldByName(parseOptions[optionIndex].reconstructOption)

				switch option.Kind() {
				case reflect.Int:
					new, _ := strconv.Atoi(matches[1])
					option.SetInt(int64(new))
				case reflect.String:
					option.SetString(matches[1])
				default:
					return options, fmt.Errorf("Unhandeld option type")
				}
				optionIndex += 1
			} else {
				if headerEnd.MatchString(line) {
					return options, nil
				}
			}
		}
	}
	return options, fmt.Errorf("No end of header found")
}

func extractInformation(g *errgroup.Group, ch chan []byte, cfg configs) error {
	inputfile, err := os.Open(cfg.file)
	if err != nil {
		return fmt.Errorf("Could not open file %s: %s\n", cfg.file, err.Error())
	}
	defer inputfile.Close()
	svg := bufio.NewScanner(inputfile)
	var yLast int
	var packet []int
	defer close(ch)

	opt, err := checkHeader(svg)
	if err != nil {
		return err
	}

	pixel, err := regexp.Compile("^<rect x=\"(\\d+)\" y=\"(\\d+)\" width=\"\\d+\" height=\"\\d+\" style=\"fill:rgb\\((\\d+),(\\d+),(\\d+)\\)\" />$")
	if err != nil {
		return err
	}
	svgEnd, err := regexp.Compile("</svg>")
	if err != nil {
		return err
	}

	for svg.Scan() {
		line := svg.Text()
		matches := pixel.FindStringSubmatch(line)
		if len(matches) == 6 {
			pixelX, _ := strconv.Atoi(matches[1])
			pixelY, _ := strconv.Atoi(matches[2])
			if pixelY != yLast {
				yLast = pixelY
				if err := createPacket(ch, packet, opt.BpP); err != nil {
					return err
				}
				packet = packet[:0]
			}
			if pixelX >= opt.LimitX {
				return fmt.Errorf("x-coordinate (%d) is bigger than the limit (%d)\n", pixelX, opt.LimitX)
			}
			r, _ := strconv.Atoi(matches[3])
			g, _ := strconv.Atoi(matches[4])
			b, _ := strconv.Atoi(matches[5])
			packet = append(packet, r, g, b)
		} else if svgEnd.MatchString(line) {
			fmt.Println("End matches")
			if len(packet) != 0 {
				return createPacket(ch, packet, opt.BpP)
			}
		}
	}
	return nil
}

func createPcap(g *errgroup.Group, ch chan []byte, cfg configs) error {
	filename := cfg.prefix
	filename += ".pcap"
	output, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("Could not create file %s: %s\n", filename, err.Error())
	}
	defer output.Close()
	w := pcapgo.NewWriter(output)
	w.WriteFileHeader(65536, layers.LinkTypeEthernet)

	for i, ok := <-ch; ok; i, ok = <-ch {
		w.WritePacket(gopacket.CaptureInfo{CaptureLength: len(i), Length: len(i), InterfaceIndex: 0}, i)
	}

	return nil
}

func reconstruct(g *errgroup.Group, cfg configs) error {
	ch := make(chan []byte)

	go extractInformation(g, ch, cfg)

	g.Go(func() error {
		return createPcap(g, ch, cfg)
	})

	return g.Wait()
}
<|endoftext|>


<commit_before>package ekstep

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/gorilla/mux"
	"github.com/projectOpenRAP/OpenRAP/apiserver/config"
)

type EkstepConfig struct {
	router      *mux.Router
	contentJson ContentListingJson
	//	contentJson ContentHomeConfig
	deviceConfig *config.DeviceConfig
}

var EkstepConfigGlobal *EkstepConfig
var logger *config.Tracelog

var routes map[string]http.HandlerFunc = map[string]http.HandlerFunc{
	//API for homepage
	"/api/page/v1/assemble/org.ekstep.genie.content.home":     contentHomeHandler,
	"/data/v3/pageApi/assemble/org.ekstep.genie.content.home": contentHomeHandler,

	//API for specific ecar
	"/api/learning/v2/content/{contentID}": contentIdHandler,
	"/content/v3/read/{contentID}":         contentIdHandler,

	//API for different types of search
	"/api/search/v2/search": searchHandler,
	"/composite/v3/search":  searchHandler,

	//API for telemetry
	"/api/telemetry/v1/telemetry": telemetryHandler,
	"/data/v3/telemetry":          telemetryHandler,

	//Private api
	//API to add/remove ecar from search index
	"/api/ekstepdb/{jsonfile}": ekstepIndexJsonFileHandler,
}

func EkstepInit(router *mux.Router) {
	c := &EkstepConfig{}

	//Load Device configuration
	c.deviceConfig = config.DeviceConfigGet()
	if c.deviceConfig == nil {
		logger.Error.Fatal("ES: Couldn't parse device config json")
	}
	logger = c.deviceConfig.Logger

	c.router = router
	c.contentJson = c.ContentListingJsonLoad()
	c.registerRoute()
	EkstepConfigGlobal = c

	//	ContentHomeConfigGlobal = m.contentJson
	//ContentHomeConfigGlobal = contentHomeConfigLoad()
	uuidInit()
	/*
		jd := config.DeviceDataJsonDirPath()
		if jd == nil {
			log.Fatal("Couldn't found json directory in config json")
		}

		indexDbPath := bleveDbDir + string(os.PathSeparator) + indexName
		log.Printf("index path: %s\n", indexDbPath)
		SearchInit(bleveDbDir, indexName, *jd)
	*/
	//SearchEngineInit(dbDir, indexName, jsonDir)
	SearchEngineInit("/var/www/ekstep/datadir", "es.db", "/var/www/ekstep/json_dir")
	logger.Trace.Println("ES module initialized...")
}

func (ms *EkstepConfig) ContentListingJsonLoad() ContentListingJson {
	var c ContentListingJson

	cj := ms.deviceConfig.ConfigJsonAbsFilename()

	raw, err := ioutil.ReadFile(cj)
	if err != nil {
		logger.Error.Fatalf("ES: Error opening content json file: %v", err)
		return c
	}
	json.Unmarshal(raw, &c)
	return c
}

func (c *EkstepConfig) registerRoute() error {
	for route, handler := range routes {
		c.router.HandleFunc(route, handler)
	}
	logger.Trace.Println("ES: Registered route for REST api")
	return nil
}

var RFd *os.File

func uuidInit() {
	f, err := os.Open("/dev/urandom")
	if err != nil {
		log.Fatal(err)
	}
	RFd = f
}

func UUIDGet() string {
	b := make([]byte, 16)
	RFd.Read(b)
	b[6] = (b[6] & 0x0f) | 0x40
	b[8] = (b[8] & 0x3f) | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
<commit_msg>added api endpoint for qa build<commit_after>package ekstep

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/gorilla/mux"
	"github.com/projectOpenRAP/OpenRAP/apiserver/config"
)

type EkstepConfig struct {
	router      *mux.Router
	contentJson ContentListingJson
	//	contentJson ContentHomeConfig
	deviceConfig *config.DeviceConfig
}

var EkstepConfigGlobal *EkstepConfig
var logger *config.Tracelog

var routes map[string]http.HandlerFunc = map[string]http.HandlerFunc{
	//API for homepage
	"/api/page/v1/assemble/org.ekstep.genie.content.home":     contentHomeHandler,
	"/data/v3/pageApi/assemble/org.ekstep.genie.content.home": contentHomeHandler,
	//QA api
	"/api/data/v3/pageApi/assemble/org.ekstep.genie.content.home": contentHomeHandler,

	//API for specific ecar
	"/api/learning/v2/content/{contentID}": contentIdHandler,
	"/content/v3/read/{contentID}":         contentIdHandler,
	//QA api
	"/api/content/v3/read/{contentID}": contentIdHandler,

	//API for different types of search
	"/api/search/v2/search": searchHandler,
	"/composite/v3/search":  searchHandler,
	//QA api
	"/api/composite/v3/search": searchHandler,

	//API for telemetry
	"/api/telemetry/v1/telemetry": telemetryHandler,
	"/data/v3/telemetry":          telemetryHandler,
	//QA api
	"/api/data/v3/telemetry": telemetryHandler,

	//Private api
	//API to add/remove ecar from search index
	"/api/ekstepdb/{jsonfile}": ekstepIndexJsonFileHandler,
}

func EkstepInit(router *mux.Router) {
	c := &EkstepConfig{}

	//Load Device configuration
	c.deviceConfig = config.DeviceConfigGet()
	if c.deviceConfig == nil {
		logger.Error.Fatal("ES: Couldn't parse device config json")
	}
	logger = c.deviceConfig.Logger

	c.router = router
	c.contentJson = c.ContentListingJsonLoad()
	c.registerRoute()
	EkstepConfigGlobal = c

	//	ContentHomeConfigGlobal = m.contentJson
	//ContentHomeConfigGlobal = contentHomeConfigLoad()
	uuidInit()
	/*
		jd := config.DeviceDataJsonDirPath()
		if jd == nil {
			log.Fatal("Couldn't found json directory in config json")
		}

		indexDbPath := bleveDbDir + string(os.PathSeparator) + indexName
		log.Printf("index path: %s\n", indexDbPath)
		SearchInit(bleveDbDir, indexName, *jd)
	*/
	//SearchEngineInit(dbDir, indexName, jsonDir)
	SearchEngineInit("/var/www/ekstep/datadir", "es.db", "/var/www/ekstep/json_dir")
	logger.Trace.Println("ES module initialized...")
}

func (ms *EkstepConfig) ContentListingJsonLoad() ContentListingJson {
	var c ContentListingJson

	cj := ms.deviceConfig.ConfigJsonAbsFilename()

	raw, err := ioutil.ReadFile(cj)
	if err != nil {
		logger.Error.Fatalf("ES: Error opening content json file: %v", err)
		return c
	}
	json.Unmarshal(raw, &c)
	return c
}

func (c *EkstepConfig) registerRoute() error {
	for route, handler := range routes {
		c.router.HandleFunc(route, handler)
	}
	logger.Trace.Println("ES: Registered route for REST api")
	return nil
}

var RFd *os.File

func uuidInit() {
	f, err := os.Open("/dev/urandom")
	if err != nil {
		log.Fatal(err)
	}
	RFd = f
}

func UUIDGet() string {
	b := make([]byte, 16)
	RFd.Read(b)
	b[6] = (b[6] & 0x0f) | 0x40
	b[8] = (b[8] & 0x3f) | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
<|endoftext|>


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

package git

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
	"time"

	"github.com/xanzy/go-gitlab"
)

const (
	invalidGitLabToken = "The token configured for GitLab group %s is not valid!"
)

// GetContent implements the Git interface
func (g *GitLab) GetContent(project, path string) (*File, interface{}, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	treeOpts := &gitlab.ListTreeOptions{
		Path: gitlab.String(path),
	}
	tree, resp, err := g.client.Repositories.ListTree(ns, treeOpts)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return nil, nil, nil
			case http.StatusUnauthorized:
				return nil, nil, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return nil, nil, fmt.Errorf("Error retrieving tree for %s: %v", path, err)
	}

	if len(tree) > 0 {
		var files []string
		for _, file := range tree {
			files = append(files, filepath.Join(path, file.Name))
		}

		return nil, files, nil
	}

	fileOpts := &gitlab.GetFileOptions{
		Ref: gitlab.String("master"),
	}
	file, resp, err := g.client.RepositoryFiles.GetFile(ns, path, fileOpts)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return nil, nil, nil
			case http.StatusUnauthorized:
				return nil, nil, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return nil, nil, fmt.Errorf("Error retrieving file %s: %v", path, err)
	}

	f := &File{
		Content: file.Content,
		SHA:     file.CommitID,
	}

	if file.Encoding == "base64" {
		content, err := base64.StdEncoding.DecodeString(file.Content)
		if err != nil {
			return nil, nil, fmt.Errorf("Error decoding file %s, %v", path, err)
		}

		f.Content = string(content)
	}

	return f, nil, nil
}

// CreateFile implements the Git interface
func (g *GitLab) CreateFile(project, path, msg string, usr *User, content []byte) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	opts := &gitlab.CreateFileOptions{
		Branch:        gitlab.String("master"),
		AuthorEmail:   &usr.Mail,
		AuthorName:    &usr.Name,
		Content:       gitlab.String(string(content)),
		CommitMessage: gitlab.String(msg),
	}
	_, resp, err := g.client.RepositoryFiles.CreateFile(ns, path, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error creating file %s: %v", path, err)
	}

	return g.shaOfLatestCommit(project)
}

// UpdateFile implements the Git interface
func (g *GitLab) UpdateFile(project, path, sha, msg string, usr *User, content []byte) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	opts := &gitlab.UpdateFileOptions{
		Branch:        gitlab.String("master"),
		AuthorEmail:   &usr.Mail,
		AuthorName:    &usr.Name,
		Content:       gitlab.String(string(content)),
		CommitMessage: gitlab.String(msg),
	}
	_, resp, err := g.client.RepositoryFiles.UpdateFile(ns, path, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error updating file %s: %v", path, err)
	}

	return g.shaOfLatestCommit(project)
}

// DeleteFile implements the Git interface
func (g *GitLab) DeleteFile(project, path, sha, msg string, usr *User) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	opts := &gitlab.DeleteFileOptions{
		Branch:        gitlab.String("master"),
		AuthorEmail:   &usr.Mail,
		AuthorName:    &usr.Name,
		CommitMessage: gitlab.String(msg),
	}
	resp, err := g.client.RepositoryFiles.DeleteFile(ns, path, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error deleting file %s: %v", path, err)
	}

	return g.shaOfLatestCommit(project)
}

// DeleteDirectory implements the Git interface
func (g *GitLab) DeleteDirectory(project, msg string, dir interface{}, usr *User) error {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	for _, file := range dir.([]string) {
		// Need a special case for when deleting data bag items
		fn := strings.TrimPrefix(file, "data_bags/")
		msg := fmt.Sprintf(msg, strings.TrimSuffix(fn, ".json"))

		opts := &gitlab.DeleteFileOptions{
			Branch:        gitlab.String("master"),
			AuthorEmail:   &usr.Mail,
			AuthorName:    &usr.Name,
			CommitMessage: gitlab.String(msg),
		}
		resp, err := g.client.RepositoryFiles.DeleteFile(ns, file, opts)
		if err != nil {
			if resp != nil && resp.StatusCode == http.StatusUnauthorized {
				return fmt.Errorf(invalidGitLabToken, g.group)
			}
			return fmt.Errorf("Error deleting file %s: %v", file, err)
		}
	}

	return nil
}

// GetDiff implements the Git interface
func (g *GitLab) GetDiff(project, user, sha string) (string, error) {
	u := fmt.Sprintf("/%s/%s/commit/%s.diff", g.group, project, sha)

	req, err := g.client.NewRequest("GET", u, nil, nil)
	if err != nil {
		return "", err
	}

	// Make sure we do not use the API path here!
	req.URL, err = req.URL.Parse(u)
	if err != nil {
		return "", err
	}

	var diff bytes.Buffer
	resp, err := g.client.Do(req, &diff)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error retrieving commit %s: %v", sha, err)
	}

	if diff.Len() == 0 {
		return "", nil
	}

	const layout = "Mon Jan 2 3:04 2006"
	t := time.Now()

	msg := fmt.Sprintf("Commit : %s\nDate   : %s\nUser   : %s\n
%s",
		sha,
		t.Format(layout),
		user,
		diff.String(),
	)

	return msg, nil
}

// GetArchiveLink implements the Git interface
func (g *GitLab) GetArchiveLink(project, tag string) (*url.URL, error) {
	ns := fmt.Sprintf("%s%2F%s", g.group, project)

	_, resp, err := g.client.Projects.GetProject(ns)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return nil, nil
			case http.StatusUnauthorized:
				return nil, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return nil, fmt.Errorf("Error retrieving archive link of project %s: %v", project, err)
	}

	u, err := url.Parse(
		fmt.Sprintf("/api/v4/projects/%s/repository/archive.tar.gz?ref=%s&private_token=%s",
			ns,
			tag,
			g.token,
		),
	)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse archive link: %v", err)
	}

	return g.client.BaseURL().ResolveReference(u), nil
}

// TagRepo implements the Git interface
func (g *GitLab) TagRepo(project, tag string, usr *User) error {
	ns := fmt.Sprintf("%s/%s", g.group, project)
	message := fmt.Sprint("Tagged by Chef-Guard\n")

	opts := &gitlab.CreateTagOptions{
		TagName: gitlab.String(tag),
		Ref:     gitlab.String("master"),
		Message: gitlab.String(message),
	}
	_, resp, err := g.client.Tags.CreateTag(ns, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return fmt.Errorf(invalidGitLabToken, g.group)
		}
		return fmt.Errorf("Error creating tag for project %s: %v", project, err)
	}

	return nil
}

// TagExists implements the Git interface
func (g *GitLab) TagExists(project, tag string) (bool, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	tags, resp, err := g.client.Tags.ListTags(ns)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return false, nil
			case http.StatusUnauthorized:
				return false, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return false, fmt.Errorf("Error retrieving tags of project %s: %v", project, err)
	}

	for _, t := range tags {
		if t.Name == tag {
			return true, nil
		}
	}

	return false, nil
}

// UntagRepo implements the Git interface
func (g *GitLab) UntagRepo(project, tag string) error {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	resp, err := g.client.Tags.DeleteTag(ns, tag)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return fmt.Errorf(invalidGitLabToken, g.group)
		}
		return fmt.Errorf("Error deleting tag %s: %v", tag, err)
	}

	return nil
}

func (g *GitLab) shaOfLatestCommit(project string) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	commit, resp, err := g.client.Commits.GetCommit(ns, "master")
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error retrieving SHA of latest commit: %v", err)
	}

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

package git

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
	"time"

	"github.com/xanzy/go-gitlab"
)

const (
	invalidGitLabToken = "The token configured for GitLab group %s is not valid!"
)

// GetContent implements the Git interface
func (g *GitLab) GetContent(project, path string) (*File, interface{}, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	treeOpts := &gitlab.ListTreeOptions{
		Path: gitlab.String(path),
	}
	tree, resp, err := g.client.Repositories.ListTree(ns, treeOpts)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return nil, nil, nil
			case http.StatusUnauthorized:
				return nil, nil, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return nil, nil, fmt.Errorf("Error retrieving tree for %s: %v", path, err)
	}

	if len(tree) > 0 {
		var files []string
		for _, file := range tree {
			files = append(files, filepath.Join(path, file.Name))
		}

		return nil, files, nil
	}

	fileOpts := &gitlab.GetFileOptions{
		Ref: gitlab.String("master"),
	}
	file, resp, err := g.client.RepositoryFiles.GetFile(ns, path, fileOpts)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return nil, nil, nil
			case http.StatusUnauthorized:
				return nil, nil, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return nil, nil, fmt.Errorf("Error retrieving file %s: %v", path, err)
	}

	f := &File{
		Content: file.Content,
		SHA:     file.CommitID,
	}

	if file.Encoding == "base64" {
		content, err := base64.StdEncoding.DecodeString(file.Content)
		if err != nil {
			return nil, nil, fmt.Errorf("Error decoding file %s, %v", path, err)
		}

		f.Content = string(content)
	}

	return f, nil, nil
}

// CreateFile implements the Git interface
func (g *GitLab) CreateFile(project, path, msg string, usr *User, content []byte) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	opts := &gitlab.CreateFileOptions{
		Branch:        gitlab.String("master"),
		AuthorEmail:   &usr.Mail,
		AuthorName:    &usr.Name,
		Content:       gitlab.String(string(content)),
		CommitMessage: gitlab.String(msg),
	}
	_, resp, err := g.client.RepositoryFiles.CreateFile(ns, path, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error creating file %s: %v", path, err)
	}

	return g.shaOfLatestCommit(project)
}

// UpdateFile implements the Git interface
func (g *GitLab) UpdateFile(project, path, sha, msg string, usr *User, content []byte) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	opts := &gitlab.UpdateFileOptions{
		Branch:        gitlab.String("master"),
		AuthorEmail:   &usr.Mail,
		AuthorName:    &usr.Name,
		Content:       gitlab.String(string(content)),
		CommitMessage: gitlab.String(msg),
	}
	_, resp, err := g.client.RepositoryFiles.UpdateFile(ns, path, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error updating file %s: %v", path, err)
	}

	return g.shaOfLatestCommit(project)
}

// DeleteFile implements the Git interface
func (g *GitLab) DeleteFile(project, path, sha, msg string, usr *User) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	opts := &gitlab.DeleteFileOptions{
		Branch:        gitlab.String("master"),
		AuthorEmail:   &usr.Mail,
		AuthorName:    &usr.Name,
		CommitMessage: gitlab.String(msg),
	}
	resp, err := g.client.RepositoryFiles.DeleteFile(ns, path, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error deleting file %s: %v", path, err)
	}

	return g.shaOfLatestCommit(project)
}

// DeleteDirectory implements the Git interface
func (g *GitLab) DeleteDirectory(project, msg string, dir interface{}, usr *User) error {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	for _, file := range dir.([]string) {
		// Need a special case for when deleting data bag items
		fn := strings.TrimPrefix(file, "data_bags/")
		msg := fmt.Sprintf(msg, strings.TrimSuffix(fn, ".json"))

		opts := &gitlab.DeleteFileOptions{
			Branch:        gitlab.String("master"),
			AuthorEmail:   &usr.Mail,
			AuthorName:    &usr.Name,
			CommitMessage: gitlab.String(msg),
		}
		resp, err := g.client.RepositoryFiles.DeleteFile(ns, file, opts)
		if err != nil {
			if resp != nil && resp.StatusCode == http.StatusUnauthorized {
				return fmt.Errorf(invalidGitLabToken, g.group)
			}
			return fmt.Errorf("Error deleting file %s: %v", file, err)
		}
	}

	return nil
}

// GetDiff implements the Git interface
func (g *GitLab) GetDiff(project, user, sha string) (string, error) {
	u := fmt.Sprintf("/%s/%s/commit/%s.diff", g.group, project, sha)

	req, err := g.client.NewRequest("GET", u, nil, nil)
	if err != nil {
		return "", err
	}

	// Make sure we do not use the API path here!
	req.URL, err = req.URL.Parse(u)
	if err != nil {
		return "", err
	}

	var diff bytes.Buffer
	resp, err := g.client.Do(req, &diff)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error retrieving commit %s: %v", sha, err)
	}

	if diff.Len() == 0 {
		return "", nil
	}

	const layout = "Mon Jan 2 3:04 2006"
	t := time.Now()

	msg := fmt.Sprintf("Commit : %s\nDate   : %s\nUser   : %s\n
%s",
		sha,
		t.Format(layout),
		user,
		diff.String(),
	)

	return msg, nil
}

// GetArchiveLink implements the Git interface
func (g *GitLab) GetArchiveLink(project, tag string) (*url.URL, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	_, resp, err := g.client.Projects.GetProject(ns)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return nil, nil
			case http.StatusUnauthorized:
				return nil, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return nil, fmt.Errorf("Error retrieving archive link of project %s: %v", project, err)
	}

	u, err := url.Parse(
		fmt.Sprintf("/api/v4/projects/%s/repository/archive.tar.gz?ref=%s&private_token=%s",
			url.QueryEscape(ns),
			tag,
			g.token,
		),
	)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse archive link: %v", err)
	}

	return g.client.BaseURL().ResolveReference(u), nil
}

// TagRepo implements the Git interface
func (g *GitLab) TagRepo(project, tag string, usr *User) error {
	ns := fmt.Sprintf("%s/%s", g.group, project)
	message := fmt.Sprint("Tagged by Chef-Guard\n")

	opts := &gitlab.CreateTagOptions{
		TagName: gitlab.String(tag),
		Ref:     gitlab.String("master"),
		Message: gitlab.String(message),
	}
	_, resp, err := g.client.Tags.CreateTag(ns, opts)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return fmt.Errorf(invalidGitLabToken, g.group)
		}
		return fmt.Errorf("Error creating tag for project %s: %v", project, err)
	}

	return nil
}

// TagExists implements the Git interface
func (g *GitLab) TagExists(project, tag string) (bool, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	tags, resp, err := g.client.Tags.ListTags(ns)
	if err != nil {
		if resp != nil {
			switch resp.StatusCode {
			case http.StatusNotFound:
				return false, nil
			case http.StatusUnauthorized:
				return false, fmt.Errorf(invalidGitLabToken, g.group)
			}
		}
		return false, fmt.Errorf("Error retrieving tags of project %s: %v", project, err)
	}

	for _, t := range tags {
		if t.Name == tag {
			return true, nil
		}
	}

	return false, nil
}

// UntagRepo implements the Git interface
func (g *GitLab) UntagRepo(project, tag string) error {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	resp, err := g.client.Tags.DeleteTag(ns, tag)
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return fmt.Errorf(invalidGitLabToken, g.group)
		}
		return fmt.Errorf("Error deleting tag %s: %v", tag, err)
	}

	return nil
}

func (g *GitLab) shaOfLatestCommit(project string) (string, error) {
	ns := fmt.Sprintf("%s/%s", g.group, project)

	commit, resp, err := g.client.Commits.GetCommit(ns, "master")
	if err != nil {
		if resp != nil && resp.StatusCode == http.StatusUnauthorized {
			return "", fmt.Errorf(invalidGitLabToken, g.group)
		}
		return "", fmt.Errorf("Error retrieving SHA of latest commit: %v", err)
	}

	return commit.ID, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/iron-io/titan/runner/drivers"
	"github.com/iron-io/titan/runner/drivers/common"
	"github.com/iron-io/titan/runner/drivers/docker"
)

type DriverType string

const (
	Docker DriverType = "docker"
)

func FactoryDriver(driverName DriverType, cfg *common.Config, hostname string) (drivers.Driver, error) {
	switch driverName {
	case Docker:
		return docker.NewDocker(cfg, hostname)
	default:
		panic("invalid driver")
	}
}
<commit_msg>Remove factory for now<commit_after><|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"koding/kite/kd/build"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
)

var (
	profile = flag.String("c", "", "Define config profile to be included")
	region  = flag.String("r", "", "Define region profile to be included")
)

type pkg struct {
	appName       string
	importPath    string
	files         []string
	version       string
	upstartScript string
}

func main() {
	flag.Parse()

	if flag.NFlag() != 2 {
		fmt.Println("Please define config -c and region -r")
		os.Exit(1)
	}

	err := buildPackages()
	if err != nil {
		fmt.Println(err)
	}
}

func buildPackages() error {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return errors.New("GOPATH is not set")
	}

	kdproxyPath := "koding/kontrol/kontrolproxy/"
	kdproxyUpstart := filepath.Join(gopath, "src", kdproxyPath, "files/kontrolproxy.conf")

	// change our upstartscript because it's a template
	configUpstart, err := prepareUpstart(kdproxyUpstart)
	if err != nil {
		return err
	}
	defer os.Remove(configUpstart)

	kontrolproxy := pkg{
		appName:    "kontrolproxy",
		importPath: kdproxyPath,
		files: []string{
			filepath.Join(gopath, "src", kdproxyPath, "files"),
		},
		version:       "0.0.1",
		upstartScript: configUpstart,
	}

	return kontrolproxy.build()
}

func prepareUpstart(path string) (string, error) {
	temps := struct {
		Profile string
		Region  string
	}{
		*profile,
		*region,
	}

	file, err := ioutil.TempFile(".", "gopackage_")
	if err != nil {
		return "", err
	}
	defer file.Close()

	t, err := template.ParseFiles(path)
	if err != nil {
		return "", err
	}

	if err := t.Execute(file, temps); err != nil {
		return "", err
	}

	return file.Name(), nil
}

func (p *pkg) build() error {
	fmt.Printf("building '%s' for config '%s' and regions '%s'\n", p.appName, *profile, *region)

	// prepare config folder
	tempDir, err := ioutil.TempDir(".", "gopackage_")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tempDir)

	configDir := filepath.Join(tempDir, "config")
	os.MkdirAll(configDir, 0755)

	// koding-config-manager needs it
	err = ioutil.WriteFile("VERSION", []byte(p.version), 0755)
	if err != nil {
		return err
	}
	defer os.Remove("VERSION")

	// create config and include into config folder
	config, err := exec.Command("node", "-e", "require('koding-config-manager').printJson('main."+*profile+"')").CombinedOutput()
	if err != nil {
		return err
	}

	configFile := filepath.Join(configDir, fmt.Sprintf("main.%s.json", *profile))
	err = ioutil.WriteFile(configFile, config, 0644)
	if err != nil {
		return err
	}

	p.files = append(p.files, configDir)

	// Now it's time to build
	if runtime.GOOS != "linux" {
		return errors.New("Not supported. Please run on a linux machine.")
	}

	deb := &build.Deb{
		AppName:       p.appName,
		Version:       p.version,
		ImportPath:    p.importPath,
		Files:         strings.Join(p.files, ","),
		InstallPrefix: "opt/kite",
		UpstartScript: p.upstartScript,
	}

	debFile, err := deb.Build()
	if err != nil {
		log.Println("linux:", err)
	}

	fmt.Printf("success '%s' is ready. Some helpful commands for you:\n\n", debFile)
	fmt.Printf("  show deb content   : dpkg -c %s\n", debFile)
	fmt.Printf("  show basic info    : dpkg -f %s\n", debFile)
	fmt.Printf("  install to machine : dpkg -i %s\n\n", debFile)

	return nil
}
<commit_msg>go/package: another improvemnt to package<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"koding/kite/kd/build"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
)

var (
	profile = flag.String("c", "", "Define config profile to be included")
	region  = flag.String("r", "", "Define region profile to be included")
)

type pkg struct {
	appName       string
	importPath    string
	files         []string
	version       string
	upstartScript string
}

func main() {
	flag.Parse()

	if flag.NFlag() != 2 {
		fmt.Println("Please define config -c and region -r")
		os.Exit(1)
	}

	err := buildPackages()
	if err != nil {
		fmt.Println(err)
	}
}

func buildPackages() error {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return errors.New("GOPATH is not set")
	}

	kdproxyPath := "koding/kontrol/kontrolproxy/"
	kdproxyUpstart := filepath.Join(gopath, "src", kdproxyPath, "files/kontrolproxy.conf")

	// change our upstartscript because it's a template
	configUpstart, err := prepareUpstart(kdproxyUpstart)
	if err != nil {
		return err
	}
	defer os.Remove(configUpstart)

	kontrolproxy := pkg{
		appName:    "kontrolproxy",
		importPath: kdproxyPath,
		files: []string{
			filepath.Join(gopath, "src", kdproxyPath, "files"),
		},
		version:       "0.0.1",
		upstartScript: configUpstart,
	}

	return kontrolproxy.build()
}

func prepareUpstart(path string) (string, error) {
	temps := struct {
		Profile string
		Region  string
	}{
		*profile,
		*region,
	}

	file, err := ioutil.TempFile(".", "gopackage_")
	if err != nil {
		return "", err
	}
	defer file.Close()

	t, err := template.ParseFiles(path)
	if err != nil {
		return "", err
	}

	if err := t.Execute(file, temps); err != nil {
		return "", err
	}

	return file.Name(), nil
}

func (p *pkg) build() error {
	fmt.Printf("building '%s' for config '%s' and regions '%s'\n", p.appName, *profile, *region)

	// prepare config folder
	tempDir, err := ioutil.TempDir(".", "gopackage_")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tempDir)

	configDir := filepath.Join(tempDir, "config")
	os.MkdirAll(configDir, 0755)

	// koding-config-manager needs it
	err = ioutil.WriteFile("VERSION", []byte(p.version), 0755)
	if err != nil {
		return err
	}
	defer os.Remove("VERSION")

	// create config and include into config folder
	config, err := exec.Command("node", "-e", "require('koding-config-manager').printJson('main."+*profile+"')").CombinedOutput()
	if err != nil {
		return err
	}

	// prettify content of "config"
	var d map[string]interface{}
	if err := json.Unmarshal(config, &d); err != nil {
		return err
	}

	config, err = json.MarshalIndent(d, "", "  ")
	if err != nil {
		return err
	}

	configFile := filepath.Join(configDir, fmt.Sprintf("main.%s.json", *profile))
	err = ioutil.WriteFile(configFile, config, 0644)
	if err != nil {
		return err
	}

	p.files = append(p.files, configDir)

	// Now it's time to build
	if runtime.GOOS != "linux" {
		return errors.New("Not supported. Please run on a linux machine.")
	}

	deb := &build.Deb{
		AppName:       p.appName,
		Version:       p.version,
		ImportPath:    p.importPath,
		Files:         strings.Join(p.files, ","),
		InstallPrefix: "opt/kite",
		UpstartScript: p.upstartScript,
	}

	debFile, err := deb.Build()
	if err != nil {
		log.Println("linux:", err)
	}

	fmt.Printf("success '%s' is ready. Some helpful commands for you:\n\n", debFile)
	fmt.Printf("  show deb content   : dpkg -c %s\n", debFile)
	fmt.Printf("  show basic info    : dpkg -f %s\n", debFile)
	fmt.Printf("  install to machine : dpkg -i %s\n\n", debFile)

	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"time"

	"appengine/datastore"
	"github.com/MiniProfiler/go/miniprofiler"
	mpg "github.com/MiniProfiler/go/miniprofiler_gae"
	"github.com/gorilla/mux"
	"github.com/mjibson/goon"
)

var router = new(mux.Router)
var templates *template.Template

func init() {
	var err error

	if templates, err = template.New("").Funcs(funcs).
		ParseFiles(
		"templates/base.html",
		"templates/admin-all-feeds.html",
		"templates/admin-date-formats.html",
		"templates/admin-feed.html",
		"templates/admin-stats.html",
	); err != nil {
		log.Fatal(err)
	}

	router.Handle("/", mpg.NewHandler(Main)).Name("main")
	router.Handle("/login/google", mpg.NewHandler(LoginGoogle)).Name("login-google")
	router.Handle("/logout", mpg.NewHandler(Logout)).Name("logout")
	router.Handle("/oauth2callback", mpg.NewHandler(Oauth2Callback)).Name("oauth2callback")
	router.Handle("/tasks/import-opml", mpg.NewHandler(ImportOpmlTask)).Name("import-opml-task")
	router.Handle("/tasks/import-reader", mpg.NewHandler(ImportReaderTask)).Name("import-reader-task")
	router.Handle("/tasks/update-feed", mpg.NewHandler(UpdateFeed)).Name("update-feed")
	router.Handle("/tasks/update-feeds", mpg.NewHandler(UpdateFeeds)).Name("update-feeds")
	router.Handle("/tasks/subscribe-feed", mpg.NewHandler(SubscribeFeed)).Name("subscribe-feed")
	router.Handle("/push/{feed}", mpg.NewHandler(SubscribeCallback)).Name("subscribe-callback")
	router.Handle("/user/add-subscription", mpg.NewHandler(AddSubscription)).Name("add-subscription")
	router.Handle("/user/clear-feeds", mpg.NewHandler(ClearFeeds)).Name("clear-feeds")
	router.Handle("/user/delete-account", mpg.NewHandler(DeleteAccount)).Name("delete-account")
	router.Handle("/user/export-opml", mpg.NewHandler(ExportOpml)).Name("export-opml")
	router.Handle("/user/get-contents", mpg.NewHandler(GetContents)).Name("get-contents")
	router.Handle("/user/get-feed", mpg.NewHandler(GetFeed)).Name("get-feed")
	router.Handle("/user/import/opml", mpg.NewHandler(ImportOpml)).Name("import-opml")
	router.Handle("/user/import/reader", mpg.NewHandler(ImportReader)).Name("import-reader")
	router.Handle("/user/list-feeds", mpg.NewHandler(ListFeeds)).Name("list-feeds")
	router.Handle("/user/mark-all-read", mpg.NewHandler(MarkAllRead)).Name("mark-all-read")
	router.Handle("/user/mark-read", mpg.NewHandler(MarkRead)).Name("mark-read")
	router.Handle("/user/save-options", mpg.NewHandler(SaveOptions)).Name("save-options")
	router.Handle("/user/upload-opml", mpg.NewHandler(UploadOpml)).Name("upload-opml")

	router.Handle("/admin/all-feeds", mpg.NewHandler(AllFeeds)).Name("all-feeds")
	router.Handle("/admin/all-feeds-opml", mpg.NewHandler(AllFeedsOpml)).Name("all-feeds-opml")
	router.Handle("/admin/date-formats", mpg.NewHandler(AdminDateFormats)).Name("admin-date-formats")
	router.Handle("/admin/feed", mpg.NewHandler(AdminFeed)).Name("admin-feed")
	router.Handle("/admin/stats", mpg.NewHandler(AdminStats)).Name("admin-stats")
	router.Handle("/admin/update-feed", mpg.NewHandler(AdminUpdateFeed)).Name("admin-update-feed")
	router.Handle("/_ah/start", mpg.NewHandler(BackendStart))
	router.Handle("/_ah/stop", mpg.NewHandler(BackendStop))

	http.Handle("/", router)

	miniprofiler.ShowControls = true
	miniprofiler.StartHidden = true
	miniprofiler.ToggleShortcut = "Alt+C"
}

func Main(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	if err := templates.ExecuteTemplate(w, "base.html", includes(c, w, r)); err != nil {
		serveError(w, err)
	}
}

func addFeed(c mpg.Context, userid string, outline *OpmlOutline) error {
	gn := goon.FromContext(c)
	o := outline.Outline[0]
	c.Infof("adding feed %v to user %s", o.XmlUrl, userid)

	f := Feed{Url: o.XmlUrl}
	if err := gn.Get(&f); err == datastore.ErrNoSuchEntity {
		if feed, stories := fetchFeed(c, o.XmlUrl, o.XmlUrl); feed == nil {
			return fmt.Errorf("could not add feed %s", o.XmlUrl)
		} else {
			f = *feed
			f.Updated = time.Time{}
			f.Checked = f.Updated
			f.NextUpdate = f.Updated
			gn.Put(&f)
			if err := updateFeed(c, f.Url, feed, stories); err != nil {
				return err
			}

			o.XmlUrl = feed.Url
			o.HtmlUrl = feed.Link
			if o.Title == "" {
				o.Title = feed.Title
			}
		}
	} else if err != nil {
		return err
	} else {
		o.HtmlUrl = f.Link
		if o.Title == "" {
			o.Title = f.Title
		}
	}
	o.Text = ""

	return nil
}

func mergeUserOpml(ud *UserData, outlines ...*OpmlOutline) {
	var fs Opml
	json.Unmarshal(ud.Opml, &fs)
	urls := make(map[string]bool)

	for _, o := range fs.Outline {
		if o.XmlUrl != "" {
			urls[o.XmlUrl] = true
		} else {
			for _, so := range o.Outline {
				urls[so.XmlUrl] = true
			}
		}
	}

	mergeOutline := func(label string, outline *OpmlOutline) {
		if _, present := urls[outline.XmlUrl]; present {
			return
		} else {
			urls[outline.XmlUrl] = true

			if label == "" {
				fs.Outline = append(fs.Outline, outline)
			} else {
				done := false
				for _, ol := range fs.Outline {
					if ol.Title == label && ol.XmlUrl == "" {
						ol.Outline = append(ol.Outline, outline)
						done = true
						break
					}
				}
				if !done {
					fs.Outline = append(fs.Outline, &OpmlOutline{
						Title:   label,
						Outline: []*OpmlOutline{outline},
					})
				}
			}
		}
	}

	for _, outline := range outlines {
		if outline.XmlUrl != "" {
			mergeOutline("", outline)
		} else {
			for _, o := range outline.Outline {
				mergeOutline(outline.Title, o)
			}
		}
	}

	ud.Opml, _ = json.Marshal(&fs)
}
<commit_msg>For existing feeds, don't send fragments to PuSH<commit_after>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"encoding/json"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"time"

	"appengine/datastore"
	"github.com/MiniProfiler/go/miniprofiler"
	mpg "github.com/MiniProfiler/go/miniprofiler_gae"
	"github.com/gorilla/mux"
	"github.com/mjibson/goon"
)

var router = new(mux.Router)
var templates *template.Template

func init() {
	var err error

	if templates, err = template.New("").Funcs(funcs).
		ParseFiles(
		"templates/base.html",
		"templates/admin-all-feeds.html",
		"templates/admin-date-formats.html",
		"templates/admin-feed.html",
		"templates/admin-stats.html",
	); err != nil {
		log.Fatal(err)
	}

	router.Handle("/", mpg.NewHandler(Main)).Name("main")
	router.Handle("/login/google", mpg.NewHandler(LoginGoogle)).Name("login-google")
	router.Handle("/logout", mpg.NewHandler(Logout)).Name("logout")
	router.Handle("/oauth2callback", mpg.NewHandler(Oauth2Callback)).Name("oauth2callback")
	router.Handle("/tasks/import-opml", mpg.NewHandler(ImportOpmlTask)).Name("import-opml-task")
	router.Handle("/tasks/import-reader", mpg.NewHandler(ImportReaderTask)).Name("import-reader-task")
	router.Handle("/tasks/update-feed", mpg.NewHandler(UpdateFeed)).Name("update-feed")
	router.Handle("/tasks/update-feeds", mpg.NewHandler(UpdateFeeds)).Name("update-feeds")
	router.Handle("/tasks/subscribe-feed", mpg.NewHandler(SubscribeFeed)).Name("subscribe-feed")
	router.Handle("/push/{feed}", mpg.NewHandler(SubscribeCallback)).Name("subscribe-callback")
	router.Handle("/user/add-subscription", mpg.NewHandler(AddSubscription)).Name("add-subscription")
	router.Handle("/user/clear-feeds", mpg.NewHandler(ClearFeeds)).Name("clear-feeds")
	router.Handle("/user/delete-account", mpg.NewHandler(DeleteAccount)).Name("delete-account")
	router.Handle("/user/export-opml", mpg.NewHandler(ExportOpml)).Name("export-opml")
	router.Handle("/user/get-contents", mpg.NewHandler(GetContents)).Name("get-contents")
	router.Handle("/user/get-feed", mpg.NewHandler(GetFeed)).Name("get-feed")
	router.Handle("/user/import/opml", mpg.NewHandler(ImportOpml)).Name("import-opml")
	router.Handle("/user/import/reader", mpg.NewHandler(ImportReader)).Name("import-reader")
	router.Handle("/user/list-feeds", mpg.NewHandler(ListFeeds)).Name("list-feeds")
	router.Handle("/user/mark-all-read", mpg.NewHandler(MarkAllRead)).Name("mark-all-read")
	router.Handle("/user/mark-read", mpg.NewHandler(MarkRead)).Name("mark-read")
	router.Handle("/user/save-options", mpg.NewHandler(SaveOptions)).Name("save-options")
	router.Handle("/user/upload-opml", mpg.NewHandler(UploadOpml)).Name("upload-opml")

	router.Handle("/admin/all-feeds", mpg.NewHandler(AllFeeds)).Name("all-feeds")
	router.Handle("/admin/all-feeds-opml", mpg.NewHandler(AllFeedsOpml)).Name("all-feeds-opml")
	router.Handle("/admin/date-formats", mpg.NewHandler(AdminDateFormats)).Name("admin-date-formats")
	router.Handle("/admin/feed", mpg.NewHandler(AdminFeed)).Name("admin-feed")
	router.Handle("/admin/stats", mpg.NewHandler(AdminStats)).Name("admin-stats")
	router.Handle("/admin/update-feed", mpg.NewHandler(AdminUpdateFeed)).Name("admin-update-feed")
	router.Handle("/_ah/start", mpg.NewHandler(BackendStart))
	router.Handle("/_ah/stop", mpg.NewHandler(BackendStop))

	http.Handle("/", router)

	miniprofiler.ShowControls = true
	miniprofiler.StartHidden = true
	miniprofiler.ToggleShortcut = "Alt+C"
}

func Main(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	if err := templates.ExecuteTemplate(w, "base.html", includes(c, w, r)); err != nil {
		serveError(w, err)
	}
}

func addFeed(c mpg.Context, userid string, outline *OpmlOutline) error {
	gn := goon.FromContext(c)
	o := outline.Outline[0]
	c.Infof("adding feed %v to user %s", o.XmlUrl, userid)
	fu, ferr := url.Parse(o.XmlUrl)
	if ferr != nil {
		return ferr
	}
	fu.Fragment = ""
	o.XmlUrl = fu.String()

	f := Feed{Url: o.XmlUrl}
	if err := gn.Get(&f); err == datastore.ErrNoSuchEntity {
		if feed, stories := fetchFeed(c, o.XmlUrl, o.XmlUrl); feed == nil {
			return fmt.Errorf("could not add feed %s", o.XmlUrl)
		} else {
			f = *feed
			f.Updated = time.Time{}
			f.Checked = f.Updated
			f.NextUpdate = f.Updated
			gn.Put(&f)
			if err := updateFeed(c, f.Url, feed, stories); err != nil {
				return err
			}

			o.XmlUrl = feed.Url
			o.HtmlUrl = feed.Link
			if o.Title == "" {
				o.Title = feed.Title
			}
		}
	} else if err != nil {
		return err
	} else {
		o.HtmlUrl = f.Link
		if o.Title == "" {
			o.Title = f.Title
		}
	}
	o.Text = ""

	return nil
}

func mergeUserOpml(ud *UserData, outlines ...*OpmlOutline) {
	var fs Opml
	json.Unmarshal(ud.Opml, &fs)
	urls := make(map[string]bool)

	for _, o := range fs.Outline {
		if o.XmlUrl != "" {
			urls[o.XmlUrl] = true
		} else {
			for _, so := range o.Outline {
				urls[so.XmlUrl] = true
			}
		}
	}

	mergeOutline := func(label string, outline *OpmlOutline) {
		if _, present := urls[outline.XmlUrl]; present {
			return
		} else {
			urls[outline.XmlUrl] = true

			if label == "" {
				fs.Outline = append(fs.Outline, outline)
			} else {
				done := false
				for _, ol := range fs.Outline {
					if ol.Title == label && ol.XmlUrl == "" {
						ol.Outline = append(ol.Outline, outline)
						done = true
						break
					}
				}
				if !done {
					fs.Outline = append(fs.Outline, &OpmlOutline{
						Title:   label,
						Outline: []*OpmlOutline{outline},
					})
				}
			}
		}
	}

	for _, outline := range outlines {
		if outline.XmlUrl != "" {
			mergeOutline("", outline)
		} else {
			for _, o := range outline.Outline {
				mergeOutline(outline.Title, o)
			}
		}
	}

	ud.Opml, _ = json.Marshal(&fs)
}
<|endoftext|>


<commit_before>package melware

import (
	"io/ioutil"
	"strconv"
	"crypto/md5"
	"fmt"
	"io"
	"net/http"
	"github.com/ridewindx/mel"
)

const defaultMaxAge = 60 * 60 * 24 * 365; // 1 year

func Favicon(path string, maxAge ...int) mel.Handler {
	favicon, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	age := defaultMaxAge
	if len(maxAge) > 0 {
		age = maxAge[0]
	}

	hash := md5.New()
	io.WriteString(hash, string(favicon))
	etag := fmt.Sprintf("%x", hash.Sum(nil))

	return func(c *mel.Context) {
		req := c.Request
		if req.URL.Path != "/favicon.ico" {
			c.Next()
			return
		}

		if req.Method != "GET" && req.Method != "HEAD" {
			var status int
			if req.Method == "OPTIONS" {
				status = 200
			} else {
				status = 405
			}
			c.Header("Allow", "GET, HEAD, OPTIONS")
			c.Header("Content-Length", "0")
			c.Writer.WriteHeader(status)
			return
		}

		c.Header("Cache-Control", "public, max-age=" + strconv.Itoa(age))

		body := favicon
		if match, ok := req.Header["If-None-Match"]; ok {
			if match[0] == etag {
				c.Writer.WriteHeader(http.StatusNotModified)
				body = []byte{}
			}
		} else {
			c.Header("ETag", etag)
		}

		c.Writer.Write(body)
		return
	}
}
<commit_msg>Update<commit_after>package melware

import (
	"io/ioutil"
	"strconv"
	"crypto/md5"
	"fmt"
	"io"
	"net/http"
	"github.com/ridewindx/mel"
)

const defaultMaxAge = 60 * 60 * 24 * 365; // 1 year

func Favicon(path string, maxAge ...int) mel.Handler {
	favicon, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	age := defaultMaxAge
	if len(maxAge) > 0 {
		age = maxAge[0]
	}

	hash := md5.New()
	io.WriteString(hash, string(favicon))
	etag := fmt.Sprintf("%x", hash.Sum(nil))

	return func(c *mel.Context) {
		req := c.Request
		if req.URL.Path != "/favicon.ico" {
			c.Next()
			return
		}

		if req.Method != "GET" && req.Method != "HEAD" {
			var status int
			if req.Method == "OPTIONS" {
				status = 200
			} else {
				status = 405
			}
			c.Header("Allow", "GET, HEAD, OPTIONS")
			c.Header("Content-Length", "0")
			c.Writer.WriteHeader(status)
			return
		}

		c.Header("Cache-Control", "public, max-age=" + strconv.Itoa(age))

		body := favicon
		ifNoneMatch := req.Header.Get("If-None-Match")
		if ifNoneMatch == etag {
			c.Writer.WriteHeader(http.StatusNotModified)
			body = []byte{}
		} else if len(ifNoneMatch) == 0{
			c.Header("ETag", etag)
		}

		c.Writer.Write(body)
		return
	}
}
<|endoftext|>