<commit_before>package main

import (
	"crypto/sha256"
	"database/sql"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// TODO: change these to be cmd args instead!
const DB_FIL = "/home/lmas/projects/ss13_se/src/db.sqlite3"

// Dir to save new graphs in
const SAVE_DIR = "/home/lmas/projects/ss13_se/src/static/graphs"

// How far back in time the graphs will go
var LAST_WEEK = time.Now().AddDate(0, 0, -7)
var LAST_MONTH = time.Now().AddDate(0, -1, 0)

var WEEK_DAYS = [7]string{
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday",
}

func main() {
	// open a db connection
	db, err := sql.Open("sqlite3", DB_FIL)
	checkerror(err)
	defer db.Close()

	// loop over each server in db
	rows, err := db.Query("select id, title from gameservers_server")
	checkerror(err)
	defer rows.Close()

	var (
		id    int
		title string
	)
	for rows.Next() {
		err := rows.Scan(&id, &title)
		checkerror(err)
		weeklyhistorygraph(db, id, title)
		monthlyhistorygraph(db, id, title)
		monthlyaveragedaygraph(db, id, title)
	}
	err = rows.Err()
	checkerror(err)
}

func checkerror(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func setuptemppaths(prefix string, title string) (f *os.File, name string, path string) {
	// create a tmp file
	file, err := ioutil.TempFile("", prefix)
	checkerror(err)

	// Make sure we have somewhere to save the stored graphs in
	err = os.MkdirAll(SAVE_DIR, 0777)
	checkerror(err)
	hash := fmt.Sprintf("%x", sha256.Sum256([]byte(title)))
	path = filepath.Join(SAVE_DIR, fmt.Sprintf("%s%s", prefix, hash))

	return file, file.Name(), path
}

func runcommand(cmd string, title string, args ...string) {
	out, err := exec.Command(cmd, args...).CombinedOutput()
	if err != nil && len(out) > 0 {
		log.Printf("ERROR running '%s' for '%s': \n%s\n", cmd, title, out)
	}
	checkerror(err)
}
func weeklyhistorygraph(db *sql.DB, id int, title string) {
	// Get the rows for the server, newer then LAST_WEEK and only on the hour
	rows, err := db.Query("select created,players "+
		"from gameservers_serverhistory "+
		"where server_id = ? and created >= ? and strftime('%M', created) = '00' "+
		"order by created asc",
		id, LAST_WEEK)
	checkerror(err)
	defer rows.Close()

	var (
		created time.Time
		players int
		data    []string
	)
	// Scan in each row and store it in mem
	for rows.Next() {
		err := rows.Scan(&created, &players)
		checkerror(err)
		data = append(data, fmt.Sprintf("%d, %d\n", created.Unix(), players))
		checkerror(err)
	}
	err = rows.Err()
	checkerror(err)

	// No need to continue running if there's no data to work with
	if len(data) < 1 {
		return
	}

	// Create a new temp file, get it's filepath and get the final storage path
	ifile, ifilename, ofilename := setuptemppaths("week-time-", title)
	defer func() {
		ifile.Close()
		os.Remove(ifilename)
	}()

	// Write the server data to the tmp file
	for _, line := range data {
		_, err = ifile.WriteString(line)
		checkerror(err)
	}

	// And finally run the plotter against the file
	runcommand("./plot_time.sh", title, ifilename, ofilename)
}

func monthlyhistorygraph(db *sql.DB, id int, title string) {
	// Rows for server, newer then LAST_WEEK and only every 6th hour
	rows, err := db.Query("select created,players "+
		"from gameservers_serverhistory "+
		"where server_id = ? and created >= ? and strftime('%M', created) = '00' "+
		"and strftime('%H', created) in ('00', '06', '12', '18') "+
		"order by created asc",
		id, LAST_MONTH)
	checkerror(err)
	defer rows.Close()

	var (
		created time.Time
		players int
		data    []string
	)
	for rows.Next() {
		err := rows.Scan(&created, &players)
		checkerror(err)
		data = append(data, fmt.Sprintf("%d, %d\n", created.Unix(), players))
		checkerror(err)
	}
	err = rows.Err()
	checkerror(err)

	if len(data) < 1 {
		return
	}

	ifile, ifilename, ofilename := setuptemppaths("month-time-", title)
	defer func() {
		ifile.Close()
		os.Remove(ifilename)
	}()

	for _, line := range data {
		_, err = ifile.WriteString(line)
		checkerror(err)
	}

	runcommand("./plot_time.sh", title, ifilename, ofilename)
}

func monthlyaveragedaygraph(db *sql.DB, id int, title string) {
	rows, err := db.Query("select "+
		"strftime('%w', created) as weekday, avg(players) "+
		"from gameservers_serverhistory "+
		"where server_id = ? and created >= ? "+
		"group by weekday;", id, LAST_MONTH)
	checkerror(err)
	defer rows.Close()

	var (
		day     int
		players float64
		data    []string
	)

	for rows.Next() {
		err := rows.Scan(&day, &players)
		checkerror(err)
		data = append(data, fmt.Sprintf("%s, %f\n", WEEK_DAYS[day], players))
	}
	err = rows.Err()
	checkerror(err)

	if len(data) < 1 {
		return
	}

	// If Sunday (WEEK_DAYS[0]) is the first day in the list, we have to
	// move it to the end. Fucking wankers and their weird start of week shit...
	if strings.HasPrefix(data[0], WEEK_DAYS[0]) {
		data = append(data[1:len(data)], data[0])
	}

	ifile, ifilename, ofilename := setuptemppaths("month-avg_day-", title)
	defer func() {
		ifile.Close()
		os.Remove(ifilename)
	}()

	for _, line := range data {
		_, err = ifile.WriteString(line)
		checkerror(err)
	}

	runcommand("./plot_bar.sh", title, ifilename, ofilename)
}
<commit_msg>Added naive threading using dumb and simple goroutines.<commit_after>package main

import (
	"crypto/sha256"
	"database/sql"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// TODO: change these to be cmd args instead!
const DB_FIL = "/home/lmas/projects/ss13_se/src/db.sqlite3"

// Dir to save new graphs in
const SAVE_DIR = "/home/lmas/projects/ss13_se/src/static/graphs"

// How far back in time the graphs will go
var LAST_WEEK = time.Now().AddDate(0, 0, -7)
var LAST_MONTH = time.Now().AddDate(0, -1, 0)

var WEEK_DAYS = [7]string{
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday",
}

func main() {
	// open a db connection
	db, err := sql.Open("sqlite3", DB_FIL)
	checkerror(err)
	defer db.Close()

	// loop over each server in db
	rows, err := db.Query("select id, title from gameservers_server")
	checkerror(err)
	defer rows.Close()

	var (
		id    int
		title string
		group sync.WaitGroup
	)
	for rows.Next() {
		err := rows.Scan(&id, &title)
		checkerror(err)

		// Make a new dumb goroutine
		group.Add(1)
		go updategraphs(db, &group, id, title)
	}
	err = rows.Err()
	checkerror(err)

	// Wait for all goroutines to finish
	group.Wait()
}

func updategraphs(db *sql.DB, group *sync.WaitGroup, id int, title string) {
	defer group.Done()
	weeklyhistorygraph(db, id, title)
	monthlyhistorygraph(db, id, title)
	monthlyaveragedaygraph(db, id, title)
}

func checkerror(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func setuptemppaths(prefix string, title string) (f *os.File, name string, path string) {
	// create a tmp file
	file, err := ioutil.TempFile("", prefix)
	checkerror(err)

	// Make sure we have somewhere to save the stored graphs in
	err = os.MkdirAll(SAVE_DIR, 0777)
	checkerror(err)
	hash := fmt.Sprintf("%x", sha256.Sum256([]byte(title)))
	path = filepath.Join(SAVE_DIR, fmt.Sprintf("%s%s", prefix, hash))

	return file, file.Name(), path
}

func runcommand(cmd string, title string, args ...string) {
	out, err := exec.Command(cmd, args...).CombinedOutput()
	if err != nil && len(out) > 0 {
		log.Printf("ERROR running '%s' for '%s': \n%s\n", cmd, title, out)
	}
	checkerror(err)
}
func weeklyhistorygraph(db *sql.DB, id int, title string) {
	// Get the rows for the server, newer then LAST_WEEK and only on the hour
	rows, err := db.Query("select created,players "+
		"from gameservers_serverhistory "+
		"where server_id = ? and created >= ? and strftime('%M', created) = '00' "+
		"order by created asc",
		id, LAST_WEEK)
	checkerror(err)
	defer rows.Close()

	var (
		created time.Time
		players int
		data    []string
	)
	// Scan in each row and store it in mem
	for rows.Next() {
		err := rows.Scan(&created, &players)
		checkerror(err)
		data = append(data, fmt.Sprintf("%d, %d\n", created.Unix(), players))
		checkerror(err)
	}
	err = rows.Err()
	checkerror(err)

	// No need to continue running if there's no data to work with
	if len(data) < 1 {
		return
	}

	// Create a new temp file, get it's filepath and get the final storage path
	ifile, ifilename, ofilename := setuptemppaths("week-time-", title)
	defer func() {
		ifile.Close()
		os.Remove(ifilename)
	}()

	// Write the server data to the tmp file
	for _, line := range data {
		_, err = ifile.WriteString(line)
		checkerror(err)
	}

	// And finally run the plotter against the file
	runcommand("./plot_time.sh", title, ifilename, ofilename)
}

func monthlyhistorygraph(db *sql.DB, id int, title string) {
	// Rows for server, newer then LAST_WEEK and only every 6th hour
	rows, err := db.Query("select created,players "+
		"from gameservers_serverhistory "+
		"where server_id = ? and created >= ? and strftime('%M', created) = '00' "+
		"and strftime('%H', created) in ('00', '06', '12', '18') "+
		"order by created asc",
		id, LAST_MONTH)
	checkerror(err)
	defer rows.Close()

	var (
		created time.Time
		players int
		data    []string
	)
	for rows.Next() {
		err := rows.Scan(&created, &players)
		checkerror(err)
		data = append(data, fmt.Sprintf("%d, %d\n", created.Unix(), players))
		checkerror(err)
	}
	err = rows.Err()
	checkerror(err)

	if len(data) < 1 {
		return
	}

	ifile, ifilename, ofilename := setuptemppaths("month-time-", title)
	defer func() {
		ifile.Close()
		os.Remove(ifilename)
	}()

	for _, line := range data {
		_, err = ifile.WriteString(line)
		checkerror(err)
	}

	runcommand("./plot_time.sh", title, ifilename, ofilename)
}

func monthlyaveragedaygraph(db *sql.DB, id int, title string) {
	rows, err := db.Query("select "+
		"strftime('%w', created) as weekday, avg(players) "+
		"from gameservers_serverhistory "+
		"where server_id = ? and created >= ? "+
		"group by weekday;", id, LAST_MONTH)
	checkerror(err)
	defer rows.Close()

	var (
		day     int
		players float64
		data    []string
	)

	for rows.Next() {
		err := rows.Scan(&day, &players)
		checkerror(err)
		data = append(data, fmt.Sprintf("%s, %f\n", WEEK_DAYS[day], players))
	}
	err = rows.Err()
	checkerror(err)

	if len(data) < 1 {
		return
	}

	// If Sunday (WEEK_DAYS[0]) is the first day in the list, we have to
	// move it to the end. Fucking wankers and their weird start of week shit...
	if strings.HasPrefix(data[0], WEEK_DAYS[0]) {
		data = append(data[1:len(data)], data[0])
	}

	ifile, ifilename, ofilename := setuptemppaths("month-avg_day-", title)
	defer func() {
		ifile.Close()
		os.Remove(ifilename)
	}()

	for _, line := range data {
		_, err = ifile.WriteString(line)
		checkerror(err)
	}

	runcommand("./plot_bar.sh", title, ifilename, ofilename)
}
<|endoftext|>


<commit_before>// This file contains functions transpiling unary and binary operator
// expressions.

package transpiler

import (
	"fmt"
	"go/token"

	goast "go/ast"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/types"
	"github.com/elliotchance/c2go/util"
)

func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) (
	*goast.BinaryExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	right, rightType, newPre, newPost, err := transpileToExpr(n.Children[1], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	operator := getTokenForOperator(n.Operator)
	returnType := types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType)

	if operator == token.LAND {
		left = types.CastExpr(p, left, leftType, "bool")
		right = types.CastExpr(p, right, rightType, "bool")

		return &goast.BinaryExpr{
			X:  left,
			Op: operator,
			Y:  right,
		}, "bool", preStmts, postStmts, nil
	}

	// Convert "(0)" to "nil" when we are dealing with equality.
	if (operator == token.NEQ || operator == token.EQL) &&
		types.IsNullExpr(right) {
		if types.ResolveType(p, leftType) == "string" {
			p.AddImport("github.com/elliotchance/c2go/noarch")
			left = util.NewCallExpr("noarch.NullTerminatedString", left)
			right = &goast.BasicLit{
				Kind:  token.STRING,
				Value: `""`,
			}
		} else {
			right = goast.NewIdent("nil")
		}
	}

	if operator == token.ASSIGN {
		right = types.CastExpr(p, right, rightType, returnType)
	}

	return &goast.BinaryExpr{
		X:  left,
		Op: operator,
		Y:  right,
	}, types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType), preStmts, postStmts, nil
}

func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
	goast.Expr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}
	operator := getTokenForOperator(n.Operator)

	// Unfortunately we cannot use the Go increment operators because we are not
	// providing any position information for tokens. This means that the ++/--
	// would be placed before the expression and would be invalid in Go.
	//
	// Until it can be properly fixed (can we trick Go into to placing it after
	// the expression with a magic position?) we will have to return a
	// BinaryExpr with the same functionality.
	if operator == token.INC || operator == token.DEC {
		binaryOperator := "+="
		if operator == token.DEC {
			binaryOperator = "-="
		}

		return transpileBinaryOperator(&ast.BinaryOperator{
			Type:     n.Type,
			Operator: binaryOperator,
			Children: []ast.Node{
				n.Children[0], &ast.IntegerLiteral{
					Type:     "int",
					Value:    "1",
					Children: []ast.Node{},
				},
			},
		}, p)
	}

	// Otherwise handle like a unary operator.
	e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	if operator == token.NOT {
		if eType == "bool" || eType == "_Bool" {
			return &goast.UnaryExpr{
				X:  e,
				Op: operator,
			}, "bool", preStmts, postStmts, nil
		}

		t := types.ResolveType(p, eType)
		if t == "string" {
			return &goast.BinaryExpr{
				X:  e,
				Op: token.EQL,
				Y: &goast.BasicLit{
					Kind:  token.STRING,
					Value: `""`,
				},
			}, "bool", preStmts, postStmts, nil
		}

		p.AddImport("github.com/elliotchance/c2go/noarch")

		functionName := fmt.Sprintf("noarch.Not%s", util.Ucfirst(t))

		return &goast.CallExpr{
			Fun:  goast.NewIdent(functionName),
			Args: []goast.Expr{e},
		}, eType, preStmts, postStmts, nil
	}

	if operator == token.MUL {
		if eType == "const char *" {
			return &goast.IndexExpr{
				X: e,
				Index: &goast.BasicLit{
					Kind:  token.INT,
					Value: "0",
				},
			}, "char", preStmts, postStmts, nil
		}

		t, err := types.GetDereferenceType(eType)
		if err != nil {
			return nil, "", preStmts, postStmts, err
		}

		return &goast.StarExpr{
			X: e,
		}, t, preStmts, postStmts, nil
	}

	if operator == token.AND {
		eType += " *"
	}

	return &goast.UnaryExpr{
		X:  e,
		Op: operator,
	}, eType, preStmts, postStmts, nil
}

