<commit_before>package parser

import (
	"testing"
)

var repoMap = map[string]string{
	"df":  "zerowidth/dotfiles",
	"df2": "zerowidth/dotfiles2", // prefix collision
	"lg2": "libgit2/libgit2",
}

func TestParse(t *testing.T) {
	repoTests := []struct {
		input string // the input
		repo  string // the expected repo match or expansion
	}{
		{"", ""},                     // no input, no repo match
		{"df", "zerowidth/dotfiles"}, // match shorthand
		{" df", ""},                  // no match, leading space
		{"foo/bar", "foo/bar"},       // fully qualified
	}

	repoIssueTests := []struct {
		input string // the input
		repo  string // the expected repo match or expansion
		issue string // the expected issue match
	}{
		{"", "", ""}, // no issue nor repo
		{"df 123", "zerowidth/dotfiles", "123"},
		{"df#123", "zerowidth/dotfiles", "123"},
		{"df #123", "zerowidth/dotfiles", "123"}, // space and hash
		{"df123", "zerowidth/dotfiles", "123"},   // prefix match
		{"df2 34", "zerowidth/dotfiles2", "34"},
		{"df234", "zerowidth/dotfiles2", "34"}, // prefix match
		{"lg2 123", "libgit2/libgit2", "123"},
		{"lg2123", "libgit2/libgit2", "123"},  // prefix match
		{"foo/bar 123", "foo/bar", "123"},     // fully qualified
		{"df 0123", "zerowidth/dotfiles", ""}, // invalid issue
	}

	for _, tc := range repoTests {
		result := Parse(repoMap, tc.input)
		if result.Repo != tc.repo {
			t.Errorf("input %#v: expected repo %#v, got %#v", tc.input, tc.repo, result.Repo)
		}
	}

	for _, tc := range repoIssueTests {
		result := Parse(repoMap, tc.input)
		if result.Repo != tc.repo {
			t.Errorf("input %#v: expected repo %#v, got %#v", tc.input, tc.repo, result.Repo)
		}
		if result.Issue != tc.issue {
			t.Errorf("input %#v: expected issue %#v, got %#v", tc.input, tc.issue, result.Issue)
		}
	}

}
<commit_msg>Pull comments into test cases themselves for better error output<commit_after>package parser

import (
	"testing"
)

var repoMap = map[string]string{
	"df":  "zerowidth/dotfiles",
	"df2": "zerowidth/dotfiles2", // prefix collision
}

func TestParse(t *testing.T) {
	repoTests := []struct {
		input   string // the input
		repo    string // the expected repo match or expansion
		example string // what the case is an example of
	}{
		{"", "", "no input, no repo match"},
		{"df", "zerowidth/dotfiles", "match shorthand"},
		{" df", "", "no match, leading space"},
		{"foo/bar", "foo/bar", "fully qualified repo name"},
	}

	repoIssueTests := []struct {
		input   string // the input
		repo    string // the expected repo match or expansion
		issue   string // the expected issue match
		example string // what the case is an example of
	}{
		{"", "", "", "no issue no repo"},
		{"df 123", "zerowidth/dotfiles", "123", "normal expansion"},
		{"df#123", "zerowidth/dotfiles", "123", "expansion with #"},
		{"df #123", "zerowidth/dotfiles", "123", "space and # both"},
		{"df123", "zerowidth/dotfiles", "123", "prefix match"},
		{"df2 34", "zerowidth/dotfiles2", "34", "numeric suffix on shorthand"},
		{"df234", "zerowidth/dotfiles2", "34", "numerix suffix with no space"},
		{"foo/bar 123", "foo/bar", "123", "fully qualified repo"},
		{"df 0123", "zerowidth/dotfiles", "", "invalid issue"},
	}

	for _, tc := range repoTests {
		result := Parse(repoMap, tc.input)
		if result.Repo != tc.repo {
			t.Errorf("Parse(%#v): %s: expected repo %#v, got %#v", tc.input, tc.example, tc.repo, result.Repo)
		}
	}

	for _, tc := range repoIssueTests {
		result := Parse(repoMap, tc.input)
		if result.Repo != tc.repo {
			t.Errorf("Parse(%#v): %s: expected repo %#v, got %#v", tc.input, tc.example, tc.repo, result.Repo)
		}
		if result.Issue != tc.issue {
			t.Errorf("Parse(%#v): %s: expected issue %#v, got %#v", tc.input, tc.example, tc.issue, result.Issue)
		}
	}

}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"io"

	"code.google.com/p/go-uuid/uuid"
	docker "github.com/fsouza/go-dockerclient"
)

const (
	pwd    = "pwd"
	absPwd = "/" + pwd
)

func createContainerOpts(img, workdir, site, org, repo string, env ...string) docker.CreateContainerOptions {
	defaultEnv := []string{"GO15VENDOREXPERIMENT=1", "SITE=" + site, "ORG=" + org, "REPO=" + repo}
	return docker.CreateContainerOptions{
		Name: fmt.Sprintf("build-%s-%s-%s-%s", site, org, repo, uuid.New()),
		Config: &docker.Config{
			Env:   append(defaultEnv, env...),
			Image: img,
			Volumes: map[string]struct{}{
				workdir: struct{}{},
			},
			Mounts: []docker.Mount{
				docker.Mount{Name: "pwd", Source: workdir, Destination: absPwd, Mode: "rx"},
			},
		},
		HostConfig: &docker.HostConfig{},
	}
}

// attachContainerOpts returns docker.AttachToContainerOptions with output and error streams turned on
// as well as logs. the returned io.Reader will output both stdout and stderr
func attachToContainerOpts(containerID string) (docker.AttachToContainerOptions, io.Reader) {
	r, w := io.Pipe()
	// var stdoutBuf, stderrBuf bytes.Buffer
	opts := docker.AttachToContainerOptions{
		Container:    containerID,
		OutputStream: w,
		ErrorStream:  w,
		Logs:         true,
		Stream:       true,
		Stdout:       true,
		Stderr:       true,
	}

	return opts, r
}
<commit_msg>switch to new uuid version<commit_after>package handlers

import (
	"fmt"
	"io"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/pborman/uuid"
)

const (
	pwd    = "pwd"
	absPwd = "/" + pwd
)

func createContainerOpts(img, workdir, site, org, repo string, env ...string) docker.CreateContainerOptions {
	defaultEnv := []string{"GO15VENDOREXPERIMENT=1", "SITE=" + site, "ORG=" + org, "REPO=" + repo}
	return docker.CreateContainerOptions{
		Name: fmt.Sprintf("build-%s-%s-%s-%s", site, org, repo, uuid.New()),
		Config: &docker.Config{
			Env:   append(defaultEnv, env...),
			Image: img,
			Volumes: map[string]struct{}{
				workdir: struct{}{},
			},
			Mounts: []docker.Mount{
				docker.Mount{Name: pwd, Source: workdir, Destination: absPwd, Mode: "rx"},
			},
		},
		HostConfig: &docker.HostConfig{},
	}
}

// attachContainerOpts returns docker.AttachToContainerOptions with output and error streams turned on
// as well as logs. the returned io.Reader will output both stdout and stderr
func attachToContainerOpts(containerID string) (docker.AttachToContainerOptions, io.Reader) {
	r, w := io.Pipe()
	// var stdoutBuf, stderrBuf bytes.Buffer
	opts := docker.AttachToContainerOptions{
		Container:    containerID,
		OutputStream: w,
		ErrorStream:  w,
		Logs:         true,
		Stream:       true,
		Stdout:       true,
		Stderr:       true,
	}

	return opts, r
}
<|endoftext|>


<commit_before>package harness

// This file handles the app code introspection.
// It catalogs the controllers, their methods, and their arguments.

import (
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"log"
	"os"
	"play"
	"unicode"
)

type ControllerSpec struct {
	PackageName string
	StructName  string
	ImportPath  string
	MethodSpecs []*MethodSpec

	// Used internally to identify controllers that indirectly embed *play.Controller.
	embeddedTypes []*embeddedTypeName
}

// This is a description of a call to c.Render(..)
// It documents the argument names used, in order to propagate them to RenderArgs.
type renderCall struct {
	Line int
	Names []string
}

type MethodSpec struct {
	Name string    // Name of the method, e.g. "Index"
	Args []*MethodArg  // Argument descriptors
	RenderCalls []*renderCall  // Descriptions of Render() invocations from this Method.
}

type MethodArg struct {
	Name string  // Name of the argument.
	TypeName string  // The name of the type, e.g. "int", "*pkg.UserType"
}

type embeddedTypeName struct {
	PackageName, StructName string
}

// Maps a controller simple name (e.g. "Login") to the methods for which it is a
// receiver.
type methodMap map[string][]*MethodSpec

// Parse the app directory and return a list of the controller types found.
// Returns a CompileError if the parsing fails.
func ScanControllers(path string) (specs []*ControllerSpec, compileError *play.CompileError) {
	// Parse files within the path.
	var pkgs map[string]*ast.Package
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, path, func(f os.FileInfo) bool { return !f.IsDir() }, 0)
	if err != nil {
		if errList, ok := err.(scanner.ErrorList); ok {
			var pos token.Position = errList[0].Pos
			return nil, &play.CompileError{
				SourceType: ".go source",
				Title: "Go Compilation Error",
				Path: pos.Filename,
				Description: errList[0].Msg,
				Line: pos.Line,
				Column: pos.Column,
				SourceLines: play.MustReadLines(pos.Filename),
			}
		}
		ast.Print(nil, err)
		log.Fatalf("Failed to parse dir: %s", err)
	}

	// For each package... (often only "controllers")
	for _, pkg := range pkgs {
		var structSpecs []*ControllerSpec
		methodSpecs := make(methodMap)

		// For each source file in the package...
		for _, file := range pkg.Files {

			// For each declaration in the source file...
			for _, decl := range file.Decls {

				// Match and add both structs and methods
				structSpecs = appendStruct(structSpecs, pkg, decl)
				appendMethod(fset, methodSpecs, decl)
			}
		}

		// Filter the struct specs to just the ones that embed play.Controller.
		structSpecs = filterControllers(structSpecs)

		// Add the method specs to them.
		for _, spec := range structSpecs {
			spec.MethodSpecs = methodSpecs[spec.StructName]
		}

		// Add the prepared ControllerSpecs to the list.
		specs = append(specs, structSpecs...)
	}
	return
}

// If this Decl is a struct type definition, it is summarized and added to specs.
// Else, specs is returned unchanged.
func appendStruct(specs []*ControllerSpec, pkg *ast.Package, decl ast.Decl) []*ControllerSpec {
	// Filter out non-Struct type declarations.
	genDecl, ok := decl.(*ast.GenDecl)
	if !ok {
		return specs
	}

	if genDecl.Tok != token.TYPE {
		return specs
	}

	if len(genDecl.Specs) != 1 {
		play.LOG.Printf("Surprising: Decl does not have 1 Spec: %v", genDecl)
		return specs
	}

	spec := genDecl.Specs[0].(*ast.TypeSpec)
	structType, ok := spec.Type.(*ast.StructType)
	if !ok {
		return specs
	}

	// At this point we know it's a type declaration for a struct.
	// Fill in the rest of the info by diving into the fields.
	// Add it provisionally to the Controller list -- it's later filtered using field info.
	controllerSpec := &ControllerSpec{
		PackageName: pkg.Name,
		StructName: spec.Name.Name,
		ImportPath: play.ImportPath + "/app/" + pkg.Name,
	}

	for _, field := range structType.Fields.List {
		// If field.Names is set, it's not an embedded type.
		if field.Names != nil {
			continue
		}

		// A direct "sub-type" has an ast.Field like:
		// StarExpr { SelectorExpr { "play", "Controller" } }
		starExpr, ok := field.Type.(*ast.StarExpr)
		if !ok {
			continue
		}

		selectorExpr, ok := starExpr.X.(*ast.SelectorExpr)
		if !ok {
			continue
		}

		pkgIdent, ok := selectorExpr.X.(*ast.Ident)
		if !ok {
			continue
		}

		controllerSpec.embeddedTypes = append(controllerSpec.embeddedTypes, &embeddedTypeName{
			PackageName: pkgIdent.Name,
			StructName: selectorExpr.Sel.Name,
		})
	}

	return append(specs, controllerSpec)
}

