<commit_before>package dom

import (
	"fmt"
	"strings"
)

type domElement struct {
	localName     string       // The local part, without the (optional) namespace prefix.
	nodes         []Node       // Child nodes.
	parentNode    Node         // Parent node
	attributes    NamedNodeMap // Attributes on this element.
	ownerDocument Document     // Owner document.
	namespaceURI  string       // Namespace uri.

	// Element specific things:
	tagName string // The complete tagname given, with prefix.
}

func newElement() Element {
	e := &domElement{}
	return e
}

func (de *domElement) GetNodeName() string {
	return de.tagName
}

func (de *domElement) GetNodeType() NodeType {
	return ElementNode
}

// NodeValue should return null/nil for Element types like the spec says,
// but Go does not permit nil strings which are not pointers. So for now we
// just return an empty string at all times.
func (de *domElement) GetNodeValue() string {
	return ""
}

func (de *domElement) GetLocalName() string {
	if index := strings.Index(de.tagName, ":"); index >= 0 {
		return de.tagName[index+1:]
	}
	return de.tagName
}

func (de *domElement) GetChildNodes() []Node {
	return de.nodes
}

func (de *domElement) GetParentNode() Node {
	return de.parentNode
}

func (de *domElement) GetFirstChild() Node {
	if de.HasChildNodes() {
		return de.nodes[0]
	}
	return nil
}

func (de *domElement) GetAttributes() NamedNodeMap {
	return de.attributes
}

func (de *domElement) GetOwnerDocument() Document {
	return de.ownerDocument
}

func (de *domElement) AppendChild(child Node) error {
	if de == child {
		return fmt.Errorf("%v: adding a node to itself as a child", ErrorHierarchyRequest)
	}
	child.setParentNode(de)
	de.nodes = append(de.nodes, child)
	return nil
}

func (de *domElement) HasChildNodes() bool {
	return len(de.nodes) > 0
}

func (de *domElement) GetNamespaceURI() string {
	return de.namespaceURI
}

func (de *domElement) GetNamespacePrefix() string {
	// TODO: namespace prefix
	if index := strings.Index(de.tagName, ":"); index >= 0 {
		return de.tagName[0:index]
	}
	return ""
}

func (de *domElement) SetTagName(name string) {
	de.tagName = name
}

func (de *domElement) GetTagName() string {
	return de.tagName
}

func (de *domElement) SetAttribute(name, value string) {
	if de.attributes == nil {
		de.attributes = newNamedNodeMap()
	}

	attr := newAttr()
	attr.setName(name)
	attr.SetValue(value)
	attr.setOwnerElement(de)
	de.attributes.SetNamedItem(attr)
}

// SetAttributeNode adds a new attribute node. If an attribute with that name (nodeName) is
// already present in the element, it is replaced by the new one. Replacing an attribute node
// by itself has no effect. To add a new attribute node with a qualified name and namespace
// URI, use the setAttributeNodeNS method.
// TODO: implement above
func (de *domElement) SetAttributeNode(a Attr) {
	if de.attributes == nil {
		de.attributes = newNamedNodeMap()
	}

	a.setOwnerElement(de)
	de.attributes.SetNamedItem(a)
}

func (de *domElement) GetAttribute(name string) string {
	if de.attributes == nil {
		// TODO: no attributes, return empty string??
		return ""
	}
	if theAttr := de.attributes.GetNamedItem(name); theAttr != nil {
		return theAttr.GetNodeValue()
	}

	// Not found, can return an empty string as per spec.
	return ""
}

// GetElementsByTagName finds all descendant element with the given tagname.
// This implementation does a recursive search.
func (de *domElement) GetElementsByTagName(tagname string) []Element {
	var elements []Element

	var traverse func(n Node)
	traverse = func(n Node) {
		for _, child := range n.GetChildNodes() {
			// only check elements:
			if elem, ok := child.(Element); ok {
				if elem.GetNodeName() == tagname {
					elements = append(elements, elem)
				}
			}

			traverse(child)
		}
	}
	traverse(de)

	return elements
}

func (de *domElement) GetElementsByTagNameNS(namespaceURI, tagname string) []Element {
	var elements []Element

	var traverse func(n Node)
	traverse = func(n Node) {
		for _, child := range n.GetChildNodes() {
			// only check elements:
			if elem, ok := child.(Element); ok {
				if elem.GetNodeName() == tagname &&
					elem.GetNamespaceURI() == namespaceURI {
					elements = append(elements, elem)
				}
			}

			traverse(child)
		}
	}
	traverse(de)

	return elements
}

// Private functions:
func (de *domElement) setParentNode(parent Node) {
	de.parentNode = parent
}

func (de *domElement) setOwnerDocument(d Document) {
	de.ownerDocument = d
}

func (de *domElement) setNamespaceURI(uri string) {
	de.namespaceURI = uri
}

func (de *domElement) String() string {
	return fmt.Sprintf("%s, <%s>, ns=%s, attrs=%v",
		de.GetNodeType(), de.tagName, de.namespaceURI, de.attributes)
}
<commit_msg>Refactor of GetElementsByTagName(NS).<commit_after>package dom

import (
	"fmt"
	"strings"
)

type domElement struct {
	localName     string       // The local part, without the (optional) namespace prefix.
	nodes         []Node       // Child nodes.
	parentNode    Node         // Parent node
	attributes    NamedNodeMap // Attributes on this element.
	ownerDocument Document     // Owner document.
	namespaceURI  string       // Namespace uri.

	// Element specific things:
	tagName string // The complete tagname given, with prefix.
}

func newElement() Element {
	e := &domElement{}
	return e
}

func (de *domElement) GetNodeName() string {
	return de.tagName
}

func (de *domElement) GetNodeType() NodeType {
	return ElementNode
}

// NodeValue should return null/nil for Element types like the spec says,
// but Go does not permit nil strings which are not pointers. So for now we
// just return an empty string at all times.
func (de *domElement) GetNodeValue() string {
	return ""
}

func (de *domElement) GetLocalName() string {
	if index := strings.Index(de.tagName, ":"); index >= 0 {
		return de.tagName[index+1:]
	}
	return de.tagName
}

func (de *domElement) GetChildNodes() []Node {
	return de.nodes
}

func (de *domElement) GetParentNode() Node {
	return de.parentNode
}

func (de *domElement) GetFirstChild() Node {
	if de.HasChildNodes() {
		return de.nodes[0]
	}
	return nil
}

func (de *domElement) GetAttributes() NamedNodeMap {
	return de.attributes
}

func (de *domElement) GetOwnerDocument() Document {
	return de.ownerDocument
}

func (de *domElement) AppendChild(child Node) error {
	if de == child {
		return fmt.Errorf("%v: adding a node to itself as a child", ErrorHierarchyRequest)
	}
	child.setParentNode(de)
	de.nodes = append(de.nodes, child)
	return nil
}

func (de *domElement) HasChildNodes() bool {
	return len(de.nodes) > 0
}

func (de *domElement) GetNamespaceURI() string {
	return de.namespaceURI
}

func (de *domElement) GetNamespacePrefix() string {
	// TODO: namespace prefix
	if index := strings.Index(de.tagName, ":"); index >= 0 {
		return de.tagName[0:index]
	}
	return ""
}

func (de *domElement) SetTagName(name string) {
	de.tagName = name
}

func (de *domElement) GetTagName() string {
	return de.tagName
}

func (de *domElement) SetAttribute(name, value string) {
	if de.attributes == nil {
		de.attributes = newNamedNodeMap()
	}

	attr := newAttr()
	attr.setName(name)
	attr.SetValue(value)
	attr.setOwnerElement(de)
	de.attributes.SetNamedItem(attr)
}

// SetAttributeNode adds a new attribute node. If an attribute with that name (nodeName) is
// already present in the element, it is replaced by the new one. Replacing an attribute node
// by itself has no effect. To add a new attribute node with a qualified name and namespace
// URI, use the setAttributeNodeNS method.
// TODO: implement above
func (de *domElement) SetAttributeNode(a Attr) {
	if de.attributes == nil {
		de.attributes = newNamedNodeMap()
	}

	a.setOwnerElement(de)
	de.attributes.SetNamedItem(a)
}

func (de *domElement) GetAttribute(name string) string {
	if de.attributes == nil {
		// TODO: no attributes, return empty string??
		return ""
	}
	if theAttr := de.attributes.GetNamedItem(name); theAttr != nil {
		return theAttr.GetNodeValue()
	}

	// Not found, can return an empty string as per spec.
	return ""
}

// GetElementsByTagName finds all descendant element with the given tagname.
// This implementation does a recursive search.
func (de *domElement) GetElementsByTagName(tagname string) []Element {
	return de.getElementsBy("", tagname, false)
}

func (de *domElement) GetElementsByTagNameNS(namespaceURI, tagname string) []Element {
	return de.getElementsBy(namespaceURI, tagname, true)
}

// getElementsBy finds descandant elements with the given (optional) namespaceURI and tagname.
// When the 'includeNamespace' is set to true, the namespace URI is explicitly checked for
// equality. If false, no namespace check will be done. The elements are returned as a 'live'
// slice.
func (de *domElement) getElementsBy(namespaceURI, tagname string, includeNamespace bool) []Element {
	var elements []Element

	var traverse func(n Node)
	traverse = func(n Node) {
		for _, child := range n.GetChildNodes() {
			// only check elements:
			if elem, ok := child.(Element); ok {
				if includeNamespace && elem.GetNodeName() == tagname && elem.GetNamespaceURI() == namespaceURI {
					// include namespace equality, if chosen.
					elements = append(elements, elem)
				} else if !includeNamespace && elem.GetNodeName() == tagname {
					// do not include namespace equality, just the tagname
					elements = append(elements, elem)
				}

			}

			traverse(child)
		}
	}
	traverse(de)

	return elements
}

// Private functions:
func (de *domElement) setParentNode(parent Node) {
	de.parentNode = parent
}

func (de *domElement) setOwnerDocument(d Document) {
	de.ownerDocument = d
}

func (de *domElement) setNamespaceURI(uri string) {
	de.namespaceURI = uri
}