// transpileConditionalOperator transpiles a conditional (also known as a
// ternary) operator:
//
//     a ? b : c
//
// We cannot simply convert these to an "if" statement becuase they by inside
// another expression.
//
// Since Go does not support the ternary operator or inline "if" statements we
// use a function, noarch.Ternary() to work the same way.
//
// It is also important to note that C only evaulates the "b" or "c" condition
// based on the result of "a" (from the above example). So we wrap the "b" and
// "c" in closures so that the Ternary function will only evaluate one of them.
func transpileConditionalOperator(n *ast.ConditionalOperator, p *program.Program) (
	*goast.CallExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	a, _, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	b, _, newPre, newPost, err := transpileToExpr(n.Children[1], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	c, _, newPre, newPost, err := transpileToExpr(n.Children[2], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	p.AddImport("github.com/elliotchance/c2go/noarch")

	// The following code will generate the Go AST that will simulate a
	// conditional (ternary) operator, in the form of:
	//
	//     noarch.Ternary(
	//         $1,
	//         func () interface{} {
	//             return $2
	//         },
	//         func () interface{} {
	//             return $3
	//         },
	//     )
	//
	// $2 and $3 (the true and false condition respectively) must be wrapped in
	// a closure so that they are not both executed.
	return &goast.CallExpr{
		Fun: goast.NewIdent("noarch.Ternary"),
		Args: []goast.Expr{
			a,
			newTernaryWrapper(b),
			newTernaryWrapper(c),
		},
	}, n.Type, preStmts, postStmts, nil
}

// newTernaryWrapper is a helper method used by transpileConditionalOperator().
// It will wrap an expression in a closure.
func newTernaryWrapper(e goast.Expr) *goast.FuncLit {
	return &goast.FuncLit{
		Type: &goast.FuncType{
			Params: &goast.FieldList{},
			Results: &goast.FieldList{
				List: []*goast.Field{
					&goast.Field{
						Type: &goast.InterfaceType{
							Methods: &goast.FieldList{},
						},
					},
				},
			},
		},
		Body: &goast.BlockStmt{
			List: []goast.Stmt{
				&goast.ReturnStmt{
					Results: []goast.Expr{e},
				},
			},
		},
	}
}

// transpileParenExpr transpiles an expression that is wrapped in parentheses.
// There is a special case where "(0)" is treated as a NULL (since that's what
// the macro expands to). We have to return the type as "null" since we don't
// know at this point what the NULL expression will be used in conjuction with.
func transpileParenExpr(n *ast.ParenExpr, p *program.Program) (
	*goast.ParenExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	r := &goast.ParenExpr{
		X: e,
	}
	if types.IsNullExpr(r) {
		eType = "null"
	}

	return r, eType, preStmts, postStmts, nil
}

func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.Program) (*goast.BinaryExpr, string, error) {
	left, _, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", err
	}

	right, _, err := transpileToExpr(n.Children[1], p)
	if err != nil {
		return nil, "", err
	}

	return &goast.BinaryExpr{
		X:  left,
		Y:  right,
		Op: getTokenForOperator(n.Opcode),
	}, "", nil
}

// getTokenForOperator returns the Go operator token for the provided C
// operator.
func getTokenForOperator(operator string) token.Token {
	switch operator {
	// Arithmetic
	case "--":
		return token.DEC
	case "++":
		return token.INC
	case "+":
		return token.ADD
	case "-":
		return token.SUB
	case "*":
		return token.MUL
	case "/":
		return token.QUO
	case "%":
		return token.REM

	// Assignment
	case "=":
		return token.ASSIGN
	case "+=":
		return token.ADD_ASSIGN
	case "-=":
		return token.SUB_ASSIGN
	case "*=":
		return token.MUL_ASSIGN
	case "/=":
		return token.QUO_ASSIGN
	case "%=":
		return token.REM_ASSIGN
	case "&=":
		return token.AND_ASSIGN
	case "|=":
		return token.OR_ASSIGN
	case "^=":
		return token.XOR_ASSIGN
	case "<<=":
		return token.SHL_ASSIGN
	case ">>=":
		return token.SHR_ASSIGN

	// Bitwise
	case "&":
		return token.AND
	case "|":
		return token.OR
	case "~":
		return token.XOR
	case ">>":
		return token.SHR
	case "<<":
		return token.SHL

	// Comparison
	case ">=":
		return token.GEQ
	case "<=":
		return token.LEQ
	case "<":
		return token.LSS
	case ">":
		return token.GTR
	case "!=":
		return token.NEQ
	case "==":
		return token.EQL

	// Logical
	case "!":
		return token.NOT
	case "&&":
		return token.LAND
	case "||":
		return token.LOR
	}

	panic(fmt.Sprintf("unknown operator: %s", operator))
}
<commit_msg>Fixing tests<commit_after>// This file contains functions transpiling unary and binary operator
// expressions.

package transpiler

import (
	"fmt"
	"go/token"

	goast "go/ast"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/types"
	"github.com/elliotchance/c2go/util"
)

func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) (
	*goast.BinaryExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	right, rightType, newPre, newPost, err := transpileToExpr(n.Children[1], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	operator := getTokenForOperator(n.Operator)
	returnType := types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType)

	if operator == token.LAND {
		left = types.CastExpr(p, left, leftType, "bool")
		right = types.CastExpr(p, right, rightType, "bool")

		return &goast.BinaryExpr{
			X:  left,
			Op: operator,
			Y:  right,
		}, "bool", preStmts, postStmts, nil
	}

	// Convert "(0)" to "nil" when we are dealing with equality.
	if (operator == token.NEQ || operator == token.EQL) &&
		types.IsNullExpr(right) {
		if types.ResolveType(p, leftType) == "string" {
			p.AddImport("github.com/elliotchance/c2go/noarch")
			left = util.NewCallExpr("noarch.NullTerminatedString", left)
			right = &goast.BasicLit{
				Kind:  token.STRING,
				Value: `""`,
			}
		} else {
			right = goast.NewIdent("nil")
		}
	}

	if operator == token.ASSIGN {
		right = types.CastExpr(p, right, rightType, returnType)
	}

	return &goast.BinaryExpr{
		X:  left,
		Op: operator,
		Y:  right,
	}, types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType), preStmts, postStmts, nil
}

func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
	goast.Expr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}
	operator := getTokenForOperator(n.Operator)

	// Unfortunately we cannot use the Go increment operators because we are not
	// providing any position information for tokens. This means that the ++/--
	// would be placed before the expression and would be invalid in Go.
	//
	// Until it can be properly fixed (can we trick Go into to placing it after
	// the expression with a magic position?) we will have to return a
	// BinaryExpr with the same functionality.
	if operator == token.INC || operator == token.DEC {
		binaryOperator := "+="
		if operator == token.DEC {
			binaryOperator = "-="
		}

		return transpileBinaryOperator(&ast.BinaryOperator{
			Type:     n.Type,
			Operator: binaryOperator,
			Children: []ast.Node{
				n.Children[0], &ast.IntegerLiteral{
					Type:     "int",
					Value:    "1",
					Children: []ast.Node{},
				},
			},
		}, p)
	}

	// Otherwise handle like a unary operator.
	e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	if operator == token.NOT {
		if eType == "bool" || eType == "_Bool" {
			return &goast.UnaryExpr{
				X:  e,
				Op: operator,
			}, "bool", preStmts, postStmts, nil
		}

		t := types.ResolveType(p, eType)
		if t == "string" {
			return &goast.BinaryExpr{
				X:  e,
				Op: token.EQL,
				Y: &goast.BasicLit{
					Kind:  token.STRING,
					Value: `""`,
				},
			}, "bool", preStmts, postStmts, nil
		}

		p.AddImport("github.com/elliotchance/c2go/noarch")

		functionName := fmt.Sprintf("noarch.Not%s", util.Ucfirst(t))

		return &goast.CallExpr{
			Fun:  goast.NewIdent(functionName),
			Args: []goast.Expr{e},
		}, eType, preStmts, postStmts, nil
	}

	if operator == token.MUL {
		if eType == "const char *" {
			return &goast.IndexExpr{
				X: e,
				Index: &goast.BasicLit{
					Kind:  token.INT,
					Value: "0",
				},
			}, "char", preStmts, postStmts, nil
		}

		t, err := types.GetDereferenceType(eType)
		if err != nil {
			return nil, "", preStmts, postStmts, err
		}

		return &goast.StarExpr{
			X: e,
		}, t, preStmts, postStmts, nil
	}

	if operator == token.AND {
		eType += " *"
	}

	return &goast.UnaryExpr{
		X:  e,
		Op: operator,
	}, eType, preStmts, postStmts, nil
}

