<commit_before>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package main

// This is here the command line arguments are parsed and executed.

import (
	"github.com/zenoss/glog"
	"github.com/zenoss/serviced/dao"

	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

// mapImageNames translates values of service.ImageId using the mapping.
func mapImageNames(service *dao.ServiceDefinition, mapping map[string]string) {
	if _, found := mapping[service.ImageId]; found {
		service.ImageId = mapping[service.ImageId]
	}
	for i, _ := range service.Services {
		mapImageNames(&service.Services[i], mapping)
	}
}

// CmdCompileTemplate traverses the given directory of service definitions
// and prints the generated json struct to stdout.
func (cli *ServicedCli) CmdCompileTemplate(args ...string) error {
	cmd := Subcmd("compile-template", "[OPTIONS] DIR", "Read the given directory of service definitions compile to a single json struct")

        imageMappings := make(ListOpts, 0)
        cmd.Var(&imageMappings, "map", "Map a given image name to another (e.g. -map zenoss/zenoss5x:quay.io/zenoss-core:alpha2 )")

	if err := cmd.Parse(args); err != nil {
		return err
	}
	if len(cmd.Args()) != 1 {
		cmd.Usage()
		return nil
	}

	mapping := make(map[string]string)
	for _, spec := range imageMappings {
		parts := strings.Split(spec, ":")
		if len(parts) != 2 {
			glog.Fatalf("invalid mapping spec: %s", spec)
		}
		mapping[parts[0]] = parts[1]
	}

	template, err := dao.ServiceDefinitionFromPath(cmd.Arg(0))
	if err != nil {
		return err
	}
	mapImageNames(template, mapping)
	output, err := json.MarshalIndent(template, "", "    ")
	if err != nil {
		return err
	}
	fmt.Println(string(output))
	return nil
}

// List the service templates associated with the control plane.
func (cli *ServicedCli) CmdTemplates(args ...string) error {
	cmd := Subcmd("templates", "[OPTIONS]", "List templates")

	var verbose bool
	cmd.BoolVar(&verbose, "verbose", false, "Show JSON representation for each template")

	var raw bool
	cmd.BoolVar(&raw, "raw", false, "Don't show header line")

	if err := cmd.Parse(args); err != nil {
		return err
	}

	c := getClient()

	var serviceTemplates map[string]*dao.ServiceTemplate
	var unused int
	err := c.GetServiceTemplates(unused, &serviceTemplates)
	if err != nil {
		glog.Fatalf("Could not get list of templates: %s", err)
	}

	if verbose == false {
		outfmt := "%-36s %-16s %-32.32s\n"

		if raw == false {
			fmt.Printf("%-36s %-16s %-32s\n", "TEMPLATE ID", "NAME", "DESCRIPTION")
		} else {
			outfmt = "%s|%s|%s\n"
		}

		for id, t := range serviceTemplates {
			fmt.Printf(outfmt, id, t.Name, t.Description)
		}
	} else {
		for id, template := range serviceTemplates {
			if t, err := json.MarshalIndent(template, " ", " "); err == nil {
				if verbose {
					fmt.Printf("%s: %s\n", id, t)
				}
			}
		}
	}

	return err
}

// Add a service template to the control plane.
func (cli *ServicedCli) CmdAddTemplate(args ...string) error {

	cmd := Subcmd("add-template", "[INPUT]", "Add a template. Use - for standard input. "+
		"[INPUT] is either a json file or template directory.")
	if err := cmd.Parse(args); err != nil {
		return err
	}
	var serviceTemplate dao.ServiceTemplate
	if len(cmd.Args()) != 1 {
		cmd.Usage()
		return nil
	}

	if cmd.Arg(0) == "-" {
		// Read from standard input
		dec := json.NewDecoder(os.Stdin)
		err := dec.Decode(&serviceTemplate)
		if err != nil {
			glog.Fatalf("Could not read ServiceTemplate from stdin: %s", err)
		}
	} else {
		// is the input a file or directory
		nodeinfo, err := os.Stat(cmd.Arg(0))
		if err != nil {
			glog.Fatalf("Could not ServiceTemplate from %s: %s", cmd.Arg(0), err)
		}

		if nodeinfo.IsDir() {
			sdefinition, err := dao.ServiceDefinitionFromPath(cmd.Arg(0))
			if err != nil {
				glog.Fatalf("Could not read template from directory %s: %s", nodeinfo.Name(), err)
			}
			serviceTemplate.Services = make([]dao.ServiceDefinition, 1)
			serviceTemplate.Services[0] = *sdefinition
			serviceTemplate.Name = sdefinition.Name
		} else {
			// Read the argument as a file
			templateStr, err := ioutil.ReadFile(cmd.Arg(0))
			if err != nil {
				glog.Fatalf("Could not read ServiceTemplate from file: %s", err)
			}
			err = json.Unmarshal(templateStr, &serviceTemplate)
			if err != nil {
				glog.Fatalf("Could not unmarshal ServiceTemplate from file: %s", err)
			}
		}

	}

	c := getClient()
	var templateId string
	err := c.AddServiceTemplate(serviceTemplate, &templateId)
	if err != nil {
		glog.Fatalf("Could not add service template:  %s", err)
	}
	fmt.Println(templateId)

	return nil
}

// Remove a service template associated with the control plane.
func (cli *ServicedCli) CmdRemoveTemplate(args ...string) error {

	cmd := Subcmd("remove-template", "[OPTIONS]", "Remove a service template")
	if err := cmd.Parse(args); err != nil {
		return err
	}

	if len(cmd.Args()) != 1 {
		cmd.Usage()
		return nil
	}

	var unused int
	if err := getClient().RemoveServiceTemplate(cmd.Arg(0), &unused); err != nil {
		glog.Fatalf("Could not remove service template: %v", err)
	}
	fmt.Println("OK")

	return nil
}

// Deploy a service template into the given pool
func (cli *ServicedCli) CmdDeployTemplate(args ...string) error {
	cmd := Subcmd("deploy-template", "[OPTIONS] TEMPLATE_ID POOL_ID DEPLOYMENT_ID", "Deploy TEMPLATE_ID into POOL_ID with a new id DEPLOYMENT_ID optional NO_AUTO_ASSIGN_IPS")

	var autoAssignIps bool
	cmd.BoolVar(&autoAssignIps, "noAutoAssignIps", true, "flag determining whether or not to set IPs automatically")

	if err := cmd.Parse(args); err != nil {
		return err
	}
	glog.V(1).Infof("Received %v arguments", len(cmd.Args()))
	if len(cmd.Args()) != 3 {
		cmd.Usage()
		return nil
	}

	deployreq := dao.ServiceTemplateDeploymentRequest{
		PoolId:       cmd.Arg(1),
		TemplateId:   cmd.Arg(0),
		DeploymentId: cmd.Arg(2),
	}

	var tenantId string
	controlPlane := getClient()
	if err := controlPlane.DeployTemplate(deployreq, &tenantId); err != nil {
		glog.Fatalf("Could not deploy service template: %v", err)
	}
	glog.V(1).Infof("OK")

	if autoAssignIps {
		if err := cli.CmdAutoAssignIps(tenantId); err != nil {
			glog.Fatalf("Could not automatically assign IPs: %v", err)
			return err
		}
		glog.Infof("Automatically assigned IP addresses to service: %v", tenantId)
	}

	return nil
}
<commit_msg>gofmt<commit_after>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package main

// This is here the command line arguments are parsed and executed.

import (
	"github.com/zenoss/glog"
	"github.com/zenoss/serviced/dao"

	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

// mapImageNames translates values of service.ImageId using the mapping.
func mapImageNames(service *dao.ServiceDefinition, mapping map[string]string) {
	if _, found := mapping[service.ImageId]; found {
		service.ImageId = mapping[service.ImageId]
	}
	for i, _ := range service.Services {
		mapImageNames(&service.Services[i], mapping)
	}
}

// CmdCompileTemplate traverses the given directory of service definitions
// and prints the generated json struct to stdout.
func (cli *ServicedCli) CmdCompileTemplate(args ...string) error {
	cmd := Subcmd("compile-template", "[OPTIONS] DIR", "Read the given directory of service definitions compile to a single json struct")

	imageMappings := make(ListOpts, 0)
	cmd.Var(&imageMappings, "map", "Map a given image name to another (e.g. -map zenoss/zenoss5x:quay.io/zenoss-core:alpha2 )")

	if err := cmd.Parse(args); err != nil {
		return err
	}
	if len(cmd.Args()) != 1 {
		cmd.Usage()
		return nil
	}

	mapping := make(map[string]string)
	for _, spec := range imageMappings {
		parts := strings.Split(spec, ":")
		if len(parts) != 2 {
			glog.Fatalf("invalid mapping spec: %s", spec)
		}
		mapping[parts[0]] = parts[1]
	}

	template, err := dao.ServiceDefinitionFromPath(cmd.Arg(0))
	if err != nil {
		return err
	}
	mapImageNames(template, mapping)
	output, err := json.MarshalIndent(template, "", "    ")
	if err != nil {
		return err
	}
	fmt.Println(string(output))
	return nil
}

// List the service templates associated with the control plane.
func (cli *ServicedCli) CmdTemplates(args ...string) error {
	cmd := Subcmd("templates", "[OPTIONS]", "List templates")

	var verbose bool
	cmd.BoolVar(&verbose, "verbose", false, "Show JSON representation for each template")

	var raw bool
	cmd.BoolVar(&raw, "raw", false, "Don't show header line")

	if err := cmd.Parse(args); err != nil {
		return err
	}

	c := getClient()

	var serviceTemplates map[string]*dao.ServiceTemplate
	var unused int
	err := c.GetServiceTemplates(unused, &serviceTemplates)
	if err != nil {
		glog.Fatalf("Could not get list of templates: %s", err)
	}

	if verbose == false {
		outfmt := "%-36s %-16s %-32.32s\n"

		if raw == false {
			fmt.Printf("%-36s %-16s %-32s\n", "TEMPLATE ID", "NAME", "DESCRIPTION")
		} else {
			outfmt = "%s|%s|%s\n"
		}

		for id, t := range serviceTemplates {
			fmt.Printf(outfmt, id, t.Name, t.Description)
		}
	} else {
		for id, template := range serviceTemplates {
			if t, err := json.MarshalIndent(template, " ", " "); err == nil {
				if verbose {
					fmt.Printf("%s: %s\n", id, t)
				}
			}
		}
	}

	return err
}

// Add a service template to the control plane.
func (cli *ServicedCli) CmdAddTemplate(args ...string) error {

	cmd := Subcmd("add-template", "[INPUT]", "Add a template. Use - for standard input. "+
		"[INPUT] is either a json file or template directory.")
	if err := cmd.Parse(args); err != nil {
		return err
	}
	var serviceTemplate dao.ServiceTemplate
	if len(cmd.Args()) != 1 {
		cmd.Usage()
		return nil
	}

	if cmd.Arg(0) == "-" {
		// Read from standard input
		dec := json.NewDecoder(os.Stdin)
		err := dec.Decode(&serviceTemplate)
		if err != nil {
			glog.Fatalf("Could not read ServiceTemplate from stdin: %s", err)
		}
	} else {
		// is the input a file or directory
		nodeinfo, err := os.Stat(cmd.Arg(0))
		if err != nil {
			glog.Fatalf("Could not ServiceTemplate from %s: %s", cmd.Arg(0), err)
		}

		if nodeinfo.IsDir() {
			sdefinition, err := dao.ServiceDefinitionFromPath(cmd.Arg(0))
			if err != nil {
				glog.Fatalf("Could not read template from directory %s: %s", nodeinfo.Name(), err)
			}
			serviceTemplate.Services = make([]dao.ServiceDefinition, 1)
			serviceTemplate.Services[0] = *sdefinition
			serviceTemplate.Name = sdefinition.Name
		} else {
			// Read the argument as a file
			templateStr, err := ioutil.ReadFile(cmd.Arg(0))
			if err != nil {
				glog.Fatalf("Could not read ServiceTemplate from file: %s", err)
			}
			err = json.Unmarshal(templateStr, &serviceTemplate)
			if err != nil {
				glog.Fatalf("Could not unmarshal ServiceTemplate from file: %s", err)
			}
		}

	}

	c := getClient()
	var templateId string
	err := c.AddServiceTemplate(serviceTemplate, &templateId)
	if err != nil {
		glog.Fatalf("Could not add service template:  %s", err)
	}
	fmt.Println(templateId)

	return nil
}

// Remove a service template associated with the control plane.
func (cli *ServicedCli) CmdRemoveTemplate(args ...string) error {

	cmd := Subcmd("remove-template", "[OPTIONS]", "Remove a service template")
	if err := cmd.Parse(args); err != nil {
		return err
	}

	if len(cmd.Args()) != 1 {
		cmd.Usage()
		return nil
	}

	var unused int
	if err := getClient().RemoveServiceTemplate(cmd.Arg(0), &unused); err != nil {
		glog.Fatalf("Could not remove service template: %v", err)
	}
	fmt.Println("OK")

	return nil
}

// Deploy a service template into the given pool
func (cli *ServicedCli) CmdDeployTemplate(args ...string) error {
	cmd := Subcmd("deploy-template", "[OPTIONS] TEMPLATE_ID POOL_ID DEPLOYMENT_ID", "Deploy TEMPLATE_ID into POOL_ID with a new id DEPLOYMENT_ID optional NO_AUTO_ASSIGN_IPS")

	var autoAssignIps bool
	cmd.BoolVar(&autoAssignIps, "noAutoAssignIps", true, "flag determining whether or not to set IPs automatically")

	if err := cmd.Parse(args); err != nil {
		return err
	}
	glog.V(1).Infof("Received %v arguments", len(cmd.Args()))
	if len(cmd.Args()) != 3 {
		cmd.Usage()
		return nil
	}

	deployreq := dao.ServiceTemplateDeploymentRequest{
		PoolId:       cmd.Arg(1),
		TemplateId:   cmd.Arg(0),
		DeploymentId: cmd.Arg(2),
	}

	var tenantId string
	controlPlane := getClient()
	if err := controlPlane.DeployTemplate(deployreq, &tenantId); err != nil {
		glog.Fatalf("Could not deploy service template: %v", err)
	}
	glog.V(1).Infof("OK")

	if autoAssignIps {
		if err := cli.CmdAutoAssignIps(tenantId); err != nil {
			glog.Fatalf("Could not automatically assign IPs: %v", err)
			return err
		}
		glog.Infof("Automatically assigned IP addresses to service: %v", tenantId)
	}

	return nil
}
<|endoftext|>


<commit_before>package session

import (
	"io/ioutil"
	"os"
	"reflect"
	"sort"
	"testing"
	"time"

	"github.com/Shopify/gozk"
)

func AssertEqual(t *testing.T, expected, actual interface{}) {
	switch expected.(type) {
	case []string:
		sort.Strings(expected.([]string))
		sort.Strings(actual.([]string))
	}

	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("Expected %s, actual %s", expected, actual)
	}
}

func AssertNodeValueEqual(t *testing.T, session *ZKSession, path, expected string) {
	data, _, err := session.Get(path)
	if err != nil {
		t.Error("Get error: ", err)
	}
	AssertEqual(t, expected, data)
}

func AssertNodeDoesNotExist(t *testing.T, session *ZKSession, path string) {
	stat, err := session.Exists(path)
	if err != nil {
		t.Error("Exists error: ", err)
	}

	if stat != nil {
		t.Error("Expected node to not exist: ", path)
	}
}

func AssertNodeExists(t *testing.T, session *ZKSession, path string) {
	stat, err := session.Exists(path)
	if err != nil {
		t.Error("Exists error: ", err)
	}

	if stat == nil {
		t.Error("Expected node to exist: ", path)
	}
}

func withTestStore(t *testing.T, f func(*ZKSession)) {
	runDir, err := ioutil.TempDir("", "zk")
	if err != nil {
		t.Error("Failed to create zookeeper run dir: ", err)
	}
	defer os.RemoveAll(runDir)

	server, err := zookeeper.CreateServer(22447, runDir, "/usr/lib/zookeeper")
	if err != nil {
		t.Error("Failed to create zookeeper server: ", err)
	}
	defer server.Stop()

	if err := server.Start(); err != nil {
		t.Error("Failed to start zookeeper server: ", err)
	}

	store, err := NewZKSession("localhost:22447", 200*time.Millisecond, nil)
	if err != nil {
		t.Error("Failed to connect to Zookeeper: ", err)
	}
	defer store.Close()

	f(store)
}

func initializeZK(t *testing.T, s *ZKSession, nodes ...string) {
	defaultAcls := []zookeeper.ACL{
		zookeeper.ACL{
			Perms:  zookeeper.PERM_ALL,
			Scheme: "world",
			Id:     "anyone",
		},
	}

	for _, node := range nodes {
		if _, err := s.Create(node, "", 0, defaultAcls); err != nil {
			t.Error("Unable to create initial value in zk: ", err)
		}
	}
}

func TestChildrenRecursiveWithNonExistingNodeShouldHaveEmptyResult(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		children, err := session.ChildrenRecursive("/test", -1)
		if err != nil {
			t.Error("ChildrenRecursive error: ", err)
		}

		AssertEqual(t, []string{}, children)
	})
}