// If decl is a Method declaration, it is summarized and added to the array
// underneath its receiver type.
// e.g. "Login" => {MethodSpec, MethodSpec, ..}
func appendMethod(fset *token.FileSet, mm methodMap, decl ast.Decl) {
	// Func declaration?
	funcDecl, ok := decl.(*ast.FuncDecl)
	if !ok {
		return
	}

	// Have a receiver?
	if funcDecl.Recv == nil {
		return
	}

	// Is it public?
	if ! unicode.IsUpper([]rune(funcDecl.Name.Name)[0]) {
		return
	}

	// Does it return a play.Result?
	if funcDecl.Type.Results == nil || len(funcDecl.Type.Results.List) != 1 {
		return
	}
	selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr)
	if ! ok {
		return
	}
	if pkgIdent, ok := selExpr.X.(*ast.Ident); !ok || pkgIdent.Name != "play" {
		return
	}
	if selExpr.Sel.Name != "Result" {
		return
	}

	// Get the receiver type, "dereferencing" it if necessary
	var recvTypeName string
	var recvType ast.Expr = funcDecl.Recv.List[0].Type
	if recvStarType, ok := recvType.(*ast.StarExpr); ok {
		recvTypeName = recvStarType.X.(*ast.Ident).Name
	} else {
		recvTypeName = recvType.(*ast.Ident).Name
	}

	method := &MethodSpec{
		Name: funcDecl.Name.Name,
	}

	// Add a description of the arguments to the method.
	for _, field := range funcDecl.Type.Params.List {
		for _, name := range field.Names {
			method.Args = append(method.Args, &MethodArg{
				Name: name.Name,
				TypeName: ExprName(field.Type),
			})
		}
	}

	// Add a description of the calls to Render from the method.
	// Inspect every node (e.g. always return true).
	method.RenderCalls = []*renderCall{}
	ast.Inspect(funcDecl.Body, func(node ast.Node) bool {
		// Is it a function call?
		callExpr, ok := node.(*ast.CallExpr)
		if ! ok {
			return true
		}

		// Is it calling (*Controller).Render?
		selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
		if ! ok {
			return true
		}

		// The type of the receiver is not easily available, so just store every
		// call to any method called Render.
		if selExpr.Sel.Name != "Render" {
			return true
		}

		// Add this call's args to the renderArgs.
		pos := fset.Position(selExpr.Sel.NamePos)
		renderCall := &renderCall{
			Line: pos.Line,
			Names: []string{},
		}
		for _, arg := range callExpr.Args {
			argIdent, ok := arg.(*ast.Ident)
			if ! ok {
				log.Println("Unnamed argument to Render call:", pos)
				continue
			}
			renderCall.Names = append(renderCall.Names, argIdent.Name)
		}
		method.RenderCalls = append(method.RenderCalls, renderCall)
		return true
	})

	mm[recvTypeName] = append(mm[recvTypeName], method)
}

func (s *ControllerSpec) SimpleName() string {
	return s.PackageName + "." + s.StructName
}

func (s *embeddedTypeName) SimpleName() string {
	return s.PackageName + "." + s.StructName
}

// Remove any types that do not (directly or indirectly) embed *play.Controller.
func filterControllers(specs []*ControllerSpec) (filtered []*ControllerSpec) {
	// Do a search in the "embedded type graph", starting with play.Controller.
	nodeQueue := []string {"play.Controller"}
	for _, controllerSimpleName := range nodeQueue {
		for _, spec := range specs {
			if play.ContainsString(nodeQueue, spec.SimpleName()) {
				continue  // Already added
			}

			// Look through the embedded types to see if the current type is among them.
			for _, embeddedType := range spec.embeddedTypes {

				// If so, add this type's simple name to the nodeQueue, and it's spec to
				// the filtered list.
				if controllerSimpleName == embeddedType.SimpleName() {
					nodeQueue = append(nodeQueue, spec.SimpleName())
					filtered = append(filtered, spec)
					break
				}
			}
		}
	}
	return
}

func ExprName(expr ast.Expr) string {
	switch t := expr.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.SelectorExpr:
		return ExprName(t.X) + "." + ExprName(t.Sel)
	case *ast.StarExpr:
		return "*" + ExprName(t.X)
	default:
		ast.Print(nil, expr)
		panic("Failed to generate name for field.")
	}
	return ""
}
<commit_msg>Bugfix to get Render(..) to find the right line with multi-line arguments<commit_after>package harness

// This file handles the app code introspection.
// It catalogs the controllers, their methods, and their arguments.

import (
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"log"
	"os"
	"play"
	"unicode"
)

type ControllerSpec struct {
	PackageName string
	StructName  string
	ImportPath  string
	MethodSpecs []*MethodSpec

	// Used internally to identify controllers that indirectly embed *play.Controller.
	embeddedTypes []*embeddedTypeName
}

// This is a description of a call to c.Render(..)
// It documents the argument names used, in order to propagate them to RenderArgs.
type renderCall struct {
	Line int
	Names []string
}

type MethodSpec struct {
	Name string    // Name of the method, e.g. "Index"
	Args []*MethodArg  // Argument descriptors
	RenderCalls []*renderCall  // Descriptions of Render() invocations from this Method.
}

type MethodArg struct {
	Name string  // Name of the argument.
	TypeName string  // The name of the type, e.g. "int", "*pkg.UserType"
}

type embeddedTypeName struct {
	PackageName, StructName string
}

// Maps a controller simple name (e.g. "Login") to the methods for which it is a
// receiver.
type methodMap map[string][]*MethodSpec

// Parse the app directory and return a list of the controller types found.
// Returns a CompileError if the parsing fails.
func ScanControllers(path string) (specs []*ControllerSpec, compileError *play.CompileError) {
	// Parse files within the path.
	var pkgs map[string]*ast.Package
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, path, func(f os.FileInfo) bool { return !f.IsDir() }, 0)
	if err != nil {
		if errList, ok := err.(scanner.ErrorList); ok {
			var pos token.Position = errList[0].Pos
			return nil, &play.CompileError{
				SourceType: ".go source",
				Title: "Go Compilation Error",
				Path: pos.Filename,
				Description: errList[0].Msg,
				Line: pos.Line,
				Column: pos.Column,
				SourceLines: play.MustReadLines(pos.Filename),
			}
		}
		ast.Print(nil, err)
		log.Fatalf("Failed to parse dir: %s", err)
	}

	// For each package... (often only "controllers")
	for _, pkg := range pkgs {
		var structSpecs []*ControllerSpec
		methodSpecs := make(methodMap)

		// For each source file in the package...
		for _, file := range pkg.Files {

			// For each declaration in the source file...
			for _, decl := range file.Decls {

				// Match and add both structs and methods
				structSpecs = appendStruct(structSpecs, pkg, decl)
				appendMethod(fset, methodSpecs, decl)
			}
		}

		// Filter the struct specs to just the ones that embed play.Controller.
		structSpecs = filterControllers(structSpecs)

		// Add the method specs to them.
		for _, spec := range structSpecs {
			spec.MethodSpecs = methodSpecs[spec.StructName]
		}

		// Add the prepared ControllerSpecs to the list.
		specs = append(specs, structSpecs...)
	}
	return
}

// If this Decl is a struct type definition, it is summarized and added to specs.
// Else, specs is returned unchanged.
func appendStruct(specs []*ControllerSpec, pkg *ast.Package, decl ast.Decl) []*ControllerSpec {
	// Filter out non-Struct type declarations.
	genDecl, ok := decl.(*ast.GenDecl)
	if !ok {
		return specs
	}

	if genDecl.Tok != token.TYPE {
		return specs
	}

	if len(genDecl.Specs) != 1 {
		play.LOG.Printf("Surprising: Decl does not have 1 Spec: %v", genDecl)
		return specs
	}

	spec := genDecl.Specs[0].(*ast.TypeSpec)
	structType, ok := spec.Type.(*ast.StructType)
	if !ok {
		return specs
	}

	// At this point we know it's a type declaration for a struct.
	// Fill in the rest of the info by diving into the fields.
	// Add it provisionally to the Controller list -- it's later filtered using field info.
	controllerSpec := &ControllerSpec{
		PackageName: pkg.Name,
		StructName: spec.Name.Name,
		ImportPath: play.ImportPath + "/app/" + pkg.Name,
	}

	for _, field := range structType.Fields.List {
		// If field.Names is set, it's not an embedded type.
		if field.Names != nil {
			continue
		}

		// A direct "sub-type" has an ast.Field like:
		// StarExpr { SelectorExpr { "play", "Controller" } }
		starExpr, ok := field.Type.(*ast.StarExpr)
		if !ok {
			continue
		}

		selectorExpr, ok := starExpr.X.(*ast.SelectorExpr)
		if !ok {
			continue
		}

		pkgIdent, ok := selectorExpr.X.(*ast.Ident)
		if !ok {
			continue
		}

		controllerSpec.embeddedTypes = append(controllerSpec.embeddedTypes, &embeddedTypeName{
			PackageName: pkgIdent.Name,
			StructName: selectorExpr.Sel.Name,
		})
	}

	return append(specs, controllerSpec)
}

// If decl is a Method declaration, it is summarized and added to the array
// underneath its receiver type.
// e.g. "Login" => {MethodSpec, MethodSpec, ..}
func appendMethod(fset *token.FileSet, mm methodMap, decl ast.Decl) {
	// Func declaration?
	funcDecl, ok := decl.(*ast.FuncDecl)
	if !ok {
		return
	}

	// Have a receiver?
	if funcDecl.Recv == nil {
		return
	}

	// Is it public?
	if ! unicode.IsUpper([]rune(funcDecl.Name.Name)[0]) {
		return
	}

	// Does it return a play.Result?
	if funcDecl.Type.Results == nil || len(funcDecl.Type.Results.List) != 1 {
		return
	}
	selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr)
	if ! ok {
		return
	}
	if pkgIdent, ok := selExpr.X.(*ast.Ident); !ok || pkgIdent.Name != "play" {
		return
	}
	if selExpr.Sel.Name != "Result" {
		return
	}

	// Get the receiver type, "dereferencing" it if necessary
	var recvTypeName string
	var recvType ast.Expr = funcDecl.Recv.List[0].Type
	if recvStarType, ok := recvType.(*ast.StarExpr); ok {
		recvTypeName = recvStarType.X.(*ast.Ident).Name
	} else {
		recvTypeName = recvType.(*ast.Ident).Name
	}

	method := &MethodSpec{
		Name: funcDecl.Name.Name,
	}

	// Add a description of the arguments to the method.
	for _, field := range funcDecl.Type.Params.List {
		for _, name := range field.Names {
			method.Args = append(method.Args, &MethodArg{
				Name: name.Name,
				TypeName: ExprName(field.Type),
			})
		}
	}

	// Add a description of the calls to Render from the method.
	// Inspect every node (e.g. always return true).
	method.RenderCalls = []*renderCall{}
	ast.Inspect(funcDecl.Body, func(node ast.Node) bool {
		// Is it a function call?
		callExpr, ok := node.(*ast.CallExpr)
		if ! ok {
			return true
		}

		// Is it calling (*Controller).Render?
		selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
		if ! ok {
			return true
		}

		// The type of the receiver is not easily available, so just store every
		// call to any method called Render.
		if selExpr.Sel.Name != "Render" {
			return true
		}

		// Add this call's args to the renderArgs.
		pos := fset.Position(callExpr.Rparen)
		renderCall := &renderCall{
			Line: pos.Line,
			Names: []string{},
		}
		for _, arg := range callExpr.Args {
			argIdent, ok := arg.(*ast.Ident)
			if ! ok {
				log.Println("Unnamed argument to Render call:", pos)
				continue
			}
			renderCall.Names = append(renderCall.Names, argIdent.Name)
		}
		method.RenderCalls = append(method.RenderCalls, renderCall)
		return true
	})

	mm[recvTypeName] = append(mm[recvTypeName], method)
}

func (s *ControllerSpec) SimpleName() string {
	return s.PackageName + "." + s.StructName
}

func (s *embeddedTypeName) SimpleName() string {
	return s.PackageName + "." + s.StructName
}

// Remove any types that do not (directly or indirectly) embed *play.Controller.
func filterControllers(specs []*ControllerSpec) (filtered []*ControllerSpec) {
	// Do a search in the "embedded type graph", starting with play.Controller.
	nodeQueue := []string {"play.Controller"}
	for _, controllerSimpleName := range nodeQueue {
		for _, spec := range specs {
			if play.ContainsString(nodeQueue, spec.SimpleName()) {
				continue  // Already added
			}

			// Look through the embedded types to see if the current type is among them.
			for _, embeddedType := range spec.embeddedTypes {

				// If so, add this type's simple name to the nodeQueue, and it's spec to
				// the filtered list.
				if controllerSimpleName == embeddedType.SimpleName() {
					nodeQueue = append(nodeQueue, spec.SimpleName())
					filtered = append(filtered, spec)
					break
				}
			}
		}
	}
	return
}

func ExprName(expr ast.Expr) string {
	switch t := expr.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.SelectorExpr:
		return ExprName(t.X) + "." + ExprName(t.Sel)
	case *ast.StarExpr:
		return "*" + ExprName(t.X)
	default:
		ast.Print(nil, expr)
		panic("Failed to generate name for field.")
	}
	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

type jsonObjectRaw map[string]json.RawMessage
type jsonObject map[string]interface{}

type tilePosition struct {
	collection string
	path       string
}

var fileList = make(map[string][]tilePosition, 4096)

func getJSONRawSlice(r jsonObjectRaw, k string) (*[]jsonObjectRaw, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var rawSlice []jsonObjectRaw
	err := json.Unmarshal(blob, &rawSlice)
	if err != nil {
		return nil, err
	}
	return &rawSlice, nil
}

func getJSONSlice(r jsonObjectRaw, k string) (*[]jsonObject, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var decodedSlice []jsonObject
	err := json.Unmarshal(blob, &decodedSlice)
	if err != nil {
		return nil, err
	}
	return &decodedSlice, nil
}

func getJSONRawObject(r jsonObjectRaw, k string) (*jsonObjectRaw, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var decodedObject jsonObjectRaw
	err := json.Unmarshal(blob, &decodedObject)
	if err != nil {
		return nil, err
	}
	return &decodedObject, nil
}