// transpileConditionalOperator transpiles a conditional (also known as a
// ternary) operator:
//
//     a ? b : c
//
// We cannot simply convert these to an "if" statement becuase they by inside
// another expression.
//
// Since Go does not support the ternary operator or inline "if" statements we
// use a function, noarch.Ternary() to work the same way.
//
// It is also important to note that C only evaulates the "b" or "c" condition
// based on the result of "a" (from the above example). So we wrap the "b" and
// "c" in closures so that the Ternary function will only evaluate one of them.
func transpileConditionalOperator(n *ast.ConditionalOperator, p *program.Program) (
	*goast.CallExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	a, _, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	b, _, newPre, newPost, err := transpileToExpr(n.Children[1], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	c, _, newPre, newPost, err := transpileToExpr(n.Children[2], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	p.AddImport("github.com/elliotchance/c2go/noarch")

	// The following code will generate the Go AST that will simulate a
	// conditional (ternary) operator, in the form of:
	//
	//     noarch.Ternary(
	//         $1,
	//         func () interface{} {
	//             return $2
	//         },
	//         func () interface{} {
	//             return $3
	//         },
	//     )
	//
	// $2 and $3 (the true and false condition respectively) must be wrapped in
	// a closure so that they are not both executed.
	return &goast.CallExpr{
		Fun: goast.NewIdent("noarch.Ternary"),
		Args: []goast.Expr{
			a,
			newTernaryWrapper(b),
			newTernaryWrapper(c),
		},
	}, n.Type, preStmts, postStmts, nil
}

// newTernaryWrapper is a helper method used by transpileConditionalOperator().
// It will wrap an expression in a closure.
func newTernaryWrapper(e goast.Expr) *goast.FuncLit {
	return &goast.FuncLit{
		Type: &goast.FuncType{
			Params: &goast.FieldList{},
			Results: &goast.FieldList{
				List: []*goast.Field{
					&goast.Field{
						Type: &goast.InterfaceType{
							Methods: &goast.FieldList{},
						},
					},
				},
			},
		},
		Body: &goast.BlockStmt{
			List: []goast.Stmt{
				&goast.ReturnStmt{
					Results: []goast.Expr{e},
				},
			},
		},
	}
}

// transpileParenExpr transpiles an expression that is wrapped in parentheses.
// There is a special case where "(0)" is treated as a NULL (since that's what
// the macro expands to). We have to return the type as "null" since we don't
// know at this point what the NULL expression will be used in conjuction with.
func transpileParenExpr(n *ast.ParenExpr, p *program.Program) (
	*goast.ParenExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	e, eType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	r := &goast.ParenExpr{
		X: e,
	}
	if types.IsNullExpr(r) {
		eType = "null"
	}

	return r, eType, preStmts, postStmts, nil
}

func transpileCompoundAssignOperator(n *ast.CompoundAssignOperator, p *program.Program) (
	*goast.BinaryExpr, string, []goast.Stmt, []goast.Stmt, error) {
	preStmts := []goast.Stmt{}
	postStmts := []goast.Stmt{}

	left, _, newPre, newPost, err := transpileToExpr(n.Children[0], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	right, _, newPre, newPost, err := transpileToExpr(n.Children[1], p)
	if err != nil {
		return nil, "", nil, nil, err
	}

	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

	return &goast.BinaryExpr{
		X:  left,
		Y:  right,
		Op: getTokenForOperator(n.Opcode),
	}, "", preStmts, postStmts, nil
}

// getTokenForOperator returns the Go operator token for the provided C
// operator.
func getTokenForOperator(operator string) token.Token {
	switch operator {
	// Arithmetic
	case "--":
		return token.DEC
	case "++":
		return token.INC
	case "+":
		return token.ADD
	case "-":
		return token.SUB
	case "*":
		return token.MUL
	case "/":
		return token.QUO
	case "%":
		return token.REM

	// Assignment
	case "=":
		return token.ASSIGN
	case "+=":
		return token.ADD_ASSIGN
	case "-=":
		return token.SUB_ASSIGN
	case "*=":
		return token.MUL_ASSIGN
	case "/=":
		return token.QUO_ASSIGN
	case "%=":
		return token.REM_ASSIGN
	case "&=":
		return token.AND_ASSIGN
	case "|=":
		return token.OR_ASSIGN
	case "^=":
		return token.XOR_ASSIGN
	case "<<=":
		return token.SHL_ASSIGN
	case ">>=":
		return token.SHR_ASSIGN

	// Bitwise
	case "&":
		return token.AND
	case "|":
		return token.OR
	case "~":
		return token.XOR
	case ">>":
		return token.SHR
	case "<<":
		return token.SHL

	// Comparison
	case ">=":
		return token.GEQ
	case "<=":
		return token.LEQ
	case "<":
		return token.LSS
	case ">":
		return token.GTR
	case "!=":
		return token.NEQ
	case "==":
		return token.EQL

	// Logical
	case "!":
		return token.NOT
	case "&&":
		return token.LAND
	case "||":
		return token.LOR
	}

	panic(fmt.Sprintf("unknown operator: %s", operator))
}
<|endoftext|>


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

package twurlrc

import (
	"testing"
)

var SAMPLE string = `
---
configuration:
  default_profile:
  - userA
  - CONSUMERKEYA
profiles:
  userA:
    CONSUMERKEYA:
      consumer_secret: CONSUMERSECRETA
      username: userA
      consumer_key: CONSUMERKEYA
      secret: SECRETA
      token: TOKENA
  userB:
    CONSUMERKEYB:
      consumer_secret: CONSUMERSECRETB
      username: userB
      consumer_key: CONSUMERKEYB
      secret: SECRETB
      token: TOKENB
    CONSUMERKEYC:
      consumer_secret: CONSUMERSECRETC
      username: userB
      consumer_key: CONSUMERKEYC
      secret: SECRETC
      token: TOKENC`

// Compares two arrays for set equality (both have same members).
func Compare(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	set := map[string]struct{}{}
	for _, val := range a {
		set[val] = struct{}{}
	}
	for _, val := range b {
		if _, ok := set[val]; ok == false {
			return false
		}
	}
	return true
}

// Tests parting a piece of sample data.
func TestParse(t *testing.T) {
	twrc, err := Parse(SAMPLE)
	if err != nil {
		t.Error(err.String())
	}
	profiles := twrc.GetProfiles()
	if !Compare(profiles, []string{"userA", "userB"}) {
		t.Error("GetProfiles did not return correct data")
		t.Log(profiles)
	}
	keys := twrc.GetKeys("userB")
	if !Compare(keys, []string{"CONSUMERKEYB", "CONSUMERKEYC"}) {
		t.Error("GetKeys did not return correct data")
		t.Log(keys)
	}
	cred := twrc.GetDefaultCredentials()
	if cred.Token != "TOKENA" {
		t.Error("Invalid default token")
	}
	if cred.Username != "userA" {
		t.Error("Invalid default user")
	}
	if cred.ConsumerKey != "CONSUMERKEYA" {
		t.Error("Invalid default consumer key")
	}
	if cred.ConsumerSecret != "CONSUMERSECRETA" {
		t.Error("Invalid default consumer secret")
	}
	if cred.Secret != "SECRETA" {
		t.Error("Invalid default secret")
	}
	cred = twrc.GetCredentials("userB", "CONSUMERKEYC")
	if cred.Token != "TOKENC" {
		t.Error("Invalid requested token")
	}
	if cred.Username != "userB" {
		t.Error("Invalid requested user")
	}
	if cred.ConsumerKey != "CONSUMERKEYC" {
		t.Error("Invalid requested consumer key")
	}
	if cred.ConsumerSecret != "CONSUMERSECRETC" {
		t.Error("Invalid requested consumer secret")
	}
	if cred.Secret != "SECRETC" {
		t.Error("Invalid requested secret")
	}
}
<commit_msg>Update test for go1<commit_after>// Copyright 2012 Twitter, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package twurlrc

import (
	"testing"
)

var SAMPLE string = `
---
configuration:
  default_profile:
  - userA
  - CONSUMERKEYA
profiles:
  userA:
    CONSUMERKEYA:
      consumer_secret: CONSUMERSECRETA
      username: userA
      consumer_key: CONSUMERKEYA
      secret: SECRETA
      token: TOKENA
  userB:
    CONSUMERKEYB:
      consumer_secret: CONSUMERSECRETB
      username: userB
      consumer_key: CONSUMERKEYB
      secret: SECRETB
      token: TOKENB
    CONSUMERKEYC:
      consumer_secret: CONSUMERSECRETC
      username: userB
      consumer_key: CONSUMERKEYC
      secret: SECRETC
      token: TOKENC`

// Compares two arrays for set equality (both have same members).
func Compare(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	set := map[string]struct{}{}
	for _, val := range a {
		set[val] = struct{}{}
	}
	for _, val := range b {
		if _, ok := set[val]; ok == false {
			return false
		}
	}
	return true
}

// Tests parting a piece of sample data.
func TestParse(t *testing.T) {
	twrc, err := Parse(SAMPLE)
	if err != nil {
		t.Error(err.Error())
	}
	profiles := twrc.GetProfiles()
	if !Compare(profiles, []string{"userA", "userB"}) {
		t.Error("GetProfiles did not return correct data")
		t.Log(profiles)
	}
	keys := twrc.GetKeys("userB")
	if !Compare(keys, []string{"CONSUMERKEYB", "CONSUMERKEYC"}) {
		t.Error("GetKeys did not return correct data")
		t.Log(keys)
	}
	cred := twrc.GetDefaultCredentials()
	if cred.Token != "TOKENA" {
		t.Error("Invalid default token")
	}
	if cred.Username != "userA" {
		t.Error("Invalid default user")
	}
	if cred.ConsumerKey != "CONSUMERKEYA" {
		t.Error("Invalid default consumer key")
	}
	if cred.ConsumerSecret != "CONSUMERSECRETA" {
		t.Error("Invalid default consumer secret")
	}
	if cred.Secret != "SECRETA" {
		t.Error("Invalid default secret")
	}
	cred = twrc.GetCredentials("userB", "CONSUMERKEYC")
	if cred.Token != "TOKENC" {
		t.Error("Invalid requested token")
	}
	if cred.Username != "userB" {
		t.Error("Invalid requested user")
	}
	if cred.ConsumerKey != "CONSUMERKEYC" {
		t.Error("Invalid requested consumer key")
	}
	if cred.ConsumerSecret != "CONSUMERSECRETC" {
		t.Error("Invalid requested consumer secret")
	}
	if cred.Secret != "SECRETC" {
		t.Error("Invalid requested secret")
	}
}
<|endoftext|>


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

//
//	reflect router
//
package LVRouter

import (
	"fmt"
	. "github.com/slowfei/leafveingo"
	"reflect"
)

var (
	//	controller default url request ("http://localhost:8080/") method
	CONTROLLER_DEFAULT_METHOD = "Index"
)

//
//	reflect router other option
//
type ReflectRouterOption struct {
	scheme string // "http" || "https" || ""(wildcard)
	host   string // "svn.slowfei.com" || "wwww.slowfei.com" || ""(wildcard)
}

/**
 *	default option
 */
func DefaultReflectRouterOption() ReflectRouterOption {
	option := ReflectRouterOption{}
	option.host = ""
	option.scheme = ""
	return option
}

/**
 *	set scheme
 *	"http" || "https" || ""(wildcard)
 */
func (o *ReflectRouterOption) SetScheme(scheme string) *ReflectRouterOption {
	o.scheme = scheme
	return o
}

/**
 *	set host
 *	"svn.slowfei.com" || "wwww.slowfei.com" || ""(wildcard)
 */
func (o *ReflectRouterOption) SetHost(host string) *ReflectRouterOption {
	o.host = host
	return o
}

/**
 *	checked params
 */
func (o *ReflectRouterOption) checked() {

}

//
//	reflect router
//
//	rule:
//		router key = "/"
//			   URL = GET http://localhost:8080/
//		 func name = Index
//
//		router key = "/"
//			   URL = POST http://localhost:8080/
//		 func name = PostIndex
//
//		router key = "/admin/"
//			   URL = GET http://localhost:8080/admin/login
//		 func name = Login
//
//		router key = "/admin/"
//			   URL = POST http://localhost:8080/admin/login
//		 func name = PostLogin
//
//	控制器分的指针传递和值传递
//		值传递：
//		CreateReflectController("/home/", HomeController{})
//		每次请求(http://localhost:8080/home/)时 controller 都会根据设置的控制器类型新建立一个对象进行处理
//
//		地址传递：
//		CreateReflectController("/admin/", &AdminController{})
//		跟值传递相反，每次请求时都会使用设置的控制器地址进行处理，应用结束也不会改变，每次请求控制器都不会改变内存地址
//		这里涉及到并发时同时使用一个内存地址处理的问题，不过目前还没有弄到锁，并发后期会进行改进和处理。
type ReflectRouter struct {
	routerKey       string                // router key
	implBeforeAfter BeforeAfterController // implement interface
	implAdeRouter   AdeRouterController   // implement interface
	ctlRefVal       reflect.Value         // controller reflect value
	checkFuncName   map[string]int        // check func name map

	info    string
	typestr string
}

/**
 *	create reflect router controller
 *
 *	@param routerKey	"/" || "/home/" || "/admin/"
 *	@param controller
 */
func CreateReflectController(routerKey string, controller interface{}) IRouter {
	return CreateReflectControllerWithOption(routerKey, controller, DefaultReflectRouterOption())
}

/**
 *	create reflect router controller with option
 *
 *	@param option 	other params option
 */
func CreateReflectControllerWithOption(routerKey string, controller interface{}, option ReflectRouterOption) IRouter {
	option.checked()
	strBeforeAfter := ""
	strAde := ""

	refRouter := &ReflectRouter{routerKey: routerKey, checkFuncName: make(map[string]int)}
	refRouter.ctlRefVal = reflect.ValueOf(controller)

	if refRouter.ctlRefVal.Type().Implements(RefTypeBeforeAfterController) {
		refRouter.implBeforeAfter = controller.(BeforeAfterController)
		strBeforeAfter = "(Implemented BeforeAfterController)"
	}

	if refRouter.ctlRefVal.Type().Implements(RefTypeAdeRouterController) {
		refRouter.implAdeRouter = controller.(AdeRouterController)
		strAde = "(Implemented AdeRouterController)"
	}

	refType := refRouter.ctlRefVal.Type()
	for i := 0; i < refType.NumMethod(); i++ {
		refMet := refType.Method(i)
		funcName := refMet.Name
		if funcName[0] >= 'A' && funcName[0] <= 'Z' {
			refRouter.checkFuncName[funcName] = i
		}
	}

	refRouter.typestr = refType.String()
	refRouter.info = fmt.Sprintf("%v  \t router : %#v  %v%v", refType, routerKey, strBeforeAfter, strAde)

	return refRouter
}

/**
 *	func name suffix handle
 *
 *	@param funcName
 *	@param option
 */
func (r *ReflectRouter) funcNameSuffixHandle(funcName string, option RouterOption) string {
	result := funcName

	urlSuffix := option.UrlSuffix

	if 0 != len(urlSuffix) {
		firstc := urlSuffix[0]
		if firstc >= 'a' && firstc <= 'z' {
			firstc -= 'a' - 'A'
		}
		first := string(firstc)
		urlSuffix = first + urlSuffix[1:]

		tempFunc := funcName + urlSuffix

		if _, ok := r.checkFuncName[tempFunc]; ok {
			result = tempFunc
		}
	}

	return result
}

/**
 *	get func params
 *
 *	@param funcType
 *	@param
 */
func (r *ReflectRouter) getFuncArgs(funcType reflect.Type, context *HttpContext) []reflect.Value {
	argsNum := funcType.NumIn()
	args := make([]reflect.Value, argsNum, argsNum)

	for i := 0; i < argsNum; i++ {
		in := funcType.In(i)
		typeString := in.String()
		var argsValue reflect.Value

		switch typeString {
		case "*http.Request":
			argsValue = reflect.ValueOf(context.Request)
		case "http.Request":
			argsValue = reflect.ValueOf(context.Request).Elem()
		case "*url.URL":
			argsValue = reflect.ValueOf(context.Request.URL)
		case "url.URL":
			argsValue = reflect.ValueOf(context.Request.URL).Elem()
		case "*leafveingo.HttpContext":
			argsValue = reflect.ValueOf(context)
		case "leafveingo.HttpContext":
			argsValue = reflect.ValueOf(context).Elem()
		case "[]uint8":
			body := context.RequestBody()
			if nil != body {
				argsValue = reflect.ValueOf(body)
			} else {
				argsValue = reflect.Zero(in)
			}
		case "http.ResponseWriter":
			argsValue = reflect.ValueOf(context.RespWrite)
		case "LVSession.HttpSession":
			session, _ := context.Session(false)
			if nil != session {
				argsValue = reflect.ValueOf(session)
			} else {
				argsValue = reflect.Zero(in)
			}
		default:
			val, err := context.PackStructFormByRefType(in)
			if nil == err {
				argsValue = val
			} else {
				context.LVServer().Log().Debug(err.Error())
			}
		}

		if reflect.Invalid == argsValue.Kind() {
			argsValue = reflect.Zero(in)
		}

		args[i] = argsValue
	}

	return args
}

//# mark ReflectRouter override IRouter -------------------------------------------------------------------------------------------

func (r *ReflectRouter) RouterKey() string {
	return r.routerKey
}

func (r *ReflectRouter) ParseFuncName(context *HttpContext, option RouterOption) (funcName string, statusCode HttpStatus, err error) {

	/* 高级路由实现操作 */
	if nil != r.implAdeRouter {
		var params map[string]string = nil
		funcName, params = r.implAdeRouter.RouterMethodParse(option)

		if 0 == len(funcName) {
			statusCode = Status404
		} else {
			statusCode = Status200
		}

		if 0 != len(params) {
			values := context.Request.URL.Query()
			for k, v := range params {
				values.Set(k, v)
			}
			context.Request.URL.RawQuery = values.Encode()
		}
		return
	}

	statusCode = Status404
	method := option.RequestMethod
	reqPath := option.RouterPath

	/* parse func name prefix */
	funcNamePrefix := ""
	if "get" != method {
		firstc := method[0]
		if firstc >= 'a' && firstc <= 'z' {
			firstc -= 'a' - 'A'
		}
		first := string(firstc)
		funcNamePrefix = first + method[1:]
	}

	/* parse func name */

	//	url = "http://localhost:8080/router/" router key = "/router/" || "/router"
	//	reqPath = "" || "/" to Default func name
	if 0 == len(reqPath) || (1 == len(reqPath) && '/' == reqPath[0]) {
		statusCode = Status200
		funcName = r.funcNameSuffixHandle(funcNamePrefix+CONTROLLER_DEFAULT_METHOD, option)
		return
	}

	//	url = "http://localhost:8080/router/[reqPath]" router key = "/router/"
	//	reqPath = "list" funcName = "List"
	//	reqPath = "list#!json" || "list[^a-zA-Z]*json" funcName = "ListJson"
	//	reqPath = "list/user"  funcName = "ListUser"
	//	reqPath = "list/user/auto" || "list[^a-zA-Z]+user[^a-zA-Z]+auto"  funcName = "ListUserAuto"

	nameByte := make([]byte, len(reqPath))
	isUpper := true
	writeIdx := 0

	count := len(reqPath)
	for i := 0; i < count; i++ {
		c := reqPath[i]

		AZ := c >= 'A' && c <= 'Z'
		az := c >= 'a' && c <= 'z'

		if AZ || az {
			if isUpper {
				isUpper = false
				if az {
					c -= 'a' - 'A'
				}
			}
			nameByte[writeIdx] = c
			writeIdx++
		} else {
			isUpper = true
		}
	}

	if 0 != writeIdx {
		funcName = r.funcNameSuffixHandle(funcNamePrefix+string(nameByte[:writeIdx]), option)
		statusCode = Status200
	} else {
		statusCode = Status404
	}

	return
}

func (r *ReflectRouter) ParseTemplatePath(context *HttpContext, funcName string, option RouterOption) string {

	if 0 == len(funcName) {
		return ""
	}

	path := r.routerKey
	pathLen := len(path)
	name := funcName
	nameLen := len(name)

	if '/' == path[0] {
		path = path[1:]
		pathLen = len(path)
	}
	if '/' == path[pathLen-1] {
		path = path[:pathLen-1]
	}
	if '/' == name[0] {
		name = name[1:]
		nameLen = len(name)
	}
	if '/' == name[nameLen-1] {
		name = name[:nameLen-1]
	}

	return path + "/" + name + context.LVServer().TemplateSuffix()
}

func (r *ReflectRouter) CallFunc(context *HttpContext, funcName string, option RouterOption) (returnValue interface{}, statusCode HttpStatus, err error) {

	if index, ok := r.checkFuncName[funcName]; ok {
		statusCode = Status200

		refMet := r.ctlRefVal.Method(index)

		//	get params
		args := r.getFuncArgs(refMet.Type(), context)

		//	call method
		reVals := refMet.Call(args)

		if 0 != len(reVals) {
			returnValue = reVals[0].Interface()
		}

	} else {
		statusCode = Status404
		err = NewLeafveinError("(" + r.typestr + ") not found func name: " + funcName)
	}

	return
}

func (r *ReflectRouter) CallFuncBefore(context *HttpContext, option RouterOption) HttpStatus {
	statucCode := Status200

	if nil != r.implBeforeAfter {
		statucCode = r.implBeforeAfter.Before(context, option)
	}

	return statucCode
}

func (r *ReflectRouter) CallFuncAfter(context *HttpContext, option RouterOption) {
	if nil != r.implBeforeAfter {
		r.implBeforeAfter.After(context, option)
	}
}

func (r *ReflectRouter) Info() string {
	return r.info
}
<commit_msg>修改指针控制器和值控制器<commit_after>//	Copyright 2014 slowfei And The Contributors All rights reserved.
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
//  Create on 2014-06-16
//  Update on 2014-06-30
//  Email  slowfei#foxmail.com
//  Home   http://www.slowfei.com

//
//	reflect router
//
package LVRouter

import (
	"fmt"
	. "github.com/slowfei/leafveingo"
	"reflect"
)

var (
	//	controller default url request ("http://localhost:8080/") method
	CONTROLLER_DEFAULT_METHOD = "Index"
)

//
//	reflect router other option
//
type ReflectRouterOption struct {
	scheme string // "http" || "https" || ""(wildcard)
	host   string // "svn.slowfei.com" || "wwww.slowfei.com" || ""(wildcard)
}

/**
 *	default option
 */
func DefaultReflectRouterOption() ReflectRouterOption {
	option := ReflectRouterOption{}
	option.host = ""
	option.scheme = ""
	return option
}

/**
 *	set scheme
 *	"http" || "https" || ""(wildcard)
 */
func (o *ReflectRouterOption) SetScheme(scheme string) *ReflectRouterOption {
	o.scheme = scheme
	return o
}

/**
 *	set host
 *	"svn.slowfei.com" || "wwww.slowfei.com" || ""(wildcard)
 */
func (o *ReflectRouterOption) SetHost(host string) *ReflectRouterOption {
	o.host = host
	return o
}

/**
 *	checked params
 */
func (o *ReflectRouterOption) checked() {

}

//
//	reflect router
//
//	rule:
//		router key = "/"
//			   URL = GET http://localhost:8080/
//		 func name = Index
//
//		router key = "/"
//			   URL = POST http://localhost:8080/
//		 func name = PostIndex
//
//		router key = "/"
//			   URL = Get http://localhost:8080/user#!list
//		 func name = UserList
//
//		router key = "/"
//			   URL = Post http://localhost:8080/user[^a-zA-Z]+list[^a-zA-Z]+auto
//		 func name = PostUserListAuto
//
//		router key = "/admin/"
//			   URL = GET http://localhost:8080/admin/login
//		 func name = Login
//
//		router key = "/admin/"
//			   URL = POST http://localhost:8080/admin/login
//		 func name = PostLogin
//
//	控制器分的指针传递和值传递
//		值传递：
//		CreateReflectController("/home/", HomeController{})
//		每次请求(http://localhost:8080/home/)时 controller 都会根据设置的控制器类型新建立一个对象进行处理
//
//		指针传递：
//		CreateReflectController("/admin/", &AdminController{})
//		跟值传递相反，每次请求时都会使用设置的控制器地址进行处理，应用结束也不会改变，每次请求控制器都不会改变内存地址
//		这里涉及到并发时同时使用一个内存地址处理的问题，不过目前还没有弄到锁，并发后期会进行改进和处理。
type ReflectRouter struct {
	routerKey       string                // router key
	implBeforeAfter BeforeAfterController // implement interface
	implAdeRouter   AdeRouterController   // implement interface
	ctlRefVal       reflect.Value         // controller reflect value
	checkFuncName   map[string]int        // check func name map

	info    string
	typestr string
}

/**
 *	create reflect router controller
 *
 *	@param routerKey	"/" || "/home/" || "/admin/"
 *	@param controller
 */
func CreateReflectController(routerKey string, controller interface{}) IRouter {
	return CreateReflectControllerWithOption(routerKey, controller, DefaultReflectRouterOption())
}

/**
 *	create reflect router controller with option
 *
 *	@param option 	other params option
 */
func CreateReflectControllerWithOption(routerKey string, controller interface{}, option ReflectRouterOption) IRouter {
	option.checked()
	strBeforeAfter := ""
	strAde := ""

	refRouter := new(ReflectRouter)
	refRouter.routerKey = routerKey
	refRouter.checkFuncName = make(map[string]int)
	refRouter.ctlRefVal = reflect.ValueOf(controller)

	if refRouter.ctlRefVal.Type().Implements(RefTypeBeforeAfterController) {
		refRouter.implBeforeAfter = controller.(BeforeAfterController)
		strBeforeAfter = "(Implemented BeforeAfterController)"
	}

	if refRouter.ctlRefVal.Type().Implements(RefTypeAdeRouterController) {
		refRouter.implAdeRouter = controller.(AdeRouterController)
		strAde = "(Implemented AdeRouterController)"
	}

	refType := refRouter.ctlRefVal.Type()
	for i := 0; i < refType.NumMethod(); i++ {
		refMet := refType.Method(i)
		funcName := refMet.Name
		if funcName[0] >= 'A' && funcName[0] <= 'Z' {
			refRouter.checkFuncName[funcName] = i
		}
	}

	refRouter.typestr = refType.String()
	refRouter.info = fmt.Sprintf("%v  \t router : %#v  %v%v", refType, routerKey, strBeforeAfter, strAde)

	return refRouter
}

/**
 *	func name suffix handle
 *
 *	@param funcName
 *	@param option
 */
func (r *ReflectRouter) funcNameSuffixHandle(funcName string, option *RouterOption) string {
	result := funcName

	urlSuffix := option.UrlSuffix

	if 0 != len(urlSuffix) {
		firstc := urlSuffix[0]
		if firstc >= 'a' && firstc <= 'z' {
			firstc -= 'a' - 'A'
		}
		first := string(firstc)
		urlSuffix = first + urlSuffix[1:]

		tempFunc := funcName + urlSuffix

		if _, ok := r.checkFuncName[tempFunc]; ok {
			result = tempFunc
		}
	}

	return result
}

/**
 *	get func params
 *
 *	@param funcType
 *	@param
 */
func (r *ReflectRouter) getFuncArgs(funcType reflect.Type, context *HttpContext) []reflect.Value {
	argsNum := funcType.NumIn()
	args := make([]reflect.Value, argsNum, argsNum)

	for i := 0; i < argsNum; i++ {
		in := funcType.In(i)
		typeString := in.String()
		var argsValue reflect.Value

		switch typeString {
		case "*http.Request":
			argsValue = reflect.ValueOf(context.Request)
		case "http.Request":
			argsValue = reflect.ValueOf(context.Request).Elem()
		case "*url.URL":
			argsValue = reflect.ValueOf(context.Request.URL)
		case "url.URL":
			argsValue = reflect.ValueOf(context.Request.URL).Elem()
		case "*leafveingo.HttpContext":
			argsValue = reflect.ValueOf(context)
		case "leafveingo.HttpContext":
			argsValue = reflect.ValueOf(context).Elem()
		case "[]uint8":
			body := context.RequestBody()
			if nil != body {
				argsValue = reflect.ValueOf(body)
			} else {
				argsValue = reflect.Zero(in)
			}
		case "http.ResponseWriter":
			argsValue = reflect.ValueOf(context.RespWrite)
		case "LVSession.HttpSession":
			session, _ := context.Session(false)
			if nil != session {
				argsValue = reflect.ValueOf(session)
			} else {
				argsValue = reflect.Zero(in)
			}
		default:
			val, err := context.PackStructFormByRefType(in)
			if nil == err {
				argsValue = val
			} else {
				context.LVServer().Log().Debug(err.Error())
			}
		}

		if reflect.Invalid == argsValue.Kind() {
			argsValue = reflect.Zero(in)
		}

		args[i] = argsValue
	}

	return args
}

//# mark ReflectRouter override IRouter -------------------------------------------------------------------------------------------

func (r *ReflectRouter) AfterRouterParse(context *HttpContext, option *RouterOption) HttpStatus {
	statusCode := Status200

	if reflect.Ptr != r.ctlRefVal.Kind() {
		option.RouterDataRefVal = reflect.New(r.ctlRefVal.Type())
	}

	return statusCode
}

func (r *ReflectRouter) ParseFuncName(context *HttpContext, option *RouterOption) (funcName string, statusCode HttpStatus, err error) {

	/* 高级路由实现操作 */
	if nil != r.implAdeRouter {
		var params map[string]string = nil

		if reflect.Invalid != option.RouterDataRefVal.Kind() {
			adeRouter := option.RouterDataRefVal.Interface().(AdeRouterController)
			funcName, params = adeRouter.RouterMethodParse(option)
		} else {
			funcName, params = r.implAdeRouter.RouterMethodParse(option)
		}

		if 0 == len(funcName) {
			statusCode = Status404
		} else {
			statusCode = Status200
		}

		if 0 != len(params) {
			values := context.Request.URL.Query()
			for k, v := range params {
				values.Set(k, v)
			}
			context.Request.URL.RawQuery = values.Encode()
		}
		return
	}

	statusCode = Status404
	method := option.RequestMethod
	reqPath := option.RouterPath

	/* parse func name prefix */
	funcNamePrefix := ""
	if "get" != method {
		firstc := method[0]
		if firstc >= 'a' && firstc <= 'z' {
			firstc -= 'a' - 'A'
		}
		first := string(firstc)
		funcNamePrefix = first + method[1:]
	}

	/* parse func name */

	//	url = "http://localhost:8080/router/" router key = "/router/" || "/router"
	//	reqPath = "" || "/" to Default func name
	if 0 == len(reqPath) || (1 == len(reqPath) && '/' == reqPath[0]) {
		statusCode = Status200
		funcName = r.funcNameSuffixHandle(funcNamePrefix+CONTROLLER_DEFAULT_METHOD, option)
		return
	}

	//	url = "http://localhost:8080/router/[reqPath]" router key = "/router/"
	//	reqPath = "list" funcName = "List"
	//	reqPath = "list#!json" || "list[^a-zA-Z]*json" funcName = "ListJson"
	//	reqPath = "list/user"  funcName = "ListUser"
	//	reqPath = "list/user/auto" || "list[^a-zA-Z]+user[^a-zA-Z]+auto"  funcName = "ListUserAuto"

	nameByte := make([]byte, len(reqPath))
	isUpper := true
	writeIdx := 0

	count := len(reqPath)
	for i := 0; i < count; i++ {
		c := reqPath[i]

		AZ := c >= 'A' && c <= 'Z'
		az := c >= 'a' && c <= 'z'

		if AZ || az {
			if isUpper {
				isUpper = false
				if az {
					c -= 'a' - 'A'
				}
			}
			nameByte[writeIdx] = c
			writeIdx++
		} else {
			isUpper = true
		}
	}

	if 0 != writeIdx {
		funcName = r.funcNameSuffixHandle(funcNamePrefix+string(nameByte[:writeIdx]), option)
		statusCode = Status200
	} else {
		statusCode = Status404
	}

	return
}

func (r *ReflectRouter) CallFuncBefore(context *HttpContext, option *RouterOption) HttpStatus {
	statucCode := Status200

	if nil != r.implBeforeAfter {
		if reflect.Invalid != option.RouterDataRefVal.Kind() {
			beforeAfter := option.RouterDataRefVal.Interface().(BeforeAfterController)
			statucCode = beforeAfter.Before(context, option)
		} else {
			statucCode = r.implBeforeAfter.Before(context, option)
		}
	}

	return statucCode
}

func (r *ReflectRouter) CallFunc(context *HttpContext, funcName string, option *RouterOption) (returnValue interface{}, statusCode HttpStatus, err error) {

	if index, ok := r.checkFuncName[funcName]; ok {
		statusCode = Status200

		var controller reflect.Value

		if reflect.Invalid != option.RouterDataRefVal.Kind() {
			controller = option.RouterDataRefVal
		} else {
			controller = r.ctlRefVal
		}

		refMet := controller.Method(index)

		//	get params
		args := r.getFuncArgs(refMet.Type(), context)

		//	call method
		reVals := refMet.Call(args)

		if 0 != len(reVals) {
			returnValue = reVals[0].Interface()
		}

	} else {
		statusCode = Status404
		err = NewLeafveinError("(" + r.typestr + ") not found func name: " + funcName)
	}

	return
}

func (r *ReflectRouter) ParseTemplatePath(context *HttpContext, funcName string, option *RouterOption) string {

	if 0 == len(funcName) {
		return ""
	}

	path := r.routerKey
	pathLen := len(path)
	name := funcName
	nameLen := len(name)

	if '/' == path[0] {
		path = path[1:]
		pathLen = len(path)
	}
	if '/' == path[pathLen-1] {
		path = path[:pathLen-1]
	}
	if '/' == name[0] {
		name = name[1:]
		nameLen = len(name)
	}
	if '/' == name[nameLen-1] {
		name = name[:nameLen-1]
	}

	return path + "/" + name + context.LVServer().TemplateSuffix()
}

func (r *ReflectRouter) CallFuncAfter(context *HttpContext, option *RouterOption) {
	if nil != r.implBeforeAfter {
		if reflect.Invalid == option.RouterDataRefVal.Kind() {
			beforeAfter := option.RouterDataRefVal.Interface().(BeforeAfterController)
			beforeAfter.After(context, option)
		} else {
			r.implBeforeAfter.After(context, option)
		}
	}
}

func (r *ReflectRouter) RouterKey() string {
	return r.routerKey
}

func (r *ReflectRouter) Info() string {
	return r.info
}
<|endoftext|>


<commit_before>package sensu

import "fmt"

// GetClients returns a slice of all clients
func (s *Sensu) GetClients() ([]interface{}, error) {
	return s.getSlice("clients", DefaultLimit)
}

// GetClient returns a map of a specific client corresponding to the provided client name
func (s *Sensu) GetClient(client string) (map[string]interface{}, error) {
	return s.getMap(fmt.Sprintf("clients/%s", client))
}

// GetClientHistory returns a slice containing the history of a specific check corresponding to the provided client name
func (s *Sensu) GetClientHistory(client string) ([]interface{}, error) {
	return s.getSlice(fmt.Sprintf("clients/%s/history", client), NoLimit)
}

// DeleteClient deletes a client using its name
func (s *Sensu) DeleteClient(client string) error {
	return s.delete(fmt.Sprintf("clients/%s", client))
}
<commit_msg>Disable pagination in fetching clients from the Sensu API<commit_after>package sensu

import "fmt"

// GetClients returns a slice of all clients
func (s *Sensu) GetClients() ([]interface{}, error) {
	return s.getSlice("clients", NoLimit)
}

// GetClient returns a map of a specific client corresponding to the provided client name
func (s *Sensu) GetClient(client string) (map[string]interface{}, error) {
	return s.getMap(fmt.Sprintf("clients/%s", client))
}

// GetClientHistory returns a slice containing the history of a specific check corresponding to the provided client name
func (s *Sensu) GetClientHistory(client string) ([]interface{}, error) {
	return s.getSlice(fmt.Sprintf("clients/%s/history", client), NoLimit)
}

// DeleteClient deletes a client using its name
func (s *Sensu) DeleteClient(client string) error {
	return s.delete(fmt.Sprintf("clients/%s", client))
}
<|endoftext|>


<commit_before>/*

aufs driver directory structure

.
├── layers // Metadata of layers
│   ├── 1
│   ├── 2
│   └── 3
├── diff  // Content of the layer
│   ├── 1  // Contains layers that need to be mounted for the id
│   ├── 2
│   └── 3
└── mnt    // Mount points for the rw layers to be mounted
    ├── 1
    ├── 2
    └── 3

*/

package aufs

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/graphdriver"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/chrootarchive"
	mountpk "github.com/docker/docker/pkg/mount"
	"github.com/docker/docker/utils"
	"github.com/docker/libcontainer/label"
)

var (
	ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
	incompatibleFsMagic = []graphdriver.FsMagic{
		graphdriver.FsMagicBtrfs,
		graphdriver.FsMagicAufs,
	}
)

func init() {
	graphdriver.Register("aufs", Init)
}

type Driver struct {
	root       string
	sync.Mutex // Protects concurrent modification to active
	active     map[string]int
}

// New returns a new AUFS driver.
// An error is returned if AUFS is not supported.
func Init(root string, options []string) (graphdriver.Driver, error) {
	// Try to load the aufs kernel module
	if err := supportsAufs(); err != nil {
		return nil, graphdriver.ErrNotSupported
	}

	rootdir := path.Dir(root)

	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return nil, fmt.Errorf("Couldn't stat the root directory: %s", err)
	}

	for _, magic := range incompatibleFsMagic {
		if graphdriver.FsMagic(buf.Type) == magic {
			return nil, graphdriver.ErrIncompatibleFS
		}
	}

	paths := []string{
		"mnt",
		"diff",
		"layers",
	}

	a := &Driver{
		root:   root,
		active: make(map[string]int),
	}

	// Create the root aufs driver dir and return
	// if it already exists
	// If not populate the dir structure
	if err := os.MkdirAll(root, 0755); err != nil {
		if os.IsExist(err) {
			return a, nil
		}
		return nil, err
	}

	if err := mountpk.MakePrivate(root); err != nil {
		return nil, err
	}

	for _, p := range paths {
		if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
			return nil, err
		}
	}
	return a, nil
}