func TestChildrenRecursiveWithNodesShouldHaveResult(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		nodes := []string{"/test", "/test/foo", "/test/bar", "/test/bar/eggs"}
		initializeZK(t, session, nodes...)

		children, err := session.ChildrenRecursive("/test", -1)
		if err != nil {
			t.Error("ChildrenRecursive error: ", err)
		}

		AssertEqual(t, nodes[1:], children)
	})
}

func TestChildrenRecursiveWithLimitedDepthShouldReturnSubset(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		nodes := []string{"/test", "/test/foo", "/test/bar", "/test/bar/eggs", "/test/bar/eggs/spam"}
		initializeZK(t, session, nodes...)

		children, err := session.ChildrenRecursive("/test", 2)
		if err != nil {
			t.Error("ChildrenRecursive error: ", err)
		}

		AssertEqual(t, []string{"/test/foo", "/test/bar", "/test/bar/eggs"}, children)
	})
}

func TestCreateRecursiveAndSetWithNoParentsShouldCreateNodes(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		if err := session.CreateRecursiveAndSet("/test/foo/bar", "foobar"); err != nil {
			t.Error("CreateRecursiveAndSet error: ", err)
		}

		AssertNodeValueEqual(t, session, "/test/foo/bar", "foobar")
	})
}

func TestCreateRecursiveAndSetWithParentsShouldNotChangeData(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		initializeZK(t, session, "/test", "/test/foo")

		if err := session.CreateRecursiveAndSet("/test/foo/bar", "foobar"); err != nil {
			t.Error("CreateRecursiveAndSet error: ", err)
		}

		if _, err := session.Set("/test/foo", "spam", 0); err != nil {
			t.Error("Set error: ", err)
		}

		AssertNodeValueEqual(t, session, "/test/foo", "spam")
		AssertNodeValueEqual(t, session, "/test/foo/bar", "foobar")
	})
}

func TestDeleteRecursiveShouldDelete(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		initializeZK(t, session, "/test", "/test/foo", "/test/foo/bar", "/test/foo/bar/spam")

		if err := session.DeleteRecursive("/test/foo"); err != nil {
			t.Error("DeleteRecursive error: ", err)
		}

		AssertNodeDoesNotExist(t, session, "/test/foo/bar/spam")
		AssertNodeDoesNotExist(t, session, "/test/foo/bar")
		AssertNodeDoesNotExist(t, session, "/test/foo")
		AssertNodeExists(t, session, "/test")
	})
}
<commit_msg>Use system classpath to launch ZK<commit_after>package session

import (
	"io/ioutil"
	"os"
	"reflect"
	"sort"
	"testing"
	"time"

	"github.com/Shopify/gozk"
)

func AssertEqual(t *testing.T, expected, actual interface{}) {
	switch expected.(type) {
	case []string:
		sort.Strings(expected.([]string))
		sort.Strings(actual.([]string))
	}

	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("Expected %s, actual %s", expected, actual)
	}
}

func AssertNodeValueEqual(t *testing.T, session *ZKSession, path, expected string) {
	data, _, err := session.Get(path)
	if err != nil {
		t.Error("Get error: ", err)
	}
	AssertEqual(t, expected, data)
}

func AssertNodeDoesNotExist(t *testing.T, session *ZKSession, path string) {
	stat, err := session.Exists(path)
	if err != nil {
		t.Error("Exists error: ", err)
	}

	if stat != nil {
		t.Error("Expected node to not exist: ", path)
	}
}

func AssertNodeExists(t *testing.T, session *ZKSession, path string) {
	stat, err := session.Exists(path)
	if err != nil {
		t.Error("Exists error: ", err)
	}

	if stat == nil {
		t.Error("Expected node to exist: ", path)
	}
}

func withTestStore(t *testing.T, f func(*ZKSession)) {
	runDir, err := ioutil.TempDir("", "zk")
	if err != nil {
		t.Error("Failed to create zookeeper run dir: ", err)
	}
	defer os.RemoveAll(runDir)

	server, err := zookeeper.CreateServer(22447, runDir, "")
	if err != nil {
		t.Error("Failed to create zookeeper server: ", err)
	}
	defer server.Stop()

	if err := server.Start(); err != nil {
		t.Error("Failed to start zookeeper server: ", err)
	}

	store, err := NewZKSession("localhost:22447", 200*time.Millisecond, nil)
	if err != nil {
		t.Error("Failed to connect to Zookeeper: ", err)
	}
	defer store.Close()

	f(store)
}

func initializeZK(t *testing.T, s *ZKSession, nodes ...string) {
	defaultAcls := []zookeeper.ACL{
		zookeeper.ACL{
			Perms:  zookeeper.PERM_ALL,
			Scheme: "world",
			Id:     "anyone",
		},
	}

	for _, node := range nodes {
		if _, err := s.Create(node, "", 0, defaultAcls); err != nil {
			t.Error("Unable to create initial value in zk: ", err)
		}
	}
}

func TestChildrenRecursiveWithNonExistingNodeShouldHaveEmptyResult(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		children, err := session.ChildrenRecursive("/test", -1)
		if err != nil {
			t.Error("ChildrenRecursive error: ", err)
		}

		AssertEqual(t, []string{}, children)
	})
}

func TestChildrenRecursiveWithNodesShouldHaveResult(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		nodes := []string{"/test", "/test/foo", "/test/bar", "/test/bar/eggs"}
		initializeZK(t, session, nodes...)

		children, err := session.ChildrenRecursive("/test", -1)
		if err != nil {
			t.Error("ChildrenRecursive error: ", err)
		}

		AssertEqual(t, nodes[1:], children)
	})
}

func TestChildrenRecursiveWithLimitedDepthShouldReturnSubset(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		nodes := []string{"/test", "/test/foo", "/test/bar", "/test/bar/eggs", "/test/bar/eggs/spam"}
		initializeZK(t, session, nodes...)

		children, err := session.ChildrenRecursive("/test", 2)
		if err != nil {
			t.Error("ChildrenRecursive error: ", err)
		}

		AssertEqual(t, []string{"/test/foo", "/test/bar", "/test/bar/eggs"}, children)
	})
}

func TestCreateRecursiveAndSetWithNoParentsShouldCreateNodes(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		if err := session.CreateRecursiveAndSet("/test/foo/bar", "foobar"); err != nil {
			t.Error("CreateRecursiveAndSet error: ", err)
		}

		AssertNodeValueEqual(t, session, "/test/foo/bar", "foobar")
	})
}

func TestCreateRecursiveAndSetWithParentsShouldNotChangeData(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		initializeZK(t, session, "/test", "/test/foo")

		if err := session.CreateRecursiveAndSet("/test/foo/bar", "foobar"); err != nil {
			t.Error("CreateRecursiveAndSet error: ", err)
		}

		if _, err := session.Set("/test/foo", "spam", 0); err != nil {
			t.Error("Set error: ", err)
		}

		AssertNodeValueEqual(t, session, "/test/foo", "spam")
		AssertNodeValueEqual(t, session, "/test/foo/bar", "foobar")
	})
}

func TestDeleteRecursiveShouldDelete(t *testing.T) {
	withTestStore(t, func(session *ZKSession) {
		initializeZK(t, session, "/test", "/test/foo", "/test/foo/bar", "/test/foo/bar/spam")

		if err := session.DeleteRecursive("/test/foo"); err != nil {
			t.Error("DeleteRecursive error: ", err)
		}

		AssertNodeDoesNotExist(t, session, "/test/foo/bar/spam")
		AssertNodeDoesNotExist(t, session, "/test/foo/bar")
		AssertNodeDoesNotExist(t, session, "/test/foo")
		AssertNodeExists(t, session, "/test")
	})
}
<|endoftext|>


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

package main

import (
    "bytes"
    "database/sql"
    "encoding/binary"
    sqlite "github.com/mattn/go-sqlite3"
    "log"
    "os"
)

type Symbol struct {
    Name    string
    Unisr   string
    File    string
    Line    int
    Col     int
}

type SymbolsDB struct {
    db                  *sql.DB

    insertFile          *sql.Stmt
    selectFileInfo      *sql.Stmt
    insertSymb          *sql.Stmt
    selectSymbDecl      *sql.Stmt
    delFileRef          *sql.Stmt
    insertFuncDef       *sql.Stmt
    insertFuncDecDef    *sql.Stmt
    insertSymbUse       *sql.Stmt
    insertFuncCall      *sql.Stmt
}