func (de *domElement) String() string {
	return fmt.Sprintf("%s, <%s>, ns=%s, attrs=%v",
		de.GetNodeType(), de.tagName, de.namespaceURI, de.attributes)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package memfs_test

import (
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
	"testing"
	"time"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/samples/memfs"
	"github.com/jacobsa/gcsfuse/timeutil"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

func TestMemFS(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type MemFSTest struct {
	clock timeutil.SimulatedClock
	mfs   *fuse.MountedFileSystem
}

var _ SetUpInterface = &MemFSTest{}
var _ TearDownInterface = &MemFSTest{}

func init() { RegisterTestSuite(&MemFSTest{}) }

func (t *MemFSTest) SetUp(ti *TestInfo) {
	var err error

	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Now())

	// Set up a temporary directory for mounting.
	mountPoint, err := ioutil.TempDir("", "memfs_test")
	if err != nil {
		panic("ioutil.TempDir: " + err.Error())
	}

	// Mount a file system.
	fs := memfs.NewMemFS(&t.clock)
	if t.mfs, err = fuse.Mount(mountPoint, fs); err != nil {
		panic("Mount: " + err.Error())
	}

	if err = t.mfs.WaitForReady(context.Background()); err != nil {
		panic("MountedFileSystem.WaitForReady: " + err.Error())
	}
}

func (t *MemFSTest) TearDown() {
	// Unmount the file system. Try again on "resource busy" errors.
	delay := 10 * time.Millisecond
	for {
		err := t.mfs.Unmount()
		if err == nil {
			break
		}

		if strings.Contains(err.Error(), "resource busy") {
			log.Println("Resource busy error while unmounting; trying again")
			time.Sleep(delay)
			delay = time.Duration(1.3 * float64(delay))
			continue
		}

		panic("MountedFileSystem.Unmount: " + err.Error())
	}

	if err := t.mfs.Join(context.Background()); err != nil {
		panic("MountedFileSystem.Join: " + err.Error())
	}
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *MemFSTest) ContentsOfEmptyFileSystem() {
	entries, err := ioutil.ReadDir(t.mfs.Dir())

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir() {
	var err error
	var fi os.FileInfo
	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create a directory within the root.
	createTime := t.clock.Now()
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Simulate time proceeding.
	t.clock.AdvanceTime(time.Second)

	// Stat the directory.
	fi, err = os.Stat(dirName)

	AssertEq(nil, err)
	ExpectEq("dir", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(os.ModeDir|0754, fi.Mode())
	ExpectEq(0, fi.ModTime().Sub(createTime))
	ExpectTrue(fi.IsDir())

	// Read the directory.
	entries, err := ioutil.ReadDir(dirName)

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir_AlreadyExists() {
	var err error
	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create the directory once.
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Attempt to create it again.
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("exists")))
}

func (t *MemFSTest) Mkdir_IntermediateIsFile() {
	var err error

	// Create a file.
	fileName := path.Join(t.mfs.Dir(), "foo")
	err = ioutil.WriteFile(fileName, []byte{}, 0700)
	AssertEq(nil, err)

	// Attempt to create a directory within the file.
	dirName := path.Join(fileName, "dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}

func (t *MemFSTest) Mkdir_IntermediateIsNonExistent() {
	var err error

	// Attempt to create a sub-directory of a non-existent sub-directory.
	dirName := path.Join(t.mfs.Dir(), "foo/dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("no such file or directory")))
}

func (t *MemFSTest) CreateNewFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) CreateNewFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NotAFile() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NonExistent() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonEmpty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_Empty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NotADirectory() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonExistent() {
	AssertTrue(false, "TODO")
}
<commit_msg>Added better tests for statting new dirs.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package memfs_test

import (
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
	"syscall"
	"testing"
	"time"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/samples/memfs"
	"github.com/jacobsa/gcsfuse/timeutil"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

func TestMemFS(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func currentUid() uint32

func currentGid() uint32

func timespecToTime(ts syscall.Timespec) time.Time

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type MemFSTest struct {
	clock timeutil.SimulatedClock
	mfs   *fuse.MountedFileSystem
}

var _ SetUpInterface = &MemFSTest{}
var _ TearDownInterface = &MemFSTest{}

func init() { RegisterTestSuite(&MemFSTest{}) }

func (t *MemFSTest) SetUp(ti *TestInfo) {
	var err error

	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Now())

	// Set up a temporary directory for mounting.
	mountPoint, err := ioutil.TempDir("", "memfs_test")
	if err != nil {
		panic("ioutil.TempDir: " + err.Error())
	}

	// Mount a file system.
	fs := memfs.NewMemFS(&t.clock)
	if t.mfs, err = fuse.Mount(mountPoint, fs); err != nil {
		panic("Mount: " + err.Error())
	}

	if err = t.mfs.WaitForReady(context.Background()); err != nil {
		panic("MountedFileSystem.WaitForReady: " + err.Error())
	}
}

func (t *MemFSTest) TearDown() {
	// Unmount the file system. Try again on "resource busy" errors.
	delay := 10 * time.Millisecond
	for {
		err := t.mfs.Unmount()
		if err == nil {
			break
		}

		if strings.Contains(err.Error(), "resource busy") {
			log.Println("Resource busy error while unmounting; trying again")
			time.Sleep(delay)
			delay = time.Duration(1.3 * float64(delay))
			continue
		}

		panic("MountedFileSystem.Unmount: " + err.Error())
	}

	if err := t.mfs.Join(context.Background()); err != nil {
		panic("MountedFileSystem.Join: " + err.Error())
	}
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *MemFSTest) ContentsOfEmptyFileSystem() {
	entries, err := ioutil.ReadDir(t.mfs.Dir())

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir() {
	var err error
	var fi os.FileInfo
	var stat *syscall.Stat_t

	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create a directory within the root.
	createTime := t.clock.Now()
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Simulate time proceeding.
	t.clock.AdvanceTime(time.Second)

	// Stat the directory.
	fi, err = os.Stat(dirName)
	stat = fi.Sys().(*syscall.Stat_t)

	AssertEq(nil, err)
	ExpectEq("dir", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(os.ModeDir|0754, fi.Mode())
	ExpectEq(0, fi.ModTime().Sub(createTime))
	ExpectTrue(fi.IsDir())

	ExpectEq(1, stat.Nlink)
	ExpectEq(currentUid(), stat.Uid)
	ExpectEq(currentGid(), stat.Gid)
	ExpectEq(0, stat.Size)
	ExpectEq(createTime, timespecToTime(stat.Atimespec))
	ExpectEq(createTime, timespecToTime(stat.Mtimespec))
	ExpectEq(createTime, timespecToTime(stat.Ctimespec))

	// Read the directory.
	entries, err := ioutil.ReadDir(dirName)

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir_AlreadyExists() {
	var err error
	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create the directory once.
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Attempt to create it again.
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("exists")))
}

func (t *MemFSTest) Mkdir_IntermediateIsFile() {
	var err error

	// Create a file.
	fileName := path.Join(t.mfs.Dir(), "foo")
	err = ioutil.WriteFile(fileName, []byte{}, 0700)
	AssertEq(nil, err)

	// Attempt to create a directory within the file.
	dirName := path.Join(fileName, "dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}

func (t *MemFSTest) Mkdir_IntermediateIsNonExistent() {
	var err error

	// Attempt to create a sub-directory of a non-existent sub-directory.
	dirName := path.Join(t.mfs.Dir(), "foo/dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("no such file or directory")))
}

func (t *MemFSTest) CreateNewFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) CreateNewFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NotAFile() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NonExistent() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonEmpty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_Empty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NotADirectory() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonExistent() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/golang/protobuf/protoc-gen-go/plugin"

	pgghelpers "moul.io/protoc-gen-gotemplate/helpers"
)

type GenericTemplateBasedEncoder struct {
	templateDir    string
	service        *descriptor.ServiceDescriptorProto
	file           *descriptor.FileDescriptorProto
	enum           []*descriptor.EnumDescriptorProto
	debug          bool
	destinationDir string
}

type Ast struct {
	BuildDate      time.Time                          `json:"build-date"`
	BuildHostname  string                             `json:"build-hostname"`
	BuildUser      string                             `json:"build-user"`
	GoPWD          string                             `json:"go-pwd,omitempty"`
	PWD            string                             `json:"pwd"`
	Debug          bool                               `json:"debug"`
	DestinationDir string                             `json:"destination-dir"`
	File           *descriptor.FileDescriptorProto    `json:"file"`
	RawFilename    string                             `json:"raw-filename"`
	Filename       string                             `json:"filename"`
	TemplateDir    string                             `json:"template-dir"`
	Service        *descriptor.ServiceDescriptorProto `json:"service"`
	Enum           []*descriptor.EnumDescriptorProto  `json:"enum"`
}

func NewGenericServiceTemplateBasedEncoder(templateDir string, service *descriptor.ServiceDescriptorProto, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) {
	e = &GenericTemplateBasedEncoder{
		service:        service,
		file:           file,
		templateDir:    templateDir,
		debug:          debug,
		destinationDir: destinationDir,
		enum:           file.GetEnumType(),
	}
	if debug {
		log.Printf("new encoder: file=%q service=%q template-dir=%q", file.GetName(), service.GetName(), templateDir)
	}
	pgghelpers.InitPathMap(file)

	return
}

func NewGenericTemplateBasedEncoder(templateDir string, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) {
	e = &GenericTemplateBasedEncoder{
		service:        nil,
		file:           file,
		templateDir:    templateDir,
		enum:           file.GetEnumType(),
		debug:          debug,
		destinationDir: destinationDir,
	}
	if debug {
		log.Printf("new encoder: file=%q template-dir=%q", file.GetName(), templateDir)
	}
	pgghelpers.InitPathMap(file)

	return
}

func (e *GenericTemplateBasedEncoder) templates() ([]string, error) {
	filenames := []string{}

	err := filepath.Walk(e.templateDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if filepath.Ext(path) != ".tmpl" {
			return nil
		}
		rel, err := filepath.Rel(e.templateDir, path)
		if err != nil {
			return err
		}
		if e.debug {
			log.Printf("new template: %q", rel)
		}

		filenames = append(filenames, rel)
		return nil
	})
	return filenames, err
}

func (e *GenericTemplateBasedEncoder) genAst(templateFilename string) (*Ast, error) {
	// prepare the ast passed to the template engine
	hostname, err := os.Hostname()
	if err != nil {
		return nil, err
	}
	pwd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	goPwd := ""
	if os.Getenv("GOPATH") != "" {
		goPwd, err = filepath.Rel(os.Getenv("GOPATH")+"/src", pwd)
		if err != nil {
			return nil, err
		}
		if strings.Contains(goPwd, "../") {
			goPwd = ""
		}
	}
	ast := Ast{
		BuildDate:      time.Now(),
		BuildHostname:  hostname,
		BuildUser:      os.Getenv("USER"),
		PWD:            pwd,
		GoPWD:          goPwd,
		File:           e.file,
		TemplateDir:    e.templateDir,
		DestinationDir: e.destinationDir,
		RawFilename:    templateFilename,
		Filename:       "",
		Service:        e.service,
		Enum:           e.enum,
	}
	buffer := new(bytes.Buffer)

	unescaped, err := url.QueryUnescape(templateFilename)
	if err != nil {
		log.Printf("failed to unescape filepath %q: %v", templateFilename, err)
	} else {
		templateFilename = unescaped
	}

	tmpl, err := template.New("").Funcs(pgghelpers.ProtoHelpersFuncMap).Parse(templateFilename)
	if err != nil {
		return nil, err
	}
	if err := tmpl.Execute(buffer, ast); err != nil {
		return nil, err
	}
	ast.Filename = buffer.String()
	return &ast, nil
}

func (e *GenericTemplateBasedEncoder) buildContent(templateFilename string) (string, string, error) {
	// initialize template engine
	fullPath := filepath.Join(e.templateDir, templateFilename)
	templateName := filepath.Base(fullPath)
	tmpl, err := template.New(templateName).Funcs(pgghelpers.ProtoHelpersFuncMap).ParseFiles(fullPath)
	if err != nil {
		return "", "", err
	}

	ast, err := e.genAst(templateFilename)
	if err != nil {
		return "", "", err
	}

	// generate the content
	buffer := new(bytes.Buffer)
	if err := tmpl.Execute(buffer, ast); err != nil {
		return "", "", err
	}

	return buffer.String(), ast.Filename, nil
}

func (e *GenericTemplateBasedEncoder) Files() []*plugin_go.CodeGeneratorResponse_File {
	templates, err := e.templates()
	if err != nil {
		log.Fatalf("cannot get templates from %q: %v", e.templateDir, err)
	}

	length := len(templates)
	files := make([]*plugin_go.CodeGeneratorResponse_File, 0, length)
	errChan := make(chan error, length)
	resultChan := make(chan *plugin_go.CodeGeneratorResponse_File, length)
	for _, templateFilename := range templates {
		go func(tmpl string) {
			var translatedFilename, content string
			content, translatedFilename, err = e.buildContent(tmpl)
			if err != nil {
				errChan <- err
				return
			}
			filename := translatedFilename[:len(translatedFilename)-len(".tmpl")]

			resultChan <- &plugin_go.CodeGeneratorResponse_File{
				Content: &content,
				Name:    &filename,
			}
		}(templateFilename)
	}
	for i := 0; i < length; i++ {
		select {
		case f := <-resultChan:
			files = append(files, f)
		case err = <-errChan:
		}
	}
	if err != nil {
		panic(err)
	}
	return files
}
<commit_msg>fixes intermittent error reporting<commit_after>package main

import (
	"bytes"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/golang/protobuf/protoc-gen-go/plugin"

	pgghelpers "moul.io/protoc-gen-gotemplate/helpers"
)

type GenericTemplateBasedEncoder struct {
	templateDir    string
	service        *descriptor.ServiceDescriptorProto
	file           *descriptor.FileDescriptorProto
	enum           []*descriptor.EnumDescriptorProto
	debug          bool
	destinationDir string
}

type Ast struct {
	BuildDate      time.Time                          `json:"build-date"`
	BuildHostname  string                             `json:"build-hostname"`
	BuildUser      string                             `json:"build-user"`
	GoPWD          string                             `json:"go-pwd,omitempty"`
	PWD            string                             `json:"pwd"`
	Debug          bool                               `json:"debug"`
	DestinationDir string                             `json:"destination-dir"`
	File           *descriptor.FileDescriptorProto    `json:"file"`
	RawFilename    string                             `json:"raw-filename"`
	Filename       string                             `json:"filename"`
	TemplateDir    string                             `json:"template-dir"`
	Service        *descriptor.ServiceDescriptorProto `json:"service"`
	Enum           []*descriptor.EnumDescriptorProto  `json:"enum"`
}

func NewGenericServiceTemplateBasedEncoder(templateDir string, service *descriptor.ServiceDescriptorProto, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) {
	e = &GenericTemplateBasedEncoder{
		service:        service,
		file:           file,
		templateDir:    templateDir,
		debug:          debug,
		destinationDir: destinationDir,
		enum:           file.GetEnumType(),
	}
	if debug {
		log.Printf("new encoder: file=%q service=%q template-dir=%q", file.GetName(), service.GetName(), templateDir)
	}
	pgghelpers.InitPathMap(file)

	return
}

func NewGenericTemplateBasedEncoder(templateDir string, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) {
	e = &GenericTemplateBasedEncoder{
		service:        nil,
		file:           file,
		templateDir:    templateDir,
		enum:           file.GetEnumType(),
		debug:          debug,
		destinationDir: destinationDir,
	}
	if debug {
		log.Printf("new encoder: file=%q template-dir=%q", file.GetName(), templateDir)
	}
	pgghelpers.InitPathMap(file)

	return
}

func (e *GenericTemplateBasedEncoder) templates() ([]string, error) {
	filenames := []string{}

	err := filepath.Walk(e.templateDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		if filepath.Ext(path) != ".tmpl" {
			return nil
		}
		rel, err := filepath.Rel(e.templateDir, path)
		if err != nil {
			return err
		}
		if e.debug {
			log.Printf("new template: %q", rel)
		}

		filenames = append(filenames, rel)
		return nil
	})
	return filenames, err
}

func (e *GenericTemplateBasedEncoder) genAst(templateFilename string) (*Ast, error) {
	// prepare the ast passed to the template engine
	hostname, err := os.Hostname()
	if err != nil {
		return nil, err
	}
	pwd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	goPwd := ""
	if os.Getenv("GOPATH") != "" {
		goPwd, err = filepath.Rel(os.Getenv("GOPATH")+"/src", pwd)
		if err != nil {
			return nil, err
		}
		if strings.Contains(goPwd, "../") {
			goPwd = ""
		}
	}
	ast := Ast{
		BuildDate:      time.Now(),
		BuildHostname:  hostname,
		BuildUser:      os.Getenv("USER"),
		PWD:            pwd,
		GoPWD:          goPwd,
		File:           e.file,
		TemplateDir:    e.templateDir,
		DestinationDir: e.destinationDir,
		RawFilename:    templateFilename,
		Filename:       "",
		Service:        e.service,
		Enum:           e.enum,
	}
	buffer := new(bytes.Buffer)

	unescaped, err := url.QueryUnescape(templateFilename)
	if err != nil {
		log.Printf("failed to unescape filepath %q: %v", templateFilename, err)
	} else {
		templateFilename = unescaped
	}

	tmpl, err := template.New("").Funcs(pgghelpers.ProtoHelpersFuncMap).Parse(templateFilename)
	if err != nil {
		return nil, err
	}
	if err := tmpl.Execute(buffer, ast); err != nil {
		return nil, err
	}
	ast.Filename = buffer.String()
	return &ast, nil
}

func (e *GenericTemplateBasedEncoder) buildContent(templateFilename string) (string, string, error) {
	// initialize template engine
	fullPath := filepath.Join(e.templateDir, templateFilename)
	templateName := filepath.Base(fullPath)
	tmpl, err := template.New(templateName).Funcs(pgghelpers.ProtoHelpersFuncMap).ParseFiles(fullPath)
	if err != nil {
		return "", "", err
	}

	ast, err := e.genAst(templateFilename)
	if err != nil {
		return "", "", err
	}

	// generate the content
	buffer := new(bytes.Buffer)
	if err := tmpl.Execute(buffer, ast); err != nil {
		return "", "", err
	}

	return buffer.String(), ast.Filename, nil
}

func (e *GenericTemplateBasedEncoder) Files() []*plugin_go.CodeGeneratorResponse_File {
	templates, err := e.templates()
	if err != nil {
		log.Fatalf("cannot get templates from %q: %v", e.templateDir, err)
	}

	length := len(templates)
	files := make([]*plugin_go.CodeGeneratorResponse_File, 0, length)
	errChan := make(chan error, length)
	resultChan := make(chan *plugin_go.CodeGeneratorResponse_File, length)
	for _, templateFilename := range templates {
		go func(tmpl string) {
			var translatedFilename, content string
			content, translatedFilename, err = e.buildContent(tmpl)
			if err != nil {
				errChan <- err
				return
			}
			filename := translatedFilename[:len(translatedFilename)-len(".tmpl")]

			resultChan <- &plugin_go.CodeGeneratorResponse_File{
				Content: &content,
				Name:    &filename,
			}
		}(templateFilename)
	}
	for i := 0; i < length; i++ {
		select {
		case f := <-resultChan:
			files = append(files, f)
		case err = <-errChan:
			panic(err)
		}
	}
	return files
}
<|endoftext|>


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

package runtime_test

import (
	"bytes"
	"runtime"
	"testing"
)

const (
	typeScalar  = 0
	typePointer = 1
)

// TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
func TestGCInfo(t *testing.T) {
	verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
	verifyGCInfo(t, "bss string", &bssString, infoString)
	verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
	verifyGCInfo(t, "bss iface", &bssIface, infoIface)

	verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
	verifyGCInfo(t, "data string", &dataString, infoString)
	verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
	verifyGCInfo(t, "data eface", &dataEface, infoEface)
	verifyGCInfo(t, "data iface", &dataIface, infoIface)

	{
		var x Ptr
		verifyGCInfo(t, "stack Ptr", &x, infoPtr)
		runtime.KeepAlive(x)
	}
	{
		var x ScalarPtr
		verifyGCInfo(t, "stack ScalarPtr", &x, infoScalarPtr)
		runtime.KeepAlive(x)
	}
	{
		var x PtrScalar
		verifyGCInfo(t, "stack PtrScalar", &x, infoPtrScalar)
		runtime.KeepAlive(x)
	}
	{
		var x BigStruct
		verifyGCInfo(t, "stack BigStruct", &x, infoBigStruct())
		runtime.KeepAlive(x)
	}
	{
		var x string
		verifyGCInfo(t, "stack string", &x, infoString)
		runtime.KeepAlive(x)
	}
	{
		var x []string
		verifyGCInfo(t, "stack slice", &x, infoSlice)
		runtime.KeepAlive(x)
	}
	{
		var x any
		verifyGCInfo(t, "stack eface", &x, infoEface)
		runtime.KeepAlive(x)
	}
	{
		var x Iface
		verifyGCInfo(t, "stack iface", &x, infoIface)
		runtime.KeepAlive(x)
	}

	for i := 0; i < 10; i++ {
		verifyGCInfo(t, "heap Ptr", runtime.Escape(new(Ptr)), trimDead(infoPtr))
		verifyGCInfo(t, "heap PtrSlice", runtime.Escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
		verifyGCInfo(t, "heap ScalarPtr", runtime.Escape(new(ScalarPtr)), trimDead(infoScalarPtr))
		verifyGCInfo(t, "heap ScalarPtrSlice", runtime.Escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
		verifyGCInfo(t, "heap PtrScalar", runtime.Escape(new(PtrScalar)), trimDead(infoPtrScalar))
		verifyGCInfo(t, "heap BigStruct", runtime.Escape(new(BigStruct)), trimDead(infoBigStruct()))
		verifyGCInfo(t, "heap string", runtime.Escape(new(string)), trimDead(infoString))
		verifyGCInfo(t, "heap eface", runtime.Escape(new(any)), trimDead(infoEface))
		verifyGCInfo(t, "heap iface", runtime.Escape(new(Iface)), trimDead(infoIface))
	}
}

func verifyGCInfo(t *testing.T, name string, p any, mask0 []byte) {
	mask := runtime.GCMask(p)
	if !bytes.Equal(mask, mask0) {
		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
		return
	}
}

func trimDead(mask []byte) []byte {
	for len(mask) > 0 && mask[len(mask)-1] == typeScalar {
		mask = mask[:len(mask)-1]
	}
	return mask
}

var infoPtr = []byte{typePointer}

type Ptr struct {
	*byte
}

var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}

type ScalarPtr struct {
	q int
	w *int
	e int
	r *int
	t int
	y *int
}

var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}

var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)

type PtrScalar struct {
	q *int
	w int
	e *int
	r int
	t *int
	y int
}

var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}

type BigStruct struct {
	q *int
	w byte
	e [17]byte
	r []byte
	t int
	y uint16
	u uint64
	i string
}

func infoBigStruct() []byte {
	switch runtime.GOARCH {
	case "386", "arm", "mips", "mipsle":
		return []byte{
			typePointer,                                                // q *int
			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
			typePointer, typeScalar, typeScalar, // r []byte
			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
			typePointer, typeScalar, // i string
		}
	case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm":
		return []byte{
			typePointer,                        // q *int
			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
			typePointer, typeScalar, typeScalar, // r []byte
			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
			typePointer, typeScalar, // i string
		}
	default:
		panic("unknown arch")
	}
}

type Iface interface {
	f()
}

type IfaceImpl int

func (IfaceImpl) f() {
}

var (
	// BSS
	bssPtr       Ptr
	bssScalarPtr ScalarPtr
	bssPtrScalar PtrScalar
	bssBigStruct BigStruct
	bssString    string
	bssSlice     []string
	bssEface     any
	bssIface     Iface

	// DATA
	dataPtr             = Ptr{new(byte)}
	dataScalarPtr       = ScalarPtr{q: 1}
	dataPtrScalar       = PtrScalar{w: 1}
	dataBigStruct       = BigStruct{w: 1}
	dataString          = "foo"
	dataSlice           = []string{"foo"}
	dataEface     any   = 42
	dataIface     Iface = IfaceImpl(42)

	infoString = []byte{typePointer, typeScalar}
	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
	infoEface  = []byte{typeScalar, typePointer}
	infoIface  = []byte{typeScalar, typePointer}
)
<commit_msg>runtime: add loong64 to architectures known to TestGCInfo<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime_test

import (
	"bytes"
	"runtime"
	"testing"
)

const (
	typeScalar  = 0
	typePointer = 1
)

// TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
func TestGCInfo(t *testing.T) {
	verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
	verifyGCInfo(t, "bss string", &bssString, infoString)
	verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
	verifyGCInfo(t, "bss iface", &bssIface, infoIface)

	verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
	verifyGCInfo(t, "data string", &dataString, infoString)
	verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
	verifyGCInfo(t, "data eface", &dataEface, infoEface)
	verifyGCInfo(t, "data iface", &dataIface, infoIface)

	{
		var x Ptr
		verifyGCInfo(t, "stack Ptr", &x, infoPtr)
		runtime.KeepAlive(x)
	}
	{
		var x ScalarPtr
		verifyGCInfo(t, "stack ScalarPtr", &x, infoScalarPtr)
		runtime.KeepAlive(x)
	}
	{
		var x PtrScalar
		verifyGCInfo(t, "stack PtrScalar", &x, infoPtrScalar)
		runtime.KeepAlive(x)
	}
	{
		var x BigStruct
		verifyGCInfo(t, "stack BigStruct", &x, infoBigStruct())
		runtime.KeepAlive(x)
	}
	{
		var x string
		verifyGCInfo(t, "stack string", &x, infoString)
		runtime.KeepAlive(x)
	}
	{
		var x []string
		verifyGCInfo(t, "stack slice", &x, infoSlice)
		runtime.KeepAlive(x)
	}
	{
		var x any
		verifyGCInfo(t, "stack eface", &x, infoEface)
		runtime.KeepAlive(x)
	}
	{
		var x Iface
		verifyGCInfo(t, "stack iface", &x, infoIface)
		runtime.KeepAlive(x)
	}

	for i := 0; i < 10; i++ {
		verifyGCInfo(t, "heap Ptr", runtime.Escape(new(Ptr)), trimDead(infoPtr))
		verifyGCInfo(t, "heap PtrSlice", runtime.Escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
		verifyGCInfo(t, "heap ScalarPtr", runtime.Escape(new(ScalarPtr)), trimDead(infoScalarPtr))
		verifyGCInfo(t, "heap ScalarPtrSlice", runtime.Escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
		verifyGCInfo(t, "heap PtrScalar", runtime.Escape(new(PtrScalar)), trimDead(infoPtrScalar))
		verifyGCInfo(t, "heap BigStruct", runtime.Escape(new(BigStruct)), trimDead(infoBigStruct()))
		verifyGCInfo(t, "heap string", runtime.Escape(new(string)), trimDead(infoString))
		verifyGCInfo(t, "heap eface", runtime.Escape(new(any)), trimDead(infoEface))
		verifyGCInfo(t, "heap iface", runtime.Escape(new(Iface)), trimDead(infoIface))
	}
}

func verifyGCInfo(t *testing.T, name string, p any, mask0 []byte) {
	mask := runtime.GCMask(p)
	if !bytes.Equal(mask, mask0) {
		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
		return
	}
}

func trimDead(mask []byte) []byte {
	for len(mask) > 0 && mask[len(mask)-1] == typeScalar {
		mask = mask[:len(mask)-1]
	}
	return mask
}

var infoPtr = []byte{typePointer}

type Ptr struct {
	*byte
}

var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}

type ScalarPtr struct {
	q int
	w *int
	e int
	r *int
	t int
	y *int
}

var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}

var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)

type PtrScalar struct {
	q *int
	w int
	e *int
	r int
	t *int
	y int
}

var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}

type BigStruct struct {
	q *int
	w byte
	e [17]byte
	r []byte
	t int
	y uint16
	u uint64
	i string
}

func infoBigStruct() []byte {
	switch runtime.GOARCH {
	case "386", "arm", "mips", "mipsle":
		return []byte{
			typePointer,                                                // q *int
			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
			typePointer, typeScalar, typeScalar, // r []byte
			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
			typePointer, typeScalar, // i string
		}
	case "arm64", "amd64", "loong64", "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm":
		return []byte{
			typePointer,                        // q *int
			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
			typePointer, typeScalar, typeScalar, // r []byte
			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
			typePointer, typeScalar, // i string
		}
	default:
		panic("unknown arch")
	}
}

type Iface interface {
	f()
}

type IfaceImpl int

func (IfaceImpl) f() {
}

var (
	// BSS
	bssPtr       Ptr
	bssScalarPtr ScalarPtr
	bssPtrScalar PtrScalar
	bssBigStruct BigStruct
	bssString    string
	bssSlice     []string
	bssEface     any
	bssIface     Iface

	// DATA
	dataPtr             = Ptr{new(byte)}
	dataScalarPtr       = ScalarPtr{q: 1}
	dataPtrScalar       = PtrScalar{w: 1}
	dataBigStruct       = BigStruct{w: 1}
	dataString          = "foo"
	dataSlice           = []string{"foo"}
	dataEface     any   = 42
	dataIface     Iface = IfaceImpl(42)

	infoString = []byte{typePointer, typeScalar}
	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
	infoEface  = []byte{typeScalar, typePointer}
	infoIface  = []byte{typeScalar, typePointer}
)
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 genesis

import (
	"fmt"
	"sync"

	"golang.org/x/net/context"

	"github.com/op/go-logging"
	"github.com/openblockchain/obc-peer/openchain"
	"github.com/openblockchain/obc-peer/openchain/chaincode"
	"github.com/openblockchain/obc-peer/openchain/container"
	"github.com/openblockchain/obc-peer/openchain/crypto"
	"github.com/openblockchain/obc-peer/openchain/ledger"
	"github.com/openblockchain/obc-peer/protos"
	"github.com/spf13/viper"
)

var genesisLogger = logging.MustGetLogger("genesis")

var makeGenesisError error
var once sync.Once

// MakeGenesis creates the genesis block based on configuration in openchain.yaml
// and adds it to the blockchain.
func MakeGenesis(secCxt crypto.Peer) error {
	once.Do(func() {
		ledger, err := ledger.GetLedger()
		if err != nil {
			makeGenesisError = err
			return
		}

		if ledger.GetBlockchainSize() > 0 {
			// genesis block already exists
			return
		}

		genesisLogger.Info("Creating genesis block.")

		ledger.BeginTxBatch(0)
		var genesisTransactions []*protos.Transaction

		if deploySystemChaincodeEnabled() {
			vpTransaction, deployErr := deployUpdateValidityPeriodChaincode(secCxt)

			if deployErr != nil {
				genesisLogger.Error("Error deploying chaincode for genesis block.", deployErr)
				makeGenesisError = deployErr
				return
			}

			genesisTransactions = append(genesisTransactions, vpTransaction)

			fmt.Println("*********************!!!!!!!!!!!!!!!********** ID %s", vpTransaction.ChaincodeID.Name)
		}

		genesis := viper.GetStringMap("ledger.blockchain.genesisBlock")

		if genesis == nil {
			genesisLogger.Info("No genesis block chaincodes defined.")
		} else {

			chaincodes, chaincodesOK := genesis["chaincode"].([]interface{})
			if !chaincodesOK {
				genesisLogger.Info("No genesis block chaincodes defined.")
				ledger.CommitTxBatch(0, genesisTransactions, nil)
				return
			}

			genesisLogger.Debug("Genesis chaincodes are %s", chaincodes)

			for i := 0; i < len(chaincodes); i++ {
				genesisLogger.Debug("Chaincode %d is %s", i, chaincodes[i])

				chaincodeMap, chaincodeMapOK := chaincodes[i].(map[interface{}]interface{})
				if !chaincodeMapOK {
					genesisLogger.Error("Invalid chaincode defined in genesis configuration:", chaincodes[i])
					makeGenesisError = fmt.Errorf("Invalid chaincode defined in genesis configuration: %s", chaincodes[i])
					return
				}

				path, pathOK := chaincodeMap["path"].(string)
				if !pathOK {
					genesisLogger.Error("Invalid chaincode URL defined in genesis configuration:", chaincodeMap["path"])
					makeGenesisError = fmt.Errorf("Invalid chaincode URL defined in genesis configuration: %s", chaincodeMap["path"])
					return
				}

				chaincodeType, chaincodeTypeOK := chaincodeMap["type"].(string)
				if !chaincodeTypeOK {
					genesisLogger.Error("Invalid chaincode type defined in genesis configuration:", chaincodeMap["type"])
					makeGenesisError = fmt.Errorf("Invalid chaincode type defined in genesis configuration: %s", chaincodeMap["type"])
					return
				}

				chaincodeID := &protos.ChaincodeID{Path: path, Name: ""}

				genesisLogger.Debug("Genesis chaincodeID %s", chaincodeID)
				genesisLogger.Debug("Genesis chaincode type %s", chaincodeType)

				constructorMap, constructorMapOK := chaincodeMap["constructor"].(map[interface{}]interface{})
				if !constructorMapOK {
					genesisLogger.Error("Invalid chaincode constructor defined in genesis configuration:", chaincodeMap["constructor"])
					makeGenesisError = fmt.Errorf("Invalid chaincode constructor defined in genesis configuration: %s", chaincodeMap["constructor"])
					return
				}

				var spec protos.ChaincodeSpec
				if constructorMap == nil {
					genesisLogger.Debug("Genesis chaincode has no constructor.")
					spec = protos.ChaincodeSpec{Type: protos.ChaincodeSpec_Type(protos.ChaincodeSpec_Type_value[chaincodeType]), ChaincodeID: chaincodeID}
				} else {

					ctorFunc, ctorFuncOK := constructorMap["func"].(string)
					if !ctorFuncOK {
						genesisLogger.Error("Invalid chaincode constructor function defined in genesis configuration:", constructorMap["func"])
						makeGenesisError = fmt.Errorf("Invalid chaincode constructor function args defined in genesis configuration: %s", constructorMap["func"])
						return
					}

					ctorArgs, ctorArgsOK := constructorMap["args"].([]interface{})
					if !ctorArgsOK {
						genesisLogger.Error("Invalid chaincode constructor args defined in genesis configuration:", constructorMap["args"])
						makeGenesisError = fmt.Errorf("Invalid chaincode constructor args defined in genesis configuration: %s", constructorMap["args"])
						return
					}

					genesisLogger.Debug("Genesis chaincode constructor func %s", ctorFunc)
					genesisLogger.Debug("Genesis chaincode constructor args %s", ctorArgs)
					var ctorArgsStringArray []string
					for j := 0; j < len(ctorArgs); j++ {
						ctorArgsStringArray = append(ctorArgsStringArray, ctorArgs[j].(string))
					}

					spec = protos.ChaincodeSpec{Type: protos.ChaincodeSpec_Type(protos.ChaincodeSpec_Type_value[chaincodeType]), ChaincodeID: chaincodeID, CtorMsg: &protos.ChaincodeInput{Function: ctorFunc, Args: ctorArgsStringArray}}
				}

				transaction, _, deployErr := DeployLocal(context.Background(), &spec, secCxt)
				if deployErr != nil {
					genesisLogger.Error("Error deploying chaincode for genesis block.", deployErr)
					makeGenesisError = deployErr
					return
				}

				genesisTransactions = append(genesisTransactions, transaction)
			}
		}

		genesisLogger.Info("Adding %d system chaincodes to the genesis block.", len(genesisTransactions))
		ledger.CommitTxBatch(0, genesisTransactions, nil)

	})
	return makeGenesisError
}

//BuildLocal builds a given chaincode code
func BuildLocal(context context.Context, spec *protos.ChaincodeSpec) (*protos.ChaincodeDeploymentSpec, error) {
	genesisLogger.Debug("Received build request for chaincode spec: %v", spec)
	mode := viper.GetString("chaincode.chaincoderunmode")
	var codePackageBytes []byte
	if mode != chaincode.DevModeUserRunsChaincode {
		if err := openchain.CheckSpec(spec); err != nil {
			genesisLogger.Debug("check spec failed: %s", err)
			return nil, err
		}
		// Build the spec
		var err error
		codePackageBytes, err = container.GetChaincodePackageBytes(spec)
		if err != nil {
			genesisLogger.Error(fmt.Sprintf("Error getting VM: %s", err))
			return nil, err
		}
	}
	chaincodeDeploymentSpec := &protos.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
	return chaincodeDeploymentSpec, nil
}

// DeployLocal deploys the supplied chaincode image to the local peer
func DeployLocal(ctx context.Context, spec *protos.ChaincodeSpec, secCxt crypto.Peer) (*protos.Transaction, []byte, error) {
	// First build and get the deployment spec
	chaincodeDeploymentSpec, err := BuildLocal(ctx, spec)

	if err != nil {
		genesisLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v\n\n error: %s", spec, err))
		return nil, nil, err
	}

	transaction, err := protos.NewChaincodeDeployTransaction(chaincodeDeploymentSpec, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name)
	if err != nil {
		return nil, nil, fmt.Errorf("Error deploying chaincode: %s ", err)
	}
	//chaincode.NewChaincodeSupport(chaincode.DefaultChain, peer.GetPeerEndpoint, false, 120000)
	result, err := chaincode.Execute(ctx, chaincode.GetChain(chaincode.DefaultChain), transaction, secCxt)
	return transaction, result, err
}

func deploySystemChaincodeEnabled() bool {
	// If the deployment of system chaincode is enabled in the configuration file return the configured value
	if viper.IsSet("ledger.blockchain.deploy-system-chaincode") {
		return viper.GetBool("ledger.blockchain.deploy-system-chaincode")
	}

	// Deployment of system chaincode is enabled by default if no configuration was specified.
	return true
}

func deployUpdateValidityPeriodChaincode(secCxt crypto.Peer) (*protos.Transaction, error) {
	//TODO It should be configurable, not hardcoded
	vpChaincodePath := "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update"
	vpFunction := "init"

	//TODO: this should be the login token for the component in charge of the validity period update.
	//This component needs to be registered in the system to be able to invoke the update validity period system chaincode.
	vpToken := "system_chaincode_invoker"

	var vpCtorArgsStringArray []string

	validityPeriodSpec := &protos.ChaincodeSpec{Type: protos.ChaincodeSpec_GOLANG,
		ChaincodeID: &protos.ChaincodeID{Path: vpChaincodePath,
			Name: "",
		},
		CtorMsg: &protos.ChaincodeInput{Function: vpFunction,
			Args: vpCtorArgsStringArray,
		},
	}

	validityPeriodSpec.SecureContext = string(vpToken)

	vpTransaction, _, deployErr := DeployLocal(context.Background(), validityPeriodSpec, secCxt)

	if deployErr != nil {
		genesisLogger.Error("Error deploying validity period chaincode for genesis block.", deployErr)
		makeGenesisError = deployErr
		return nil, deployErr
	}

	return vpTransaction, nil
} <commit_msg>Removed Println line in genesis.go<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 genesis

import (
	"fmt"
	"sync"

	"golang.org/x/net/context"

	"github.com/op/go-logging"
	"github.com/openblockchain/obc-peer/openchain"
	"github.com/openblockchain/obc-peer/openchain/chaincode"
	"github.com/openblockchain/obc-peer/openchain/container"
	"github.com/openblockchain/obc-peer/openchain/crypto"
	"github.com/openblockchain/obc-peer/openchain/ledger"
	"github.com/openblockchain/obc-peer/protos"
	"github.com/spf13/viper"
)

var genesisLogger = logging.MustGetLogger("genesis")

var makeGenesisError error
var once sync.Once

// MakeGenesis creates the genesis block based on configuration in openchain.yaml
// and adds it to the blockchain.
func MakeGenesis(secCxt crypto.Peer) error {
	once.Do(func() {
		ledger, err := ledger.GetLedger()
		if err != nil {
			makeGenesisError = err
			return
		}

		if ledger.GetBlockchainSize() > 0 {
			// genesis block already exists
			return
		}

		genesisLogger.Info("Creating genesis block.")

		ledger.BeginTxBatch(0)
		var genesisTransactions []*protos.Transaction

		if deploySystemChaincodeEnabled() {
			vpTransaction, deployErr := deployUpdateValidityPeriodChaincode(secCxt)

			if deployErr != nil {
				genesisLogger.Error("Error deploying chaincode for genesis block.", deployErr)
				makeGenesisError = deployErr
				return
			}

			genesisTransactions = append(genesisTransactions, vpTransaction)
		}

		genesis := viper.GetStringMap("ledger.blockchain.genesisBlock")

		if genesis == nil {
			genesisLogger.Info("No genesis block chaincodes defined.")
		} else {

			chaincodes, chaincodesOK := genesis["chaincode"].([]interface{})
			if !chaincodesOK {
				genesisLogger.Info("No genesis block chaincodes defined.")
				ledger.CommitTxBatch(0, genesisTransactions, nil)
				return
			}

			genesisLogger.Debug("Genesis chaincodes are %s", chaincodes)

			for i := 0; i < len(chaincodes); i++ {
				genesisLogger.Debug("Chaincode %d is %s", i, chaincodes[i])

				chaincodeMap, chaincodeMapOK := chaincodes[i].(map[interface{}]interface{})
				if !chaincodeMapOK {
					genesisLogger.Error("Invalid chaincode defined in genesis configuration:", chaincodes[i])
					makeGenesisError = fmt.Errorf("Invalid chaincode defined in genesis configuration: %s", chaincodes[i])
					return
				}

				path, pathOK := chaincodeMap["path"].(string)
				if !pathOK {
					genesisLogger.Error("Invalid chaincode URL defined in genesis configuration:", chaincodeMap["path"])
					makeGenesisError = fmt.Errorf("Invalid chaincode URL defined in genesis configuration: %s", chaincodeMap["path"])
					return
				}

				chaincodeType, chaincodeTypeOK := chaincodeMap["type"].(string)
				if !chaincodeTypeOK {
					genesisLogger.Error("Invalid chaincode type defined in genesis configuration:", chaincodeMap["type"])
					makeGenesisError = fmt.Errorf("Invalid chaincode type defined in genesis configuration: %s", chaincodeMap["type"])
					return
				}

				chaincodeID := &protos.ChaincodeID{Path: path, Name: ""}

				genesisLogger.Debug("Genesis chaincodeID %s", chaincodeID)
				genesisLogger.Debug("Genesis chaincode type %s", chaincodeType)

				constructorMap, constructorMapOK := chaincodeMap["constructor"].(map[interface{}]interface{})
				if !constructorMapOK {
					genesisLogger.Error("Invalid chaincode constructor defined in genesis configuration:", chaincodeMap["constructor"])
					makeGenesisError = fmt.Errorf("Invalid chaincode constructor defined in genesis configuration: %s", chaincodeMap["constructor"])
					return
				}

				var spec protos.ChaincodeSpec
				if constructorMap == nil {
					genesisLogger.Debug("Genesis chaincode has no constructor.")
					spec = protos.ChaincodeSpec{Type: protos.ChaincodeSpec_Type(protos.ChaincodeSpec_Type_value[chaincodeType]), ChaincodeID: chaincodeID}
				} else {

					ctorFunc, ctorFuncOK := constructorMap["func"].(string)
					if !ctorFuncOK {
						genesisLogger.Error("Invalid chaincode constructor function defined in genesis configuration:", constructorMap["func"])
						makeGenesisError = fmt.Errorf("Invalid chaincode constructor function args defined in genesis configuration: %s", constructorMap["func"])
						return
					}

					ctorArgs, ctorArgsOK := constructorMap["args"].([]interface{})
					if !ctorArgsOK {
						genesisLogger.Error("Invalid chaincode constructor args defined in genesis configuration:", constructorMap["args"])
						makeGenesisError = fmt.Errorf("Invalid chaincode constructor args defined in genesis configuration: %s", constructorMap["args"])
						return
					}

					genesisLogger.Debug("Genesis chaincode constructor func %s", ctorFunc)
					genesisLogger.Debug("Genesis chaincode constructor args %s", ctorArgs)
					var ctorArgsStringArray []string
					for j := 0; j < len(ctorArgs); j++ {
						ctorArgsStringArray = append(ctorArgsStringArray, ctorArgs[j].(string))
					}

					spec = protos.ChaincodeSpec{Type: protos.ChaincodeSpec_Type(protos.ChaincodeSpec_Type_value[chaincodeType]), ChaincodeID: chaincodeID, CtorMsg: &protos.ChaincodeInput{Function: ctorFunc, Args: ctorArgsStringArray}}
				}

				transaction, _, deployErr := DeployLocal(context.Background(), &spec, secCxt)
				if deployErr != nil {
					genesisLogger.Error("Error deploying chaincode for genesis block.", deployErr)
					makeGenesisError = deployErr
					return
				}

				genesisTransactions = append(genesisTransactions, transaction)
			}
		}

		genesisLogger.Info("Adding %d system chaincodes to the genesis block.", len(genesisTransactions))
		ledger.CommitTxBatch(0, genesisTransactions, nil)

	})
	return makeGenesisError
}

//BuildLocal builds a given chaincode code
func BuildLocal(context context.Context, spec *protos.ChaincodeSpec) (*protos.ChaincodeDeploymentSpec, error) {
	genesisLogger.Debug("Received build request for chaincode spec: %v", spec)
	mode := viper.GetString("chaincode.chaincoderunmode")
	var codePackageBytes []byte
	if mode != chaincode.DevModeUserRunsChaincode {
		if err := openchain.CheckSpec(spec); err != nil {
			genesisLogger.Debug("check spec failed: %s", err)
			return nil, err
		}
		// Build the spec
		var err error
		codePackageBytes, err = container.GetChaincodePackageBytes(spec)
		if err != nil {
			genesisLogger.Error(fmt.Sprintf("Error getting VM: %s", err))
			return nil, err
		}
	}
	chaincodeDeploymentSpec := &protos.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
	return chaincodeDeploymentSpec, nil
}

// DeployLocal deploys the supplied chaincode image to the local peer
func DeployLocal(ctx context.Context, spec *protos.ChaincodeSpec, secCxt crypto.Peer) (*protos.Transaction, []byte, error) {
	// First build and get the deployment spec
	chaincodeDeploymentSpec, err := BuildLocal(ctx, spec)

	if err != nil {
		genesisLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v\n\n error: %s", spec, err))
		return nil, nil, err
	}

	transaction, err := protos.NewChaincodeDeployTransaction(chaincodeDeploymentSpec, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name)
	if err != nil {
		return nil, nil, fmt.Errorf("Error deploying chaincode: %s ", err)
	}
	//chaincode.NewChaincodeSupport(chaincode.DefaultChain, peer.GetPeerEndpoint, false, 120000)
	result, err := chaincode.Execute(ctx, chaincode.GetChain(chaincode.DefaultChain), transaction, secCxt)
	return transaction, result, err
}

func deploySystemChaincodeEnabled() bool {
	// If the deployment of system chaincode is enabled in the configuration file return the configured value
	if viper.IsSet("ledger.blockchain.deploy-system-chaincode") {
		return viper.GetBool("ledger.blockchain.deploy-system-chaincode")
	}

	// Deployment of system chaincode is enabled by default if no configuration was specified.
	return true
}

func deployUpdateValidityPeriodChaincode(secCxt crypto.Peer) (*protos.Transaction, error) {
	//TODO It should be configurable, not hardcoded
	vpChaincodePath := "github.com/openblockchain/obc-peer/openchain/system_chaincode/validity_period_update"
	vpFunction := "init"

	//TODO: this should be the login token for the component in charge of the validity period update.
	//This component needs to be registered in the system to be able to invoke the update validity period system chaincode.
	vpToken := "system_chaincode_invoker"

	var vpCtorArgsStringArray []string

	validityPeriodSpec := &protos.ChaincodeSpec{Type: protos.ChaincodeSpec_GOLANG,
		ChaincodeID: &protos.ChaincodeID{Path: vpChaincodePath,
			Name: "",
		},
		CtorMsg: &protos.ChaincodeInput{Function: vpFunction,
			Args: vpCtorArgsStringArray,
		},
	}

	validityPeriodSpec.SecureContext = string(vpToken)

	vpTransaction, _, deployErr := DeployLocal(context.Background(), validityPeriodSpec, secCxt)

	if deployErr != nil {
		genesisLogger.Error("Error deploying validity period chaincode for genesis block.", deployErr)
		makeGenesisError = deployErr
		return nil, deployErr
	}

	return vpTransaction, nil
} <|endoftext|>


<commit_before>package event_lib

import (
	"bytes"
	"errors"
	"log"
	"text/template"
	"time"
	//"net/url"

	"gopkg.in/mgo.v2/bson"

	"scal"
	"scal/settings"
	"scal/storage"
	. "scal/user_lib"
)

/*
// PublicJoinPolicy
const (
    FreeToJoin = "FreeToJoin"
    NoJoin = "NoJoin"
    //JoinNeedsVerify = "JoinNeedsVerify" // makes implementation more complex
)
*/

type EventMetaModel struct {
	EventId      bson.ObjectId    `bson:"_id"`
	EventType    string           `bson:"eventType"`
	CreationTime time.Time        `bson:"creationTime"`
	OwnerEmail   string           `bson:"ownerEmail"`
	IsPublic     bool             `bson:"isPublic"`
	AccessEmails []string         `bson:"accessEmails"`
	GroupId      *bson.ObjectId   `bson:"groupId"`
	GroupModel   *EventGroupModel `bson:"-"`

	//PublicJoinPolicy string         `bson:"publicJoinPolicy"` // not indexed
	PublicJoinOpen bool `bson:"publicJoinOpen"`
	MaxAttendees   int  `bson:"maxAttendees"`
}

type InviteEmailTemplateParams struct {
	EventModel  *BaseEventModel
	SenderEmail string
	SenderName  string
	Email       string
	Name        string
	JoinURL     string
}

func (self EventMetaModel) UniqueM() scal.M {
	return scal.M{
		"_id": self.EventId,
	}
}
func (self EventMetaModel) Collection() string {
	return storage.C_eventMeta
}
func (self EventMetaModel) GroupIdHex() string {
	if self.GroupId != nil {
		return self.GroupId.Hex()
	}
	return ""
}
func (self EventMetaModel) JsonM() scal.M {
	return scal.M{
		"creationTime":   self.CreationTime,
		"ownerEmail":     self.OwnerEmail,
		"isPublic":       self.IsPublic,
		"accessEmails":   self.AccessEmails,
		"groupId":        self.GroupIdHex(),
		"publicJoinOpen": self.PublicJoinOpen,
		"maxAttendees":   self.MaxAttendees,
	}
}
func (self *EventMetaModel) CanReadFull(email string) bool {
	if email == self.OwnerEmail {
		return true
	}
	for _, aEmail := range self.AccessEmails {
		if email == aEmail {
			return true
		}
	}
	if self.GroupModel != nil {
		for _, aEmail := range self.GroupModel.ReadAccessEmails {
			if email == aEmail {
				return true
			}
		}
	}
	return false
}
func (self *EventMetaModel) CanRead(email string) bool {
	if self.IsPublic {
		return true
	}
	return self.CanReadFull(email)
}
func (self *EventMetaModel) GetAttending(
	db storage.Database,
	email string,
) string {
	// returns YES, NO, or MAYBE
	attendingModel, _ := LoadEventAttendingModel(db, self.EventId, email)
	return attendingModel.Attending
}
func (self *EventMetaModel) SetAttending(
	db storage.Database,
	email string,
	attending string,
) error {
	// attending: YES, NO, or MAYBE
	attendingModel, err := LoadEventAttendingModel(db, self.EventId, email)
	if err != nil {
		return err
	}
	attendingModel.Attending = attending
	attendingModel.ModifiedTime = time.Now()
	err = attendingModel.Save(db)
	return err
}
func (self *EventMetaModel) AttendingStatusCount(
	db storage.Database,
	attending string,
) (int, error) {
	return db.FindCount(
		storage.C_attending,
		scal.M{
			"eventId":   self.EventId,
			"attending": attending,
		},
	)
}
func (self *EventMetaModel) Join(db storage.Database, email string) error {
	// does not make any changes on self
	if self.GetAttending(db, email) == YES {
		return errors.New("you have already joined this event")
	}
	if !self.CanReadFull(email) {
		if self.IsPublic {
			if !self.PublicJoinOpen {
				return errors.New("this public event is not open for joining")
			}
		} else {
			return errors.New("no access, no join")
		}
	}
	if self.MaxAttendees > 0 {
		attendingCount, err := self.AttendingStatusCount(db, YES)
		if err != nil {
			return err
		}
		if attendingCount >= self.MaxAttendees {
			return errors.New("maximum attendees exceeded, can not join event")
		}
	}
	self.SetAttending(db, email, YES)
	return nil
}
func (self *EventMetaModel) Leave(db storage.Database, email string) error {
	// does not make any changes on self
	if self.GetAttending(db, email) == NO {
		if self.CanReadFull(email) {
			return errors.New("you are not attending for this event")
		}
	}
	self.SetAttending(db, email, NO)
	return nil
}
func (self *EventMetaModel) PublicCanJoin() bool {
	return self.IsPublic && self.PublicJoinOpen
}
func (self *EventMetaModel) Invite(
	db storage.Database,
	email string,
	inviteEmails *[]string,
	remoteIp string,
	host string,
) (error, int) {
	/*
		returns (err, errCode)
		errCode values:
			scal.BadRequest
			scal.Forbidden
			scal.InternalServerError
	*/
	var err error
	if inviteEmails == nil {
		return errors.New("missing 'inviteEmails'"), scal.BadRequest
	}
	if len(*inviteEmails) == 0 {
		return errors.New("empty 'inviteEmails'"), scal.BadRequest
	}

	fullAc := self.CanReadFull(email)
	public := self.PublicCanJoin()
	if !(fullAc || public) {
		return errors.New("not allowed to invite to this event"), scal.Forbidden
	}
	if fullAc {
		accessEmailsMap := make(map[string]bool)
		newAccessEmails := make(
			[]string,
			0,
			len(self.AccessEmails) + len(*inviteEmails),
		)
		for _, aEmail := range self.AccessEmails {
			accessEmailsMap[aEmail] = true
			newAccessEmails = append(newAccessEmails, aEmail)
		}
		for _, inviteEmail := range *inviteEmails {
			_, found := accessEmailsMap[inviteEmail]
			if !found {
				newAccessEmails = append(newAccessEmails, inviteEmail)
			}
		}
		now := time.Now()
		metaChangeLog := EventMetaChangeLogModel{
			Time:     now,
			Email:    email,
			RemoteIp: remoteIp,
			EventId:  self.EventId,
			FuncName: "SetEventAccess",
			AccessEmails: &[2][]string{
				self.AccessEmails,
				newAccessEmails,
			},
		}
		self.AccessEmails = newAccessEmails
		err = db.Insert(metaChangeLog)
		if err != nil {
			return err, scal.InternalServerError
		}
		err = db.Update(self)
		if err != nil {
			return err, scal.InternalServerError
		}
	}

	eventRev, err := LoadLastRevisionModel(db, &self.EventId)
	if err != nil {
		if db.IsNotFound(err) {
			return errors.New("event not found"), scal.BadRequest
		} else {
			return err, scal.InternalServerError
		}
	}
	eventModel, err := LoadBaseEventModel(db, eventRev.Sha1)
	if err != nil {
		return err, scal.InternalServerError
	}

	tplText := settings.EVENT_INVITE_EMAIL_TEMPLATE
	user := UserModelByEmail(email, db)
	if user == nil {
		return errors.New("user not found"), scal.InternalServerError
	}
	eventUrl := host +
		"/event/" +
		self.EventType + "/" +
		self.EventId.Hex() + "/"
	joinURL := eventUrl + "join"
	for _, inviteEmail := range *inviteEmails {
		subject := "Invitation to event: " + eventModel.Summary
		tpl, err := template.New(subject).Parse(tplText)
		if err != nil {
			return err, scal.InternalServerError
		}
		var inviteName string
		inviteUser := UserModelByEmail(inviteEmail, db)
		if inviteUser == nil {
			//return errors.New("invited email not found"), scal.BadRequest
			// FIXME
			inviteName = ""
		} else {
			inviteName = inviteUser.FullName
		}

		tplParams := InviteEmailTemplateParams{
			EventModel:  eventModel,
			SenderEmail: email,
			SenderName:  user.FullName,
			Email:       inviteEmail,
			Name:        inviteName,
			JoinURL:     joinURL,
		}
		buf := bytes.NewBufferString("")
		err = tpl.Execute(buf, tplParams)
		if err != nil {
			return err, scal.InternalServerError
		}
		emailBody := buf.String()
		scal.SendEmail(
			inviteEmail,
			subject,
			false, // isHtml
			emailBody,
		)
	}
	return nil, 200
}
func (self *EventMetaModel) GetEmailsByAttendingStatus(
	db storage.Database,
	attending string,
) []string {
	emailStructs := []struct {
		Email string `bson:"email"`
	}{}
	err := db.FindAll(
		storage.C_attending,
		scal.M{
			"eventId":   self.EventId,
			"attending": attending,
		},
		&emailStructs,
	)
	if err != nil {
		log.Printf(
			"Internal Error: GetAttendingEmails: eventId=%v: %s\n",
			self.EventId,
			err.Error(),
		)
	}
	emails := make([]string, len(emailStructs))
	for i, m := range emailStructs {
		emails[i] = m.Email
	}
	return emails
}
func (self *EventMetaModel) GetAttendingEmails(db storage.Database) []string {
	return self.GetEmailsByAttendingStatus(db, YES)
}
func (self *EventMetaModel) GetNotAttendingEmails(db storage.Database) []string {
	return self.GetEmailsByAttendingStatus(db, NO)
}
func (self *EventMetaModel) GetMaybeAttendingEmails(db storage.Database) []string {
	return self.GetEmailsByAttendingStatus(db, MAYBE)
}

func LoadEventMetaModel(
	db storage.Database,
	eventId *bson.ObjectId,
	loadGroup bool,
) (*EventMetaModel, error) {
	var err error
	eventMeta := EventMetaModel{
		EventId: *eventId,
	}
	err = db.Get(&eventMeta)
	if err != nil {
		return nil, err
	}
	if loadGroup && eventMeta.GroupId != nil {
		// groupModel, err, internalErr
		groupModel, err, _ := LoadGroupModelById(
			"groupId",
			db,
			eventMeta.GroupId,
		)
		if err != nil {
			return nil, err
		}
		eventMeta.GroupModel = groupModel
	}
	return &eventMeta, nil
}

type EventMetaChangeLogModel struct {
	Time     time.Time     `bson:"time"`
	Email    string        `bson:"email"`
	RemoteIp string        `bson:"remoteIp"`
	EventId  bson.ObjectId `bson:"eventId"`
	FuncName string        `bson:"funcName"`

	GroupId        *[2]*bson.ObjectId `bson:"groupId,omitempty"`
	OwnerEmail     *[2]*string        `bson:"ownerEmail,omitempty"`
	IsPublic       *[2]bool           `bson:"isPublic,omitempty"`
	AccessEmails   *[2][]string       `bson:"accessEmails,omitempty"`
	PublicJoinOpen *[2]bool           `bson:"publicJoinOpen,omitempty"`
	MaxAttendees   *[2]int            `bson:"maxAttendees,omitempty"`
}

func (model EventMetaChangeLogModel) Collection() string {
	return storage.C_eventMetaChangeLog
}

func GetEventMetaPipeResults(
	db storage.Database,
	pipeline *[]scal.M,
) (*[]scal.M, error) {
	results := []scal.M{}
	for res := range db.PipeIter(storage.C_eventMeta, pipeline) {
		if err := res.Err; err != nil {
			return nil, err
		}
		if eventId, ok := res.M["_id"]; ok {
			res.M["eventId"] = eventId
			delete(res.M, "_id")
		}
		if dataI, ok := res.M["data"]; ok {
			data := dataI.(scal.M)
			delete(data, "_id")
			res.M["data"] = data
		}
		results = append(results, res.M)
	}
	return &results, nil
}
<commit_msg>fmt fix in event_lib/meta.go<commit_after>package event_lib

import (
	"bytes"
	"errors"
	"log"
	"text/template"
	"time"
	//"net/url"

	"gopkg.in/mgo.v2/bson"

	"scal"
	"scal/settings"
	"scal/storage"
	. "scal/user_lib"
)

/*
// PublicJoinPolicy
const (
    FreeToJoin = "FreeToJoin"
    NoJoin = "NoJoin"
    //JoinNeedsVerify = "JoinNeedsVerify" // makes implementation more complex
)
*/

type EventMetaModel struct {
	EventId      bson.ObjectId    `bson:"_id"`
	EventType    string           `bson:"eventType"`
	CreationTime time.Time        `bson:"creationTime"`
	OwnerEmail   string           `bson:"ownerEmail"`
	IsPublic     bool             `bson:"isPublic"`
	AccessEmails []string         `bson:"accessEmails"`
	GroupId      *bson.ObjectId   `bson:"groupId"`
	GroupModel   *EventGroupModel `bson:"-"`

	//PublicJoinPolicy string         `bson:"publicJoinPolicy"` // not indexed
	PublicJoinOpen bool `bson:"publicJoinOpen"`
	MaxAttendees   int  `bson:"maxAttendees"`
}

type InviteEmailTemplateParams struct {
	EventModel  *BaseEventModel
	SenderEmail string
	SenderName  string
	Email       string
	Name        string
	JoinURL     string
}

func (self EventMetaModel) UniqueM() scal.M {
	return scal.M{
		"_id": self.EventId,
	}
}
func (self EventMetaModel) Collection() string {
	return storage.C_eventMeta
}
func (self EventMetaModel) GroupIdHex() string {
	if self.GroupId != nil {
		return self.GroupId.Hex()
	}
	return ""
}
func (self EventMetaModel) JsonM() scal.M {
	return scal.M{
		"creationTime":   self.CreationTime,
		"ownerEmail":     self.OwnerEmail,
		"isPublic":       self.IsPublic,
		"accessEmails":   self.AccessEmails,
		"groupId":        self.GroupIdHex(),
		"publicJoinOpen": self.PublicJoinOpen,
		"maxAttendees":   self.MaxAttendees,
	}
}
func (self *EventMetaModel) CanReadFull(email string) bool {
	if email == self.OwnerEmail {
		return true
	}
	for _, aEmail := range self.AccessEmails {
		if email == aEmail {
			return true
		}
	}
	if self.GroupModel != nil {
		for _, aEmail := range self.GroupModel.ReadAccessEmails {
			if email == aEmail {
				return true
			}
		}
	}
	return false
}
func (self *EventMetaModel) CanRead(email string) bool {
	if self.IsPublic {
		return true
	}
	return self.CanReadFull(email)
}
func (self *EventMetaModel) GetAttending(
	db storage.Database,
	email string,
) string {
	// returns YES, NO, or MAYBE
	attendingModel, _ := LoadEventAttendingModel(db, self.EventId, email)
	return attendingModel.Attending
}
func (self *EventMetaModel) SetAttending(
	db storage.Database,
	email string,
	attending string,
) error {
	// attending: YES, NO, or MAYBE
	attendingModel, err := LoadEventAttendingModel(db, self.EventId, email)
	if err != nil {
		return err
	}
	attendingModel.Attending = attending
	attendingModel.ModifiedTime = time.Now()
	err = attendingModel.Save(db)
	return err
}
func (self *EventMetaModel) AttendingStatusCount(
	db storage.Database,
	attending string,
) (int, error) {
	return db.FindCount(
		storage.C_attending,
		scal.M{
			"eventId":   self.EventId,
			"attending": attending,
		},
	)
}
func (self *EventMetaModel) Join(db storage.Database, email string) error {
	// does not make any changes on self
	if self.GetAttending(db, email) == YES {
		return errors.New("you have already joined this event")
	}
	if !self.CanReadFull(email) {
		if self.IsPublic {
			if !self.PublicJoinOpen {
				return errors.New("this public event is not open for joining")
			}
		} else {
			return errors.New("no access, no join")
		}
	}
	if self.MaxAttendees > 0 {
		attendingCount, err := self.AttendingStatusCount(db, YES)
		if err != nil {
			return err
		}
		if attendingCount >= self.MaxAttendees {
			return errors.New("maximum attendees exceeded, can not join event")
		}
	}
	self.SetAttending(db, email, YES)
	return nil
}
func (self *EventMetaModel) Leave(db storage.Database, email string) error {
	// does not make any changes on self
	if self.GetAttending(db, email) == NO {
		if self.CanReadFull(email) {
			return errors.New("you are not attending for this event")
		}
	}
	self.SetAttending(db, email, NO)
	return nil
}
func (self *EventMetaModel) PublicCanJoin() bool {
	return self.IsPublic && self.PublicJoinOpen
}
func (self *EventMetaModel) Invite(
	db storage.Database,
	email string,
	inviteEmails *[]string,
	remoteIp string,
	host string,
) (error, int) {
	/*
		returns (err, errCode)
		errCode values:
			scal.BadRequest
			scal.Forbidden
			scal.InternalServerError
	*/
	var err error
	if inviteEmails == nil {
		return errors.New("missing 'inviteEmails'"), scal.BadRequest
	}
	if len(*inviteEmails) == 0 {
		return errors.New("empty 'inviteEmails'"), scal.BadRequest
	}

	fullAc := self.CanReadFull(email)
	public := self.PublicCanJoin()
	if !(fullAc || public) {
		return errors.New("not allowed to invite to this event"), scal.Forbidden
	}
	if fullAc {
		accessEmailsMap := make(map[string]bool)
		newAccessEmails := make(
			[]string,
			0,
			len(self.AccessEmails)+len(*inviteEmails),
		)
		for _, aEmail := range self.AccessEmails {
			accessEmailsMap[aEmail] = true
			newAccessEmails = append(newAccessEmails, aEmail)
		}
		for _, inviteEmail := range *inviteEmails {
			_, found := accessEmailsMap[inviteEmail]
			if !found {
				newAccessEmails = append(newAccessEmails, inviteEmail)
			}
		}
		now := time.Now()
		metaChangeLog := EventMetaChangeLogModel{
			Time:     now,
			Email:    email,
			RemoteIp: remoteIp,
			EventId:  self.EventId,
			FuncName: "SetEventAccess",
			AccessEmails: &[2][]string{
				self.AccessEmails,
				newAccessEmails,
			},
		}
		self.AccessEmails = newAccessEmails
		err = db.Insert(metaChangeLog)
		if err != nil {
			return err, scal.InternalServerError
		}
		err = db.Update(self)
		if err != nil {
			return err, scal.InternalServerError
		}
	}

	eventRev, err := LoadLastRevisionModel(db, &self.EventId)
	if err != nil {
		if db.IsNotFound(err) {
			return errors.New("event not found"), scal.BadRequest
		} else {
			return err, scal.InternalServerError
		}
	}
	eventModel, err := LoadBaseEventModel(db, eventRev.Sha1)
	if err != nil {
		return err, scal.InternalServerError
	}

	tplText := settings.EVENT_INVITE_EMAIL_TEMPLATE
	user := UserModelByEmail(email, db)
	if user == nil {
		return errors.New("user not found"), scal.InternalServerError
	}
	eventUrl := host +
		"/event/" +
		self.EventType + "/" +
		self.EventId.Hex() + "/"
	joinURL := eventUrl + "join"
	for _, inviteEmail := range *inviteEmails {
		subject := "Invitation to event: " + eventModel.Summary
		tpl, err := template.New(subject).Parse(tplText)
		if err != nil {
			return err, scal.InternalServerError
		}
		var inviteName string
		inviteUser := UserModelByEmail(inviteEmail, db)
		if inviteUser == nil {
			//return errors.New("invited email not found"), scal.BadRequest
			// FIXME
			inviteName = ""
		} else {
			inviteName = inviteUser.FullName
		}

		tplParams := InviteEmailTemplateParams{
			EventModel:  eventModel,
			SenderEmail: email,
			SenderName:  user.FullName,
			Email:       inviteEmail,
			Name:        inviteName,
			JoinURL:     joinURL,
		}
		buf := bytes.NewBufferString("")
		err = tpl.Execute(buf, tplParams)
		if err != nil {
			return err, scal.InternalServerError
		}
		emailBody := buf.String()
		scal.SendEmail(
			inviteEmail,
			subject,
			false, // isHtml
			emailBody,
		)
	}
	return nil, 200
}
func (self *EventMetaModel) GetEmailsByAttendingStatus(
	db storage.Database,
	attending string,
) []string {
	emailStructs := []struct {
		Email string `bson:"email"`
	}{}
	err := db.FindAll(
		storage.C_attending,
		scal.M{
			"eventId":   self.EventId,
			"attending": attending,
		},
		&emailStructs,
	)
	if err != nil {
		log.Printf(
			"Internal Error: GetAttendingEmails: eventId=%v: %s\n",
			self.EventId,
			err.Error(),
		)
	}
	emails := make([]string, len(emailStructs))
	for i, m := range emailStructs {
		emails[i] = m.Email
	}
	return emails
}
func (self *EventMetaModel) GetAttendingEmails(db storage.Database) []string {
	return self.GetEmailsByAttendingStatus(db, YES)
}
func (self *EventMetaModel) GetNotAttendingEmails(db storage.Database) []string {
	return self.GetEmailsByAttendingStatus(db, NO)
}
func (self *EventMetaModel) GetMaybeAttendingEmails(db storage.Database) []string {
	return self.GetEmailsByAttendingStatus(db, MAYBE)
}

func LoadEventMetaModel(
	db storage.Database,
	eventId *bson.ObjectId,
	loadGroup bool,
) (*EventMetaModel, error) {
	var err error
	eventMeta := EventMetaModel{
		EventId: *eventId,
	}
	err = db.Get(&eventMeta)
	if err != nil {
		return nil, err
	}
	if loadGroup && eventMeta.GroupId != nil {
		// groupModel, err, internalErr
		groupModel, err, _ := LoadGroupModelById(
			"groupId",
			db,
			eventMeta.GroupId,
		)
		if err != nil {
			return nil, err
		}
		eventMeta.GroupModel = groupModel
	}
	return &eventMeta, nil
}

type EventMetaChangeLogModel struct {
	Time     time.Time     `bson:"time"`
	Email    string        `bson:"email"`
	RemoteIp string        `bson:"remoteIp"`
	EventId  bson.ObjectId `bson:"eventId"`
	FuncName string        `bson:"funcName"`

	GroupId        *[2]*bson.ObjectId `bson:"groupId,omitempty"`
	OwnerEmail     *[2]*string        `bson:"ownerEmail,omitempty"`
	IsPublic       *[2]bool           `bson:"isPublic,omitempty"`
	AccessEmails   *[2][]string       `bson:"accessEmails,omitempty"`
	PublicJoinOpen *[2]bool           `bson:"publicJoinOpen,omitempty"`
	MaxAttendees   *[2]int            `bson:"maxAttendees,omitempty"`
}

func (model EventMetaChangeLogModel) Collection() string {
	return storage.C_eventMetaChangeLog
}

func GetEventMetaPipeResults(
	db storage.Database,
	pipeline *[]scal.M,
) (*[]scal.M, error) {
	results := []scal.M{}
	for res := range db.PipeIter(storage.C_eventMeta, pipeline) {
		if err := res.Err; err != nil {
			return nil, err
		}
		if eventId, ok := res.M["_id"]; ok {
			res.M["eventId"] = eventId
			delete(res.M, "_id")
		}
		if dataI, ok := res.M["data"]; ok {
			data := dataI.(scal.M)
			delete(data, "_id")
			res.M["data"] = data
		}
		results = append(results, res.M)
	}
	return &results, nil
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

package huebee

import (
	"github.com/muesli/beehive/bees"
)

type HueBeeFactory struct {
	bees.BeeFactory
}

// Interface impl

func (factory *HueBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface {
	bee := HueBee{
		Bee:    bees.NewBee(name, factory.Name(), description, options),
		bridge: options.GetValue("bridge").(string),
		key:    options.GetValue("key").(string),
	}

	return &bee
}

func (factory *HueBeeFactory) Name() string {
	return "huebee"
}

func (factory *HueBeeFactory) Description() string {
	return "A Philips hue module for beehive"
}

func (factory *HueBeeFactory) Image() string {
	return factory.Name() + ".png"
}

func (factory *HueBeeFactory) Options() []bees.BeeOptionDescriptor {
	opts := []bees.BeeOptionDescriptor{
		{
			Name:        "bridge",
			Description: "Address of the Hue bridge, eg: 192.168.0.1",
			Type:        "url",
			Mandatory:   true,
		},
		{
			Name:        "key",
			Description: "Key used for auth with the bridge",
			Type:        "string",
			Mandatory:   true,
		},
	}
	return opts
}

func (factory *HueBeeFactory) Events() []bees.EventDescriptor {
	events := []bees.EventDescriptor{}
	return events
}

func (factory *HueBeeFactory) Actions() []bees.ActionDescriptor {
	actions := []bees.ActionDescriptor{
		{
			Namespace:   factory.Name(),
			Name:        "switch",
			Description: "Switches on/off a Hue light",
			Options: []bees.PlaceholderDescriptor{
				{
					Name:        "light",
					Description: "ID of the light you want to switch on or off",
					Type:        "int",
				},
				{
					Name:        "state",
					Description: "New state of the light, true for turning it on",
					Type:        "bool",
				},
			},
		},
	}
	return actions
}

func init() {
	f := HueBeeFactory{}
	bees.RegisterFactory(&f)
}
<commit_msg>Fixed HueBee's action descriptors<commit_after>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

package huebee

import (
	"github.com/muesli/beehive/bees"
)

type HueBeeFactory struct {
	bees.BeeFactory
}

// Interface impl

func (factory *HueBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface {
	bee := HueBee{
		Bee:    bees.NewBee(name, factory.Name(), description, options),
		bridge: options.GetValue("bridge").(string),
		key:    options.GetValue("key").(string),
	}

	return &bee
}

func (factory *HueBeeFactory) Name() string {
	return "huebee"
}

func (factory *HueBeeFactory) Description() string {
	return "A Philips hue module for beehive"
}

func (factory *HueBeeFactory) Image() string {
	return factory.Name() + ".png"
}

func (factory *HueBeeFactory) Options() []bees.BeeOptionDescriptor {
	opts := []bees.BeeOptionDescriptor{
		{
			Name:        "bridge",
			Description: "Address of the Hue bridge, eg: 192.168.0.1",
			Type:        "url",
			Mandatory:   true,
		},
		{
			Name:        "key",
			Description: "Key used for auth with the bridge",
			Type:        "string",
			Mandatory:   true,
		},
	}
	return opts
}

func (factory *HueBeeFactory) Events() []bees.EventDescriptor {
	events := []bees.EventDescriptor{}
	return events
}

func (factory *HueBeeFactory) Actions() []bees.ActionDescriptor {
	actions := []bees.ActionDescriptor{
		{
			Namespace:   factory.Name(),
			Name:        "switch",
			Description: "Switches on/off a Hue light",
			Options: []bees.PlaceholderDescriptor{
				{
					Name:        "light",
					Description: "ID of the light you want to switch on or off",
					Type:        "int",
				},
				{
					Name:        "state",
					Description: "New state of the light, true for turning it on",
					Type:        "bool",
				},
			},
		},
		{
			Namespace:   factory.Name(),
			Name:        "setcolor",
			Description: "Changes the color of a Hue light",
			Options: []bees.PlaceholderDescriptor{
				{
					Name:        "light",
					Description: "ID of the light you want to switch on or off",
					Type:        "int",
				},
				{
					Name:        "color",
					Description: "New color of the light you want to change",
					Type:        "string",
				},
				{
					Name:        "brightness",
					Description: "New brightness of the light you want to change",
					Type:        "int",
				},
			},
		},
	}
	return actions
}

func init() {
	f := HueBeeFactory{}
	bees.RegisterFactory(&f)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/bitrise-io/go-pathutil"
	"gopkg.in/yaml.v2"
)

/*
	File storage methods
*/
func loadEnvMap() ([]envModel, error) {
	envsYML, err := readEnvMapFromFile(currentEnvStoreFilePath)
	if err != nil {
		return []envModel{}, err
	}

	return convertToEnvModelArray(envsYML), nil
}

func loadEnvMapOrCreate() ([]envModel, error) {
	envModels, err := loadEnvMap()
	if err != nil {
		if err.Error() == "No environment variable list found" {
			_, err = initAtPath(currentEnvStoreFilePath)
			return []envModel{}, err
		}
		return []envModel{}, err
	}
	return envModels, nil
}

func updateOrAddToEnvlist(envs []envModel, env envModel) ([]envModel, error) {
	var newEnvs []envModel
	exist := false

	for _, eModel := range envs {
		if eModel.Key == env.Key {
			exist = true
			newEnvs = append(newEnvs, env)
		} else {
			newEnvs = append(newEnvs, eModel)
		}
	}

	if exist == false {
		newEnvs = append(newEnvs, env)
	}

	err := writeEnvMapToFile(currentEnvStoreFilePath, newEnvs)
	if err != nil {
		return []envModel{}, err
	}

	return newEnvs, nil
}

func readEnvMapFromFile(pth string) (envsYMLModel, error) {
	isExists, err := pathutil.IsPathExists(pth)
	if err != nil {
		return envsYMLModel{}, err
	}
	if isExists == false {
		return envsYMLModel{}, errors.New("No environment variable list found")
	}

	bytes, err := ioutil.ReadFile(pth)
	if err != nil {
		return envsYMLModel{}, err
	}

	var envsModel envsYMLModel
	err = yaml.Unmarshal(bytes, &envsModel)
	if err != nil {
		return envsYMLModel{}, err
	}

	return envsModel, nil
}

func generateFormattedYMLForEnvModels(envs []envModel) ([]byte, error) {
	envYML := convertToEnvsYMLModel(envs)

	bytes, err := yaml.Marshal(envYML)
	if err != nil {
		return []byte{}, err
	}

	return bytes, nil
}

func writeEnvMapToFile(pth string, envs []envModel) error {
	if pth == "" {
		return errors.New("No path provided")
	}

	file, err := os.Create(pth)
	if err != nil {
		return err
	}
	defer file.Close()

	jsonContBytes, err := generateFormattedYMLForEnvModels(envs)
	if err != nil {
		return err
	}

	_, err = file.Write(jsonContBytes)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>missing error handling<commit_after>package main

import (
	"errors"
	"io/ioutil"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/go-pathutil"
	"gopkg.in/yaml.v2"
)

/*
	File storage methods
*/
func loadEnvMap() ([]envModel, error) {
	envsYML, err := readEnvMapFromFile(currentEnvStoreFilePath)
	if err != nil {
		return []envModel{}, err
	}

	return convertToEnvModelArray(envsYML), nil
}

func loadEnvMapOrCreate() ([]envModel, error) {
	envModels, err := loadEnvMap()
	if err != nil {
		if err.Error() == "No environment variable list found" {
			_, err = initAtPath(currentEnvStoreFilePath)
			return []envModel{}, err
		}
		return []envModel{}, err
	}
	return envModels, nil
}

func updateOrAddToEnvlist(envs []envModel, env envModel) ([]envModel, error) {
	var newEnvs []envModel
	exist := false

	for _, eModel := range envs {
		if eModel.Key == env.Key {
			exist = true
			newEnvs = append(newEnvs, env)
		} else {
			newEnvs = append(newEnvs, eModel)
		}
	}

	if exist == false {
		newEnvs = append(newEnvs, env)
	}

	err := writeEnvMapToFile(currentEnvStoreFilePath, newEnvs)
	if err != nil {
		return []envModel{}, err
	}

	return newEnvs, nil
}

func readEnvMapFromFile(pth string) (envsYMLModel, error) {
	isExists, err := pathutil.IsPathExists(pth)
	if err != nil {
		return envsYMLModel{}, err
	}
	if isExists == false {
		return envsYMLModel{}, errors.New("No environment variable list found")
	}

	bytes, err := ioutil.ReadFile(pth)
	if err != nil {
		return envsYMLModel{}, err
	}

	var envsModel envsYMLModel
	err = yaml.Unmarshal(bytes, &envsModel)
	if err != nil {
		return envsYMLModel{}, err
	}

	return envsModel, nil
}

func generateFormattedYMLForEnvModels(envs []envModel) ([]byte, error) {
	envYML := convertToEnvsYMLModel(envs)

	bytes, err := yaml.Marshal(envYML)
	if err != nil {
		return []byte{}, err
	}

	return bytes, nil
}

func writeEnvMapToFile(pth string, envs []envModel) error {
	if pth == "" {
		return errors.New("No path provided")
	}

	file, err := os.Create(pth)
	if err != nil {
		return err
	}
	defer func() {
		err := file.Close()
		if err != nil {
			log.Fatalln("Failed to close file:", err)
		}
	}()

	jsonContBytes, err := generateFormattedYMLForEnvModels(envs)
	if err != nil {
		return err
	}

	_, err = file.Write(jsonContBytes)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>