// Return a nil error if the kernel supports aufs
// We cannot modprobe because inside dind modprobe fails
// to run
func supportsAufs() error {
	// We can try to modprobe aufs first before looking at
	// proc/filesystems for when aufs is supported
	exec.Command("modprobe", "aufs").Run()

	f, err := os.Open("/proc/filesystems")
	if err != nil {
		return err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		if strings.Contains(s.Text(), "aufs") {
			return nil
		}
	}
	return ErrAufsNotSupported
}

func (a Driver) rootPath() string {
	return a.root
}

func (Driver) String() string {
	return "aufs"
}

func (a Driver) Status() [][2]string {
	ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
	return [][2]string{
		{"Root Dir", a.rootPath()},
		{"Dirs", fmt.Sprintf("%d", len(ids))},
	}
}

// Exists returns true if the given id is registered with
// this driver
func (a Driver) Exists(id string) bool {
	if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
		return false
	}
	return true
}

// Three folders are created for each id
// mnt, layers, and diff
func (a *Driver) Create(id, parent string) error {
	if err := a.createDirsFor(id); err != nil {
		return err
	}
	// Write the layers metadata
	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
	if err != nil {
		return err
	}
	defer f.Close()

	if parent != "" {
		ids, err := getParentIds(a.rootPath(), parent)
		if err != nil {
			return err
		}

		if _, err := fmt.Fprintln(f, parent); err != nil {
			return err
		}
		for _, i := range ids {
			if _, err := fmt.Fprintln(f, i); err != nil {
				return err
			}
		}
	}
	return nil
}