func (db *SymbolsDB) empty() bool {
    rows, err := db.db.Query(`SELECT name FROM sqlite_master
                            WHERE type='table' AND name='files';`)
    if err != nil {
        log.Fatal("check empty ", err)
    }
    defer rows.Close()

    return !rows.Next()
}

func (db *SymbolsDB) initDB() {
    initStmt := `
        CREATE TABLE files (
            id          INTEGER,
            file_info   BLOB,
            path        TEXT UNIQUE NOT NULL,
            PRIMARY     KEY(id)
        );
        CREATE TABLE symbol_decls (
            name    TEXT NOT NULL,
            unisr   TEXT NOT NULL,
            file    INTEGER,
            line    INTEGER,
            col     INTEGER,

            param   INTEGER DEFAULT 0,

            def     INTEGER DEFAULT 0,

            PRIMARY KEY(file, line, col)
            FOREIGN KEY(file) REFERENCES files(id) ON DELETE CASCADE
        );
        CREATE TABLE func_decs_defs (
            dec_file    INTEGER,
            dec_line    INTEGER,
            dec_col     INTEGER,

            def_file    INTEGER,
            def_line    INTEGER,
            def_col     INTEGER,

            PRIMARY KEY(dec_file, dec_line, dec_col,
                        def_file, dec_line, dec_col)

            FOREIGN KEY(dec_file, dec_line, dec_col)
                REFERENCES symbol_decls(file, line, col) ON DELETE CASCADE
            FOREIGN KEY(def_file, def_line, def_col)
                REFERENCES symbol_decls(file, line, col) ON DELETE CASCADE
        );
        CREATE TABLE symbol_uses (
            call        INTEGER DEFAULT 0,

            file        INTEGER,
            line        INTEGER,
            col         INTEGER,

            dec_file    INTEGER,
            dec_line    INTEGER,
            dec_col     INTEGER,

            PRIMARY KEY(file, line, col)

            FOREIGN KEY(dec_file, dec_line, dec_col)
                REFERENCES symbol_decls(file, line, col) ON DELETE CASCADE
        );
    `
    _, err := db.db.Exec(initStmt)
    if err != nil {
        log.Fatal("init db ", err)
    }
}

func OpenSymbolsDB(path string) *SymbolsDB {
    db, err := sql.Open("sqlite3", path)
    if err != nil {
        log.Fatal("open db ", err)
    }

    r := &SymbolsDB{db: db}

    db.Exec(`PRAGMA foreign_keys = ON;`)

    if r.empty() {
        r.initDB()
    }

    r.insertFile, err = db.Prepare(`
        INSERT INTO files(path, file_info) VALUES (?, ?);
    `)
    if err != nil {
        log.Fatal("prepare insert files ", err)
    }

    r.selectFileInfo, err = db.Prepare(`
        SELECT file_info FROM files WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare select hash ", err)
    }

    r.insertSymb, err = db.Prepare(`
        INSERT OR IGNORE INTO symbol_decls(name, unisr, file, line, col, param)
            SELECT ?, ?, id, ?, ?, ? FROM files
            WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare insert symbol ", err)
    }

    r.selectSymbDecl, err = db.Prepare(`
        SELECT st.name, st.unisr, path, st.line, st.col
            FROM symbol_decls st, symbol_uses su, files
            WHERE su.dec_file = st.file AND su.dec_line = st.line AND
                su.dec_col = st.col AND st.file = id AND
                path = ? AND su.line = ? AND su.col = ?;
    `)
    if err != nil {
        log.Fatal("prepare select symbol ", err)
    }

    r.delFileRef, err = db.Prepare(`
        DELETE FROM files WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare delete file ", err)
    }

    r.insertFuncDef, err = db.Prepare(`
        INSERT OR IGNORE INTO symbol_decls(name, unisr, file, line, col, def)
            SELECT ?, ?, id, ?, ?, 1 FROM files
            WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare insert func def ", err)
    }

    r.insertFuncDecDef, err = db.Prepare(`
        INSERT INTO func_decs_defs
            SELECT f1.id, ?, ?, f2.id, ?, ? FROM files f1, files f2
            WHERE f1.path = ? AND f2.path = ?;
    `)
    if err != nil {
        log.Fatal("prepare insert func dec/def ", err)
    }

    r.insertSymbUse, err = db.Prepare(`
        INSERT OR IGNORE INTO symbol_uses
            SELECT 0, f1.id, ?, ?, f2.id, ?, ? FROM files f1, files f2
                WHERE f1.path = ? AND f2.path = ?;
    `)
    if err != nil {
        log.Fatal("preapre insert symbol use ", err)
    }

    r.insertFuncCall, err = db.Prepare(`
        INSERT OR REPLACE INTO symbol_uses
            SELECT 1, f1.id, ?, ?, f2.id, ?, ? FROM files f1, files f2
                WHERE f1.path = ? AND f2.path = ?;
    `)
    if err != nil {
        log.Fatal("preapre insert func call ", err)
    }

    return r
}

func (db *SymbolsDB) InsertFuncCall(call, dec *Symbol) {
    _, err := db.insertFuncCall.Exec(call.Line, call.Col,
                                     dec.Line, dec.Col,
                                     call.File, dec.File)
    if err != nil {
        log.Fatal("insert func call ", err)
    }
}

func (db *SymbolsDB) InsertSymbolUse(use, dec *Symbol) {
    _, err := db.insertSymbUse.Exec(use.Line, use.Col,
                                    dec.Line, dec.Col,
                                    use.File, dec.File)
    if err != nil {
        log.Fatal("insert symbol user ", err)
    }
}

func (db *SymbolsDB) InsertSymbol(sym *Symbol) {
    _, err := db.insertSymb.Exec(sym.Name, sym.Unisr,
                                 sym.Line, sym.Col, false, sym.File)
    if err != nil {
        log.Fatal("insert symbol ", err)
    }
}

func (db *SymbolsDB) InsertParamDecl(sym *Symbol) {
    _, err := db.insertSymb.Exec(sym.Name, sym.Unisr,
                                 sym.Line, sym.Col, true, sym.File)
    if err != nil {
        log.Fatal("insert symbol param ", err)
    }
}

func (db *SymbolsDB) GetSymbolDecl(use *Symbol) *Symbol {
    r, err := db.selectSymbDecl.Query(use.File, use.Line, use.Col)
    if err != nil {
        log.Fatal("select symbol decl ", err)
    }
    defer r.Close()

    if r.Next() {
        s := new(Symbol)

        err = r.Scan(&s.Name, &s.Unisr, &s.File, &s.Line, &s.Col)
        if err != nil {
            log.Fatal("scan symbol ", err)
        }

        return s
    } else {
        return nil
    }
}

func getFileInfoBytes(fi os.FileInfo) []byte {
    timeBytes, err := fi.ModTime().MarshalBinary()
    if err != nil {
        log.Fatal("time to bytes ", err)
    }

    var dir byte
    if fi.IsDir() {
        dir = 1
    } else {
        dir = 0
    }

    data := []interface{}{
        fi.Size(),
        fi.Mode(),
        timeBytes,
        dir,
    }
    buf := new(bytes.Buffer)
    for _, v := range data {
        err := binary.Write(buf, binary.BigEndian, v)
        if err != nil {
            log.Panic("getting bytes from FileInfo ", err)
        }
    }
    return buf.Bytes()
}

func (db *SymbolsDB) getFileInfoBytesDB(file string) (bool, []byte) {
    r, err := db.selectFileInfo.Query(file)
    if err != nil {
        log.Fatal("select file info ", err)
    }
    defer r.Close()

    if r.Next() {
        var inDbFileInfo []byte

        err := r.Scan(&inDbFileInfo)
        if err != nil {
            log.Fatal("scanning file info ", err)
        }

        return true, inDbFileInfo
    } else {
        return false, nil
    }

}

/*
 * This function checks if the file exist and it is up to date. If it is not
 * not up to date, it will remove the current references of the file in the DB.
 * In either case, it will insert a new file entry in the DB and the Parser
 * should be called to populate the DB with the new symbols.
 */
func (db *SymbolsDB) NeedToProcessFile(file string) bool {
    fi, err := os.Stat(file)
    if err != nil {
        log.Println(err, ": unable to read file ", file)
        db.RemoveFileReferences(file)
        return false
    }

    fiBytes := getFileInfoBytes(fi)
    exist, inDbFiBytes := db.getFileInfoBytesDB(file)

    if exist {
        if bytes.Compare(fiBytes, inDbFiBytes) == 0 {
            // the file info in the DB and the file are the same; nothing to process.
            return false
        } else {
            // not up to date, remove all references
            db.RemoveFileReferences(file)
        }
    }

    _, err = db.insertFile.Exec(file, fiBytes)
    if err != nil {
        sqliteErr := err.(sqlite.Error)
        if sqliteErr.ExtendedCode == sqlite.ErrConstraintUnique {
            /* two threads tried to add the same file, fail the second one */
            return false
        } else {
            log.Fatal("insert file ", err)
        }
    }

    return true
}

func (db *SymbolsDB) RemoveFileReferences(file string) {
    _, err := db.delFileRef.Exec(file)
    if err != nil {
        log.Fatal("delete file ", err)
    }
}

func (db *SymbolsDB) GetSetFilesInDB() map[string]bool {
    rows, err := db.db.Query(`SELECT path FROM files;`)
    if err != nil {
        log.Fatal("select files ", err)
    }
    defer rows.Close()

    fileSet := map[string]bool{}
    for rows.Next() {
        var path string

        err := rows.Scan(&path)
        if err != nil {
            log.Fatal("scan path ", err)
        }

        fileSet[path] = true
    }

    return fileSet
}

func (db *SymbolsDB) InsertFuncDef(def *Symbol) {
    /* insert function definition. Ignore if already exists. */
    _, err := db.insertFuncDef.Exec(def.Name, def.Unisr,
                                    def.Line, def.Col, def.File)
    if err != nil {
        log.Fatal("insert func def ", err)
    }
}

func (db *SymbolsDB) InsertFuncSymb(dec, def *Symbol) {
    db.db.Query(`BEGIN TRANSACTION;`)

    db.InsertFuncDef(def)
    db.InsertSymbol(dec)

    /* point this declaration to its definition */
    _, err := db.insertFuncDecDef.Exec(
        dec.Line, dec.Col,
        def.Line, def.Col,
        dec.File, def.File)
    if err != nil {
        log.Fatal("insert func dec to def ", err)
    }

    db.db.Query(`COMMIT TRANSACTION;`)
}

func (db *SymbolsDB) Close() {
    db.insertFile.Close()
    db.selectFileInfo.Close()
    db.insertSymb.Close()
    db.selectSymbDecl.Close()
    db.delFileRef.Close()
    db.insertFuncDef.Close()
    db.insertFuncDecDef.Close()
    db.insertSymbUse.Close()
    db.insertFuncCall.Close()
    db.db.Close()
}
<commit_msg>Fixing SQL statement to find symbol declaration<commit_after>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
    "bytes"
    "database/sql"
    "encoding/binary"
    sqlite "github.com/mattn/go-sqlite3"
    "log"
    "os"
)

type Symbol struct {
    Name    string
    Unisr   string
    File    string
    Line    int
    Col     int
}

type SymbolsDB struct {
    db                  *sql.DB

    insertFile          *sql.Stmt
    selectFileInfo      *sql.Stmt
    insertSymb          *sql.Stmt
    selectSymbDecl      *sql.Stmt
    delFileRef          *sql.Stmt
    insertFuncDef       *sql.Stmt
    insertFuncDecDef    *sql.Stmt
    insertSymbUse       *sql.Stmt
    insertFuncCall      *sql.Stmt
}

func (db *SymbolsDB) empty() bool {
    rows, err := db.db.Query(`SELECT name FROM sqlite_master
                            WHERE type='table' AND name='files';`)
    if err != nil {
        log.Fatal("check empty ", err)
    }
    defer rows.Close()

    return !rows.Next()
}