func getJSONObject(r jsonObjectRaw, k string) (*jsonObject, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var decodedObject jsonObject
	err := json.Unmarshal(blob, &decodedObject)
	if err != nil {
		return nil, err
	}
	return &decodedObject, nil
}

func findHomeDir() string {
	u, err := user.Current()
	if err != nil {
		log.Fatal("error: unable to get the username:", err)
	}
	return u.HomeDir
}

func readSettingsBlob(userConfig string) ([]byte, error) {
	settings := filepath.Join(userConfig, "hex-kit", "Settings")
	log.Print("Reading user settings from: ", settings)
	settingsBlob, err := ioutil.ReadFile(settings)
	return settingsBlob, err
}

// https://electron.atom.io/docs/api/app/#appgetpathname
func getSettings() jsonObjectRaw {
	var userConfig string
	var settingsBlob []byte
	var settingsRaw jsonObjectRaw
	var err error
	switch runtime.GOOS {
	case "darwin":
		homeDir := findHomeDir()
		userConfig = filepath.Join(homeDir, "Library", "Application Support")
		settingsBlob, err = readSettingsBlob(userConfig)
	case "linux":
		userConfig = os.Getenv("XDG_CONFIG_HOME")
		if userConfig != "" {
			settingsBlob, err = readSettingsBlob(userConfig)
		}
		if userConfig == "" || err != nil {
			homeDir := findHomeDir()
			userConfig = filepath.Join(homeDir, ".config")
			settingsBlob, err = readSettingsBlob(userConfig)
		}
	case "windows":
		userConfig = os.Getenv("APPDATA")
		if userConfig == "" {
			log.Fatal("Unable to find user config (no APPDATA environment variable)")
		}
		settingsBlob, err = readSettingsBlob(userConfig)
	}
	// Did the log read succeed
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(settingsBlob, &settingsRaw)
	if err != nil {
		log.Fatal(err)
	}
	return settingsRaw
}

// Search fon all png files under the current path
func pathMap(collectionName, basePath string) filepath.WalkFunc {
	return func(path string, info os.FileInfo, err error) error {
		if err != nil {
			log.Fatal("fatal: while searching for PNG files:", err)
		}
		tileName := info.Name()
		lenPath := len(path)
		if lenPath > 4 && path[lenPath-4:] == ".png" {
			relPathTile, err := filepath.Rel(basePath, path)
			if err != nil {
				log.Fatal("fatal:", path, "is not under", basePath, ":", err)
			}
			var tp tilePosition
			tp.collection = collectionName
			tp.path = relPathTile
			fileList[tileName] = append(fileList[tileName], tp)
		}
		return nil
	}
}