func (a *Driver) createDirsFor(id string) error {
	paths := []string{
		"mnt",
		"diff",
	}

	for _, p := range paths {
		if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
			return err
		}
	}
	return nil
}

// Unmount and remove the dir information
func (a *Driver) Remove(id string) error {
	// Protect the a.active from concurrent access
	a.Lock()
	defer a.Unlock()

	if a.active[id] != 0 {
		log.Errorf("Warning: removing active id %s", id)
	}

	// Make sure the dir is umounted first
	if err := a.unmount(id); err != nil {
		return err
	}
	tmpDirs := []string{
		"mnt",
		"diff",
	}

	// Atomically remove each directory in turn by first moving it out of the
	// way (so that docker doesn't find it anymore) before doing removal of
	// the whole tree.
	for _, p := range tmpDirs {

		realPath := path.Join(a.rootPath(), p, id)
		tmpPath := path.Join(a.rootPath(), p, fmt.Sprintf("%s-removing", id))
		if err := os.Rename(realPath, tmpPath); err != nil && !os.IsNotExist(err) {
			return err
		}
		defer os.RemoveAll(tmpPath)
	}

	// Remove the layers file for the id
	if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
		return err
	}
	return nil
}

// Return the rootfs path for the id
// This will mount the dir at it's given path
func (a *Driver) Get(id, mountLabel string) (string, error) {
	ids, err := getParentIds(a.rootPath(), id)
	if err != nil {
		if !os.IsNotExist(err) {
			return "", err
		}
		ids = []string{}
	}

	// Protect the a.active from concurrent access
	a.Lock()
	defer a.Unlock()

	count := a.active[id]

	// If a dir does not have a parent ( no layers )do not try to mount
	// just return the diff path to the data
	out := path.Join(a.rootPath(), "diff", id)
	if len(ids) > 0 {
		out = path.Join(a.rootPath(), "mnt", id)

		if count == 0 {
			if err := a.mount(id, mountLabel); err != nil {
				return "", err
			}
		}
	}

	a.active[id] = count + 1

	return out, nil
}