func (db *SymbolsDB) initDB() {
    initStmt := `
        CREATE TABLE files (
            id          INTEGER,
            file_info   BLOB,
            path        TEXT UNIQUE NOT NULL,
            PRIMARY     KEY(id)
        );
        CREATE TABLE symbol_decls (
            name    TEXT NOT NULL,
            unisr   TEXT NOT NULL,
            file    INTEGER,
            line    INTEGER,
            col     INTEGER,

            param   INTEGER DEFAULT 0,

            def     INTEGER DEFAULT 0,

            PRIMARY KEY(file, line, col)
            FOREIGN KEY(file) REFERENCES files(id) ON DELETE CASCADE
        );
        CREATE TABLE func_decs_defs (
            dec_file    INTEGER,
            dec_line    INTEGER,
            dec_col     INTEGER,

            def_file    INTEGER,
            def_line    INTEGER,
            def_col     INTEGER,

            PRIMARY KEY(dec_file, dec_line, dec_col,
                        def_file, dec_line, dec_col)

            FOREIGN KEY(dec_file, dec_line, dec_col)
                REFERENCES symbol_decls(file, line, col) ON DELETE CASCADE
            FOREIGN KEY(def_file, def_line, def_col)
                REFERENCES symbol_decls(file, line, col) ON DELETE CASCADE
        );
        CREATE TABLE symbol_uses (
            call        INTEGER DEFAULT 0,

            file        INTEGER,
            line        INTEGER,
            col         INTEGER,

            dec_file    INTEGER,
            dec_line    INTEGER,
            dec_col     INTEGER,

            PRIMARY KEY(file, line, col)

            FOREIGN KEY(dec_file, dec_line, dec_col)
                REFERENCES symbol_decls(file, line, col) ON DELETE CASCADE
        );
    `
    _, err := db.db.Exec(initStmt)
    if err != nil {
        log.Fatal("init db ", err)
    }
}