func main() {
	if len(os.Args) != 3 {
		log.Println("Usage:", os.Args[0], "HexkitPath MapPath")
		return
	}

	// Build the list of collections
	collectionsDir := make(map[string]string)
	settings := getSettings()
	collections, err := getJSONRawObject(settings, "tiles")
	if err != nil {
		log.Fatal("Error: unable to parse user settings:", err)
	}
	for name, collectionBlob := range *collections {
		var collection jsonObject
		err := json.Unmarshal(collectionBlob, &collection)
		if err != nil {
			log.Fatal("Error: unable to parse user settings:", err)
		}
		// Ignore source if hidden
		hiddenIntf, ok := collection["hidden"]
		if ok {
			hidden, isBool := hiddenIntf.(bool)
			if isBool && hidden {
				continue
			}
		}
		pathIntf, ok := collection["path"]
		if !ok {
			log.Fatal("Error: unable to parse user settings: no path for", name)
		}
		path, ok := pathIntf.(string)
		if !ok {
			log.Fatal("Error: unable to parse user settings: the path for", name, "is not a string")
		}
		// Relative collection path
		if path[0] != os.PathSeparator {
			collectionsDir[name] = filepath.Join(os.Args[1], "resources", "app.asar.unpacked", path)
			continue
		}
		// Absolute collection path
		collectionsDir[name] = path
	}

	// Build the list of PNG files
	for name, path := range collectionsDir {
		err := filepath.Walk(path, pathMap(name, path))
		if err != nil {
			log.Fatal(err)
		}
	}
	// Read the file
	mapFile := os.Args[2]
	mapBlob, err := ioutil.ReadFile(mapFile)
	if err != nil {
		log.Fatal(err)
	}

	// Decode it in hexMap
	var hexMap jsonObjectRaw
	err = json.Unmarshal(mapBlob, &hexMap)
	if err != nil {
		log.Fatal(err)
	}

	// Get the layers list
	layers, err := getJSONRawSlice(hexMap, "layers")
	if err != nil {
		log.Fatal("Map format error", err)
	}

	// Search for tiles
	layersModified := false
	for i, v := range *layers {
		tiles, err := getJSONSlice(v, "tiles")
		if err != nil {
			log.Fatal("Map format error in layer", i+1, ":", err)
		}
		// Search for the source of tiles
		tilesModified := false
		for j, t := range *tiles {
			// Ignore undefined tiles
			if t == nil {
				continue
			}
			sourceBlob, ok := t["source"]
			if !ok {
				log.Println("Layer", i+1, "Tile", j+1, "no tile source found")
				continue
			}
			source, ok := sourceBlob.(string)
			if !ok {
				log.Println("Layer", i+1, "Tile", j+1, "the tile source is incorrect (not a string)")
				continue
			}
			// Skip the default blank tiles
			if source[:6] == "Blank:" {
				continue
			}
			// Have we found the tile
			nameSelect := regexp.MustCompile(`[^:/\\]+$`)
			fileName := nameSelect.FindString(source)
			pathList, ok := fileList[fileName]
			if !ok {
				log.Println("Layer", i+1, "Tile", j+1, "unable to find tile image file for", source)
				continue
			}
			// Search for the current path in the
			firstSplit := strings.SplitN(source, ":", 2)
			if len(firstSplit) < 2 {
				log.Println("Layer", i+1, "Tile", j+1, "incorrect source:", source)
				continue
			}
			targetCollection := firstSplit[0]
			targetPath := firstSplit[1]
			var bestScore int
			var selected tilePosition
		pathSearch:
			for _, p := range pathList {
				if targetCollection == p.collection && targetPath == p.path {
					break pathSearch
				}
				currentScore := len(p.path)
				if targetCollection == p.collection && (currentScore+256) > bestScore {
					bestScore = currentScore + 256
					selected = p
				}
				if currentScore > bestScore {
					bestScore = currentScore
					selected = p
				}
			}
			// A new value was found: update the source
			if selected.collection != "" && selected.path != "" {
				tilesModified = true
				t["source"] = selected.collection + ":" + selected.path
			}
		}
		if tilesModified {
			tilesBlob, err := json.Marshal(tiles)
			if err != nil {
				log.Fatal(err)
			}
			v["tiles"] = tilesBlob
			layersModified = true
		}
	}
	if layersModified {
		layersBlob, err := json.Marshal(layers)
		if err != nil {
			log.Fatal(err)
		}
		hexMap["layers"] = layersBlob
	}
	b, err := json.Marshal(hexMap)
	if err != nil {
		log.Fatal(err)
	}
	_, err = os.Stdout.Write(b)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Fix the absolute path detection on Windows<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

type jsonObjectRaw map[string]json.RawMessage
type jsonObject map[string]interface{}

type tilePosition struct {
	collection string
	path       string
}

var fileList = make(map[string][]tilePosition, 4096)

func getJSONRawSlice(r jsonObjectRaw, k string) (*[]jsonObjectRaw, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var rawSlice []jsonObjectRaw
	err := json.Unmarshal(blob, &rawSlice)
	if err != nil {
		return nil, err
	}
	return &rawSlice, nil
}

func getJSONSlice(r jsonObjectRaw, k string) (*[]jsonObject, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var decodedSlice []jsonObject
	err := json.Unmarshal(blob, &decodedSlice)
	if err != nil {
		return nil, err
	}
	return &decodedSlice, nil
}

func getJSONRawObject(r jsonObjectRaw, k string) (*jsonObjectRaw, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var decodedObject jsonObjectRaw
	err := json.Unmarshal(blob, &decodedObject)
	if err != nil {
		return nil, err
	}
	return &decodedObject, nil
}

func getJSONObject(r jsonObjectRaw, k string) (*jsonObject, error) {
	blob, ok := r[k]
	if !ok {
		return nil, fmt.Errorf("No \"%s\" key in object", k)
	}
	var decodedObject jsonObject
	err := json.Unmarshal(blob, &decodedObject)
	if err != nil {
		return nil, err
	}
	return &decodedObject, nil
}

func findHomeDir() string {
	u, err := user.Current()
	if err != nil {
		log.Fatal("error: unable to get the username:", err)
	}
	return u.HomeDir
}

func readSettingsBlob(userConfig string) ([]byte, error) {
	settings := filepath.Join(userConfig, "hex-kit", "Settings")
	log.Print("Reading user settings from: ", settings)
	settingsBlob, err := ioutil.ReadFile(settings)
	return settingsBlob, err
}

// https://electron.atom.io/docs/api/app/#appgetpathname
func getSettings() jsonObjectRaw {
	var userConfig string
	var settingsBlob []byte
	var settingsRaw jsonObjectRaw
	var err error
	switch runtime.GOOS {
	case "darwin":
		homeDir := findHomeDir()
		userConfig = filepath.Join(homeDir, "Library", "Application Support")
		settingsBlob, err = readSettingsBlob(userConfig)
	case "linux":
		userConfig = os.Getenv("XDG_CONFIG_HOME")
		if userConfig != "" {
			settingsBlob, err = readSettingsBlob(userConfig)
		}
		if userConfig == "" || err != nil {
			homeDir := findHomeDir()
			userConfig = filepath.Join(homeDir, ".config")
			settingsBlob, err = readSettingsBlob(userConfig)
		}
	case "windows":
		userConfig = os.Getenv("APPDATA")
		if userConfig == "" {
			log.Fatal("Unable to find user config (no APPDATA environment variable)")
		}
		settingsBlob, err = readSettingsBlob(userConfig)
	}
	// Did the log read succeed
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(settingsBlob, &settingsRaw)
	if err != nil {
		log.Fatal(err)
	}
	return settingsRaw
}

// Search fon all png files under the current path
func pathMap(collectionName, basePath string) filepath.WalkFunc {
	return func(path string, info os.FileInfo, err error) error {
		if err != nil {
			log.Fatal("fatal: while searching for PNG files:", err)
		}
		tileName := info.Name()
		lenPath := len(path)
		if lenPath > 4 && path[lenPath-4:] == ".png" {
			relPathTile, err := filepath.Rel(basePath, path)
			if err != nil {
				log.Fatal("fatal:", path, "is not under", basePath, ":", err)
			}
			var tp tilePosition
			tp.collection = collectionName
			tp.path = relPathTile
			fileList[tileName] = append(fileList[tileName], tp)
		}
		return nil
	}
}

func main() {
	if len(os.Args) != 3 {
		log.Println("Usage:", os.Args[0], "HexkitPath MapPath")
		return
	}

	// Build the list of collections
	collectionsDir := make(map[string]string)
	settings := getSettings()
	collections, err := getJSONRawObject(settings, "tiles")
	if err != nil {
		log.Fatal("Error: unable to parse user settings:", err)
	}
	for name, collectionBlob := range *collections {
		var collection jsonObject
		err := json.Unmarshal(collectionBlob, &collection)
		if err != nil {
			log.Fatal("Error: unable to parse user settings:", err)
		}
		// Ignore source if hidden
		hiddenIntf, ok := collection["hidden"]
		if ok {
			hidden, isBool := hiddenIntf.(bool)
			if isBool && hidden {
				continue
			}
		}
		pathIntf, ok := collection["path"]
		if !ok {
			log.Fatal("Error: unable to parse user settings: no path for", name)
		}
		path, ok := pathIntf.(string)
		if !ok {
			log.Fatal("Error: unable to parse user settings: the path for", name, "is not a string")
		}
		// Relative collection path
		if !filepath.IsAbs(path) {
			collectionsDir[name] = filepath.Join(os.Args[1], "resources", "app.asar.unpacked", path)
			continue
		}
		// Absolute collection path
		collectionsDir[name] = path
	}

	// Build the list of PNG files
	for name, path := range collectionsDir {
		err := filepath.Walk(path, pathMap(name, path))
		if err != nil {
			log.Fatal(err)
		}
	}
	// Read the file
	mapFile := os.Args[2]
	mapBlob, err := ioutil.ReadFile(mapFile)
	if err != nil {
		log.Fatal(err)
	}

	// Decode it in hexMap
	var hexMap jsonObjectRaw
	err = json.Unmarshal(mapBlob, &hexMap)
	if err != nil {
		log.Fatal(err)
	}

	// Get the layers list
	layers, err := getJSONRawSlice(hexMap, "layers")
	if err != nil {
		log.Fatal("Map format error", err)
	}

	// Search for tiles
	layersModified := false
	for i, v := range *layers {
		tiles, err := getJSONSlice(v, "tiles")
		if err != nil {
			log.Fatal("Map format error in layer", i+1, ":", err)
		}
		// Search for the source of tiles
		tilesModified := false
		for j, t := range *tiles {
			// Ignore undefined tiles
			if t == nil {
				continue
			}
			sourceBlob, ok := t["source"]
			if !ok {
				log.Println("Layer", i+1, "Tile", j+1, "no tile source found")
				continue
			}
			source, ok := sourceBlob.(string)
			if !ok {
				log.Println("Layer", i+1, "Tile", j+1, "the tile source is incorrect (not a string)")
				continue
			}
			// Skip the default blank tiles
			if source[:6] == "Blank:" {
				continue
			}
			// Have we found the tile
			nameSelect := regexp.MustCompile(`[^:/\\]+$`)
			fileName := nameSelect.FindString(source)
			pathList, ok := fileList[fileName]
			if !ok {
				log.Println("Layer", i+1, "Tile", j+1, "unable to find tile image file for", source)
				continue
			}
			// Search for the current path in the
			firstSplit := strings.SplitN(source, ":", 2)
			if len(firstSplit) < 2 {
				log.Println("Layer", i+1, "Tile", j+1, "incorrect source:", source)
				continue
			}
			targetCollection := firstSplit[0]
			targetPath := firstSplit[1]
			var bestScore int
			var selected tilePosition
		pathSearch:
			for _, p := range pathList {
				if targetCollection == p.collection && targetPath == p.path {
					break pathSearch
				}
				currentScore := len(p.path)
				if targetCollection == p.collection && (currentScore+256) > bestScore {
					bestScore = currentScore + 256
					selected = p
				}
				if currentScore > bestScore {
					bestScore = currentScore
					selected = p
				}
			}
			// A new value was found: update the source
			if selected.collection != "" && selected.path != "" {
				tilesModified = true
				t["source"] = selected.collection + ":" + selected.path
			}
		}
		if tilesModified {
			tilesBlob, err := json.Marshal(tiles)
			if err != nil {
				log.Fatal(err)
			}
			v["tiles"] = tilesBlob
			layersModified = true
		}
	}
	if layersModified {
		layersBlob, err := json.Marshal(layers)
		if err != nil {
			log.Fatal(err)
		}
		hexMap["layers"] = layersBlob
	}
	b, err := json.Marshal(hexMap)
	if err != nil {
		log.Fatal(err)
	}
	_, err = os.Stdout.Write(b)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package hive

import (
	"bufio"
	"errors"
	// "fmt"
	"github.com/eaciit/errorlib"
	// "github.com/eaciit/toolkit"
	"io"
	"log"
	"os/exec"
	// "reflect"
	"strings"
)

const (
	BEE_CLI_STR  = "jdbc:hive2:"
	CLOSE_SCRIPT = "!quit"
)

type DuplexTerm struct {
	Writer     *bufio.Writer
	Reader     *bufio.Reader
	Cmd        *exec.Cmd
	CmdStr     string
	Stdin      io.WriteCloser
	Stdout     io.ReadCloser
	FnReceive  FnHiveReceive
	OutputType string
	DateFormat string
	status     chan bool
}

/*func (d *DuplexTerm) Open() (e error) {
	if d.Stdin, e = d.Cmd.StdinPipe(); e != nil {
		return
	}

	if d.Stdout, e = d.Cmd.StdoutPipe(); e != nil {
		return
	}

	d.Writer = bufio.NewWriter(d.Stdin)
	d.Reader = bufio.NewReader(d.Stdout)

	e = d.Cmd.Start()
	return
}*/

var hr HiveResult

func (d *DuplexTerm) Open() (e error) {
	if d.CmdStr != "" {
		arg := append([]string{"-c"}, d.CmdStr)
		d.Cmd = exec.Command("sh", arg...)

		if d.Stdin, e = d.Cmd.StdinPipe(); e != nil {
			return
		}

		if d.Stdout, e = d.Cmd.StdoutPipe(); e != nil {
			return
		}

		d.Writer = bufio.NewWriter(d.Stdin)
		d.Reader = bufio.NewReader(d.Stdout)
		// d.status = make(chan bool)
		e = d.Cmd.Start()
	} else {
		errorlib.Error("", "", "Open", "The Connection Config not Set")
	}

	return
}

func (d *DuplexTerm) Close() {
	result, e := d.SendInput(CLOSE_SCRIPT)

	_ = result
	_ = e

	d.Cmd.Wait()
	d.Stdin.Close()
	d.Stdout.Close()
}

func (d *DuplexTerm) SendInput(input string) (res []string, err error) {
	if d.FnReceive != nil {
		go func() {
			_, e, _ := d.process()
			_ = e
		}()
	}

	iwrite, e := d.Writer.WriteString(input + "\n")
	if iwrite == 0 {
		e = errors.New("Writing only 0 byte")
	} else {
		e = d.Writer.Flush()
	}
	if e == nil && d.FnReceive == nil {
		res, e, _ = d.process()
	}
	err = e
	return
}

/*func (d *DuplexTerm) Wait() {
	<-d.status
}*/

func (d *DuplexTerm) process() (result []string, e error, status bool) {
	isHeader := false
	// status = false
	for {
		peekBefore, _ := d.Reader.Peek(14)
		peekBeforeStr := string(peekBefore)

		bread, e := d.Reader.ReadString('\n')
		bread = strings.TrimRight(bread, "\n")

		peek, _ := d.Reader.Peek(14)
		peekStr := string(peek)

		delimiter := "\t"

		if d.OutputType == CSV {
			delimiter = ","
		}

		if isHeader {
			hr.constructHeader(bread, delimiter)
			isHeader = false
		} else if !strings.Contains(bread, BEE_CLI_STR) {
			if d.FnReceive != nil {
				/*fn := reflect.ValueOf(d.Fn)
				// tp := fn.Type().In(0)
				// tmp := reflect.New(tp).Elem()

				Parse(hr.Header, bread, &hr.ResultObj, d.OutputType, d.DateFormat)
				log.Printf("tmp: %v\n", &hr.ResultObj)

				res := fn.Call([]reflect.Value{reflect.ValueOf(hr.ResultObj)})
				log.Printf("res: %v\n", res)*/

				/*fn := reflect.ValueOf(d.Fn)
				tp := fn.Type().In(0)
				tmp := reflect.New(tp)

				xTmp := toolkit.M{}

				Parse(hr.Header, bread, &xTmp, d.OutputType, d.DateFormat)
				log.Printf("tmp: %v\n", xTmp)*/
				// log.Printf("tmp: %v\n", tmp)

				/*res := fn.Call([]reflect.Value{reflect.ValueOf(hr.ResultObj)})
				log.Printf("test: %v\n", res)
				d.FnReceive(res)*/

				hr.Result = append(hr.Result, bread)
				log.Printf("process: %v\n", hr.Result)
				Parse(hr.Header, bread, &hr.ResultObj, d.OutputType, d.DateFormat)
				d.FnReceive(hr)
			} else {
				result = append(result, bread)
			}
		}

		if d.FnReceive != nil && strings.Contains(peekBeforeStr, BEE_CLI_STR) {
			isHeader = true
		}

		/*if d.FnReceive != nil {
			if (e != nil && e.Error() == "EOF") || (strings.Contains(peekStr, CLOSE_SCRIPT)) {
				break
			}
		} else {*/
		if (e != nil && e.Error() == "EOF") || strings.Contains(peekStr, BEE_CLI_STR) {
			if d.FnReceive != nil {
				// status = true
			}
			break
		}
		// }

	}

	return
}
<commit_msg>bug fixing<commit_after>package hive

import (
	"bufio"
	"errors"
	// "fmt"
	"github.com/eaciit/errorlib"
	// "github.com/eaciit/toolkit"
	"io"
	"log"
	"os/exec"
	// "reflect"
	"strings"
)

const (
	BEE_CLI_STR  = "jdbc:hive2:"
	CLOSE_SCRIPT = "!quit"
)

type DuplexTerm struct {
	Writer     *bufio.Writer
	Reader     *bufio.Reader
	Cmd        *exec.Cmd
	CmdStr     string
	Stdin      io.WriteCloser
	Stdout     io.ReadCloser
	FnReceive  FnHiveReceive
	OutputType string
	DateFormat string
	status     chan bool
}

/*func (d *DuplexTerm) Open() (e error) {
	if d.Stdin, e = d.Cmd.StdinPipe(); e != nil {
		return
	}

	if d.Stdout, e = d.Cmd.StdoutPipe(); e != nil {
		return
	}

	d.Writer = bufio.NewWriter(d.Stdin)
	d.Reader = bufio.NewReader(d.Stdout)

	e = d.Cmd.Start()
	return
}*/

var hr HiveResult

func (d *DuplexTerm) Open() (e error) {
	if d.CmdStr != "" {
		arg := append([]string{"-c"}, d.CmdStr)
		d.Cmd = exec.Command("sh", arg...)

		if d.Stdin, e = d.Cmd.StdinPipe(); e != nil {
			return
		}

		if d.Stdout, e = d.Cmd.StdoutPipe(); e != nil {
			return
		}

		d.Writer = bufio.NewWriter(d.Stdin)
		d.Reader = bufio.NewReader(d.Stdout)
		if d.FnReceive != nil {
			go func() {
				_, e, _ := d.process()
				_ = e
			}()
		}

		e = d.Cmd.Start()
	} else {
		errorlib.Error("", "", "Open", "The Connection Config not Set")
	}

	return
}

func (d *DuplexTerm) Close() {
	result, e := d.SendInput(CLOSE_SCRIPT)

	_ = result
	_ = e

	d.Cmd.Wait()
	d.Stdin.Close()
	d.Stdout.Close()
}

func (d *DuplexTerm) SendInput(input string) (res []string, err error) {
	iwrite, e := d.Writer.WriteString(input + "\n")
	if iwrite == 0 {
		e = errors.New("Writing only 0 byte")
	} else {
		e = d.Writer.Flush()
	}
	if e == nil && d.FnReceive == nil {
		res, e, _ = d.process()
	}
	err = e
	return
}

/*func (d *DuplexTerm) Wait() {
	<-d.status
}*/

func (d *DuplexTerm) process() (result []string, e error, status bool) {
	isHeader := false
	// status = false
	for {
		peekBefore, _ := d.Reader.Peek(14)
		peekBeforeStr := string(peekBefore)

		bread, e := d.Reader.ReadString('\n')
		bread = strings.TrimRight(bread, "\n")

		peek, _ := d.Reader.Peek(14)
		peekStr := string(peek)

		delimiter := "\t"

		if d.OutputType == CSV {
			delimiter = ","
		}

		if isHeader {
			hr.constructHeader(bread, delimiter)
			isHeader = false
		} else if !strings.Contains(bread, BEE_CLI_STR) {
			if d.FnReceive != nil {
				/*fn := reflect.ValueOf(d.Fn)
				// tp := fn.Type().In(0)
				// tmp := reflect.New(tp).Elem()

				Parse(hr.Header, bread, &hr.ResultObj, d.OutputType, d.DateFormat)
				log.Printf("tmp: %v\n", &hr.ResultObj)

				res := fn.Call([]reflect.Value{reflect.ValueOf(hr.ResultObj)})
				log.Printf("res: %v\n", res)*/

				/*fn := reflect.ValueOf(d.Fn)
				tp := fn.Type().In(0)
				tmp := reflect.New(tp)

				xTmp := toolkit.M{}

				Parse(hr.Header, bread, &xTmp, d.OutputType, d.DateFormat)
				log.Printf("tmp: %v\n", xTmp)*/
				// log.Printf("tmp: %v\n", tmp)

				/*res := fn.Call([]reflect.Value{reflect.ValueOf(hr.ResultObj)})
				log.Printf("test: %v\n", res)
				d.FnReceive(res)*/

				hr.Result = append(hr.Result, bread)
				log.Printf("process: %v\n", hr.Result)
				Parse(hr.Header, bread, &hr.ResultObj, d.OutputType, d.DateFormat)
				d.FnReceive(hr)
			} else {
				result = append(result, bread)
			}
		}

		if d.FnReceive != nil && strings.Contains(peekBeforeStr, BEE_CLI_STR) {
			isHeader = true
		}

		/*if d.FnReceive != nil {
			if (e != nil && e.Error() == "EOF") || (strings.Contains(peekStr, CLOSE_SCRIPT)) {
				break
			}
		} else {*/
		if (e != nil && e.Error() == "EOF") || strings.Contains(peekStr, BEE_CLI_STR) {
			if d.FnReceive != nil {
				// status = true
			}
			break
		}
		// }

	}

	return
}
<|endoftext|>


<commit_before>package configuration

import (
	"io/ioutil"

	hjson "github.com/hjson/hjson-go"
)

// HJSONConfig is configuration loader HJSON interface
type HJSONConfig struct {
	filename string
	hsonMap  map[string]interface{}
}

// LoadFileContents load contents of file. separate function to make tests possible
func (fl *HJSONConfig) LoadFileContents(filename string) (cnt []byte, err error) {
	if filename == "" {
		return nil, NewConfigNotConfiguredError("Cannot load config file with no filename")
	}
	return ioutil.ReadFile(filename)
}

// ParseStringContents parses HSON - separated to method cause I want test that
func (fl *HJSONConfig) ParseStringContents(cnt []byte) (m map[string]interface{}, err error) {
	m = map[string]interface{}{}
	err = hjson.Unmarshal(cnt, &m)
	if nil != err {
		m = nil
		return
	}
	return
}

// SetDefaultLoadSetting sets default config file for loader
func (fl *HJSONConfig) SetDefaultLoadSetting(sl ...interface{}) (err error) {
	if len(sl) == 0 {
		return NewHJSONConfigError("No arguments given to SetDefaultLoadSetting")
	}
	a0 := sl[0]
	switch v := a0.(type) {
	case string:
		cnt, err := fl.LoadFileContents(v)
		if err != nil {
			return NewHJSONConfigError("Error loading file occured: " + err.Error())
		}
		m, err := fl.ParseStringContents(cnt)
		if err != nil {
			return err
		}
		fl.filename = v
		fl.hsonMap = m
	case []byte:
		m, err := fl.ParseStringContents(v)
		fl.filename = ""
		if err != nil {
			return err
		}
		fl.hsonMap = m
	case map[string]interface{}:
		fl.filename = ""
		fl.hsonMap = v
	default:
		return NewHJSONConfigError("HJSONConfig.SetDefaultLoadSetting() argument must be string, []byte, or map[string]interface{}")
	}
	// all error cases are solved above
	return nil
}

// CheckExternalConfig checks external configuration file and it's contents - e.g.check file before reload
func (fl *HJSONConfig) CheckExternalConfig() (err error) {
	if "" == fl.filename {
		return NewConfigUsageError("Can not check external file cause it's not configuted inside")
	}
	cnt, err := fl.LoadFileContents(fl.filename)
	if err != nil {
		return err
	}
	_, err = fl.ParseStringContents(cnt)
	if nil != err {
		return err
	}
	return nil
}

// ReloadInternalMap (re)loads internal map - if from file. If not - says ConfigUsageError
func (fl *HJSONConfig) ReloadInternalMap() (err error) {
	if "" == fl.filename {
		return NewConfigUsageError("Can not check external file cause it's not configuted inside")
	}
	cnt, err := fl.LoadFileContents(fl.filename)
	if err != nil {
		return err
	}
	m, err := fl.ParseStringContents(cnt)
	if nil != err {
		return err
	}
	fl.hsonMap = m
	return nil
}

// GetValue get any type value on programmer mind own
// usage on intialized object: fl.GetValue("a", "b", "c", "d")
// on this function would be based functions below
func (fl *HJSONConfig) GetValue(path ...string) (i interface{}, err error) {
	if nil == fl.hsonMap {
		return nil, NewConfigUsageError("No config was initialised yet")
	}
	if 0 == len(path) {
		return nil, NewConfigUsageError("You must get values with path arguments there")
	}
	currmap := fl.hsonMap
	for _, key := range path {
		val, ok := currmap[key]
		if !ok {
			return nil, NewConfigItemNotFound("Item not found")
		}
		switch v := val.(type) {
		case map[string]interface{}:
			currmap = v
		default:
			return interface{}(v), nil
		}
	}
	// here stays 1 algorithmical variant - currmap is answer itself
	return interface{}(currmap), nil
}

// GetIntValue returns integer value by path
func (fl *HJSONConfig) GetIntValue(path ...string) (i int, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return 0, err1
	}
	switch v := i1.(type) {
	case int:
		return v, nil
	default:
		return 0, NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// GetStringValue returns string value or error by path
func (fl *HJSONConfig) GetStringValue(path ...string) (s string, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return "", err1
	}
	switch v := i1.(type) {
	case string:
		return v, nil
	default:
		return "", NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// GetBooleanValue returns boolean value or error by path
func (fl *HJSONConfig) GetBooleanValue(path ...string) (b bool, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return false, err1
	}
	switch v := i1.(type) {
	case bool:
		return v, nil
	default:
		return false, NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// GetSubconfig returns config interface or nil + error
func (fl *HJSONConfig) GetSubconfig(path ...string) (c IConfig, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return nil, err1
	}
	switch v := i1.(type) {
	case map[string]interface{}:
		return &HJSONConfig{filename: "", hsonMap: v}, nil
	default:
		return nil, NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// NewHJSONConfig createc new object or gives errror
// all arguments are same as HJSONConfig.SetDefaultLoadSetting
func NewHJSONConfig(sl ...interface{}) (fl *HJSONConfig, err error) {
	fl = &HJSONConfig{}
	err = fl.SetDefaultLoadSetting(sl...)
	if err != nil {
		return nil, err
	}
	return
}
<commit_msg>GetIntValue() fix method<commit_after>package configuration

import (
	"io/ioutil"

	hjson "github.com/hjson/hjson-go"
)

// HJSONConfig is configuration loader HJSON interface
type HJSONConfig struct {
	filename string
	hsonMap  map[string]interface{}
}

// LoadFileContents load contents of file. separate function to make tests possible
func (fl *HJSONConfig) LoadFileContents(filename string) (cnt []byte, err error) {
	if filename == "" {
		return nil, NewConfigNotConfiguredError("Cannot load config file with no filename")
	}
	return ioutil.ReadFile(filename)
}

// ParseStringContents parses HSON - separated to method cause I want test that
func (fl *HJSONConfig) ParseStringContents(cnt []byte) (m map[string]interface{}, err error) {
	m = map[string]interface{}{}
	err = hjson.Unmarshal(cnt, &m)
	if nil != err {
		m = nil
		return
	}
	return
}

// SetDefaultLoadSetting sets default config file for loader
func (fl *HJSONConfig) SetDefaultLoadSetting(sl ...interface{}) (err error) {
	if len(sl) == 0 {
		return NewHJSONConfigError("No arguments given to SetDefaultLoadSetting")
	}
	a0 := sl[0]
	switch v := a0.(type) {
	case string:
		cnt, err := fl.LoadFileContents(v)
		if err != nil {
			return NewHJSONConfigError("Error loading file occured: " + err.Error())
		}
		m, err := fl.ParseStringContents(cnt)
		if err != nil {
			return err
		}
		fl.filename = v
		fl.hsonMap = m
	case []byte:
		m, err := fl.ParseStringContents(v)
		fl.filename = ""
		if err != nil {
			return err
		}
		fl.hsonMap = m
	case map[string]interface{}:
		fl.filename = ""
		fl.hsonMap = v
	default:
		return NewHJSONConfigError("HJSONConfig.SetDefaultLoadSetting() argument must be string, []byte, or map[string]interface{}")
	}
	// all error cases are solved above
	return nil
}

// CheckExternalConfig checks external configuration file and it's contents - e.g.check file before reload
func (fl *HJSONConfig) CheckExternalConfig() (err error) {
	if "" == fl.filename {
		return NewConfigUsageError("Can not check external file cause it's not configuted inside")
	}
	cnt, err := fl.LoadFileContents(fl.filename)
	if err != nil {
		return err
	}
	_, err = fl.ParseStringContents(cnt)
	if nil != err {
		return err
	}
	return nil
}

// ReloadInternalMap (re)loads internal map - if from file. If not - says ConfigUsageError
func (fl *HJSONConfig) ReloadInternalMap() (err error) {
	if "" == fl.filename {
		return NewConfigUsageError("Can not check external file cause it's not configuted inside")
	}
	cnt, err := fl.LoadFileContents(fl.filename)
	if err != nil {
		return err
	}
	m, err := fl.ParseStringContents(cnt)
	if nil != err {
		return err
	}
	fl.hsonMap = m
	return nil
}

// GetValue get any type value on programmer mind own
// usage on intialized object: fl.GetValue("a", "b", "c", "d")
// on this function would be based functions below
func (fl *HJSONConfig) GetValue(path ...string) (i interface{}, err error) {
	if nil == fl.hsonMap {
		return nil, NewConfigUsageError("No config was initialised yet")
	}
	if 0 == len(path) {
		return nil, NewConfigUsageError("You must get values with path arguments there")
	}
	currmap := fl.hsonMap
	for _, key := range path {
		val, ok := currmap[key]
		if !ok {
			return nil, NewConfigItemNotFound("Item not found")
		}
		switch v := val.(type) {
		case map[string]interface{}:
			currmap = v
		default:
			return interface{}(v), nil
		}
	}
	// here stays 1 algorithmical variant - currmap is answer itself
	return interface{}(currmap), nil
}

// GetIntValue returns integer value by path
func (fl *HJSONConfig) GetIntValue(path ...string) (i int, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return 0, err1
	}
	// TODO: to mainbraich that
	switch v := i1.(type) {
	//TODO:add to mainbranch
	case float64:
		return int(v), nil
	case int:
		return int(v), nil
	default:
		return 0, NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// GetStringValue returns string value or error by path
func (fl *HJSONConfig) GetStringValue(path ...string) (s string, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return "", err1
	}
	switch v := i1.(type) {
	case string:
		return v, nil
	default:
		return "", NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// GetBooleanValue returns boolean value or error by path
func (fl *HJSONConfig) GetBooleanValue(path ...string) (b bool, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return false, err1
	}
	switch v := i1.(type) {
	case bool:
		return v, nil
	default:
		return false, NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// GetSubconfig returns config interface or nil + error
func (fl *HJSONConfig) GetSubconfig(path ...string) (c IConfig, err error) {
	i1, err1 := fl.GetValue(path...)
	if nil != err1 {
		return nil, err1
	}
	switch v := i1.(type) {
	case map[string]interface{}:
		return &HJSONConfig{filename: "", hsonMap: v}, nil
	default:
		return nil, NewConfigTypeMismatchError("Wrong value type detected")
	}
}

// NewHJSONConfig createc new object or gives errror
// all arguments are same as HJSONConfig.SetDefaultLoadSetting
func NewHJSONConfig(sl ...interface{}) (fl *HJSONConfig, err error) {
	fl = &HJSONConfig{}
	err = fl.SetDefaultLoadSetting(sl...)
	if err != nil {
		return nil, err
	}
	return
}
<|endoftext|>


<commit_before>// +build linux

package host

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/shirou/gopsutil/internal/common"
)

type LSB struct {
	ID          string
	Release     string
	Codename    string
	Description string
}

func HostInfo() (*HostInfoStat, error) {
	ret := &HostInfoStat{
		OS: runtime.GOOS,
	}

	hostname, err := os.Hostname()
	if err == nil {
		ret.Hostname = hostname
	}

	platform, family, version, err := GetPlatformInformation()
	if err == nil {
		ret.Platform = platform
		ret.PlatformFamily = family
		ret.PlatformVersion = version
	}
	system, role, err := GetVirtualization()
	if err == nil {
		ret.VirtualizationSystem = system
		ret.VirtualizationRole = role
	}
	boot, err := BootTime()
	if err == nil {
		ret.BootTime = boot
		ret.Uptime = uptime(boot)
	}

	return ret, nil
}

// BootTime returns the system boot time expressed in seconds since the epoch.
func BootTime() (uint64, error) {
	filename := common.HostProc("stat")
	lines, err := common.ReadLines(filename)
	if err != nil {
		return 0, err
	}
	for _, line := range lines {
		if strings.HasPrefix(line, "btime") {
			f := strings.Fields(line)
			if len(f) != 2 {
				return 0, fmt.Errorf("wrong btime format")
			}
			b, err := strconv.ParseInt(f[1], 10, 64)
			if err != nil {
				return 0, err
			}
			return uint64(b), nil
		}
	}

	return 0, fmt.Errorf("could not find btime")
}

func uptime(boot uint64) uint64 {
	return uint64(time.Now().Unix()) - boot
}

func Uptime() (uint64, error) {
	boot, err := BootTime()
	if err != nil {
		return 0, err
	}
	return uptime(boot), nil
}

func Users() ([]UserStat, error) {
	utmpfile := "/var/run/utmp"

	file, err := os.Open(utmpfile)
	if err != nil {
		return nil, err
	}

	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}

	u := utmp{}
	entrySize := int(unsafe.Sizeof(u))
	count := len(buf) / entrySize

	ret := make([]UserStat, 0, count)

	for i := 0; i < count; i++ {
		b := buf[i*entrySize : i*entrySize+entrySize]

		var u utmp
		br := bytes.NewReader(b)
		err := binary.Read(br, binary.LittleEndian, &u)
		if err != nil {
			continue
		}
		user := UserStat{
			User:     common.IntToString(u.User[:]),
			Terminal: common.IntToString(u.Line[:]),
			Host:     common.IntToString(u.Host[:]),
			Started:  int(u.Tv.TvSec),
		}
		ret = append(ret, user)
	}

	return ret, nil

}

func getLSB() (*LSB, error) {
	ret := &LSB{}
	if common.PathExists("/etc/lsb-release") {
		contents, err := common.ReadLines("/etc/lsb-release")
		if err != nil {
			return ret, err // return empty
		}
		for _, line := range contents {
			field := strings.Split(line, "=")
			if len(field) < 2 {
				continue
			}
			switch field[0] {
			case "DISTRIB_ID":
				ret.ID = field[1]
			case "DISTRIB_RELEASE":
				ret.Release = field[1]
			case "DISTRIB_CODENAME":
				ret.Codename = field[1]
			case "DISTRIB_DESCRIPTION":
				ret.Description = field[1]
			}
		}
	} else if common.PathExists("/usr/bin/lsb_release") {
		out, err := exec.Command("/usr/bin/lsb_release").Output()
		if err != nil {
			return ret, err
		}
		for _, line := range strings.Split(string(out), "\n") {
			field := strings.Split(line, ":")
			if len(field) < 2 {
				continue
			}
			switch field[0] {
			case "Distributor ID":
				ret.ID = field[1]
			case "Release":
				ret.Release = field[1]
			case "Codename":
				ret.Codename = field[1]
			case "Description":
				ret.Description = field[1]
			}
		}

	}

	return ret, nil
}

func GetPlatformInformation() (platform string, family string, version string, err error) {

	lsb, err := getLSB()
	if err != nil {
		lsb = &LSB{}
	}

	if common.PathExists("/etc/oracle-release") {
		platform = "oracle"
		contents, err := common.ReadLines("/etc/oracle-release")
		if err == nil {
			version = getRedhatishVersion(contents)
		}
	} else if common.PathExists("/etc/enterprise-release") {
		platform = "oracle"
		contents, err := common.ReadLines("/etc/enterprise-release")
		if err == nil {
			version = getRedhatishVersion(contents)
		}
	} else if common.PathExists("/etc/debian_version") {
		if lsb.ID == "Ubuntu" {
			platform = "ubuntu"
			version = lsb.Release
		} else if lsb.ID == "LinuxMint" {
			platform = "linuxmint"
			version = lsb.Release
		} else {
			if common.PathExists("/usr/bin/raspi-config") {
				platform = "raspbian"
			} else {
				platform = "debian"
			}
			contents, err := common.ReadLines("/etc/debian_version")
			if err == nil {
				version = contents[0]
			}
		}
	} else if common.PathExists("/etc/redhat-release") {
		contents, err := common.ReadLines("/etc/redhat-release")
		if err == nil {
			version = getRedhatishVersion(contents)
			platform = getRedhatishPlatform(contents)
		}
	} else if common.PathExists("/etc/system-release") {
		contents, err := common.ReadLines("/etc/system-release")
		if err == nil {
			version = getRedhatishVersion(contents)
			platform = getRedhatishPlatform(contents)
		}
	} else if common.PathExists("/etc/gentoo-release") {
		platform = "gentoo"
		contents, err := common.ReadLines("/etc/gentoo-release")
		if err == nil {
			version = getRedhatishVersion(contents)
		}
	} else if common.PathExists("/etc/SuSE-release") {
		contents, err := common.ReadLines("/etc/SuSE-release")
		if err == nil {
			version = getSuseVersion(contents)
			platform = getSusePlatform(contents)
		}
		// TODO: slackware detecion
	} else if common.PathExists("/etc/arch-release") {
		platform = "arch"
		version = lsb.Release
	} else if lsb.ID == "RedHat" {
		platform = "redhat"
		version = lsb.Release
	} else if lsb.ID == "Amazon" {
		platform = "amazon"
		version = lsb.Release
	} else if lsb.ID == "ScientificSL" {
		platform = "scientific"
		version = lsb.Release
	} else if lsb.ID == "XenServer" {
		platform = "xenserver"
		version = lsb.Release
	} else if lsb.ID != "" {
		platform = strings.ToLower(lsb.ID)
		version = lsb.Release
	}

	switch platform {
	case "debian", "ubuntu", "linuxmint", "raspbian":
		family = "debian"
	case "fedora":
		family = "fedora"
	case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm":
		family = "rhel"
	case "suse", "opensuse":
		family = "suse"
	case "gentoo":
		family = "gentoo"
	case "slackware":
		family = "slackware"
	case "arch":
		family = "arch"
	case "exherbo":
		family = "exherbo"
	}

	return platform, family, version, nil

}

func getRedhatishVersion(contents []string) string {
	c := strings.ToLower(strings.Join(contents, ""))

	if strings.Contains(c, "rawhide") {
		return "rawhide"
	}
	if matches := regexp.MustCompile(`release (\d[\d.]*)`).FindStringSubmatch(c); matches != nil {
		return matches[1]
	}
	return ""
}

func getRedhatishPlatform(contents []string) string {
	c := strings.ToLower(strings.Join(contents, ""))

	if strings.Contains(c, "red hat") {
		return "redhat"
	}
	f := strings.Split(c, " ")

	return f[0]
}

func getSuseVersion(contents []string) string {
	version := ""
	for _, line := range contents {
		if matches := regexp.MustCompile(`VERSION = ([\d.]+)`).FindStringSubmatch(line); matches != nil {
			version = matches[1]
		} else if matches := regexp.MustCompile(`PATCHLEVEL = ([\d]+)`).FindStringSubmatch(line); matches != nil {
			version = version + "." + matches[1]
		}
	}
	return version
}

func getSusePlatform(contents []string) string {
	c := strings.ToLower(strings.Join(contents, ""))
	if strings.Contains(c, "opensuse") {
		return "opensuse"
	}
	return "suse"
}

func GetVirtualization() (string, string, error) {
	var system string
	var role string

	filename := common.HostProc("xen")
	if common.PathExists(filename) {
		system = "xen"
		role = "guest" // assume guest

		if common.PathExists(filename + "/capabilities") {
			contents, err := common.ReadLines(filename + "/capabilities")
			if err == nil {
				if common.StringsHas(contents, "control_d") {
					role = "host"
				}
			}
		}
	}

	filename = common.HostProc("modules")
	if common.PathExists(filename) {
		contents, err := common.ReadLines(filename)
		if err == nil {
			if common.StringsContains(contents, "kvm") {
				system = "kvm"
				role = "host"
			} else if common.StringsContains(contents, "vboxdrv") {
				system = "vbox"
				role = "host"
			} else if common.StringsContains(contents, "vboxguest") {
				system = "vbox"
				role = "guest"
			}
		}
	}

	filename = common.HostProc("cpuinfo")
	if common.PathExists(filename) {
		contents, err := common.ReadLines(filename)
		if err == nil {
			if common.StringsHas(contents, "QEMU Virtual CPU") ||
				common.StringsHas(contents, "Common KVM processor") ||
				common.StringsHas(contents, "Common 32-bit KVM processor") {
				system = "kvm"
				role = "guest"
			}
		}
	}

	filename = common.HostProc()
	if common.PathExists(filename + "/bc/0") {
		system = "openvz"
		role = "host"
	} else if common.PathExists(filename + "/vz") {
		system = "openvz"
		role = "guest"
	}

	// not use dmidecode because it requires root
	if common.PathExists(filename + "/self/status") {
		contents, err := common.ReadLines(filename + "/self/status")
		if err == nil {

			if common.StringsHas(contents, "s_context:") ||
				common.StringsHas(contents, "VxID:") {
				system = "linux-vserver"
			}
			// TODO: guest or host
		}
	}

	if common.PathExists(filename + "/self/cgroup") {
		contents, err := common.ReadLines(filename + "/self/cgroup")
		if err == nil {
			if common.StringsHas(contents, "lxc") ||
				common.StringsHas(contents, "docker") {
				system = "lxc"
				role = "guest"
			} else if common.PathExists("/usr/bin/lxc-version") { // TODO: which
				system = "lxc"
				role = "host"
			}
		}
	}

	return system, role, nil
}
<commit_msg>host_linux: Skip everything that isn't a normal process.<commit_after>// +build linux

package host

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/shirou/gopsutil/internal/common"
)

type LSB struct {
	ID          string
	Release     string
	Codename    string
	Description string
}

// from utmp.h
const USER_PROCESS = 7

func HostInfo() (*HostInfoStat, error) {
	ret := &HostInfoStat{
		OS: runtime.GOOS,
	}

	hostname, err := os.Hostname()
	if err == nil {
		ret.Hostname = hostname
	}

	platform, family, version, err := GetPlatformInformation()
	if err == nil {
		ret.Platform = platform
		ret.PlatformFamily = family
		ret.PlatformVersion = version
	}
	system, role, err := GetVirtualization()
	if err == nil {
		ret.VirtualizationSystem = system
		ret.VirtualizationRole = role
	}
	boot, err := BootTime()
	if err == nil {
		ret.BootTime = boot
		ret.Uptime = uptime(boot)
	}

	return ret, nil
}

// BootTime returns the system boot time expressed in seconds since the epoch.
func BootTime() (uint64, error) {
	filename := common.HostProc("stat")
	lines, err := common.ReadLines(filename)
	if err != nil {
		return 0, err
	}
	for _, line := range lines {
		if strings.HasPrefix(line, "btime") {
			f := strings.Fields(line)
			if len(f) != 2 {
				return 0, fmt.Errorf("wrong btime format")
			}
			b, err := strconv.ParseInt(f[1], 10, 64)
			if err != nil {
				return 0, err
			}
			return uint64(b), nil
		}
	}

	return 0, fmt.Errorf("could not find btime")
}

func uptime(boot uint64) uint64 {
	return uint64(time.Now().Unix()) - boot
}

func Uptime() (uint64, error) {
	boot, err := BootTime()
	if err != nil {
		return 0, err
	}
	return uptime(boot), nil
}

func Users() ([]UserStat, error) {
	utmpfile := "/var/run/utmp"

	file, err := os.Open(utmpfile)
	if err != nil {
		return nil, err
	}

	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}

	u := utmp{}
	entrySize := int(unsafe.Sizeof(u))
	count := len(buf) / entrySize

	ret := make([]UserStat, 0, count)

	for i := 0; i < count; i++ {
		b := buf[i*entrySize : i*entrySize+entrySize]

		var u utmp
		br := bytes.NewReader(b)
		err := binary.Read(br, binary.LittleEndian, &u)
		if err != nil {
			continue
		}
		if u.Type != USER_PROCESS {
			continue
		}
		user := UserStat{
			User:     common.IntToString(u.User[:]),
			Terminal: common.IntToString(u.Line[:]),
			Host:     common.IntToString(u.Host[:]),
			Started:  int(u.Tv.TvSec),
		}
		ret = append(ret, user)
	}

	return ret, nil

}

func getLSB() (*LSB, error) {
	ret := &LSB{}
	if common.PathExists("/etc/lsb-release") {
		contents, err := common.ReadLines("/etc/lsb-release")
		if err != nil {
			return ret, err // return empty
		}
		for _, line := range contents {
			field := strings.Split(line, "=")
			if len(field) < 2 {
				continue
			}
			switch field[0] {
			case "DISTRIB_ID":
				ret.ID = field[1]
			case "DISTRIB_RELEASE":
				ret.Release = field[1]
			case "DISTRIB_CODENAME":
				ret.Codename = field[1]
			case "DISTRIB_DESCRIPTION":
				ret.Description = field[1]
			}
		}
	} else if common.PathExists("/usr/bin/lsb_release") {
		out, err := exec.Command("/usr/bin/lsb_release").Output()
		if err != nil {
			return ret, err
		}
		for _, line := range strings.Split(string(out), "\n") {
			field := strings.Split(line, ":")
			if len(field) < 2 {
				continue
			}
			switch field[0] {
			case "Distributor ID":
				ret.ID = field[1]
			case "Release":
				ret.Release = field[1]
			case "Codename":
				ret.Codename = field[1]
			case "Description":
				ret.Description = field[1]
			}
		}

	}

	return ret, nil
}

func GetPlatformInformation() (platform string, family string, version string, err error) {

	lsb, err := getLSB()
	if err != nil {
		lsb = &LSB{}
	}

	if common.PathExists("/etc/oracle-release") {
		platform = "oracle"
		contents, err := common.ReadLines("/etc/oracle-release")
		if err == nil {
			version = getRedhatishVersion(contents)
		}
	} else if common.PathExists("/etc/enterprise-release") {
		platform = "oracle"
		contents, err := common.ReadLines("/etc/enterprise-release")
		if err == nil {
			version = getRedhatishVersion(contents)
		}
	} else if common.PathExists("/etc/debian_version") {
		if lsb.ID == "Ubuntu" {
			platform = "ubuntu"
			version = lsb.Release
		} else if lsb.ID == "LinuxMint" {
			platform = "linuxmint"
			version = lsb.Release
		} else {
			if common.PathExists("/usr/bin/raspi-config") {
				platform = "raspbian"
			} else {
				platform = "debian"
			}
			contents, err := common.ReadLines("/etc/debian_version")
			if err == nil {
				version = contents[0]
			}
		}
	} else if common.PathExists("/etc/redhat-release") {
		contents, err := common.ReadLines("/etc/redhat-release")
		if err == nil {
			version = getRedhatishVersion(contents)
			platform = getRedhatishPlatform(contents)
		}
	} else if common.PathExists("/etc/system-release") {
		contents, err := common.ReadLines("/etc/system-release")
		if err == nil {
			version = getRedhatishVersion(contents)
			platform = getRedhatishPlatform(contents)
		}
	} else if common.PathExists("/etc/gentoo-release") {
		platform = "gentoo"
		contents, err := common.ReadLines("/etc/gentoo-release")
		if err == nil {
			version = getRedhatishVersion(contents)
		}
	} else if common.PathExists("/etc/SuSE-release") {
		contents, err := common.ReadLines("/etc/SuSE-release")
		if err == nil {
			version = getSuseVersion(contents)
			platform = getSusePlatform(contents)
		}
		// TODO: slackware detecion
	} else if common.PathExists("/etc/arch-release") {
		platform = "arch"
		version = lsb.Release
	} else if lsb.ID == "RedHat" {
		platform = "redhat"
		version = lsb.Release
	} else if lsb.ID == "Amazon" {
		platform = "amazon"
		version = lsb.Release
	} else if lsb.ID == "ScientificSL" {
		platform = "scientific"
		version = lsb.Release
	} else if lsb.ID == "XenServer" {
		platform = "xenserver"
		version = lsb.Release
	} else if lsb.ID != "" {
		platform = strings.ToLower(lsb.ID)
		version = lsb.Release
	}

	switch platform {
	case "debian", "ubuntu", "linuxmint", "raspbian":
		family = "debian"
	case "fedora":
		family = "fedora"
	case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm":
		family = "rhel"
	case "suse", "opensuse":
		family = "suse"
	case "gentoo":
		family = "gentoo"
	case "slackware":
		family = "slackware"
	case "arch":
		family = "arch"
	case "exherbo":
		family = "exherbo"
	}

	return platform, family, version, nil

}

func getRedhatishVersion(contents []string) string {
	c := strings.ToLower(strings.Join(contents, ""))

	if strings.Contains(c, "rawhide") {
		return "rawhide"
	}
	if matches := regexp.MustCompile(`release (\d[\d.]*)`).FindStringSubmatch(c); matches != nil {
		return matches[1]
	}
	return ""
}

func getRedhatishPlatform(contents []string) string {
	c := strings.ToLower(strings.Join(contents, ""))

	if strings.Contains(c, "red hat") {
		return "redhat"
	}
	f := strings.Split(c, " ")

	return f[0]
}

func getSuseVersion(contents []string) string {
	version := ""
	for _, line := range contents {
		if matches := regexp.MustCompile(`VERSION = ([\d.]+)`).FindStringSubmatch(line); matches != nil {
			version = matches[1]
		} else if matches := regexp.MustCompile(`PATCHLEVEL = ([\d]+)`).FindStringSubmatch(line); matches != nil {
			version = version + "." + matches[1]
		}
	}
	return version
}

func getSusePlatform(contents []string) string {
	c := strings.ToLower(strings.Join(contents, ""))
	if strings.Contains(c, "opensuse") {
		return "opensuse"
	}
	return "suse"
}

func GetVirtualization() (string, string, error) {
	var system string
	var role string

	filename := common.HostProc("xen")
	if common.PathExists(filename) {
		system = "xen"
		role = "guest" // assume guest

		if common.PathExists(filename + "/capabilities") {
			contents, err := common.ReadLines(filename + "/capabilities")
			if err == nil {
				if common.StringsHas(contents, "control_d") {
					role = "host"
				}
			}
		}
	}

	filename = common.HostProc("modules")
	if common.PathExists(filename) {
		contents, err := common.ReadLines(filename)
		if err == nil {
			if common.StringsContains(contents, "kvm") {
				system = "kvm"
				role = "host"
			} else if common.StringsContains(contents, "vboxdrv") {
				system = "vbox"
				role = "host"
			} else if common.StringsContains(contents, "vboxguest") {
				system = "vbox"
				role = "guest"
			}
		}
	}

	filename = common.HostProc("cpuinfo")
	if common.PathExists(filename) {
		contents, err := common.ReadLines(filename)
		if err == nil {
			if common.StringsHas(contents, "QEMU Virtual CPU") ||
				common.StringsHas(contents, "Common KVM processor") ||
				common.StringsHas(contents, "Common 32-bit KVM processor") {
				system = "kvm"
				role = "guest"
			}
		}
	}

	filename = common.HostProc()
	if common.PathExists(filename + "/bc/0") {
		system = "openvz"
		role = "host"
	} else if common.PathExists(filename + "/vz") {
		system = "openvz"
		role = "guest"
	}

	// not use dmidecode because it requires root
	if common.PathExists(filename + "/self/status") {
		contents, err := common.ReadLines(filename + "/self/status")
		if err == nil {

			if common.StringsHas(contents, "s_context:") ||
				common.StringsHas(contents, "VxID:") {
				system = "linux-vserver"
			}
			// TODO: guest or host
		}
	}

	if common.PathExists(filename + "/self/cgroup") {
		contents, err := common.ReadLines(filename + "/self/cgroup")
		if err == nil {
			if common.StringsHas(contents, "lxc") ||
				common.StringsHas(contents, "docker") {
				system = "lxc"
				role = "guest"
			} else if common.PathExists("/usr/bin/lxc-version") { // TODO: which
				system = "lxc"
				role = "host"
			}
		}
	}

	return system, role, nil
}
<|endoftext|>


<commit_before>/*

Package luautil implements utility for gopher-lua.

*/
package luautil // import "a4.io/blobstash/pkg/apps/luautil"
// TODO(tsileo): move it to pkg/luautil

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/yuin/gopher-lua"
)

// FIXME(tsileo): support a custom metatable so `jsonutil.new_list/map()` and `jsonutil.is_list/map()` can work
// and jsonuti.new_list() can be dumped as an empty list via json.encode. Or use __index for __jsonutil_type "map"|"list" and a global "map"/"list" metatable from json
// map VS object, list VS array

// AddToPath append the given path the the Lua package.path
func AddToPath(L *lua.LState, npath string) {
	path := L.GetField(L.GetField(L.Get(lua.EnvironIndex), "package"), "path").(lua.LString)
	path = lua.LString(npath + "/?.lua;" + string(path))
	L.SetField(L.GetField(L.Get(lua.EnvironIndex), "package"), "path", lua.LString(path))
}

// TableToMap converts a `*lua.LTable` to a `map[string]interface{}`
func TableToMap(L *lua.LState, table *lua.LTable) map[string]interface{} {
	res, _ := tomap(L, table, map[*lua.LTable]bool{})
	return res
}

// TableToSlice converts a `*lua.LTable` to a `[]interface{}`
func TableToSlice(L *lua.LState, table *lua.LTable) []interface{} {
	_, res := tomap(L, table, map[*lua.LTable]bool{})
	return res
}

func tomap(L *lua.LState, table *lua.LTable, visited map[*lua.LTable]bool) (map[string]interface{}, []interface{}) {
	res := map[string]interface{}{}
	var arrres []interface{}
	nkey := false
	table.ForEach(func(key lua.LValue, value lua.LValue) {
		_, numberKey := key.(lua.LNumber)
		if numberKey {
			nkey = true
		}
		switch converted := value.(type) {
		case lua.LBool:
			val := false
			if converted == lua.LTrue {
				val = true
			}
			if nkey {
				arrres = append(arrres, val)
			} else {
				res[key.String()] = val
			}
		case lua.LString:
			if nkey {
				arrres = append(arrres, string(converted))
			} else {
				res[key.String()] = string(converted)
			}
		case lua.LNumber:
			if nkey {
				arrres = append(arrres, float64(converted))
			} else {
				res[key.String()] = float64(converted)
			}
		case lua.LChannel:
			panic("no channel")
		case *lua.LFunction:
			panic("no function")
		case *lua.LNilType:
			res[key.String()] = converted
		case *lua.LState:
			panic("no LState")
		case *lua.LTable:
			// if visited[converted] {
			//	panic("nested table")
			// }
			visited[converted] = true
			stres, sares := tomap(L, converted, visited)
			if nkey {
				if sares != nil {
					arrres = append(arrres, sares)
				} else {
					arrres = append(arrres, stres)
				}
			} else {
				if sares != nil {
					res[key.String()] = sares
				} else {
					res[key.String()] = stres
				}
			}
		}
	})
	if arrres == nil && L.GetMetatable(table) == L.GetGlobal("__gluapp_json_array") {
		return nil, []interface{}{}
	}
	return res, arrres
}

// Convert a Lua table to JSON
// Adapted from https://github.com/layeh/gopher-json/blob/master/util.go (Public domain)
func ToJSON(L *lua.LState, value lua.LValue) []byte {
	var data []byte
	var err error
	switch converted := value.(type) {
	case lua.LBool:
		data, err = json.Marshal(converted)
	case lua.LChannel:
		err = errors.New("ToJSON: cannot marshal channel")
	case lua.LNumber:
		data, err = json.Marshal(converted)
	case *lua.LFunction:
		err = errors.New("ToJSON: cannot marshal function")
	case *lua.LNilType:
		data, err = json.Marshal(converted)
	case *lua.LState:
		err = errors.New("ToJSON: cannot marshal LState")
	case lua.LString:
		data, err = json.Marshal(converted)
	case *lua.LTable:
		res, ares := tomap(L, converted, map[*lua.LTable]bool{})
		if ares != nil {
			data, err = json.Marshal(ares)
		} else {
			data, err = json.Marshal(res)
		}
	case *lua.LUserData:
		err = errors.New("ToJSON: cannot marshal user data")
		// TODO: call metatable __tostring?
	}
	if err != nil {
		panic(err)
	}
	return data
}

// Convert the JSON to a Lua object ready to be pushed
// Adapted from https://github.com/layeh/gopher-json/blob/master/util.go (Public domain)
func FromJSON(L *lua.LState, js []byte) lua.LValue {
	var res interface{}
	if err := json.Unmarshal(js, &res); err != nil {
		panic(err)
	}
	return fromJSON(L, res)
}

// InterfaceToLValue converts the given value to its `lua.LValue` counterpart
func InterfaceToLValue(L *lua.LState, value interface{}) lua.LValue {
	return fromJSON(L, value)
}

func fromJSON(L *lua.LState, value interface{}) lua.LValue {
	// XXX it handles so many types because the docstore uses msgpack (and it handles all the possible types)
	switch converted := value.(type) {
	case bool:
		return lua.LBool(converted)
	case int8:
		return lua.LNumber(converted)
	case int16:
		return lua.LNumber(converted)
	case int32:
		return lua.LNumber(converted)
	case uint8:
		return lua.LNumber(converted)
	case uint16:
		return lua.LNumber(converted)
	case uint32:
		return lua.LNumber(converted)
	case uint64:
		return lua.LNumber(converted)
	case int:
		return lua.LNumber(converted)
	case int64:
		return lua.LNumber(converted)
	case float64:
		return lua.LNumber(converted)
	case string:
		return lua.LString(converted)
	case []interface{}:
		arr := L.CreateTable(len(converted), 0)
		for _, item := range converted {
			arr.Append(fromJSON(L, item))
		}
		mt := L.GetGlobal("__gluapp_json_array")
		if mt != lua.LNil {
			L.SetMetatable(arr, mt)
		}
		return arr
	case []map[string]interface{}:
		arr := L.CreateTable(len(converted), 0)
		for _, item := range converted {
			arr.Append(fromJSON(L, item))
		}
		return arr
	case map[string]interface{}:
		mt := L.GetGlobal("__gluapp_json_object")
		tbl := L.CreateTable(0, len(converted))
		for key, item := range converted {
			tbl.RawSetH(lua.LString(key), fromJSON(L, item))
		}
		if mt != lua.LNil {
			L.SetMetatable(tbl, mt)
		}
		return tbl
	case nil:
		return lua.LNil
	default:
		// FIXME(tsileo): create a parser for `lua:"key_name"` and build a table by iterating the field a converting value!
		// or a ToLua(L) lua.LValue interface?
		if s, ok := converted.(fmt.Stringer); ok {
			return lua.LString(s.String())
		}
		js, err := json.Marshal(converted)
		if err == nil {
			return FromJSON(L, js)
		}
		panic(fmt.Errorf("unsupported type %+v", converted))
	}
}
<commit_msg>apps/luautil: JSON fix<commit_after>/*

Package luautil implements utility for gopher-lua.

*/
package luautil // import "a4.io/blobstash/pkg/apps/luautil"
// TODO(tsileo): move it to pkg/luautil

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/yuin/gopher-lua"
)

// FIXME(tsileo): support a custom metatable so `jsonutil.new_list/map()` and `jsonutil.is_list/map()` can work
// and jsonuti.new_list() can be dumped as an empty list via json.encode. Or use __index for __jsonutil_type "map"|"list" and a global "map"/"list" metatable from json
// map VS object, list VS array

// AddToPath append the given path the the Lua package.path
func AddToPath(L *lua.LState, npath string) {
	path := L.GetField(L.GetField(L.Get(lua.EnvironIndex), "package"), "path").(lua.LString)
	path = lua.LString(npath + "/?.lua;" + string(path))
	L.SetField(L.GetField(L.Get(lua.EnvironIndex), "package"), "path", lua.LString(path))
}

// TableToMap converts a `*lua.LTable` to a `map[string]interface{}`
func TableToMap(L *lua.LState, table *lua.LTable) map[string]interface{} {
	res, _ := tomap(L, table, map[*lua.LTable]bool{})
	return res
}

// TableToSlice converts a `*lua.LTable` to a `[]interface{}`
func TableToSlice(L *lua.LState, table *lua.LTable) []interface{} {
	_, res := tomap(L, table, map[*lua.LTable]bool{})
	return res
}

func tomap(L *lua.LState, table *lua.LTable, visited map[*lua.LTable]bool) (map[string]interface{}, []interface{}) {
	res := map[string]interface{}{}
	var arrres []interface{}
	nkey := false
	table.ForEach(func(key lua.LValue, value lua.LValue) {
		_, numberKey := key.(lua.LNumber)
		if numberKey {
			nkey = true
		}
		switch converted := value.(type) {
		case lua.LBool:
			val := false
			if converted == lua.LTrue {
				val = true
			}
			if nkey {
				arrres = append(arrres, val)
			} else {
				res[key.String()] = val
			}
		case lua.LString:
			if nkey {
				arrres = append(arrres, string(converted))
			} else {
				res[key.String()] = string(converted)
			}
		case lua.LNumber:
			if nkey {
				arrres = append(arrres, float64(converted))
			} else {
				res[key.String()] = float64(converted)
			}
		case lua.LChannel:
			panic("no channel")
		case *lua.LFunction:
			panic("no function")
		case *lua.LNilType:
			res[key.String()] = converted
		case *lua.LState:
			panic("no LState")
		case *lua.LTable:
			// if visited[converted] {
			//	panic("nested table")
			// }
			visited[converted] = true
			stres, sares := tomap(L, converted, visited)
			if nkey {
				if sares != nil {
					arrres = append(arrres, sares)
				} else {
					arrres = append(arrres, stres)
				}
			} else {
				if sares != nil {
					res[key.String()] = sares
				} else {
					res[key.String()] = stres
				}
			}
		}
	})
	if arrres == nil && L.GetGlobal("__gluapp_json_array") != lua.LNil && L.GetMetatable(table) == L.GetGlobal("__gluapp_json_array") {
		return nil, []interface{}{}
	}
	return res, arrres
}

// Convert a Lua table to JSON
// Adapted from https://github.com/layeh/gopher-json/blob/master/util.go (Public domain)
func ToJSON(L *lua.LState, value lua.LValue) []byte {
	var data []byte
	var err error
	switch converted := value.(type) {
	case lua.LBool:
		data, err = json.Marshal(converted)
	case lua.LChannel:
		err = errors.New("ToJSON: cannot marshal channel")
	case lua.LNumber:
		data, err = json.Marshal(converted)
	case *lua.LFunction:
		err = errors.New("ToJSON: cannot marshal function")
	case *lua.LNilType:
		data, err = json.Marshal(converted)
	case *lua.LState:
		err = errors.New("ToJSON: cannot marshal LState")
	case lua.LString:
		data, err = json.Marshal(converted)
	case *lua.LTable:
		res, ares := tomap(L, converted, map[*lua.LTable]bool{})
		if ares != nil {
			data, err = json.Marshal(ares)
		} else {
			data, err = json.Marshal(res)
		}
	case *lua.LUserData:
		err = errors.New("ToJSON: cannot marshal user data")
		// TODO: call metatable __tostring?
	}
	if err != nil {
		panic(err)
	}
	return data
}

// Convert the JSON to a Lua object ready to be pushed
// Adapted from https://github.com/layeh/gopher-json/blob/master/util.go (Public domain)
func FromJSON(L *lua.LState, js []byte) lua.LValue {
	var res interface{}
	if err := json.Unmarshal(js, &res); err != nil {
		panic(err)
	}
	return fromJSON(L, res)
}

// InterfaceToLValue converts the given value to its `lua.LValue` counterpart
func InterfaceToLValue(L *lua.LState, value interface{}) lua.LValue {
	return fromJSON(L, value)
}

func fromJSON(L *lua.LState, value interface{}) lua.LValue {
	// XXX it handles so many types because the docstore uses msgpack (and it handles all the possible types)
	switch converted := value.(type) {
	case bool:
		return lua.LBool(converted)
	case int8:
		return lua.LNumber(converted)
	case int16:
		return lua.LNumber(converted)
	case int32:
		return lua.LNumber(converted)
	case uint8:
		return lua.LNumber(converted)
	case uint16:
		return lua.LNumber(converted)
	case uint32:
		return lua.LNumber(converted)
	case uint64:
		return lua.LNumber(converted)
	case int:
		return lua.LNumber(converted)
	case int64:
		return lua.LNumber(converted)
	case float64:
		return lua.LNumber(converted)
	case string:
		return lua.LString(converted)
	case []interface{}:
		arr := L.CreateTable(len(converted), 0)
		for _, item := range converted {
			arr.Append(fromJSON(L, item))
		}
		mt := L.GetGlobal("__gluapp_json_array")
		if mt != lua.LNil {
			L.SetMetatable(arr, mt)
		}
		return arr
	case []map[string]interface{}:
		arr := L.CreateTable(len(converted), 0)
		for _, item := range converted {
			arr.Append(fromJSON(L, item))
		}
		return arr
	case map[string]interface{}:
		mt := L.GetGlobal("__gluapp_json_object")
		tbl := L.CreateTable(0, len(converted))
		for key, item := range converted {
			tbl.RawSetH(lua.LString(key), fromJSON(L, item))
		}
		if mt != lua.LNil {
			L.SetMetatable(tbl, mt)
		}
		return tbl
	case nil:
		return lua.LNil
	default:
		// FIXME(tsileo): create a parser for `lua:"key_name"` and build a table by iterating the field a converting value!
		// or a ToLua(L) lua.LValue interface?
		if s, ok := converted.(fmt.Stringer); ok {
			return lua.LString(s.String())
		}
		js, err := json.Marshal(converted)
		if err == nil {
			return FromJSON(L, js)
		}
		panic(fmt.Errorf("unsupported type %+v", converted))
	}
}
<|endoftext|>


<commit_before>//
// Copyright 2022 The GUAC Authors.
//
// 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 assembler

import (
	"testing"

	"github.com/guacsec/guac/pkg/assembler/graphdb"
)

const (
	dbUri string = "neo4j://localhost:7687"
)

type MockNode struct {
	Id      string
	Address string
	Name    string
	Age     *int
	Score   *int
}

func (n MockNode) Type() string {
	return "MockNode"
}

func (n MockNode) Properties() map[string]interface{} {
	properties := make(map[string]interface{})
	properties["id"] = n.Id
	properties["address"] = n.Address
	properties["name"] = n.Name
	if n.Age != nil {
		properties["age"] = *n.Age
	}
	if n.Score != nil {
		properties["score"] = *n.Score
	}
	return properties
}

func (n MockNode) PropertyNames() []string {
	keys := []string{"id", "address", "name"}
	if n.Age != nil {
		keys = append(keys, "age")
	}
	if n.Score != nil {
		keys = append(keys, "score")
	}
	return keys
}

func (n MockNode) IdentifiablePropertyNames() []string {
	// Can identify a MockNode uniquely either by id or by (name, age)
	if n.Age != nil {
		return []string{"name", "age"}
	}
	return []string{"id"}
}

type MockEdge struct {
	A, B MockNode
	Id   *int
}

func (e MockEdge) Type() string {
	return "MockEdge"
}

func (e MockEdge) Nodes() (v, u GuacNode) {
	return e.A, e.B
}

func (e MockEdge) Properties() map[string]interface{} {
	properties := make(map[string]interface{})
	if e.Id != nil {
		properties["id"] = *e.Id
	}
	return properties
}

func (e MockEdge) PropertyNames() []string {
	if e.Id != nil {
		return []string{"id"}
	}
	return []string{}
}

func (e MockEdge) IdentifiablePropertyNames() []string {
	if e.Id != nil {
		return []string{"id"}
	}
	return []string{}
}

func Test_MockNodes(t *testing.T) {
	client, err := graphdb.EmptyClientForTesting(dbUri)
	if err != nil {
		t.Fatalf("Could not obtain testing database: %v", err)
	}
	defer client.Close()

	score1 := 0
	score2 := 42
	age := 42
	n1 := MockNode{"id1", "addr1", "name1", &age, nil}
	n2 := MockNode{"id2", "addr1", "name2", nil, &score1}
	n3 := MockNode{"id3", "addr2", "name3", &age, &score2}
	edge_id := 0
	e1 := MockEdge{n1, n2, &edge_id}
	e2 := MockEdge{n2, n3, nil}
	graph := Graph{[]GuacNode{n1, n2, n3}, []GuacEdge{e1, e2}}

	err = StoreGraph(graph, client)
	if err != nil {
		t.Errorf("Could not store graph: %v", err)
	}

	// TODO: retrieve nodes from DB using the last identifiable attribute

}

func Test_SLSASubgraph(t *testing.T) {
	tests := []func() Graph{
		func() Graph {
			return Graph{}
		},
	}

	for _, test := range tests {
		_ = test() // build subgraph
		// TODO: write and read to DB
	}
}
<commit_msg>Tag `nodes_test` as integration (requires graphdb) (#93)<commit_after>//
// Copyright 2022 The GUAC Authors.
//
// 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.

//go:build integration

package assembler

import (
	"testing"

	"github.com/guacsec/guac/pkg/assembler/graphdb"
)

const (
	dbUri string = "neo4j://localhost:7687"
)

type MockNode struct {
	Id      string
	Address string
	Name    string
	Age     *int
	Score   *int
}

func (n MockNode) Type() string {
	return "MockNode"
}

func (n MockNode) Properties() map[string]interface{} {
	properties := make(map[string]interface{})
	properties["id"] = n.Id
	properties["address"] = n.Address
	properties["name"] = n.Name
	if n.Age != nil {
		properties["age"] = *n.Age
	}
	if n.Score != nil {
		properties["score"] = *n.Score
	}
	return properties
}

func (n MockNode) PropertyNames() []string {
	keys := []string{"id", "address", "name"}
	if n.Age != nil {
		keys = append(keys, "age")
	}
	if n.Score != nil {
		keys = append(keys, "score")
	}
	return keys
}

func (n MockNode) IdentifiablePropertyNames() []string {
	// Can identify a MockNode uniquely either by id or by (name, age)
	if n.Age != nil {
		return []string{"name", "age"}
	}
	return []string{"id"}
}

type MockEdge struct {
	A, B MockNode
	Id   *int
}

func (e MockEdge) Type() string {
	return "MockEdge"
}

func (e MockEdge) Nodes() (v, u GuacNode) {
	return e.A, e.B
}

func (e MockEdge) Properties() map[string]interface{} {
	properties := make(map[string]interface{})
	if e.Id != nil {
		properties["id"] = *e.Id
	}
	return properties
}

func (e MockEdge) PropertyNames() []string {
	if e.Id != nil {
		return []string{"id"}
	}
	return []string{}
}

func (e MockEdge) IdentifiablePropertyNames() []string {
	if e.Id != nil {
		return []string{"id"}
	}
	return []string{}
}

func Test_MockNodes(t *testing.T) {
	client, err := graphdb.EmptyClientForTesting(dbUri)
	if err != nil {
		t.Fatalf("Could not obtain testing database: %v", err)
	}
	defer client.Close()

	score1 := 0
	score2 := 42
	age := 42
	n1 := MockNode{"id1", "addr1", "name1", &age, nil}
	n2 := MockNode{"id2", "addr1", "name2", nil, &score1}
	n3 := MockNode{"id3", "addr2", "name3", &age, &score2}
	edge_id := 0
	e1 := MockEdge{n1, n2, &edge_id}
	e2 := MockEdge{n2, n3, nil}
	graph := Graph{[]GuacNode{n1, n2, n3}, []GuacEdge{e1, e2}}

	err = StoreGraph(graph, client)
	if err != nil {
		t.Errorf("Could not store graph: %v", err)
	}

	// TODO: retrieve nodes from DB using the last identifiable attribute

}

func Test_SLSASubgraph(t *testing.T) {
	tests := []func() Graph{
		func() Graph {
			return Graph{}
		},
	}

	for _, test := range tests {
		_ = test() // build subgraph
		// TODO: write and read to DB
	}
}
<|endoftext|>


<commit_before>package crank

import (
	"encoding/json"
	"io"
	"os"
	"time"
)

type ProcessConfig struct {
	Command      string        `json:"command"`
	StartTimeout time.Duration `json:"start_timeout"`
	StopTimeout  time.Duration `json:"stop_timeout"`
}

func LoadProcessConfig(path string) (processConfig *ProcessConfig, err error) {
	var reader io.ReadCloser
	if reader, err = os.Open(path); err != nil {
		return
	}
	defer reader.Close()

	processConfig = new(ProcessConfig)
	jsonDecoder := json.NewDecoder(reader)
	err = jsonDecoder.Decode(processConfig)
	return
}

func (self *ProcessConfig) Save(path string) error {
	writer, err := os.Create(path)
	if err != nil {
		return err
	}
	defer writer.Close()

	jsonEncoder := json.NewEncoder(writer)
	return jsonEncoder.Encode(self)
}
<commit_msg>cleanup<commit_after>package crank

import (
	"encoding/json"
	"os"
	"time"
)

type ProcessConfig struct {
	Command      string        `json:"command"`
	StartTimeout time.Duration `json:"start_timeout"`
	StopTimeout  time.Duration `json:"stop_timeout"`
}

func LoadProcessConfig(path string) (processConfig *ProcessConfig, err error) {
	var reader *os.File
	if reader, err = os.Open(path); err != nil {
		return
	}
	defer reader.Close()

	processConfig = new(ProcessConfig)
	jsonDecoder := json.NewDecoder(reader)
	err = jsonDecoder.Decode(processConfig)
	return
}

func (self *ProcessConfig) Save(path string) error {
	writer, err := os.Create(path)
	if err != nil {
		return err
	}
	defer writer.Close()

	jsonEncoder := json.NewEncoder(writer)
	return jsonEncoder.Encode(self)
}
<|endoftext|>