func (a *Driver) Put(id string) {
	// Protect the a.active from concurrent access
	a.Lock()
	defer a.Unlock()

	if count := a.active[id]; count > 1 {
		a.active[id] = count - 1
	} else {
		ids, _ := getParentIds(a.rootPath(), id)
		// We only mounted if there are any parents
		if ids != nil && len(ids) > 0 {
			a.unmount(id)
		}
		delete(a.active, id)
	}
}

// Diff produces an archive of the changes between the specified
// layer and its parent layer which may be "".
func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
	// AUFS doesn't need the parent layer to produce a diff.
	return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
		Compression: archive.Uncompressed,
		Excludes:    []string{".wh..wh.*"},
	})
}

func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
	return chrootarchive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
}

// DiffSize calculates the changes between the specified id
// and its parent and returns the size in bytes of the changes
// relative to its base filesystem directory.
func (a *Driver) DiffSize(id, parent string) (bytes int64, err error) {
	// AUFS doesn't need the parent layer to calculate the diff size.
	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
}

// ApplyDiff extracts the changeset from the given diff into the
// layer with the specified id and parent, returning the size of the
// new layer in bytes.
func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
	// AUFS doesn't need the parent id to apply the diff.
	if err = a.applyDiff(id, diff); err != nil {
		return
	}

	return a.DiffSize(id, parent)
}

// Changes produces a list of changes between the specified layer
// and its parent layer. If parent is "", then all changes will be ADD changes.
func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
	// AUFS doesn't have snapshots, so we need to get changes from all parent
	// layers.
	layers, err := a.getParentLayerPaths(id)
	if err != nil {
		return nil, err
	}
	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
}

func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
	parentIds, err := getParentIds(a.rootPath(), id)
	if err != nil {
		return nil, err
	}
	layers := make([]string, len(parentIds))

	// Get the diff paths for all the parent ids
	for i, p := range parentIds {
		layers[i] = path.Join(a.rootPath(), "diff", p)
	}
	return layers, nil
}

func (a *Driver) mount(id, mountLabel string) error {
	// If the id is mounted or we get an error return
	if mounted, err := a.mounted(id); err != nil || mounted {
		return err
	}

	var (
		target = path.Join(a.rootPath(), "mnt", id)
		rw     = path.Join(a.rootPath(), "diff", id)
	)

	layers, err := a.getParentLayerPaths(id)
	if err != nil {
		return err
	}

	if err := a.aufsMount(layers, rw, target, mountLabel); err != nil {
		return err
	}
	return nil
}

func (a *Driver) unmount(id string) error {
	if mounted, err := a.mounted(id); err != nil || !mounted {
		return err
	}
	target := path.Join(a.rootPath(), "mnt", id)
	return Unmount(target)
}

func (a *Driver) mounted(id string) (bool, error) {
	target := path.Join(a.rootPath(), "mnt", id)
	return mountpk.Mounted(target)
}

// During cleanup aufs needs to unmount all mountpoints
func (a *Driver) Cleanup() error {
	ids, err := loadIds(path.Join(a.rootPath(), "layers"))
	if err != nil {
		return err
	}

	for _, id := range ids {
		if err := a.unmount(id); err != nil {
			log.Errorf("Unmounting %s: %s", utils.TruncateID(id), err)
		}
	}

	return mountpk.Unmount(a.root)
}