func OpenSymbolsDB(path string) *SymbolsDB {
    db, err := sql.Open("sqlite3", path)
    if err != nil {
        log.Fatal("open db ", err)
    }

    r := &SymbolsDB{db: db}

    db.Exec(`PRAGMA foreign_keys = ON;`)

    if r.empty() {
        r.initDB()
    }

    r.insertFile, err = db.Prepare(`
        INSERT INTO files(path, file_info) VALUES (?, ?);
    `)
    if err != nil {
        log.Fatal("prepare insert files ", err)
    }

    r.selectFileInfo, err = db.Prepare(`
        SELECT file_info FROM files WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare select hash ", err)
    }

    r.insertSymb, err = db.Prepare(`
        INSERT OR IGNORE INTO symbol_decls(name, unisr, file, line, col, param)
            SELECT ?, ?, id, ?, ?, ? FROM files
            WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare insert symbol ", err)
    }

    r.selectSymbDecl, err = db.Prepare(`
        SELECT st.name, st.unisr, f2.path, st.line, st.col
            FROM symbol_decls st, symbol_uses su, files f1, files f2
            WHERE
                -- symbol use and symbol declaration join
                su.dec_file = st.file AND
                su.dec_line = st.line AND
                su.dec_col = st.col AND
                -- symbol declaration to file join
                f2.id = st.file AND
                -- symbol use and file join
                su.file = f1.id AND
                f1.path = ? AND su.line = ? AND su.col = ?;
    `)
    if err != nil {
        log.Fatal("prepare select symbol ", err)
    }

    r.delFileRef, err = db.Prepare(`
        DELETE FROM files WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare delete file ", err)
    }

    r.insertFuncDef, err = db.Prepare(`
        INSERT OR IGNORE INTO symbol_decls(name, unisr, file, line, col, def)
            SELECT ?, ?, id, ?, ?, 1 FROM files
            WHERE path = ?;
    `)
    if err != nil {
        log.Fatal("prepare insert func def ", err)
    }

    r.insertFuncDecDef, err = db.Prepare(`
        INSERT INTO func_decs_defs
            SELECT f1.id, ?, ?, f2.id, ?, ? FROM files f1, files f2
            WHERE f1.path = ? AND f2.path = ?;
    `)
    if err != nil {
        log.Fatal("prepare insert func dec/def ", err)
    }

    r.insertSymbUse, err = db.Prepare(`
        INSERT OR IGNORE INTO symbol_uses
            SELECT 0, f1.id, ?, ?, f2.id, ?, ? FROM files f1, files f2
                WHERE f1.path = ? AND f2.path = ?;
    `)
    if err != nil {
        log.Fatal("preapre insert symbol use ", err)
    }

    r.insertFuncCall, err = db.Prepare(`
        INSERT OR REPLACE INTO symbol_uses
            SELECT 1, f1.id, ?, ?, f2.id, ?, ? FROM files f1, files f2
                WHERE f1.path = ? AND f2.path = ?;
    `)
    if err != nil {
        log.Fatal("preapre insert func call ", err)
    }

    return r
}

func (db *SymbolsDB) InsertFuncCall(call, dec *Symbol) {
    _, err := db.insertFuncCall.Exec(call.Line, call.Col,
                                     dec.Line, dec.Col,
                                     call.File, dec.File)
    if err != nil {
        log.Fatal("insert func call ", err)
    }
}

func (db *SymbolsDB) InsertSymbolUse(use, dec *Symbol) {
    _, err := db.insertSymbUse.Exec(use.Line, use.Col,
                                    dec.Line, dec.Col,
                                    use.File, dec.File)
    if err != nil {
        log.Fatal("insert symbol user ", err)
    }
}

func (db *SymbolsDB) InsertSymbol(sym *Symbol) {
    _, err := db.insertSymb.Exec(sym.Name, sym.Unisr,
                                 sym.Line, sym.Col, false, sym.File)
    if err != nil {
        log.Fatal("insert symbol ", err)
    }
}

func (db *SymbolsDB) InsertParamDecl(sym *Symbol) {
    _, err := db.insertSymb.Exec(sym.Name, sym.Unisr,
                                 sym.Line, sym.Col, true, sym.File)
    if err != nil {
        log.Fatal("insert symbol param ", err)
    }
}

func (db *SymbolsDB) GetSymbolDecl(use *Symbol) *Symbol {
    r, err := db.selectSymbDecl.Query(use.File, use.Line, use.Col)
    if err != nil {
        log.Fatal("select symbol decl ", err)
    }
    defer r.Close()

    if r.Next() {
        s := new(Symbol)

        err = r.Scan(&s.Name, &s.Unisr, &s.File, &s.Line, &s.Col)
        if err != nil {
            log.Fatal("scan symbol ", err)
        }

        return s
    } else {
        return nil
    }
}

func getFileInfoBytes(fi os.FileInfo) []byte {
    timeBytes, err := fi.ModTime().MarshalBinary()
    if err != nil {
        log.Fatal("time to bytes ", err)
    }

    var dir byte
    if fi.IsDir() {
        dir = 1
    } else {
        dir = 0
    }

    data := []interface{}{
        fi.Size(),
        fi.Mode(),
        timeBytes,
        dir,
    }
    buf := new(bytes.Buffer)
    for _, v := range data {
        err := binary.Write(buf, binary.BigEndian, v)
        if err != nil {
            log.Panic("getting bytes from FileInfo ", err)
        }
    }
    return buf.Bytes()
}

func (db *SymbolsDB) getFileInfoBytesDB(file string) (bool, []byte) {
    r, err := db.selectFileInfo.Query(file)
    if err != nil {
        log.Fatal("select file info ", err)
    }
    defer r.Close()

    if r.Next() {
        var inDbFileInfo []byte

        err := r.Scan(&inDbFileInfo)
        if err != nil {
            log.Fatal("scanning file info ", err)
        }

        return true, inDbFileInfo
    } else {
        return false, nil
    }

}

/*
 * This function checks if the file exist and it is up to date. If it is not
 * not up to date, it will remove the current references of the file in the DB.
 * In either case, it will insert a new file entry in the DB and the Parser
 * should be called to populate the DB with the new symbols.
 */
func (db *SymbolsDB) NeedToProcessFile(file string) bool {
    fi, err := os.Stat(file)
    if err != nil {
        log.Println(err, ": unable to read file ", file)
        db.RemoveFileReferences(file)
        return false
    }

    fiBytes := getFileInfoBytes(fi)
    exist, inDbFiBytes := db.getFileInfoBytesDB(file)

    if exist {
        if bytes.Compare(fiBytes, inDbFiBytes) == 0 {
            // the file info in the DB and the file are the same; nothing to process.
            return false
        } else {
            // not up to date, remove all references
            db.RemoveFileReferences(file)
        }
    }

    _, err = db.insertFile.Exec(file, fiBytes)
    if err != nil {
        sqliteErr := err.(sqlite.Error)
        if sqliteErr.ExtendedCode == sqlite.ErrConstraintUnique {
            /* two threads tried to add the same file, fail the second one */
            return false
        } else {
            log.Fatal("insert file ", err)
        }
    }

    return true
}

func (db *SymbolsDB) RemoveFileReferences(file string) {
    _, err := db.delFileRef.Exec(file)
    if err != nil {
        log.Fatal("delete file ", err)
    }
}

func (db *SymbolsDB) GetSetFilesInDB() map[string]bool {
    rows, err := db.db.Query(`SELECT path FROM files;`)
    if err != nil {
        log.Fatal("select files ", err)
    }
    defer rows.Close()

    fileSet := map[string]bool{}
    for rows.Next() {
        var path string

        err := rows.Scan(&path)
        if err != nil {
            log.Fatal("scan path ", err)
        }

        fileSet[path] = true
    }

    return fileSet
}

func (db *SymbolsDB) InsertFuncDef(def *Symbol) {
    /* insert function definition. Ignore if already exists. */
    _, err := db.insertFuncDef.Exec(def.Name, def.Unisr,
                                    def.Line, def.Col, def.File)
    if err != nil {
        log.Fatal("insert func def ", err)
    }
}

func (db *SymbolsDB) InsertFuncSymb(dec, def *Symbol) {
    db.db.Query(`BEGIN TRANSACTION;`)

    db.InsertFuncDef(def)
    db.InsertSymbol(dec)

    /* point this declaration to its definition */
    _, err := db.insertFuncDecDef.Exec(
        dec.Line, dec.Col,
        def.Line, def.Col,
        dec.File, def.File)
    if err != nil {
        log.Fatal("insert func dec to def ", err)
    }

    db.db.Query(`COMMIT TRANSACTION;`)
}

func (db *SymbolsDB) Close() {
    db.insertFile.Close()
    db.selectFileInfo.Close()
    db.insertSymb.Close()
    db.selectSymbDecl.Close()
    db.delFileRef.Close()
    db.insertFuncDef.Close()
    db.insertFuncDecDef.Close()
    db.insertSymbUse.Close()
    db.insertFuncCall.Close()
    db.db.Close()
}
<|endoftext|>


<commit_before>package synq

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/SYNQfm/SYNQ-Golang/upload"
	"github.com/SYNQfm/helpers/common"
)

type AssetResponse struct {
	Asset *Asset `json:"data"`
}

type AssetList struct {
	Assets []Asset `json:"data"`
}

type Asset struct {
	AccountId        string                  `json:"account_id"`
	VideoId          string                  `json:"video_id"`
	Id               string                  `json:"id"`
	Location         string                  `json:"location"`
	State            string                  `json:"state"`
	Type             string                  `json:"type"`
	CreatedAt        string                  `json:"created_at"`
	UpdatedAt        string                  `json:"updated_at"`
	Metadata         json.RawMessage         `json:"metadata"`
	VmafScore        float64                 `json:"vmaf_score"`
	Api              ApiV2                   `json:"-"`
	Video            VideoV2                 `json:"-"`
	UploadParameters upload.UploadParameters `json:"-"`
}

func (a *Asset) getApi() *ApiV2 {
	if a.Api.BaseApi != nil {
		return &a.Api
	}
	if a.Video.Api != nil && a.Video.Api.BaseApi != nil {
		return a.Video.Api
	}
	log.Panicln("asset has no valid apis to use")
	return nil
}

func (a *Asset) Update() error {
	url := a.getApi().getBaseUrl() + "/assets/" + a.Id
	data, err := json.Marshal(a)
	if err != nil {
		return err
	}
	body := bytes.NewBuffer(data)
	return a.handleAssetReq("PUT", url, body)
}

func (a *Asset) Delete() error {
	url := a.getApi().getBaseUrl() + "/assets/" + a.Id
	data, err := json.Marshal(a)
	if err != nil {
		return err
	}
	body := bytes.NewBuffer(data)
	return a.handleAssetReq("DELETE", url, body)
}

func (a *Asset) handleAssetReq(method, url string, body io.Reader) error {
	resp := AssetResponse{Asset: a}
	req, err := a.getApi().makeRequest(method, url, body)
	if err != nil {
		return err
	}
	req.Header.Add("content-type", "application/json")

	err = handleReq(a.Api, req, &resp)
	if err != nil {
		return err
	}

	return nil
}

func (a *Asset) UploadFile(fileName string) error {
	upUrl := a.Api.UploadUrl
	if upUrl == "" {
		return errors.New("invalid upload url, can not upload file")
	}
	if a.UploadParameters.Key == "" {
		// if the location exists, get the upload parameters again
		if a.Location != "" && a.Type != "" {
			ext := filepath.Ext(fileName)
			req := upload.UploadRequest{
				Type:        a.Type,
				ContentType: common.ExtToCtype(ext),
				AssetId:     a.Id,
			}
			up, err := a.Video.GetUploadParams(req)
			if err != nil {
				return err
			}
			a.UploadParameters = up
		} else {
			return errors.New("upload parameters is invalid")
		}
	}
	f, err := os.Open(fileName)
	defer f.Close()
	if os.IsNotExist(err) {
		return errors.New("file '" + fileName + "' does not exist")
	}

	params := a.UploadParameters
	if !strings.Contains(params.SignatureUrl, "http") {
		sigUrl := upUrl + params.SignatureUrl
		log.Printf("Updating sig url to include host '%s'\n", upUrl)
		params.SignatureUrl = sigUrl
	}
	aws, err := upload.CreatorFn(params)
	if err != nil {
		return err
	}
	_, err = aws.Upload(f)
	return err
}
<commit_msg>add url field (#89)<commit_after>package synq

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/SYNQfm/SYNQ-Golang/upload"
	"github.com/SYNQfm/helpers/common"
)

type AssetResponse struct {
	Asset *Asset `json:"data"`
}

type AssetList struct {
	Assets []Asset `json:"data"`
}

type Asset struct {
	AccountId        string                  `json:"account_id"`
	VideoId          string                  `json:"video_id"`
	Id               string                  `json:"id"`
	Location         string                  `json:"location"`
	Url              string                  `json:"url"`
	State            string                  `json:"state"`
	Type             string                  `json:"type"`
	CreatedAt        string                  `json:"created_at"`
	UpdatedAt        string                  `json:"updated_at"`
	Metadata         json.RawMessage         `json:"metadata"`
	VmafScore        float64                 `json:"vmaf_score"`
	Api              ApiV2                   `json:"-"`
	Video            VideoV2                 `json:"-"`
	UploadParameters upload.UploadParameters `json:"-"`
}

func (a *Asset) getApi() *ApiV2 {
	if a.Api.BaseApi != nil {
		return &a.Api
	}
	if a.Video.Api != nil && a.Video.Api.BaseApi != nil {
		return a.Video.Api
	}
	log.Panicln("asset has no valid apis to use")
	return nil
}

func (a *Asset) Update() error {
	url := a.getApi().getBaseUrl() + "/assets/" + a.Id
	data, err := json.Marshal(a)
	if err != nil {
		return err
	}
	body := bytes.NewBuffer(data)
	return a.handleAssetReq("PUT", url, body)
}

func (a *Asset) Delete() error {
	url := a.getApi().getBaseUrl() + "/assets/" + a.Id
	data, err := json.Marshal(a)
	if err != nil {
		return err
	}
	body := bytes.NewBuffer(data)
	return a.handleAssetReq("DELETE", url, body)
}

func (a *Asset) handleAssetReq(method, url string, body io.Reader) error {
	resp := AssetResponse{Asset: a}
	req, err := a.getApi().makeRequest(method, url, body)
	if err != nil {
		return err
	}
	req.Header.Add("content-type", "application/json")

	err = handleReq(a.Api, req, &resp)
	if err != nil {
		return err
	}

	return nil
}

func (a *Asset) GetUrl() string {
	if a.Url != "" {
		return a.Url
	}
	return a.Location
}

func (a *Asset) UploadFile(fileName string) error {
	upUrl := a.Api.UploadUrl
	if upUrl == "" {
		return errors.New("invalid upload url, can not upload file")
	}
	if a.UploadParameters.Key == "" {
		// if the location exists, get the upload parameters again
		if a.Location != "" && a.Type != "" {
			ext := filepath.Ext(fileName)
			req := upload.UploadRequest{
				Type:        a.Type,
				ContentType: common.ExtToCtype(ext),
				AssetId:     a.Id,
			}
			up, err := a.Video.GetUploadParams(req)
			if err != nil {
				return err
			}
			a.UploadParameters = up
		} else {
			return errors.New("upload parameters is invalid")
		}
	}
	f, err := os.Open(fileName)
	defer f.Close()
	if os.IsNotExist(err) {
		return errors.New("file '" + fileName + "' does not exist")
	}

	params := a.UploadParameters
	if !strings.Contains(params.SignatureUrl, "http") {
		sigUrl := upUrl + params.SignatureUrl
		log.Printf("Updating sig url to include host '%s'\n", upUrl)
		params.SignatureUrl = sigUrl
	}
	aws, err := upload.CreatorFn(params)
	if err != nil {
		return err
	}
	_, err = aws.Upload(f)
	return err
}
<|endoftext|>


<commit_before>// Echo kite is an example to kite that just echoes the argument back.
// Useful for debugging or testing stuff.

package main

import "github.com/koding/kite"

func main() {
	options := &kite.Options{
		Kitename:    "echo",
		Version:     "0.0.1",
		Environment: "development",
		Region:      "localhost",
		Port:        "7777",
	}

	k := kite.New(options)

	k.HandleFunc("echo", func(r *kite.Request) (interface{}, error) {
		return r.Args.One().MustString(), nil
	})

	k.Run()
}
<commit_msg>remove echo example<commit_after><|endoftext|>


<commit_before>package auth

import (
	"fmt"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/markbates/goth/gothic"
)

// BeginAuthHandler
func BeginAuthHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	gothic.BeginAuthHandler(w, r)
}

func UserLoginCallback(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	fmt.Println(gothic.GetState(r))
	user, err := gothic.CompleteUserAuth(w, r)
	if err != nil {
		panic(err)
	}

	log.Printf("%v", user)

	http.Redirect(w, r, "/", 301)

}
<commit_msg>auth calling check<commit_after>package auth

import (
	"fmt"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/markbates/goth/gothic"
)

// BeginAuthHandler
func BeginAuthHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	log.Println("Entered BeginAuthHandler")
	gothic.BeginAuthHandler(w, r)
}

func UserLoginCallback(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	log.Println("Entered UserLoginCallback")
	fmt.Println(gothic.GetState(r))
	user, err := gothic.CompleteUserAuth(w, r)
	if err != nil {
		panic(err)
	}

	log.Printf("%v", user)

	http.Redirect(w, r, "/", 301)

}
<|endoftext|>


<commit_before>package tally

import (
	"fmt"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/rpi" // This loads the RPi driver
	"log"
	"sync"
)

type GPIOOptions struct {
	TallyPins []string `long:"gpio-tally-pin"`
}

func (options GPIOOptions) Make(tally *Tally) (*GPIO, error) {
	var gpio = GPIO{
		options:   options,
		TallyPins: make(map[ID]embd.DigitalPin),
	}

	if err := gpio.init(options); err != nil {
		return nil, err
	}

	gpio.register(tally)

	return &gpio, nil
}

type GPIO struct {
	options GPIOOptions

	TallyPins map[ID]embd.DigitalPin

	stateChan chan State
	waitGroup sync.WaitGroup
}

func (gpio *GPIO) init(options GPIOOptions) error {
	if err := embd.InitGPIO(); err != nil {
		return fmt.Errorf("embd.InitGPIO: %v", err)
	}

	for i, pinName := range options.TallyPins {
		if pin, err := embd.NewDigitalPin(pinName); err != nil {
			return fmt.Errorf("embd.NewDigitalPin %v: %v", pinName, err)

			// Writing as "out" defaults to initializing the value as low.
		} else if err := pin.SetDirection(embd.Out); err != nil {
			return fmt.Errorf("pin.SetDirection %v: %v", pinName, err)
		} else {
			gpio.TallyPins[ID(i+1)] = pin
		}
	}

	return nil
}

func (gpio *GPIO) register(tally *Tally) {
	gpio.stateChan = make(chan State)
	gpio.waitGroup.Add(1)

	go gpio.run()

	tally.register(gpio.stateChan)
}

func (gpio *GPIO) close() {
	defer gpio.waitGroup.Done()

	var closed = 0

	for id, pin := range gpio.TallyPins {
		if err := pin.Close(); err != nil {
			log.Printf("tally:GPIO: close pin %v:%v: %v", id, pin, err)
		} else {
			closed++
		}
	}

	log.Printf("tally:GPIO: Closed %d pins", closed)
}

func (gpio *GPIO) run() {
	defer gpio.close()

	for state := range gpio.stateChan {
		log.Printf("tally:GPIO: Update:")

		for id, pin := range gpio.TallyPins {
			pinValue := embd.Low

			if status, exists := state.Tally[id]; !exists {
				// missing tally state for pin
			} else if status.Program {
				log.Printf("tally:GPIO:\tpin %v:%v high: %v", id, gpio.options.TallyPins[id-1], status)

				pinValue = embd.High
			}

			if err := pin.Write(pinValue); err != nil {
				log.Printf("tally:GPIO: write pin %v:%v: %v", id, pin, err)
			}
		}
	}

	log.Printf("tally:GPIO: End")
}

// Close and Wait
func (gpio *GPIO) Close() {
	log.Printf("tally:GPIO: Closing..")

	close(gpio.stateChan)

	gpio.waitGroup.Wait()
}
<commit_msg>tally/gpio: --gpio-red-pin --gpio-green-pin<commit_after>package tally

import (
	"fmt"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/rpi" // This loads the RPi driver
	"log"
	"sync"
)

type GPIOOptions struct {
	StatusGreenPin	string	 `long:"gpio-green-pin"`
	StatusRedPin	string	 `long:"gpio-red-pin"`

	TallyPins		[]string `long:"gpio-tally-pin"`
}

func (options GPIOOptions) Make(tally *Tally) (*GPIO, error) {
	var gpio = GPIO{
		options:   options,
		tallyPins: make(map[ID]embd.DigitalPin),
	}

	if err := gpio.init(options); err != nil {
		return nil, err
	}

	gpio.register(tally)

	return &gpio, nil
}

type GPIO struct {
	options GPIOOptions

	tallyPins		map[ID]embd.DigitalPin

	// red pin is high if there are sources with errors
	statusRedPin	embd.DigitalPin

	// green pin is high if there are sources with tallys
	statusGreenPin	embd.DigitalPin

	stateChan chan State
	waitGroup sync.WaitGroup
}

func openPinOut(pinName string) (embd.DigitalPin, error) {
	if pin, err := embd.NewDigitalPin(pinName); err != nil {
		return nil, fmt.Errorf("embd.NewDigitalPin %v: %v", pinName, err)

		// Writing as "out" defaults to initializing the value as low.
	} else if err := pin.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("pin.SetDirection %v: %v", pinName, err)
	} else {
		return pin, nil
	}
}

func (gpio *GPIO) init(options GPIOOptions) error {
	if err := embd.InitGPIO(); err != nil {
		return fmt.Errorf("embd.InitGPIO: %v", err)
	}

	for i, pinName := range options.TallyPins {
		if pin, err := openPinOut(pinName); err != nil {
			return err
		} else {
			gpio.tallyPins[ID(i+1)] = pin
		}
	}

	if options.StatusGreenPin == "" {

	} else if pin, err := openPinOut(options.StatusGreenPin); err != nil {
		return err
	} else {
		gpio.statusGreenPin = pin
	}
	if options.StatusRedPin == "" {

	} else if pin, err := openPinOut(options.StatusRedPin); err != nil {
		return err
	} else {
		gpio.statusRedPin = pin
	}

	return nil
}

func (gpio *GPIO) register(tally *Tally) {
	gpio.stateChan = make(chan State)
	gpio.waitGroup.Add(1)

	go gpio.run()

	tally.register(gpio.stateChan)
}

func (gpio *GPIO) close() {
	defer gpio.waitGroup.Done()

	var closed = 0

	for id, pin := range gpio.tallyPins {
		if err := pin.Close(); err != nil {
			log.Printf("tally:GPIO: close pin %v:%v: %v", id, pin, err)
		} else {
			closed++
		}
	}

	log.Printf("tally:GPIO: Closed %d pins", closed)
}

func (gpio *GPIO) update(state State) {
	log.Printf("tally:GPIO: Update:")

	var statusGreenValue = embd.Low
	var statusRedValue = embd.Low

	for id, pin := range gpio.tallyPins {
		pinValue := embd.Low

		if status, exists := state.Tally[id]; !exists {
			// missing tally state for pin
		} else {
			statusGreenValue = embd.High

			if status.Program {
				log.Printf("tally:GPIO:\tpin %v:%v high: %v", id, gpio.options.TallyPins[id-1], status)

				pinValue = embd.High
			}
		}

		if err := pin.Write(pinValue); err != nil {
			log.Printf("tally:GPIO: write pin %v:%v: %v", id, pin, err)
		}
	}

	if len(state.Errors) > 0 {
		statusRedValue = embd.High
	}

	// update status leds
	if gpio.statusGreenPin == nil {

	} else if err := gpio.statusGreenPin.Write(statusGreenValue); err != nil {
		log.Printf("tally:GPIO: write pin status-green:%v: %v", gpio.options.StatusGreenPin, err)
	}

	if gpio.statusRedPin == nil {

	} else if err := gpio.statusRedPin.Write(statusRedValue); err != nil {
		log.Printf("tally:GPIO: write pin status-red:%v: %v", gpio.options.StatusRedPin, err)
	}
}

func (gpio *GPIO) run() {
	defer gpio.close()

	for state := range gpio.stateChan {
		gpio.update(state)
	}

	log.Printf("tally:GPIO: End")
}

// Close and Wait
func (gpio *GPIO) Close() {
	log.Printf("tally:GPIO: Closing..")

	close(gpio.stateChan)

	gpio.waitGroup.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/zephyyrr/plugins"
	"log"
	"net"
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
	ph := plugins.NewManager()

	if pls, err := plugins.LoadAll("./plugins"); err == nil {
		for _, pl := range pls {
			ph.Handle(pl)
		}
	} else {
		log.Println("Error loading local plugins:", err)
	}

	go openTCPEntrance(ph, ":5436")

	ph.Muxer().AddHandler("ping", plugins.HandlerFunc(func(event plugins.Event, args plugins.Args) {
		ph.Dispatch("pong", args)
	}))

	ph.Muxer().AddHandler("log", plugins.HandlerFunc(func(event plugins.Event, args plugins.Args) {
		log.Printf("(%s): %v", event, args)
	}))

	ph.Muxer().AddHandler("square", plugins.HandlerFunc(func(event plugins.Event, args plugins.Args) {
		if x, ok := args["Argument"].(int); ok {
			ph.Dispatch("square.answer", plugins.Args{
				"argument": x,
				"answer":   x * x,
			})
		}
	}))

	ph.ListenAndServe()
}

func openTCPEntrance(man *plugins.Manager, addr string) {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		panic(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
			break
		}

		log.Println("Recieved connection from %s", conn.RemoteAddr().String())

		go func(conn net.Conn) {
			plugin, err := plugins.NewRemotePlugin(conn, conn)
			if err != nil {
				return
			}

			man.Handle(plugin)
		}(conn)
	}
}
<commit_msg>Updated the log event to use the new structhandler<commit_after>package main

import (
	"github.com/zephyyrr/plugins"
	"github.com/zephyyrr/plugins/structhandler"
	"log"
	"net"
	"time"
)

func init() {
	log.SetFlags(log.LstdFlags)
}

func main() {
	ph := plugins.NewManager()

	if pls, err := plugins.LoadAll("./plugins"); err == nil {
		for _, pl := range pls {
			log.Printf("%s, Provides: %v, Subscribes: %v", pl.Name(), pl.Provides(), pl.Subscribes())
			ph.Handle(pl)
		}
	} else {
		log.Println("Error loading local plugins:", err)
	}

	go openTCPEntrance(ph, ":5436")

	ph.Muxer().AddHandler("ping", plugins.HandlerFunc(func(event plugins.Event, args plugins.Args) {
		Log(LogEntry{"DEBUG", "main", "Recieved ping", args})
		ph.Dispatch("pong", args)
	}))

	ph.Muxer().AddHandler("log", structhandler.New(Log))

	ph.Muxer().AddHandler("square", plugins.HandlerFunc(func(event plugins.Event, args plugins.Args) {
		if x, ok := args["Argument"].(int); ok {
			ph.Dispatch("square.answer", plugins.Args{
				"argument": x,
				"answer":   x * x,
			})
		}
	}))

	go func() {
		for {
			time.Sleep(10 * time.Second)
			ph.Dispatch("ping", nil)
		}
	}()

	ph.ListenAndServe()
}

type LogEntry struct {
	Level, Origin, Message string
	Additional             map[string]interface{}
}

func Log(le LogEntry) {
	log.Printf("[%s] (%s) %s : %v", le.Level, le.Origin, le.Message, le.Additional)
}

func openTCPEntrance(man *plugins.Manager, addr string) {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		panic(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
			break
		}

		log.Println("Recieved connection from %s", conn.RemoteAddr().String())

		go func(conn net.Conn) {
			plugin, err := plugins.NewRemotePlugin(conn, conn)
			if err != nil {
				return
			}

			man.Handle(plugin)
		}(conn)
	}
}
<|endoftext|>


<commit_before>package java

import (
	"fmt"
	"log"
	"os"
)

type VM struct {
	classes       []class
	nativeMethods map[string](func(*frame))
}

type frame struct {
	stack
	variables []javaValue
}

func NewVM() (vm VM) {
	vm.nativeMethods = map[string](func(*frame)){
		"print":     nativePrintString,
		"printInt":  nativePrintInteger,
		"printChar": nativePrintChar,
	}
	return vm
}

func (vm *VM) LoadClass(path string) {
	file, _ := os.Open(path)
	class, err := parseClass(file)
	if err != nil {
		log.Panicf("unable to load %s: %v", path, err)
	}
	vm.classes = append(vm.classes, class)
}

func (vm *VM) Run() {
	var frame frame
	//TODO: push the actual command line arguments onto the stack for the main method.
	frame.push(nil)
	//TODO: this is obviously completely wrong
	var index int
	for i, c := range vm.classes {
		if c.hasMethodCalled("main") {
			index = i
		}
	}
	vm.execute(vm.classes[index].getName(), "main", &frame)
}

func nativePrintString(f *frame) {
	str := f.variables[0]
	switch str := str.(type) {
	default:
		fmt.Printf("unexpected type %T", str)
	case javaObject:
		f := str.getField("data").(javaArray)
		bytes := make([]byte, len(f))
		for i, b := range f {
			bytes[i] = byte(b.(javaByte))
		}
		fmt.Print(string(bytes))
	}
	return
}

func nativePrintInteger(f *frame) {
	i := f.variables[0].(javaInt).unbox()
	fmt.Println(i)
	return
}

func nativePrintChar(f *frame) {
	i := f.variables[0].(javaInt).unbox()
	fmt.Printf("%c", i)
	return
}

func (vm *VM) resolveClass(name string) class {
	for _, class := range vm.classes {
		// TODO: handle packages correctly
		if class.getName() == name {
			return class
		}
	}
	//TODO: raise the appropriate java exception
	log.Panicf("Could not resolve class %s\n", name)
	return class{}
}

func newFrame(method method, previousFrame *frame) frame {
	var frame frame
	numArgs := method.numArgs()
	if (method.accessFlags & Native) != 0 {
		frame.variables = make([]javaValue, method.numArgs())
	} else {
		frame.variables = make([]javaValue, method.code.maxLocals)
	}
	if (method.accessFlags & Static) != 0 {
		numArgs--
	}
	for i := numArgs; i >= 0; i-- {
		frame.variables[i] = previousFrame.pop()
	}
	return frame
}

func (vm *VM) execute(className string, methodName string, previousFrame *frame) {
	if className == "java/lang/Object" {
		return
	}
	class := vm.resolveClass(className)
	method := class.getMethod(methodName)
	frame := newFrame(method, previousFrame)

	if (method.accessFlags & Native) != 0 {
		native := vm.nativeMethods[methodName]
		if native == nil {
			log.Panicf("Unknown native method %s", methodName)
		}
		native(&frame)
		return
	}

	pc := newProgramCounter(method.code.code)
	for {
		op := pc.next()
		switch op.name {
		case "nop":
		case "iconst_0":
			frame.pushInt32(0)
		case "iconst_1":
			frame.pushInt32(1)
		case "iconst_2":
			frame.pushInt32(2)
		case "iconst_3":
			frame.pushInt32(3)
		case "iconst_4":
			frame.pushInt32(4)
		case "iconst_5":
			frame.pushInt32(5)
		case "bipush":
			frame.pushInt32(int32(op.int8()))
		case "ldc":
			s := class.getStringAt(int(op.int8() - 1))
			c := vm.resolveClass("java/lang/String")
			ref := newInstance(&c)
			arr := make([]javaValue, len(s.contents))
			for i, _ := range arr {
				arr[i] = javaByte(s.contents[i])
			}
			ref.fields["data"] = javaArray(arr)
			frame.push(ref)
		case "iload":
			index := op.int8()
			frame.push(frame.variables[index])
		case "iload_0", "aload_0":
			frame.push(frame.variables[0])
		case "iload_1", "aload_1":
			frame.push(frame.variables[1])
		case "iload_2", "aload_2":
			frame.push(frame.variables[2])
		case "iload_3", "aload_3":
			frame.push(frame.variables[3])
		case "istore":
			index := op.int8()
			frame.variables[index] = frame.pop()
		case "istore_1", "astore_1":
			frame.variables[1] = frame.pop()
		case "istore_2":
			frame.variables[2] = frame.pop()
		case "istore_3", "astore_3":
			frame.variables[3] = frame.pop()
		case "castore":
			v := frame.popInt32()
			i := frame.popInt32()
			a := frame.popArray()
			a[int(i)] = javaByte(v)
		case "caload":
			i := frame.popInt32()
			a := frame.popArray()
			c := byte(a[int(i)].(javaByte))
			frame.pushInt32(int32(c))
		case "dup":
			tmp := frame.pop()
			frame.push(tmp)
			frame.push(tmp)
		case "iadd":
			//TODO: make sure we do overflow correctly
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(x + y)
		case "isub":
			//TODO: make sure we do underflow correctly
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(y - x)
		case "imul":
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(x * y)
		case "idiv":
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(y / x)
		case "iinc":
			index := op.args[0]
			c := op.args[1]
			i := frame.variables[index].(javaInt).unbox()
			frame.variables[index] = javaInt(i + int32(c))
		case "ifne":
			c := frame.popInt32()
			if c != 0 {
				pc.jump(int(op.int16()))
			}
		case "if_icmpge":
			v2 := frame.popInt32()
			v1 := frame.popInt32()
			if v1 >= v2 {
				pc.jump(int(op.int16()))
			}
		case "if_icmple":
			v2 := frame.popInt32()
			v1 := frame.popInt32()
			if v1 <= v2 {
				pc.jump(int(op.int16()))
			}
		case "goto":
			pc.jump(int(op.int16()))
		case "ireturn", "areturn":
			previousFrame.push(frame.pop())
			return
		case "return":
			return
		case "getstatic":
			fieldRef := class.getFieldRefAt(op.uint16())
			c := vm.resolveClass(fieldRef.className())
			vm.initClass(&c, &frame)
			f := c.getField(fieldRef.fieldName())
			frame.push(f.value)
		case "putstatic":
			fieldRef := class.getFieldRefAt(op.uint16())
			c := vm.resolveClass(fieldRef.className())
			f := c.getField(fieldRef.fieldName())
			f.value = frame.pop()
		case "getfield":
			fieldRef := class.getFieldRefAt(op.uint16())
			obj := frame.popObject()
			f := obj.getField(fieldRef.fieldName())
			frame.push(f)
		case "putfield":
			fieldRef := class.getFieldRefAt(op.uint16())
			f := frame.pop()
			obj := frame.popObject()
			obj.setField(fieldRef.fieldName(), f)
		case "invokevirtual":
			methodRef := class.getMethodRefAt(op.uint16())
			vm.execute(methodRef.className(), methodRef.methodName(), &frame)
		case "invokespecial":
			methodRef := class.getMethodRefAt(op.uint16())
			vm.execute(methodRef.className(), methodRef.methodName(), &frame)
		case "invokestatic":
			methodRef := class.getMethodRefAt(op.uint16())
			vm.execute(methodRef.className(), methodRef.methodName(), &frame)
		case "new":
			classInfo := class.getClassInfoAt(op.uint16())
			c := vm.resolveClass(classInfo.className())
			ref := newInstance(&c)
			frame.push(ref)
		case "newarray":
			count := frame.popInt32()
			arr := make([]javaValue, count)
			for i, _ := range arr {
				arr[i] = javaByte(67)
			}
			frame.pushArray(arr)
		case "arraylength":
			a := frame.popArray()
			frame.pushInt32(int32(len(a)))
		default:
			panic(fmt.Sprintf("Cannot execute instruction: %v", op))
		}
	}
}

func newInstance(c *class) javaObject {
	return javaObject{make(map[string]javaValue)}
}

func (vm *VM) initClass(c *class, frame *frame) {
	if c.initialised {
		return
	}
	vm.execute(c.getName(), "<clinit>", frame)
	c.initialised = true
}

type stack struct {
	items []javaValue
	size  uint
}

type javaValue interface {
	isJavaValue()
}

func (s *stack) push(e javaValue) {
	s.items = append(s.items, e)
	s.size++
}

func (s *stack) pop() javaValue {
	if s.size == 0 {
		panic("Cannot pop from an empty stack")
	}
	e := s.items[s.size-1]
	s.size--
	s.items = s.items[:s.size]
	return e
}

type javaInt int32

func (_ javaInt) isJavaValue() {}

func (s *stack) pushInt32(i int32) {
	s.push(javaInt(i))
}

func (s *stack) popInt32() int32 {
	return int32(s.pop().(javaInt))
}

func (i javaInt) unbox() int32 {
	return int32(i)
}

type javaByte byte

func (_ javaByte) isJavaValue() {}

func (s *stack) pushByte(i byte) {
	s.push(javaByte(i))
}

func (s *stack) popByte() byte {
	return byte(s.pop().(javaByte))
}

type javaArray []javaValue

func (_ javaArray) isJavaValue() {}

func (s *stack) pushArray(a javaArray) {
	s.push(javaArray(a))
}

func (s *stack) popArray() javaArray {
	return []javaValue(s.pop().(javaArray))
}

type javaObject struct {
	fields map[string]javaValue
}

func (o *javaObject) getField(name string) javaValue {
	_, ok := o.fields[name]
	if !ok {
		o.fields[name] = javaInt(0)
	}
	return o.fields[name]
}

func (o *javaObject) setField(name string, f javaValue) {
	o.fields[name] = f
}

func (_ javaObject) isJavaValue() {}

func (s *stack) popObject() javaObject {
	return s.pop().(javaObject)
}
<commit_msg>remove special handling of java/lang/Object<commit_after>package java

import (
	"fmt"
	"log"
	"os"
)

type VM struct {
	classes       []class
	nativeMethods map[string](func(*frame))
}

type frame struct {
	stack
	variables []javaValue
}

func NewVM() (vm VM) {
	vm.nativeMethods = map[string](func(*frame)){
		"print":     nativePrintString,
		"printInt":  nativePrintInteger,
		"printChar": nativePrintChar,
	}
	return vm
}

func (vm *VM) LoadClass(path string) {
	file, _ := os.Open(path)
	class, err := parseClass(file)
	if err != nil {
		log.Panicf("unable to load %s: %v", path, err)
	}
	vm.classes = append(vm.classes, class)
}

func (vm *VM) Run() {
	var frame frame
	//TODO: push the actual command line arguments onto the stack for the main method.
	frame.push(nil)
	//TODO: this is obviously completely wrong
	var index int
	for i, c := range vm.classes {
		if c.hasMethodCalled("main") {
			index = i
		}
	}
	vm.execute(vm.classes[index].getName(), "main", &frame)
}

func nativePrintString(f *frame) {
	str := f.variables[0]
	switch str := str.(type) {
	default:
		fmt.Printf("unexpected type %T", str)
	case javaObject:
		f := str.getField("data").(javaArray)
		bytes := make([]byte, len(f))
		for i, b := range f {
			bytes[i] = byte(b.(javaByte))
		}
		fmt.Print(string(bytes))
	}
	return
}

func nativePrintInteger(f *frame) {
	i := f.variables[0].(javaInt).unbox()
	fmt.Println(i)
	return
}

func nativePrintChar(f *frame) {
	i := f.variables[0].(javaInt).unbox()
	fmt.Printf("%c", i)
	return
}

func (vm *VM) resolveClass(name string) class {
	for _, class := range vm.classes {
		// TODO: handle packages correctly
		if class.getName() == name {
			return class
		}
	}
	//TODO: raise the appropriate java exception
	log.Panicf("Could not resolve class %s\n", name)
	return class{}
}

func newFrame(method method, previousFrame *frame) frame {
	var frame frame
	numArgs := method.numArgs()
	if (method.accessFlags & Native) != 0 {
		frame.variables = make([]javaValue, method.numArgs())
	} else {
		frame.variables = make([]javaValue, method.code.maxLocals)
	}
	if (method.accessFlags & Static) != 0 {
		numArgs--
	}
	for i := numArgs; i >= 0; i-- {
		frame.variables[i] = previousFrame.pop()
	}
	return frame
}

func (vm *VM) execute(className string, methodName string, previousFrame *frame) {
	class := vm.resolveClass(className)
	method := class.getMethod(methodName)
	frame := newFrame(method, previousFrame)

	if (method.accessFlags & Native) != 0 {
		native := vm.nativeMethods[methodName]
		if native == nil {
			log.Panicf("Unknown native method %s", methodName)
		}
		native(&frame)
		return
	}

	pc := newProgramCounter(method.code.code)
	for {
		op := pc.next()
		switch op.name {
		case "nop":
		case "iconst_0":
			frame.pushInt32(0)
		case "iconst_1":
			frame.pushInt32(1)
		case "iconst_2":
			frame.pushInt32(2)
		case "iconst_3":
			frame.pushInt32(3)
		case "iconst_4":
			frame.pushInt32(4)
		case "iconst_5":
			frame.pushInt32(5)
		case "bipush":
			frame.pushInt32(int32(op.int8()))
		case "ldc":
			s := class.getStringAt(int(op.int8() - 1))
			c := vm.resolveClass("java/lang/String")
			ref := newInstance(&c)
			arr := make([]javaValue, len(s.contents))
			for i, _ := range arr {
				arr[i] = javaByte(s.contents[i])
			}
			ref.fields["data"] = javaArray(arr)
			frame.push(ref)
		case "iload":
			index := op.int8()
			frame.push(frame.variables[index])
		case "iload_0", "aload_0":
			frame.push(frame.variables[0])
		case "iload_1", "aload_1":
			frame.push(frame.variables[1])
		case "iload_2", "aload_2":
			frame.push(frame.variables[2])
		case "iload_3", "aload_3":
			frame.push(frame.variables[3])
		case "istore":
			index := op.int8()
			frame.variables[index] = frame.pop()
		case "istore_1", "astore_1":
			frame.variables[1] = frame.pop()
		case "istore_2":
			frame.variables[2] = frame.pop()
		case "istore_3", "astore_3":
			frame.variables[3] = frame.pop()
		case "castore":
			v := frame.popInt32()
			i := frame.popInt32()
			a := frame.popArray()
			a[int(i)] = javaByte(v)
		case "caload":
			i := frame.popInt32()
			a := frame.popArray()
			c := byte(a[int(i)].(javaByte))
			frame.pushInt32(int32(c))
		case "dup":
			tmp := frame.pop()
			frame.push(tmp)
			frame.push(tmp)
		case "iadd":
			//TODO: make sure we do overflow correctly
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(x + y)
		case "isub":
			//TODO: make sure we do underflow correctly
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(y - x)
		case "imul":
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(x * y)
		case "idiv":
			x := frame.popInt32()
			y := frame.popInt32()
			frame.pushInt32(y / x)
		case "iinc":
			index := op.args[0]
			c := op.args[1]
			i := frame.variables[index].(javaInt).unbox()
			frame.variables[index] = javaInt(i + int32(c))
		case "ifne":
			c := frame.popInt32()
			if c != 0 {
				pc.jump(int(op.int16()))
			}
		case "if_icmpge":
			v2 := frame.popInt32()
			v1 := frame.popInt32()
			if v1 >= v2 {
				pc.jump(int(op.int16()))
			}
		case "if_icmple":
			v2 := frame.popInt32()
			v1 := frame.popInt32()
			if v1 <= v2 {
				pc.jump(int(op.int16()))
			}
		case "goto":
			pc.jump(int(op.int16()))
		case "ireturn", "areturn":
			previousFrame.push(frame.pop())
			return
		case "return":
			return
		case "getstatic":
			fieldRef := class.getFieldRefAt(op.uint16())
			c := vm.resolveClass(fieldRef.className())
			vm.initClass(&c, &frame)
			f := c.getField(fieldRef.fieldName())
			frame.push(f.value)
		case "putstatic":
			fieldRef := class.getFieldRefAt(op.uint16())
			c := vm.resolveClass(fieldRef.className())
			f := c.getField(fieldRef.fieldName())
			f.value = frame.pop()
		case "getfield":
			fieldRef := class.getFieldRefAt(op.uint16())
			obj := frame.popObject()
			f := obj.getField(fieldRef.fieldName())
			frame.push(f)
		case "putfield":
			fieldRef := class.getFieldRefAt(op.uint16())
			f := frame.pop()
			obj := frame.popObject()
			obj.setField(fieldRef.fieldName(), f)
		case "invokevirtual":
			methodRef := class.getMethodRefAt(op.uint16())
			vm.execute(methodRef.className(), methodRef.methodName(), &frame)
		case "invokespecial":
			methodRef := class.getMethodRefAt(op.uint16())
			vm.execute(methodRef.className(), methodRef.methodName(), &frame)
		case "invokestatic":
			methodRef := class.getMethodRefAt(op.uint16())
			vm.execute(methodRef.className(), methodRef.methodName(), &frame)
		case "new":
			classInfo := class.getClassInfoAt(op.uint16())
			c := vm.resolveClass(classInfo.className())
			ref := newInstance(&c)
			frame.push(ref)
		case "newarray":
			count := frame.popInt32()
			arr := make([]javaValue, count)
			for i, _ := range arr {
				arr[i] = javaByte(67)
			}
			frame.pushArray(arr)
		case "arraylength":
			a := frame.popArray()
			frame.pushInt32(int32(len(a)))
		default:
			panic(fmt.Sprintf("Cannot execute instruction: %v", op))
		}
	}
}

func newInstance(c *class) javaObject {
	return javaObject{make(map[string]javaValue)}
}

func (vm *VM) initClass(c *class, frame *frame) {
	if c.initialised {
		return
	}
	vm.execute(c.getName(), "<clinit>", frame)
	c.initialised = true
}

type stack struct {
	items []javaValue
	size  uint
}

type javaValue interface {
	isJavaValue()
}

func (s *stack) push(e javaValue) {
	s.items = append(s.items, e)
	s.size++
}

func (s *stack) pop() javaValue {
	if s.size == 0 {
		panic("Cannot pop from an empty stack")
	}
	e := s.items[s.size-1]
	s.size--
	s.items = s.items[:s.size]
	return e
}

type javaInt int32

func (_ javaInt) isJavaValue() {}

func (s *stack) pushInt32(i int32) {
	s.push(javaInt(i))
}

func (s *stack) popInt32() int32 {
	return int32(s.pop().(javaInt))
}

func (i javaInt) unbox() int32 {
	return int32(i)
}

type javaByte byte

func (_ javaByte) isJavaValue() {}

func (s *stack) pushByte(i byte) {
	s.push(javaByte(i))
}

func (s *stack) popByte() byte {
	return byte(s.pop().(javaByte))
}

type javaArray []javaValue

func (_ javaArray) isJavaValue() {}

func (s *stack) pushArray(a javaArray) {
	s.push(javaArray(a))
}

func (s *stack) popArray() javaArray {
	return []javaValue(s.pop().(javaArray))
}

type javaObject struct {
	fields map[string]javaValue
}

func (o *javaObject) getField(name string) javaValue {
	_, ok := o.fields[name]
	if !ok {
		o.fields[name] = javaInt(0)
	}
	return o.fields[name]
}

func (o *javaObject) setField(name string, f javaValue) {
	o.fields[name] = f
}

func (_ javaObject) isJavaValue() {}

func (s *stack) popObject() javaObject {
	return s.pop().(javaObject)
}
<|endoftext|>


<commit_before>package rigo

import (
	"fmt"
	"os/user"
	"testing"
	"time"

	. "github.com/mae-global/rigo/ri"
	. "github.com/smartystreets/goconvey/convey"
)

func Test_ExampleD14(t *testing.T) {

	Convey("Example D1.4", t, func() {

		sgroup := RtString("shadinggroup")
		frames := 2
		cuser, err := user.Current()
		So(err, ShouldBeNil)

		pipe := DefaultFilePipe()
		So(pipe, ShouldNotBeNil)

		/* create a formal version of the RIB output to the pipe, RiBegin,RiEnd... instead of Begin,End... */
		ctx := New(pipe, &Configuration{Formal: true,PrettyPrint: true})
		ctx.Begin("output/exampleD14.rib")
		ctx.ArchiveRecord("structure", "Scene Bouncing Ball")
		ctx.ArchiveRecord("structure", "Creator %s-%s", Author, Version)
		ctx.ArchiveRecord("structure", "CreationDate %s", time.Now())
		ctx.ArchiveRecord("structure", "For %s", cuser.Username)
		ctx.ArchiveRecord("structure", "Frames %d", frames)
		ctx.ArchiveRecord("structure", "Shaders PIXARmarble, PIXARwood, MyUserShader")
		ctx.ArchiveRecord("structure", "CapabilitiesNeeded ShadingLanguage Displacements")
		ctx.Declare("d", "uniform point")
		ctx.Declare("squish", "uniform float")
		ctx.Option("limits", RtToken("bucketsize"), RtIntArray{6, 6})
		ctx.Option("limits", RtToken("gridsize"), RtIntArray{18})
		ctx.Format(1024, 768, 1)
		ctx.Projection(Perspective)
		ctx.Clipping(10, 1000.0)
		ctx.FrameBegin(1)
		ctx.ArchiveRecord("structure", "Shaders PIXARmarble, PIXARwood")
		ctx.ArchiveRecord("structure", "CameraOrientation %.1f %.1f %.1f %.1f %.1f %.1f", 10., 10., 10., 0., 0., 0.)
		ctx.Transform(RtMatrix{.707107, -.408248, 0.57735, 0, 0, .816497, -.57735, 0, -.707107, -.408248, -.57735, 0, 0, 0, 17.3205, 1})
		ctx.WorldBegin()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtString("myball"))
		ctx.Displacement("MyUserShader", RtString("squish"), RtInt(5))
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"tophalf"})
		ctx.Surface("plastic")
		ctx.Sphere(.5, -.5, 0, 360)
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"bothalf"})
		ctx.Surface("PIXARmarble")
		ctx.Sphere(.5, 0, .5, 360)
		ctx.AttributeEnd()
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtStringArray{"floor"})
		ctx.Surface("PIXARwood", RtString("roughness"), RtFloatArray{.3}, RtToken("d"), RtIntArray{1})
		ctx.Comment("geometry for floor")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{-100, 0, -100, -100, 0, 100, 100, 0, 100, 10, 0, -100})
		ctx.AttributeEnd()
		ctx.WorldEnd()
		ctx.FrameEnd()

		ctx.FrameBegin(2)
		ctx.ArchiveRecord("structure", "Shaders PIXARwood, PIXARmarbles")
		ctx.ArchiveRecord("structure", "CameraOrientation %.1f %.1f %.1f %.1f %.1f %.1f", 10., 20., 10., 0., 0., 0.)
		ctx.Transform(RtMatrix{.707107, -.57735, -.408248, 0, 0, .57735, -.815447, 0, -.707107, -.57735, -.408248, 0, 0, 0, 24.4949, 1})
		ctx.WorldBegin()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtStringArray{"myball"})
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"tophalf"})
		ctx.Surface("PIXARmarble")
		ctx.ShadingRate(.1)
		ctx.Sphere(.5, 0, .5, 360)
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"bothalf"})
		ctx.Surface("plastic")
		ctx.Sphere(.5, -.5, 0, 360)
		ctx.AttributeEnd()
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtStringArray{"floor"})
		ctx.Surface("PIXARwood", RtToken("roughness"), RtFloatArray{.3}, RtToken("d"), RtIntArray{1})
		ctx.Comment("geometry for floor")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{-100, 0, -100, -100, 0, 100, 100, 0, 100, 10, 0, -100})
		ctx.AttributeEnd()
		ctx.WorldEnd()
		ctx.FrameEnd()

		So(ctx.End(), ShouldBeNil)

		/* output gathered stats */
		p := pipe.GetByName(PipeToStats{}.Name())
		So(p, ShouldNotBeNil)
		s, ok := p.(*PipeToStats)
		So(s, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		p = pipe.GetByName(PipeTimer{}.Name())
		So(p, ShouldNotBeNil)
		t, ok := p.(*PipeTimer)
		So(t, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		fmt.Printf("%s%s", s, t)
	})
}

func Test_ExampleD21(t *testing.T) {

	Convey("Example D.2.1 RIB Entity", t, func() {

		pipe := DefaultFilePipe()

		ctx := NewEntity(pipe)
		ctx.Begin("output/exampleD21.rib")
		ctx.AttributeBegin("begin unit cube")
		ctx.Attribute("identifier", RtToken("name"), RtToken("unitcube"))
		ctx.Bound(RtBound{-.5, .5, -.5, .5, -.5, .5})
		ctx.TransformBegin()

		ctx.Comment("far face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})
		ctx.Rotate(90, 0, 1, 0)

		ctx.Comment("right face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})
		ctx.Rotate(90, 0, 1, 0)

		ctx.Comment("near face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})
		ctx.Rotate(90, 0, 1, 0)

		ctx.Comment("left face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})

		ctx.TransformEnd()
		ctx.TransformBegin()

		ctx.Comment("bottom face")
		ctx.Rotate(90, 1, 0, 0)
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})

		ctx.TransformEnd()
		ctx.TransformBegin()

		ctx.Comment("top face")
		ctx.Rotate(-90, 1, 0, 0)
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})

		ctx.TransformEnd()
		ctx.AttributeEnd("end unit cube")

		So(ctx.End(), ShouldBeNil)

		/* output gathered stats */
		p := pipe.GetByName(PipeToStats{}.Name())
		So(p, ShouldNotBeNil)
		s, ok := p.(*PipeToStats)
		So(s, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		p = pipe.GetByName(PipeTimer{}.Name())
		So(p, ShouldNotBeNil)
		t, ok := p.(*PipeTimer)
		So(t, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		fmt.Printf("%s%s", s, t)

	})
}
<commit_msg>added simple example with light handle unqiue generator<commit_after>package rigo

import (
	"fmt"
	"os/user"
	"testing"
	"time"

	. "github.com/mae-global/rigo/ri"
	. "github.com/mae-global/rigo/ri/handles"

	. "github.com/smartystreets/goconvey/convey"
)

func Test_ExampleD14(t *testing.T) {

	Convey("Example D1.4", t, func() {

		sgroup := RtString("shadinggroup")
		frames := 2
		cuser, err := user.Current()
		So(err, ShouldBeNil)

		pipe := DefaultFilePipe()
		So(pipe, ShouldNotBeNil)

		/* create a formal version of the RIB output to the pipe, RiBegin,RiEnd... instead of Begin,End... */
		ctx := New(pipe, &Configuration{Formal: true,PrettyPrint: true})
		ctx.Begin("output/exampleD14.rib")
		ctx.ArchiveRecord("structure", "Scene Bouncing Ball")
		ctx.ArchiveRecord("structure", "Creator %s-%s", Author, Version)
		ctx.ArchiveRecord("structure", "CreationDate %s", time.Now())
		ctx.ArchiveRecord("structure", "For %s", cuser.Username)
		ctx.ArchiveRecord("structure", "Frames %d", frames)
		ctx.ArchiveRecord("structure", "Shaders PIXARmarble, PIXARwood, MyUserShader")
		ctx.ArchiveRecord("structure", "CapabilitiesNeeded ShadingLanguage Displacements")
		ctx.Declare("d", "uniform point")
		ctx.Declare("squish", "uniform float")
		ctx.Option("limits", RtToken("bucketsize"), RtIntArray{6, 6})
		ctx.Option("limits", RtToken("gridsize"), RtIntArray{18})
		ctx.Format(1024, 768, 1)
		ctx.Projection(Perspective)
		ctx.Clipping(10, 1000.0)
		ctx.FrameBegin(1)
		ctx.ArchiveRecord("structure", "Shaders PIXARmarble, PIXARwood")
		ctx.ArchiveRecord("structure", "CameraOrientation %.1f %.1f %.1f %.1f %.1f %.1f", 10., 10., 10., 0., 0., 0.)
		ctx.Transform(RtMatrix{.707107, -.408248, 0.57735, 0, 0, .816497, -.57735, 0, -.707107, -.408248, -.57735, 0, 0, 0, 17.3205, 1})
		ctx.WorldBegin()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtString("myball"))
		ctx.Displacement("MyUserShader", RtString("squish"), RtInt(5))
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"tophalf"})
		ctx.Surface("plastic")
		ctx.Sphere(.5, -.5, 0, 360)
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"bothalf"})
		ctx.Surface("PIXARmarble")
		ctx.Sphere(.5, 0, .5, 360)
		ctx.AttributeEnd()
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtStringArray{"floor"})
		ctx.Surface("PIXARwood", RtString("roughness"), RtFloatArray{.3}, RtToken("d"), RtIntArray{1})
		ctx.Comment("geometry for floor")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{-100, 0, -100, -100, 0, 100, 100, 0, 100, 10, 0, -100})
		ctx.AttributeEnd()
		ctx.WorldEnd()
		ctx.FrameEnd()

		ctx.FrameBegin(2)
		ctx.ArchiveRecord("structure", "Shaders PIXARwood, PIXARmarbles")
		ctx.ArchiveRecord("structure", "CameraOrientation %.1f %.1f %.1f %.1f %.1f %.1f", 10., 20., 10., 0., 0., 0.)
		ctx.Transform(RtMatrix{.707107, -.57735, -.408248, 0, 0, .57735, -.815447, 0, -.707107, -.57735, -.408248, 0, 0, 0, 24.4949, 1})
		ctx.WorldBegin()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtStringArray{"myball"})
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"tophalf"})
		ctx.Surface("PIXARmarble")
		ctx.ShadingRate(.1)
		ctx.Sphere(.5, 0, .5, 360)
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", sgroup, RtStringArray{"bothalf"})
		ctx.Surface("plastic")
		ctx.Sphere(.5, -.5, 0, 360)
		ctx.AttributeEnd()
		ctx.AttributeEnd()
		ctx.AttributeBegin()
		ctx.Attribute("identifier", RtString("name"), RtStringArray{"floor"})
		ctx.Surface("PIXARwood", RtToken("roughness"), RtFloatArray{.3}, RtToken("d"), RtIntArray{1})
		ctx.Comment("geometry for floor")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{-100, 0, -100, -100, 0, 100, 100, 0, 100, 10, 0, -100})
		ctx.AttributeEnd()
		ctx.WorldEnd()
		ctx.FrameEnd()

		So(ctx.End(), ShouldBeNil)

		/* output gathered stats */
		p := pipe.GetByName(PipeToStats{}.Name())
		So(p, ShouldNotBeNil)
		s, ok := p.(*PipeToStats)
		So(s, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		p = pipe.GetByName(PipeTimer{}.Name())
		So(p, ShouldNotBeNil)
		t, ok := p.(*PipeTimer)
		So(t, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		fmt.Printf("%s%s", s, t)
	})
}

func Test_ExampleD21(t *testing.T) {

	Convey("Example D.2.1 RIB Entity", t, func() {

		pipe := DefaultFilePipe()

		ctx := NewEntity(pipe)
		ctx.Begin("output/exampleD21.rib")
		ctx.AttributeBegin("begin unit cube")
		ctx.Attribute("identifier", RtToken("name"), RtToken("unitcube"))
		ctx.Bound(RtBound{-.5, .5, -.5, .5, -.5, .5})
		ctx.TransformBegin()

		ctx.Comment("far face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})
		ctx.Rotate(90, 0, 1, 0)

		ctx.Comment("right face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})
		ctx.Rotate(90, 0, 1, 0)

		ctx.Comment("near face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})
		ctx.Rotate(90, 0, 1, 0)

		ctx.Comment("left face")
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})

		ctx.TransformEnd()
		ctx.TransformBegin()

		ctx.Comment("bottom face")
		ctx.Rotate(90, 1, 0, 0)
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})

		ctx.TransformEnd()
		ctx.TransformBegin()

		ctx.Comment("top face")
		ctx.Rotate(-90, 1, 0, 0)
		ctx.Polygon(4, RtToken("P"), RtFloatArray{.5, .5, .5, -.5, .5, .5, -.5, -.5, .5, .5, -.5, .5})

		ctx.TransformEnd()
		ctx.AttributeEnd("end unit cube")

		So(ctx.End(), ShouldBeNil)

		/* output gathered stats */
		p := pipe.GetByName(PipeToStats{}.Name())
		So(p, ShouldNotBeNil)
		s, ok := p.(*PipeToStats)
		So(s, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		p = pipe.GetByName(PipeTimer{}.Name())
		So(p, ShouldNotBeNil)
		t, ok := p.(*PipeTimer)
		So(t, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		fmt.Printf("%s%s", s, t)

	})
}

func Test_SimpleExample(t *testing.T) {

	Convey("Simple Example",t,func() {

		pipe := DefaultFilePipe()

		/* use a custom unique generator with a prefix for the light handles */
		lights := NewPrefixLightUniqueGenerator("light_")

		ctx := NewCustom(pipe,lights,nil,&Configuration{PrettyPrint:true})
		ctx.Begin("output/simple.rib")
		ctx.Display("sphere.tif","file","rgb")
		ctx.Format(320,240,1)
		ctx.Projection(Perspective,RtString("fov"),RtFloat(30))
		ctx.Translate(0,0,6)
		ctx.WorldBegin()
		ctx.LightSource("ambientlight",RtString("intensity"),RtFloat(0.5))
		ctx.LightSource("distantlight",RtString("intensity"),RtFloat(1.2),RtString("form"),RtIntArray{0,0,-6},RtString("to"),RtIntArray{0,0,0})
		ctx.Color(RtColor{1,0,0})
		ctx.Sphere(1,-1,1,360)
		ctx.WorldEnd()

		So(ctx.End(),ShouldBeNil)

		/* output gathered stats */
		p := pipe.GetByName(PipeToStats{}.Name())
		So(p, ShouldNotBeNil)
		s, ok := p.(*PipeToStats)
		So(s, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		p = pipe.GetByName(PipeTimer{}.Name())
		So(p, ShouldNotBeNil)
		t, ok := p.(*PipeTimer)
		So(t, ShouldNotBeNil)
		So(ok, ShouldBeTrue)

		fmt.Printf("%s%s", s, t)
	})
}

<|endoftext|>