func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) {
	defer func() {
		if err != nil {
			Unmount(target)
		}
	}()

	// Mount options are clipped to page size(4096 bytes). If there are more
	// layers then these are remounted individually using append.

	b := make([]byte, syscall.Getpagesize()-len(mountLabel)-50) // room for xino & mountLabel
	bp := copy(b, fmt.Sprintf("br:%s=rw", rw))

	firstMount := true
	i := 0

	for {
		for ; i < len(ro); i++ {
			layer := fmt.Sprintf(":%s=ro+wh", ro[i])

			if firstMount {
				if bp+len(layer) > len(b) {
					break
				}
				bp += copy(b[bp:], layer)
			} else {
				data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel)
				if err = mount("none", target, "aufs", MsRemount, data); err != nil {
					return
				}
			}
		}

		if firstMount {
			data := label.FormatMountLabel(fmt.Sprintf("%s,xino=/dev/shm/aufs.xino", string(b[:bp])), mountLabel)
			if err = mount("none", target, "aufs", 0, data); err != nil {
				return
			}
			firstMount = false
		}

		if i == len(ro) {
			break
		}
	}

	return
}
<commit_msg>Fix vet errors in aufs.go about Lock by value<commit_after>/*

aufs driver directory structure

.
├── layers // Metadata of layers
│   ├── 1
│   ├── 2
│   └── 3
├── diff  // Content of the layer
│   ├── 1  // Contains layers that need to be mounted for the id
│   ├── 2
│   └── 3
└── mnt    // Mount points for the rw layers to be mounted
    ├── 1
    ├── 2
    └── 3

*/

package aufs

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/graphdriver"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/chrootarchive"
	mountpk "github.com/docker/docker/pkg/mount"
	"github.com/docker/docker/utils"
	"github.com/docker/libcontainer/label"
)

var (
	ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
	incompatibleFsMagic = []graphdriver.FsMagic{
		graphdriver.FsMagicBtrfs,
		graphdriver.FsMagicAufs,
	}
)

func init() {
	graphdriver.Register("aufs", Init)
}

type Driver struct {
	root       string
	sync.Mutex // Protects concurrent modification to active
	active     map[string]int
}

// New returns a new AUFS driver.
// An error is returned if AUFS is not supported.
func Init(root string, options []string) (graphdriver.Driver, error) {
	// Try to load the aufs kernel module
	if err := supportsAufs(); err != nil {
		return nil, graphdriver.ErrNotSupported
	}

	rootdir := path.Dir(root)

	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return nil, fmt.Errorf("Couldn't stat the root directory: %s", err)
	}

	for _, magic := range incompatibleFsMagic {
		if graphdriver.FsMagic(buf.Type) == magic {
			return nil, graphdriver.ErrIncompatibleFS
		}
	}

	paths := []string{
		"mnt",
		"diff",
		"layers",
	}

	a := &Driver{
		root:   root,
		active: make(map[string]int),
	}

	// Create the root aufs driver dir and return
	// if it already exists
	// If not populate the dir structure
	if err := os.MkdirAll(root, 0755); err != nil {
		if os.IsExist(err) {
			return a, nil
		}
		return nil, err
	}

	if err := mountpk.MakePrivate(root); err != nil {
		return nil, err
	}

	for _, p := range paths {
		if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
			return nil, err
		}
	}
	return a, nil
}

// Return a nil error if the kernel supports aufs
// We cannot modprobe because inside dind modprobe fails
// to run
func supportsAufs() error {
	// We can try to modprobe aufs first before looking at
	// proc/filesystems for when aufs is supported
	exec.Command("modprobe", "aufs").Run()

	f, err := os.Open("/proc/filesystems")
	if err != nil {
		return err
	}
	defer f.Close()

	s := bufio.NewScanner(f)
	for s.Scan() {
		if strings.Contains(s.Text(), "aufs") {
			return nil
		}
	}
	return ErrAufsNotSupported
}

func (a *Driver) rootPath() string {
	return a.root
}

func (*Driver) String() string {
	return "aufs"
}

func (a *Driver) Status() [][2]string {
	ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
	return [][2]string{
		{"Root Dir", a.rootPath()},
		{"Dirs", fmt.Sprintf("%d", len(ids))},
	}
}

// Exists returns true if the given id is registered with
// this driver
func (a *Driver) Exists(id string) bool {
	if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
		return false
	}
	return true
}

// Three folders are created for each id
// mnt, layers, and diff
func (a *Driver) Create(id, parent string) error {
	if err := a.createDirsFor(id); err != nil {
		return err
	}
	// Write the layers metadata
	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
	if err != nil {
		return err
	}
	defer f.Close()

	if parent != "" {
		ids, err := getParentIds(a.rootPath(), parent)
		if err != nil {
			return err
		}

		if _, err := fmt.Fprintln(f, parent); err != nil {
			return err
		}
		for _, i := range ids {
			if _, err := fmt.Fprintln(f, i); err != nil {
				return err
			}
		}
	}
	return nil
}

func (a *Driver) createDirsFor(id string) error {
	paths := []string{
		"mnt",
		"diff",
	}

	for _, p := range paths {
		if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
			return err
		}
	}
	return nil
}

// Unmount and remove the dir information
func (a *Driver) Remove(id string) error {
	// Protect the a.active from concurrent access
	a.Lock()
	defer a.Unlock()

	if a.active[id] != 0 {
		log.Errorf("Warning: removing active id %s", id)
	}

	// Make sure the dir is umounted first
	if err := a.unmount(id); err != nil {
		return err
	}
	tmpDirs := []string{
		"mnt",
		"diff",
	}

	// Atomically remove each directory in turn by first moving it out of the
	// way (so that docker doesn't find it anymore) before doing removal of
	// the whole tree.
	for _, p := range tmpDirs {

		realPath := path.Join(a.rootPath(), p, id)
		tmpPath := path.Join(a.rootPath(), p, fmt.Sprintf("%s-removing", id))
		if err := os.Rename(realPath, tmpPath); err != nil && !os.IsNotExist(err) {
			return err
		}
		defer os.RemoveAll(tmpPath)
	}

	// Remove the layers file for the id
	if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
		return err
	}
	return nil
}

// Return the rootfs path for the id
// This will mount the dir at it's given path
func (a *Driver) Get(id, mountLabel string) (string, error) {
	ids, err := getParentIds(a.rootPath(), id)
	if err != nil {
		if !os.IsNotExist(err) {
			return "", err
		}
		ids = []string{}
	}

	// Protect the a.active from concurrent access
	a.Lock()
	defer a.Unlock()

	count := a.active[id]

	// If a dir does not have a parent ( no layers )do not try to mount
	// just return the diff path to the data
	out := path.Join(a.rootPath(), "diff", id)
	if len(ids) > 0 {
		out = path.Join(a.rootPath(), "mnt", id)

		if count == 0 {
			if err := a.mount(id, mountLabel); err != nil {
				return "", err
			}
		}
	}

	a.active[id] = count + 1

	return out, nil
}

func (a *Driver) Put(id string) {
	// Protect the a.active from concurrent access
	a.Lock()
	defer a.Unlock()

	if count := a.active[id]; count > 1 {
		a.active[id] = count - 1
	} else {
		ids, _ := getParentIds(a.rootPath(), id)
		// We only mounted if there are any parents
		if ids != nil && len(ids) > 0 {
			a.unmount(id)
		}
		delete(a.active, id)
	}
}

// Diff produces an archive of the changes between the specified
// layer and its parent layer which may be "".
func (a *Driver) Diff(id, parent string) (archive.Archive, error) {
	// AUFS doesn't need the parent layer to produce a diff.
	return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
		Compression: archive.Uncompressed,
		Excludes:    []string{".wh..wh.*"},
	})
}

func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
	return chrootarchive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
}

// DiffSize calculates the changes between the specified id
// and its parent and returns the size in bytes of the changes
// relative to its base filesystem directory.
func (a *Driver) DiffSize(id, parent string) (bytes int64, err error) {
	// AUFS doesn't need the parent layer to calculate the diff size.
	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
}

// ApplyDiff extracts the changeset from the given diff into the
// layer with the specified id and parent, returning the size of the
// new layer in bytes.
func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
	// AUFS doesn't need the parent id to apply the diff.
	if err = a.applyDiff(id, diff); err != nil {
		return
	}

	return a.DiffSize(id, parent)
}

// Changes produces a list of changes between the specified layer
// and its parent layer. If parent is "", then all changes will be ADD changes.
func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
	// AUFS doesn't have snapshots, so we need to get changes from all parent
	// layers.
	layers, err := a.getParentLayerPaths(id)
	if err != nil {
		return nil, err
	}
	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
}

func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
	parentIds, err := getParentIds(a.rootPath(), id)
	if err != nil {
		return nil, err
	}
	layers := make([]string, len(parentIds))

	// Get the diff paths for all the parent ids
	for i, p := range parentIds {
		layers[i] = path.Join(a.rootPath(), "diff", p)
	}
	return layers, nil
}

func (a *Driver) mount(id, mountLabel string) error {
	// If the id is mounted or we get an error return
	if mounted, err := a.mounted(id); err != nil || mounted {
		return err
	}

	var (
		target = path.Join(a.rootPath(), "mnt", id)
		rw     = path.Join(a.rootPath(), "diff", id)
	)

	layers, err := a.getParentLayerPaths(id)
	if err != nil {
		return err
	}

	if err := a.aufsMount(layers, rw, target, mountLabel); err != nil {
		return err
	}
	return nil
}

func (a *Driver) unmount(id string) error {
	if mounted, err := a.mounted(id); err != nil || !mounted {
		return err
	}
	target := path.Join(a.rootPath(), "mnt", id)
	return Unmount(target)
}

func (a *Driver) mounted(id string) (bool, error) {
	target := path.Join(a.rootPath(), "mnt", id)
	return mountpk.Mounted(target)
}

// During cleanup aufs needs to unmount all mountpoints
func (a *Driver) Cleanup() error {
	ids, err := loadIds(path.Join(a.rootPath(), "layers"))
	if err != nil {
		return err
	}

	for _, id := range ids {
		if err := a.unmount(id); err != nil {
			log.Errorf("Unmounting %s: %s", utils.TruncateID(id), err)
		}
	}

	return mountpk.Unmount(a.root)
}

func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) {
	defer func() {
		if err != nil {
			Unmount(target)
		}
	}()

	// Mount options are clipped to page size(4096 bytes). If there are more
	// layers then these are remounted individually using append.

	b := make([]byte, syscall.Getpagesize()-len(mountLabel)-50) // room for xino & mountLabel
	bp := copy(b, fmt.Sprintf("br:%s=rw", rw))

	firstMount := true
	i := 0

	for {
		for ; i < len(ro); i++ {
			layer := fmt.Sprintf(":%s=ro+wh", ro[i])

			if firstMount {
				if bp+len(layer) > len(b) {
					break
				}
				bp += copy(b[bp:], layer)
			} else {
				data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel)
				if err = mount("none", target, "aufs", MsRemount, data); err != nil {
					return
				}
			}
		}

		if firstMount {
			data := label.FormatMountLabel(fmt.Sprintf("%s,xino=/dev/shm/aufs.xino", string(b[:bp])), mountLabel)
			if err = mount("none", target, "aufs", 0, data); err != nil {
				return
			}
			firstMount = false
		}

		if i == len(ro) {
			break
		}
	}

	return
}
<|endoftext|>


<commit_before>package nomad

import (
	"testing"
	"time"

	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
)

func TestCoreScheduler_EvalGC(t *testing.T) {
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Insert "dead" eval
	state := s1.fsm.State()
	eval := mock.Eval()
	eval.Status = structs.EvalStatusFailed
	err := state.UpsertEvals(1000, []*structs.Evaluation{eval})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Insert "dead" alloc
	alloc := mock.Alloc()
	alloc.EvalID = eval.ID
	alloc.DesiredStatus = structs.AllocDesiredStatusFailed
	err = state.UpsertAllocs(1001, []*structs.Allocation{alloc})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Update the time tables to make this work
	tt := s1.fsm.TimeTable()
	tt.Witness(2000, time.Now().UTC().Add(-1*s1.config.EvalGCThreshold))

	// Create a core scheduler
	snap, err := state.Snapshot()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	core := NewCoreScheduler(s1, snap)

	// Attempt the GC
	gc := s1.coreJobEval(structs.CoreJobEvalGC)
	gc.ModifyIndex = 2000
	err = core.Process(gc)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should be gone
	out, err := state.EvalByID(eval.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if out != nil {
		t.Fatalf("bad: %v", out)
	}

	outA, err := state.AllocByID(alloc.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if outA != nil {
		t.Fatalf("bad: %v", outA)
	}
}

func TestCoreScheduler_NodeGC(t *testing.T) {
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Insert "dead" node
	state := s1.fsm.State()
	node := mock.Node()
	node.Status = structs.NodeStatusDown
	err := state.UpsertNode(1000, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Update the time tables to make this work
	tt := s1.fsm.TimeTable()
	tt.Witness(2000, time.Now().UTC().Add(-1*s1.config.NodeGCThreshold))

	// Create a core scheduler
	snap, err := state.Snapshot()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	core := NewCoreScheduler(s1, snap)

	// Attempt the GC
	gc := s1.coreJobEval(structs.CoreJobNodeGC)
	gc.ModifyIndex = 2000
	err = core.Process(gc)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should be gone
	out, err := state.NodeByID(node.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if out != nil {
		t.Fatalf("bad: %v", out)
	}
}

func TestCoreScheduler_JobGC(t *testing.T) {
	tests := []struct {
		test, evalStatus, allocStatus string
		shouldExist                   bool
	}{
		{
			test:        "Terminal",
			evalStatus:  structs.EvalStatusFailed,
			allocStatus: structs.AllocDesiredStatusFailed,
			shouldExist: false,
		},
		{
			test:        "Has Alloc",
			evalStatus:  structs.EvalStatusFailed,
			allocStatus: structs.AllocDesiredStatusRun,
			shouldExist: true,
		},
		{
			test:        "Has Eval",
			evalStatus:  structs.EvalStatusPending,
			allocStatus: structs.AllocDesiredStatusFailed,
			shouldExist: true,
		},
	}

	for _, test := range tests {
		s1 := testServer(t, nil)
		defer s1.Shutdown()
		testutil.WaitForLeader(t, s1.RPC)

		// Insert job.
		state := s1.fsm.State()
		job := mock.Job()
		job.GC = true
		err := state.UpsertJob(1000, job)
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Insert eval
		eval := mock.Eval()
		eval.JobID = job.ID
		eval.Status = test.evalStatus
		err = state.UpsertEvals(1001, []*structs.Evaluation{eval})
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Insert alloc
		alloc := mock.Alloc()
		alloc.JobID = job.ID
		alloc.EvalID = eval.ID
		alloc.DesiredStatus = test.allocStatus
		err = state.UpsertAllocs(1002, []*structs.Allocation{alloc})
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Update the time tables to make this work
		tt := s1.fsm.TimeTable()
		tt.Witness(2000, time.Now().UTC().Add(-1*threshold))

		// Create a core scheduler
		snap, err := state.Snapshot()
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}
		core := NewCoreScheduler(s1, snap)

		// Attempt the GC
		gc := s1.coreJobEval(structs.CoreJobJobGC)
		gc.ModifyIndex = 2000
		err = core.Process(gc)
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Should still exist
		out, err := state.JobByID(job.ID)
		if err != nil {
			t.Fatalf("test(%s) err: %v", err)
		}
		if (test.shouldExist && out == nil) || (!test.shouldExist && out != nil) {
			t.Fatalf("test(%s) bad: %v", test.test, out)
		}

		outE, err := state.EvalByID(eval.ID)
		if err != nil {
			t.Fatalf("test(%s) err: %v", err)
		}
		if (test.shouldExist && outE == nil) || (!test.shouldExist && outE != nil) {
			t.Fatalf("test(%s) bad: %v", test.test, out)
		}

		outA, err := state.AllocByID(alloc.ID)
		if err != nil {
			t.Fatalf("test(%s) err: %v", err)
		}
		if (test.shouldExist && outA == nil) || (!test.shouldExist && outA != nil) {
			t.Fatalf("test(%s) bad: %v", test.test, outA)
		}
	}
}
<commit_msg>Fix test<commit_after>package nomad

import (
	"testing"
	"time"

	"github.com/hashicorp/nomad/nomad/mock"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
)

func TestCoreScheduler_EvalGC(t *testing.T) {
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Insert "dead" eval
	state := s1.fsm.State()
	eval := mock.Eval()
	eval.Status = structs.EvalStatusFailed
	err := state.UpsertEvals(1000, []*structs.Evaluation{eval})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Insert "dead" alloc
	alloc := mock.Alloc()
	alloc.EvalID = eval.ID
	alloc.DesiredStatus = structs.AllocDesiredStatusFailed
	err = state.UpsertAllocs(1001, []*structs.Allocation{alloc})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Update the time tables to make this work
	tt := s1.fsm.TimeTable()
	tt.Witness(2000, time.Now().UTC().Add(-1*s1.config.EvalGCThreshold))

	// Create a core scheduler
	snap, err := state.Snapshot()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	core := NewCoreScheduler(s1, snap)

	// Attempt the GC
	gc := s1.coreJobEval(structs.CoreJobEvalGC)
	gc.ModifyIndex = 2000
	err = core.Process(gc)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should be gone
	out, err := state.EvalByID(eval.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if out != nil {
		t.Fatalf("bad: %v", out)
	}

	outA, err := state.AllocByID(alloc.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if outA != nil {
		t.Fatalf("bad: %v", outA)
	}
}

func TestCoreScheduler_NodeGC(t *testing.T) {
	s1 := testServer(t, nil)
	defer s1.Shutdown()
	testutil.WaitForLeader(t, s1.RPC)

	// Insert "dead" node
	state := s1.fsm.State()
	node := mock.Node()
	node.Status = structs.NodeStatusDown
	err := state.UpsertNode(1000, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Update the time tables to make this work
	tt := s1.fsm.TimeTable()
	tt.Witness(2000, time.Now().UTC().Add(-1*s1.config.NodeGCThreshold))

	// Create a core scheduler
	snap, err := state.Snapshot()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	core := NewCoreScheduler(s1, snap)

	// Attempt the GC
	gc := s1.coreJobEval(structs.CoreJobNodeGC)
	gc.ModifyIndex = 2000
	err = core.Process(gc)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Should be gone
	out, err := state.NodeByID(node.ID)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if out != nil {
		t.Fatalf("bad: %v", out)
	}
}

func TestCoreScheduler_JobGC(t *testing.T) {
	tests := []struct {
		test, evalStatus, allocStatus string
		shouldExist                   bool
	}{
		{
			test:        "Terminal",
			evalStatus:  structs.EvalStatusFailed,
			allocStatus: structs.AllocDesiredStatusFailed,
			shouldExist: false,
		},
		{
			test:        "Has Alloc",
			evalStatus:  structs.EvalStatusFailed,
			allocStatus: structs.AllocDesiredStatusRun,
			shouldExist: true,
		},
		{
			test:        "Has Eval",
			evalStatus:  structs.EvalStatusPending,
			allocStatus: structs.AllocDesiredStatusFailed,
			shouldExist: true,
		},
	}

	for _, test := range tests {
		s1 := testServer(t, nil)
		defer s1.Shutdown()
		testutil.WaitForLeader(t, s1.RPC)

		// Insert job.
		state := s1.fsm.State()
		job := mock.Job()
		job.GC = true
		err := state.UpsertJob(1000, job)
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Insert eval
		eval := mock.Eval()
		eval.JobID = job.ID
		eval.Status = test.evalStatus
		err = state.UpsertEvals(1001, []*structs.Evaluation{eval})
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Insert alloc
		alloc := mock.Alloc()
		alloc.JobID = job.ID
		alloc.EvalID = eval.ID
		alloc.DesiredStatus = test.allocStatus
		err = state.UpsertAllocs(1002, []*structs.Allocation{alloc})
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Update the time tables to make this work
		tt := s1.fsm.TimeTable()
		tt.Witness(2000, time.Now().UTC().Add(-1*s1.config.JobGCThreshold))

		// Create a core scheduler
		snap, err := state.Snapshot()
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}
		core := NewCoreScheduler(s1, snap)

		// Attempt the GC
		gc := s1.coreJobEval(structs.CoreJobJobGC)
		gc.ModifyIndex = 2000
		err = core.Process(gc)
		if err != nil {
			t.Fatalf("test(%s) err: %v", test.test, err)
		}

		// Should still exist
		out, err := state.JobByID(job.ID)
		if err != nil {
			t.Fatalf("test(%s) err: %v", err)
		}
		if (test.shouldExist && out == nil) || (!test.shouldExist && out != nil) {
			t.Fatalf("test(%s) bad: %v", test.test, out)
		}

		outE, err := state.EvalByID(eval.ID)
		if err != nil {
			t.Fatalf("test(%s) err: %v", err)
		}
		if (test.shouldExist && outE == nil) || (!test.shouldExist && outE != nil) {
			t.Fatalf("test(%s) bad: %v", test.test, out)
		}

		outA, err := state.AllocByID(alloc.ID)
		if err != nil {
			t.Fatalf("test(%s) err: %v", err)
		}
		if (test.shouldExist && outA == nil) || (!test.shouldExist && outA != nil) {
			t.Fatalf("test(%s) bad: %v", test.test, outA)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 Rene Richard

This file is part of zmq-soundtouch.

zmq-soundtouch is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

zmq-soundtouch is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with zmq-soundtouch.  If not, see <http://www.gnu.org/licenses/>.
*/

package messaging

import (
	"time"
)

type collector struct {
	zmqDealer *dealer
	zmqSub    *zmqSub
}

func NewCollector() *collector {
	zmqDealer := NewDealer()
	zmqSub := NewZmqSub()

	return &collector{zmqDealer: zmqDealer, zmqSub: zmqSub}
}

func (this *collector) Start(timeout int) {

	//The zmqDealer is the thing that get the last <x> messages
	this.zmqDealer.Start()

	time.Sleep(time.Second)

	if timeout > 0 {
		this.zmqSub.Start(timeout)
	} else {
		this.zmqSub.Start(0)
	}

	//Start up the websocket server
	//server := NewWebSocketServer("/ws")
	//go server.Listen()

}
<commit_msg>updates to collector.go<commit_after>/*
Copyright 2016 Rene Richard

This file is part of zmq-soundtouch.

zmq-soundtouch is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

zmq-soundtouch is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with zmq-soundtouch.  If not, see <http://www.gnu.org/licenses/>.
*/

package messaging

import (
	"time"
)

type collector struct {
	zmqDealer *dealer
	zmqSub    *zmqSub
}

func NewCollector() *collector {
	zmqDealer := NewDealer()
	zmqSub := NewZmqSub()

	return &collector{zmqDealer: zmqDealer, zmqSub: zmqSub}
}

func (this *collector) Start(timeout int) {

	//The zmqDealer is the thing that get the last <x> messages
	this.zmqDealer.Start()

	time.Sleep(time.Second)

	if timeout > 0 {
		this.zmqSub.Start(timeout)
	} else {
		this.zmqSub.Start(0)
	}

	//Start up the websocket server
	//server := NewWebSocketServer("/ws")
	//server.Start()

}
<|endoftext|>