<commit_before>package terraform

import (
	"log"
	"sort"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/states"

	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/dag"
)

// GraphNodeDestroyer must be implemented by nodes that destroy resources.
type GraphNodeDestroyer interface {
	dag.Vertex

	// DestroyAddr is the address of the resource that is being
	// destroyed by this node. If this returns nil, then this node
	// is not destroying anything.
	DestroyAddr() *addrs.AbsResourceInstance
}

// GraphNodeCreator must be implemented by nodes that create OR update resources.
type GraphNodeCreator interface {
	// CreateAddr is the address of the resource being created or updated
	CreateAddr() *addrs.AbsResourceInstance
}

// DestroyEdgeTransformer is a GraphTransformer that creates the proper
// references for destroy resources. Destroy resources are more complex
// in that they must be depend on the destruction of resources that
// in turn depend on the CREATION of the node being destroy.
//
// That is complicated. Visually:
//
//   B_d -> A_d -> A -> B
//
// Notice that A destroy depends on B destroy, while B create depends on
// A create. They're inverted. This must be done for example because often
// dependent resources will block parent resources from deleting. Concrete
// example: VPC with subnets, the VPC can't be deleted while there are
// still subnets.
type DestroyEdgeTransformer struct {
	// These are needed to properly build the graph of dependencies
	// to determine what a destroy node depends on. Any of these can be nil.
	Config *configs.Config
	State  *states.State

	// If configuration is present then Schemas is required in order to
	// obtain schema information from providers and provisioners in order
	// to properly resolve implicit dependencies.
	Schemas *Schemas
}

func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
	// Build a map of what is being destroyed (by address string) to
	// the list of destroyers.
	destroyers := make(map[string][]GraphNodeDestroyer)

	// Record the creators, which will need to depend on the destroyers if they
	// are only being updated.
	creators := make(map[string]GraphNodeCreator)

	// destroyersByResource records each destroyer by the AbsResourceAddress.
	// We use this because dependencies are only referenced as resources, but we
	// will want to connect all the individual instances for correct ordering.
	destroyersByResource := make(map[string][]GraphNodeDestroyer)
	for _, v := range g.Vertices() {
		switch n := v.(type) {
		case GraphNodeDestroyer:
			addrP := n.DestroyAddr()
			if addrP == nil {
				log.Printf("[WARN] DestroyEdgeTransformer: %q (%T) has no destroy address", dag.VertexName(n), v)
				continue
			}
			addr := *addrP

			key := addr.String()
			log.Printf("[TRACE] DestroyEdgeTransformer: %q (%T) destroys %s", dag.VertexName(n), v, key)
			destroyers[key] = append(destroyers[key], n)

			resAddr := addr.Resource.Resource.Absolute(addr.Module).String()
			destroyersByResource[resAddr] = append(destroyersByResource[resAddr], n)
		case GraphNodeCreator:
			addr := n.CreateAddr()
			creators[addr.String()] = n
		}
	}

	// If we aren't destroying anything, there will be no edges to make
	// so just exit early and avoid future work.
	if len(destroyers) == 0 {
		return nil
	}

	// Connect destroy despendencies as stored in the state
	for _, ds := range destroyers {
		for _, des := range ds {
			ri, ok := des.(GraphNodeResourceInstance)
			if !ok {
				continue
			}

			for _, resAddr := range ri.StateDependencies() {
				for _, desDep := range destroyersByResource[resAddr.String()] {
					log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(desDep), dag.VertexName(des))
					g.Connect(dag.BasicEdge(desDep, des))

				}
			}
		}
	}

	// connect creators to any destroyers on which they may depend
	for _, c := range creators {
		ri, ok := c.(GraphNodeResourceInstance)
		if !ok {
			continue
		}

		for _, resAddr := range ri.StateDependencies() {
			for _, desDep := range destroyersByResource[resAddr.String()] {
				log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(c), dag.VertexName(desDep))
				g.Connect(dag.BasicEdge(c, desDep))

			}
		}
	}

	// Go through and connect creators to destroyers. Going along with
	// our example, this makes: A_d => A
	for _, v := range g.Vertices() {
		cn, ok := v.(GraphNodeCreator)
		if !ok {
			continue
		}

		addr := cn.CreateAddr()
		if addr == nil {
			continue
		}

		for _, d := range destroyers[addr.String()] {
			// For illustrating our example
			a_d := d.(dag.Vertex)
			a := v

			log.Printf(
				"[TRACE] DestroyEdgeTransformer: connecting creator %q with destroyer %q",
				dag.VertexName(a), dag.VertexName(a_d))

			g.Connect(dag.BasicEdge(a, a_d))

			// Attach the destroy node to the creator
			// There really shouldn't be more than one destroyer, but even if
			// there are, any of them will represent the correct
			// CreateBeforeDestroy status.
			if n, ok := cn.(GraphNodeAttachDestroyer); ok {
				if d, ok := d.(GraphNodeDestroyerCBD); ok {
					n.AttachDestroyNode(d)
				}
			}
		}
	}

	return nil
}

// Remove any nodes that aren't needed when destroying modules.
// Variables, outputs, locals, and expanders may not be able to evaluate
// correctly, so we can remove these if nothing depends on them. The module
// closers also need to disable their use of expansion if the module itself is
// no longer present.
type pruneUnusedNodesTransformer struct {
}

func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
	// We need a reverse depth first walk of modules, processing them in order
	// from the leaf modules to the root. This allows us to remove unneeded
	// dependencies from child modules, freeing up nodes in the parent module
	// to also be removed.

	// First collect the nodes into their respective modules based on
	// configuration path.
	moduleMap := make(map[string]pruneUnusedNodesMod)
	for _, v := range g.Vertices() {
		var path addrs.Module
		switch v := v.(type) {
		case GraphNodeModulePath:
			path = v.ModulePath()
		default:
			continue
		}
		m := moduleMap[path.String()]
		m.addr = path
		m.nodes = append(m.nodes, v)

		// We need to keep track of the closers, to make sure they don't look
		// for an expansion if there's nothing being expanded.
		if c, ok := v.(*nodeCloseModule); ok {
			m.closer = c
		}
		moduleMap[path.String()] = m
	}

	// now we need to restructure the modules so we can sort them
	var modules []pruneUnusedNodesMod

	for _, mod := range moduleMap {
		modules = append(modules, mod)
	}

	// Sort them by path length, longest first, so that start with the deepest
	// modules.  The order of modules at the same tree level doesn't matter, we
	// just need to ensure that child modules are processed before parent
	// modules.
	sort.Slice(modules, func(i, j int) bool {
		return len(modules[i].addr) > len(modules[j].addr)
	})

	for _, mod := range modules {
		mod.removeUnused(g)
	}

	return nil
}

// pruneUnusedNodesMod is a container to hold the nodes that belong to a
// particular configuration module for the pruneUnusedNodesTransformer
type pruneUnusedNodesMod struct {
	addr   addrs.Module
	nodes  []dag.Vertex
	closer *nodeCloseModule
}

// Remove any unused locals, variables, outputs and expanders.  Since module
// closers can also lookup expansion info to detect orphaned instances, disable
// them if their associated expander is removed.
func (m *pruneUnusedNodesMod) removeUnused(g *Graph) {
	// We modify the nodes slice during processing here.
	// Make a copy so no one is surprised by this changing in the future.
	nodes := make([]dag.Vertex, len(m.nodes))
	copy(nodes, m.nodes)

	// since we have no defined structure within the module, just cycle through
	// the nodes in each module until there are no more removals
	removed := true
	for {
		if !removed {
			return
		}
		removed = false

		for i := 0; i < len(nodes); i++ {
			// run this in a closure, so we can return early rather than
			// dealing with complex looping and labels
			func() {
				n := nodes[i]
				switch n.(type) {
				case graphNodeTemporaryValue:
					// temporary value, which consist of variables, locals, and
					// outputs, must be kept if anything refers to them.
					if n, ok := n.(GraphNodeModulePath); ok {
						// root outputs always have an implicit dependency on
						// remote state.
						if n.ModulePath().IsRoot() {
							return
						}
					}
					for _, vv := range g.UpEdges(n) {
						// keep any value which is connected through a
						// reference
						if _, ok := vv.(GraphNodeReferencer); ok {
							return
						}
					}

				case graphNodeExpandsInstances:
					// Any nodes that expand instances are kept when their
					// instances may need to be evaluated.
					for _, vv := range g.UpEdges(n) {
						switch vv.(type) {
						case graphNodeExpandsInstances:
							// expanders can always depend on module expansion
							// themselves
							return
						case GraphNodeResourceInstance:
							// resource instances always depend on their
							// resource node, which is an expander
							return
						}
					}

				default:
					return
				}

				g.Remove(n)
				removed = true

				// remove the node from our iteration as well
				last := len(nodes) - 1
				nodes[i], nodes[last] = nodes[last], nodes[i]
				nodes = nodes[:last]
			}()
		}
	}
}
<commit_msg>add node pruning log line<commit_after>package terraform

import (
	"log"
	"sort"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/states"

	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/dag"
)

// GraphNodeDestroyer must be implemented by nodes that destroy resources.
type GraphNodeDestroyer interface {
	dag.Vertex

	// DestroyAddr is the address of the resource that is being
	// destroyed by this node. If this returns nil, then this node
	// is not destroying anything.
	DestroyAddr() *addrs.AbsResourceInstance
}

// GraphNodeCreator must be implemented by nodes that create OR update resources.
type GraphNodeCreator interface {
	// CreateAddr is the address of the resource being created or updated
	CreateAddr() *addrs.AbsResourceInstance
}

// DestroyEdgeTransformer is a GraphTransformer that creates the proper
// references for destroy resources. Destroy resources are more complex
// in that they must be depend on the destruction of resources that
// in turn depend on the CREATION of the node being destroy.
//
// That is complicated. Visually:
//
//   B_d -> A_d -> A -> B
//
// Notice that A destroy depends on B destroy, while B create depends on
// A create. They're inverted. This must be done for example because often
// dependent resources will block parent resources from deleting. Concrete
// example: VPC with subnets, the VPC can't be deleted while there are
// still subnets.
type DestroyEdgeTransformer struct {
	// These are needed to properly build the graph of dependencies
	// to determine what a destroy node depends on. Any of these can be nil.
	Config *configs.Config
	State  *states.State

	// If configuration is present then Schemas is required in order to
	// obtain schema information from providers and provisioners in order
	// to properly resolve implicit dependencies.
	Schemas *Schemas
}

func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
	// Build a map of what is being destroyed (by address string) to
	// the list of destroyers.
	destroyers := make(map[string][]GraphNodeDestroyer)

	// Record the creators, which will need to depend on the destroyers if they
	// are only being updated.
	creators := make(map[string]GraphNodeCreator)

	// destroyersByResource records each destroyer by the AbsResourceAddress.
	// We use this because dependencies are only referenced as resources, but we
	// will want to connect all the individual instances for correct ordering.
	destroyersByResource := make(map[string][]GraphNodeDestroyer)
	for _, v := range g.Vertices() {
		switch n := v.(type) {
		case GraphNodeDestroyer:
			addrP := n.DestroyAddr()
			if addrP == nil {
				log.Printf("[WARN] DestroyEdgeTransformer: %q (%T) has no destroy address", dag.VertexName(n), v)
				continue
			}
			addr := *addrP

			key := addr.String()
			log.Printf("[TRACE] DestroyEdgeTransformer: %q (%T) destroys %s", dag.VertexName(n), v, key)
			destroyers[key] = append(destroyers[key], n)

			resAddr := addr.Resource.Resource.Absolute(addr.Module).String()
			destroyersByResource[resAddr] = append(destroyersByResource[resAddr], n)
		case GraphNodeCreator:
			addr := n.CreateAddr()
			creators[addr.String()] = n
		}
	}

	// If we aren't destroying anything, there will be no edges to make
	// so just exit early and avoid future work.
	if len(destroyers) == 0 {
		return nil
	}

	// Connect destroy despendencies as stored in the state
	for _, ds := range destroyers {
		for _, des := range ds {
			ri, ok := des.(GraphNodeResourceInstance)
			if !ok {
				continue
			}

			for _, resAddr := range ri.StateDependencies() {
				for _, desDep := range destroyersByResource[resAddr.String()] {
					log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(desDep), dag.VertexName(des))
					g.Connect(dag.BasicEdge(desDep, des))

				}
			}
		}
	}

	// connect creators to any destroyers on which they may depend
	for _, c := range creators {
		ri, ok := c.(GraphNodeResourceInstance)
		if !ok {
			continue
		}

		for _, resAddr := range ri.StateDependencies() {
			for _, desDep := range destroyersByResource[resAddr.String()] {
				log.Printf("[TRACE] DestroyEdgeTransformer: %s has stored dependency of %s\n", dag.VertexName(c), dag.VertexName(desDep))
				g.Connect(dag.BasicEdge(c, desDep))

			}
		}
	}

	// Go through and connect creators to destroyers. Going along with
	// our example, this makes: A_d => A
	for _, v := range g.Vertices() {
		cn, ok := v.(GraphNodeCreator)
		if !ok {
			continue
		}

		addr := cn.CreateAddr()
		if addr == nil {
			continue
		}

		for _, d := range destroyers[addr.String()] {
			// For illustrating our example
			a_d := d.(dag.Vertex)
			a := v

			log.Printf(
				"[TRACE] DestroyEdgeTransformer: connecting creator %q with destroyer %q",
				dag.VertexName(a), dag.VertexName(a_d))

			g.Connect(dag.BasicEdge(a, a_d))

			// Attach the destroy node to the creator
			// There really shouldn't be more than one destroyer, but even if
			// there are, any of them will represent the correct
			// CreateBeforeDestroy status.
			if n, ok := cn.(GraphNodeAttachDestroyer); ok {
				if d, ok := d.(GraphNodeDestroyerCBD); ok {
					n.AttachDestroyNode(d)
				}
			}
		}
	}

	return nil
}

// Remove any nodes that aren't needed when destroying modules.
// Variables, outputs, locals, and expanders may not be able to evaluate
// correctly, so we can remove these if nothing depends on them. The module
// closers also need to disable their use of expansion if the module itself is
// no longer present.
type pruneUnusedNodesTransformer struct {
}

func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
	// We need a reverse depth first walk of modules, processing them in order
	// from the leaf modules to the root. This allows us to remove unneeded
	// dependencies from child modules, freeing up nodes in the parent module
	// to also be removed.

	// First collect the nodes into their respective modules based on
	// configuration path.
	moduleMap := make(map[string]pruneUnusedNodesMod)
	for _, v := range g.Vertices() {
		var path addrs.Module
		switch v := v.(type) {
		case GraphNodeModulePath:
			path = v.ModulePath()
		default:
			continue
		}
		m := moduleMap[path.String()]
		m.addr = path
		m.nodes = append(m.nodes, v)

		// We need to keep track of the closers, to make sure they don't look
		// for an expansion if there's nothing being expanded.
		if c, ok := v.(*nodeCloseModule); ok {
			m.closer = c
		}
		moduleMap[path.String()] = m
	}

	// now we need to restructure the modules so we can sort them
	var modules []pruneUnusedNodesMod

	for _, mod := range moduleMap {
		modules = append(modules, mod)
	}

	// Sort them by path length, longest first, so that start with the deepest
	// modules.  The order of modules at the same tree level doesn't matter, we
	// just need to ensure that child modules are processed before parent
	// modules.
	sort.Slice(modules, func(i, j int) bool {
		return len(modules[i].addr) > len(modules[j].addr)
	})

	for _, mod := range modules {
		mod.removeUnused(g)
	}

	return nil
}

// pruneUnusedNodesMod is a container to hold the nodes that belong to a
// particular configuration module for the pruneUnusedNodesTransformer
type pruneUnusedNodesMod struct {
	addr   addrs.Module
	nodes  []dag.Vertex
	closer *nodeCloseModule
}

// Remove any unused locals, variables, outputs and expanders.  Since module
// closers can also lookup expansion info to detect orphaned instances, disable
// them if their associated expander is removed.
func (m *pruneUnusedNodesMod) removeUnused(g *Graph) {
	// We modify the nodes slice during processing here.
	// Make a copy so no one is surprised by this changing in the future.
	nodes := make([]dag.Vertex, len(m.nodes))
	copy(nodes, m.nodes)

	// since we have no defined structure within the module, just cycle through
	// the nodes in each module until there are no more removals
	removed := true
	for {
		if !removed {
			return
		}
		removed = false

		for i := 0; i < len(nodes); i++ {
			// run this in a closure, so we can return early rather than
			// dealing with complex looping and labels
			func() {
				n := nodes[i]
				switch n.(type) {
				case graphNodeTemporaryValue:
					// temporary value, which consist of variables, locals, and
					// outputs, must be kept if anything refers to them.
					if n, ok := n.(GraphNodeModulePath); ok {
						// root outputs always have an implicit dependency on
						// remote state.
						if n.ModulePath().IsRoot() {
							return
						}
					}
					for _, v := range g.UpEdges(n) {
						// keep any value which is connected through a
						// reference
						if _, ok := v.(GraphNodeReferencer); ok {
							return
						}
					}

				case graphNodeExpandsInstances:
					// Any nodes that expand instances are kept when their
					// instances may need to be evaluated.
					for _, v := range g.UpEdges(n) {
						switch v.(type) {
						case graphNodeExpandsInstances:
							// expanders can always depend on module expansion
							// themselves
							return
						case GraphNodeResourceInstance:
							// resource instances always depend on their
							// resource node, which is an expander
							return
						}
					}

				default:
					return
				}

				log.Printf("[DEBUG] pruneUnusedNodes: %s is no longer needed, removing", dag.VertexName(n))
				g.Remove(n)
				removed = true

				// remove the node from our iteration as well
				last := len(nodes) - 1
				nodes[i], nodes[last] = nodes[last], nodes[i]
				nodes = nodes[:last]
			}()
		}
	}
}
<|endoftext|>


<commit_before>// +build !confonly

package encoding

import (
	"io"

	"github.com/golang/protobuf/proto"

	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/proxy/vless"
)

func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {

	switch addons.Flow {
	case vless.XRO:

		if bytes, err := proto.Marshal(addons); err != nil {
			return newError("failed to marshal addons protobuf value").Base(err)
		}
		if err := buffer.WriteByte(byte(len(bytes))); err != nil {
			return newError("failed to write addons protobuf length").Base(err)
		}
		if _, err := buffer.Write(bytes); err != nil {
			return newError("failed to write addons protobuf value").Base(err)
		}

	default:

		if err := buffer.WriteByte(0); err != nil {
			return newError("failed to write addons protobuf length").Base(err)
		}

	}

	return nil

}

func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {

	addons := new(Addons)

	buffer.Clear()
	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
		return nil, newError("failed to read addons protobuf length").Base(err)
	}

	if length := int32(buffer.Byte(0)); length != 0 {

		buffer.Clear()
		if _, err := buffer.ReadFullFrom(reader, length); err != nil {
			return nil, newError("failed to read addons protobuf value").Base(err)
		}

		if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
			return nil, newError("failed to unmarshal addons protobuf value").Base(err)
		}

		// Verification.
		switch addons.Flow {
		default:

		}

	}

	return addons, nil

}

// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, addons *Addons) buf.Writer {

	switch addons.Flow {
	case vless.XRO:

		if request.Command == protocol.RequestCommandUDP {
			return NewMultiLengthPacketWriter(writer.(buf.Writer))
		}

	}

	return buf.NewWriter(writer)

}

// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {

	switch addons.Flow {
	case vless.XRO:

		if request.Command == protocol.RequestCommandUDP {
			return NewLengthPacketReader(reader)
		}

	}

	return buf.NewReader(reader)

}

func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
	return &MultiLengthPacketWriter{
		Writer: writer,
	}
}

type MultiLengthPacketWriter struct {
	buf.Writer
}

func (w *MultiLengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	defer buf.ReleaseMulti(mb)
	mb2Write := make(buf.MultiBuffer, 0, len(mb)+1)
	for _, b := range mb {
		length := b.Len()
		if length == 0 || length+2 > buf.Size {
			continue
		}
		eb := buf.New()
		if err := eb.WriteByte(byte(length >> 8)); err != nil {
			eb.Release()
			continue
		}
		if err := eb.WriteByte(byte(length)); err != nil {
			eb.Release()
			continue
		}
		if _, err := eb.Write(b.Bytes()); err != nil {
			eb.Release()
			continue
		}
		mb2Write = append(mb2Write, eb)
	}
	if mb2Write.IsEmpty() {
		return nil
	}
	return w.Writer.WriteMultiBuffer(mb2Write)
}

func NewLengthPacketWriter(writer io.Writer) *LengthPacketWriter {
	return &LengthPacketWriter{
		Writer: writer,
		cache:  make([]byte, 0, 65536),
	}
}

type LengthPacketWriter struct {
	io.Writer
	cache []byte
}

func (w *LengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	length := mb.Len() // none of mb is nil
	//fmt.Println("Write", length)
	if length == 0 {
		return nil
	}
	defer func() {
		w.cache = w.cache[:0]
	}()
	w.cache = append(w.cache, byte(length>>8), byte(length))
	for i, b := range mb {
		w.cache = append(w.cache, b.Bytes()...)
		b.Release()
		mb[i] = nil
	}
	if _, err := w.Write(w.cache); err != nil {
		return newError("failed to write a packet").Base(err)
	}
	return nil
}

func NewLengthPacketReader(reader io.Reader) *LengthPacketReader {
	return &LengthPacketReader{
		Reader: reader,
		cache:  make([]byte, 2),
	}
}

type LengthPacketReader struct {
	io.Reader
	cache []byte
}

func (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	if _, err := io.ReadFull(r.Reader, r.cache); err != nil { // maybe EOF
		return nil, newError("failed to read packet length").Base(err)
	}
	length := int(r.cache[0])<<8 | int(r.cache[1])
	//fmt.Println("Read", length)
	mb := make(buf.MultiBuffer, 0, length/buf.Size+1)
	for length > 0 {
		size := length
		if length > buf.Size {
			size = buf.Size
		}
		length -= size
		b := buf.New()
		if _, err := b.ReadFullFrom(r.Reader, int32(size)); err != nil {
			return nil, newError("failed to read packet payload").Base(err)
		}
		mb = append(mb, b)
	}
	return mb, nil
}
<commit_msg>Fix bug<commit_after>// +build !confonly

package encoding

import (
	"io"

	"github.com/golang/protobuf/proto"

	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/proxy/vless"
)

func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {

	switch addons.Flow {
	case vless.XRO:

		bytes, err := proto.Marshal(addons)
		if err != nil {
			return newError("failed to marshal addons protobuf value").Base(err)
		}
		if err := buffer.WriteByte(byte(len(bytes))); err != nil {
			return newError("failed to write addons protobuf length").Base(err)
		}
		if _, err := buffer.Write(bytes); err != nil {
			return newError("failed to write addons protobuf value").Base(err)
		}

	default:

		if err := buffer.WriteByte(0); err != nil {
			return newError("failed to write addons protobuf length").Base(err)
		}

	}

	return nil

}

func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {

	addons := new(Addons)

	buffer.Clear()
	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
		return nil, newError("failed to read addons protobuf length").Base(err)
	}

	if length := int32(buffer.Byte(0)); length != 0 {

		buffer.Clear()
		if _, err := buffer.ReadFullFrom(reader, length); err != nil {
			return nil, newError("failed to read addons protobuf value").Base(err)
		}

		if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
			return nil, newError("failed to unmarshal addons protobuf value").Base(err)
		}

		// Verification.
		switch addons.Flow {
		default:

		}

	}

	return addons, nil

}

// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, addons *Addons) buf.Writer {

	switch addons.Flow {
	case vless.XRO:

		if request.Command == protocol.RequestCommandUDP {
			return NewMultiLengthPacketWriter(writer.(buf.Writer))
		}

	}

	return buf.NewWriter(writer)

}

// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {

	switch addons.Flow {
	case vless.XRO:

		if request.Command == protocol.RequestCommandUDP {
			return NewLengthPacketReader(reader)
		}

	}

	return buf.NewReader(reader)

}

func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
	return &MultiLengthPacketWriter{
		Writer: writer,
	}
}

type MultiLengthPacketWriter struct {
	buf.Writer
}

func (w *MultiLengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	defer buf.ReleaseMulti(mb)
	mb2Write := make(buf.MultiBuffer, 0, len(mb)+1)
	for _, b := range mb {
		length := b.Len()
		if length == 0 || length+2 > buf.Size {
			continue
		}
		eb := buf.New()
		if err := eb.WriteByte(byte(length >> 8)); err != nil {
			eb.Release()
			continue
		}
		if err := eb.WriteByte(byte(length)); err != nil {
			eb.Release()
			continue
		}
		if _, err := eb.Write(b.Bytes()); err != nil {
			eb.Release()
			continue
		}
		mb2Write = append(mb2Write, eb)
	}
	if mb2Write.IsEmpty() {
		return nil
	}
	return w.Writer.WriteMultiBuffer(mb2Write)
}

func NewLengthPacketWriter(writer io.Writer) *LengthPacketWriter {
	return &LengthPacketWriter{
		Writer: writer,
		cache:  make([]byte, 0, 65536),
	}
}

type LengthPacketWriter struct {
	io.Writer
	cache []byte
}

func (w *LengthPacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	length := mb.Len() // none of mb is nil
	//fmt.Println("Write", length)
	if length == 0 {
		return nil
	}
	defer func() {
		w.cache = w.cache[:0]
	}()
	w.cache = append(w.cache, byte(length>>8), byte(length))
	for i, b := range mb {
		w.cache = append(w.cache, b.Bytes()...)
		b.Release()
		mb[i] = nil
	}
	if _, err := w.Write(w.cache); err != nil {
		return newError("failed to write a packet").Base(err)
	}
	return nil
}

func NewLengthPacketReader(reader io.Reader) *LengthPacketReader {
	return &LengthPacketReader{
		Reader: reader,
		cache:  make([]byte, 2),
	}
}

type LengthPacketReader struct {
	io.Reader
	cache []byte
}

func (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	if _, err := io.ReadFull(r.Reader, r.cache); err != nil { // maybe EOF
		return nil, newError("failed to read packet length").Base(err)
	}
	length := int(r.cache[0])<<8 | int(r.cache[1])
	//fmt.Println("Read", length)
	mb := make(buf.MultiBuffer, 0, length/buf.Size+1)
	for length > 0 {
		size := length
		if length > buf.Size {
			size = buf.Size
		}
		length -= size
		b := buf.New()
		if _, err := b.ReadFullFrom(r.Reader, int32(size)); err != nil {
			return nil, newError("failed to read packet payload").Base(err)
		}
		mb = append(mb, b)
	}
	return mb, nil
}
<|endoftext|>


<commit_before>package parser

import (
	"fmt"
	"os"

	"github.com/ark-lang/ark-go/util"
)

type semanticAnalyzer struct {
	file *File
}

func (v *semanticAnalyzer) err(err string, stuff ...interface{}) {
	/*fmt.Printf(util.TEXT_RED+util.TEXT_BOLD+"Semantic error:"+util.TEXT_RESET+" [%s:%d:%d] %s\n",
	v.peek(0).Filename, v.peek(0).LineNumber, v.peek(0).CharNumber, fmt.Sprintf(err, stuff...))*/
	fmt.Printf(util.TEXT_RED+util.TEXT_BOLD+"Semantic error:"+util.TEXT_RESET+" %s\n",
		fmt.Sprintf(err, stuff...))
	os.Exit(2)
}

func (v *semanticAnalyzer) analyze() {
	for _, node := range v.file.nodes {
		node.analyze(v)
	}
}

func (v *Block) analyze(s *semanticAnalyzer) {
	for _, n := range v.Nodes {
		n.analyze(s)
	}
}

func (v *VariableDecl) analyze(s *semanticAnalyzer) {
	v.Variable.analyze(s)
	v.Assignment.analyze(s)
}

func (v *Variable) analyze(s *semanticAnalyzer) {
	// make sure there are no illegal attributes
	s.checkDuplicateAttrs(v.Attrs)
	for _, attr := range v.Attrs {
		switch attr.Key {
		case "deprecated":
			// value is optional, nothing to check
		default:
			s.err("Invalid variable attribute key `%s`", attr.Key)
		}
	}
}

func (v *StructDecl) analyze(s *semanticAnalyzer) {
	v.Struct.analyze(s)
}

func (v *StructType) analyze(s *semanticAnalyzer) {
	// make sure there are no illegal attributes
	s.checkDuplicateAttrs(v.Attrs)
	for _, attr := range v.Attrs {
		switch attr.Key {
		case "packed":
			if attr.Value != "" {
				s.err("Struct attribute `%s` doesn't expect value", attr.Key)
			}
		case "deprecated":
			// value is optional, nothing to check
		default:
			s.err("Invalid struct attribute key `%s`", attr.Key)
		}
	}
}

func (v *FunctionDecl) analyze(s *semanticAnalyzer) {
	v.Function.analyze(s)
}

func (v *Function) analyze(s *semanticAnalyzer) {
	// make sure there are no illegal attributes
	s.checkDuplicateAttrs(v.Attrs)
	for _, attr := range v.Attrs {
		switch attr.Key {
		case "deprecated":
			// value is optional, nothing to check
		default:
			s.err("Invalid function attribute key `%s`", attr.Key)
		}
	}
}

func (v *semanticAnalyzer) checkDuplicateAttrs(attrs []*Attr) {
	encountered := make(map[string]bool)
	for _, attr := range attrs {
		if encountered[attr.Key] {
			v.err("Duplicate attribute `%s`", attr.Key)
		}
		encountered[attr.Key] = true
	}
}

func (v *ReturnStat) analyze(s *semanticAnalyzer) {}

func (v *UnaryExpr) analyze(s *semanticAnalyzer) {
	v.Expr.analyze(s)
	switch v.Op {
	case UNOP_LOG_NOT:
		if v.Expr.GetType() == PRIMITIVE_bool {
			v.Type = PRIMITIVE_bool
		} else {
			s.err("Used logical not on non-bool")
		}
	case UNOP_BIT_NOT:
		if v.Expr.GetType().IsIntegerType() || v.Expr.GetType().IsFloatingType() {
			v.Type = v.Expr.GetType()
		} else {
			s.err("Used bitwise not on non-numeric type")
		}
	case UNOP_ADDRESS:
		v.Type = &PointerType{Addressee: v.Expr.GetType()}
		// TODO make sure v.Expr is a variable! (can't take address of a literal)
	case UNOP_DEREF:
		if ptr, ok := v.Expr.GetType().(*PointerType); ok {
			v.Type = ptr.Addressee
		} else {
			s.err("Used dereference operator on non-pointer")
		}
	default:
		panic("whoops")
	}
}

func (v *BinaryExpr) analyze(s *semanticAnalyzer) {}

func (v *StringLiteral) analyze(s *semanticAnalyzer) {}

func (v *IntegerLiteral) analyze(s *semanticAnalyzer) {}

func (v *FloatingLiteral) analyze(s *semanticAnalyzer) {}

func (v *RuneLiteral) analyze(s *semanticAnalyzer) {}
<commit_msg>semantic stuff<commit_after>package parser

import (
	"fmt"
	"os"

	"github.com/ark-lang/ark-go/util"
)

type semanticAnalyzer struct {
	file *File
}

func (v *semanticAnalyzer) err(err string, stuff ...interface{}) {
	/*fmt.Printf(util.TEXT_RED+util.TEXT_BOLD+"Semantic error:"+util.TEXT_RESET+" [%s:%d:%d] %s\n",
	v.peek(0).Filename, v.peek(0).LineNumber, v.peek(0).CharNumber, fmt.Sprintf(err, stuff...))*/
	fmt.Printf(util.TEXT_RED+util.TEXT_BOLD+"Semantic error:"+util.TEXT_RESET+" %s\n",
		fmt.Sprintf(err, stuff...))
	os.Exit(2)
}

func (v *semanticAnalyzer) analyze() {
	for _, node := range v.file.nodes {
		node.analyze(v)
	}
}

func (v *Block) analyze(s *semanticAnalyzer) {
	for _, n := range v.Nodes {
		n.analyze(s)
	}
}

func (v *VariableDecl) analyze(s *semanticAnalyzer) {
	v.Variable.analyze(s)
	v.Assignment.analyze(s)
}

func (v *Variable) analyze(s *semanticAnalyzer) {
	// make sure there are no illegal attributes
	s.checkDuplicateAttrs(v.Attrs)
	for _, attr := range v.Attrs {
		switch attr.Key {
		case "deprecated":
			// value is optional, nothing to check
		default:
			s.err("Invalid variable attribute key `%s`", attr.Key)
		}
	}
}

func (v *StructDecl) analyze(s *semanticAnalyzer) {
	v.Struct.analyze(s)
}

func (v *StructType) analyze(s *semanticAnalyzer) {
	// make sure there are no illegal attributes
	s.checkDuplicateAttrs(v.Attrs)
	for _, attr := range v.Attrs {
		switch attr.Key {
		case "packed":
			if attr.Value != "" {
				s.err("Struct attribute `%s` doesn't expect value", attr.Key)
			}
		case "deprecated":
			// value is optional, nothing to check
		default:
			s.err("Invalid struct attribute key `%s`", attr.Key)
		}
	}
}

func (v *FunctionDecl) analyze(s *semanticAnalyzer) {
	v.Function.analyze(s)
}

func (v *Function) analyze(s *semanticAnalyzer) {
	// make sure there are no illegal attributes
	s.checkDuplicateAttrs(v.Attrs)
	for _, attr := range v.Attrs {
		switch attr.Key {
		case "deprecated":
			// value is optional, nothing to check
		default:
			s.err("Invalid function attribute key `%s`", attr.Key)
		}
	}
}

func (v *semanticAnalyzer) checkDuplicateAttrs(attrs []*Attr) {
	encountered := make(map[string]bool)
	for _, attr := range attrs {
		if encountered[attr.Key] {
			v.err("Duplicate attribute `%s`", attr.Key)
		}
		encountered[attr.Key] = true
	}
}

func (v *ReturnStat) analyze(s *semanticAnalyzer) {
	v.Value.analyze(s)
	// TODO check return value same as function type
}

func (v *UnaryExpr) analyze(s *semanticAnalyzer) {
	v.Expr.analyze(s)

	switch v.Op {
	case UNOP_LOG_NOT:
		if v.Expr.GetType() == PRIMITIVE_bool {
			v.Type = PRIMITIVE_bool
		} else {
			s.err("Used logical not on non-bool")
		}
	case UNOP_BIT_NOT:
		if v.Expr.GetType().IsIntegerType() || v.Expr.GetType().IsFloatingType() {
			v.Type = v.Expr.GetType()
		} else {
			s.err("Used bitwise not on non-numeric type")
		}
	case UNOP_ADDRESS:
		v.Type = &PointerType{Addressee: v.Expr.GetType()}
		// TODO make sure v.Expr is a variable! (can't take address of a literal)
	case UNOP_DEREF:
		if ptr, ok := v.Expr.GetType().(*PointerType); ok {
			v.Type = ptr.Addressee
		} else {
			s.err("Used dereference operator on non-pointer")
		}
	default:
		panic("whoops")
	}
}

func (v *BinaryExpr) analyze(s *semanticAnalyzer) {
	v.Lhand.analyze(s)
	v.Rhand.analyze(s)
}

func (v *StringLiteral) analyze(s *semanticAnalyzer) {}

func (v *IntegerLiteral) analyze(s *semanticAnalyzer) {}

func (v *FloatingLiteral) analyze(s *semanticAnalyzer) {}

func (v *RuneLiteral) analyze(s *semanticAnalyzer) {}
<|endoftext|>


<commit_before>package base

import (
	"fmt"
	"reflect"
	"strconv"

	dataframe "github.com/rocketlaunchr/dataframe-go"

	"github.com/sjwhitworth/golearn/base"
)

// ConvertDataFrameToInstances converts a DataFrame-go dataframe object to Golearn Fixed Data Grid. Allows for compabitibility between dataframe and golearn's ML models.
// df is the dataframe Object. classAttrIndex is the index of the class Attribute in the data.
func ConvertDataFrameToInstances(df *dataframe.DataFrame, classAttrIndex int) base.FixedDataGrid {

	// Creating Attributes based on Datafraem
	names := df.Names()
	attrs := make([]base.Attribute, len(names))

	newInst := base.NewDenseInstances()

	for i := range names {
		col := df.Series[i]
		if reflect.TypeOf(col.Value(0)).Kind() == reflect.String {
			attrs[i] = new(base.CategoricalAttribute)
			attrs[i].SetName(names[i])
		} else {
			attrs[i] = base.NewFloatAttribute(names[i])
		}
	}

	// Add the attributes
	newSpecs := make([]base.AttributeSpec, len(attrs))
	for i, a := range attrs {

		newSpecs[i] = newInst.AddAttribute(a)
	}
	// Adding the class attribute
	newInst.AddClassAttribute(attrs[classAttrIndex])

	// Allocate space
	nRows := df.NRows()
	newInst.Extend(df.NRows())

	// Write the data based on DataType
	for i := 0; i < nRows; i++ {
		for j := range names {
			col := df.Series[j]

			var val string
			str, ok := col.Value(i).(string)
			val = str
			if ok != true {
				int_64, ok := col.Value(i).(int64)
				val = strconv.FormatInt(int_64, 10)
				if ok != true {
					float_64, ok := col.Value(i).(float64)
					val = fmt.Sprintf("%f", float_64)
					if ok != true {
						float_32, ok := col.Value(i).(float32)
						if ok == true {
							val = fmt.Sprintf("%f", float_32)
						}
					}
				}
			}
			newInst.Set(newSpecs[j], i, newSpecs[j].GetAttribute().GetSysValFromString(val))
		}

	}

	return newInst
}
<commit_msg>Replacing Nest with Switch Case<commit_after>package base

import (
	"fmt"
	"reflect"
	"strconv"

	dataframe "github.com/rocketlaunchr/dataframe-go"

	"github.com/sjwhitworth/golearn/base"
)

// ConvertDataFrameToInstances converts a DataFrame-go dataframe object to Golearn Fixed Data Grid. Allows for compabitibility between dataframe and golearn's ML models.
// df is the dataframe Object. classAttrIndex is the index of the class Attribute in the data.i
func ConvertDataFrameToInstances(df *dataframe.DataFrame, classAttrIndex int) base.FixedDataGrid {

	// Creating Attributes based on Datafraem
	names := df.Names()
	attrs := make([]base.Attribute, len(names))

	newInst := base.NewDenseInstances()

	for i := range names {
		col := df.Series[i]
		if reflect.TypeOf(col.Value(0)).Kind() == reflect.String {
			attrs[i] = new(base.CategoricalAttribute)
			attrs[i].SetName(names[i])
		} else {
			attrs[i] = base.NewFloatAttribute(names[i])
		}
	}

	// Add the attributes
	newSpecs := make([]base.AttributeSpec, len(attrs))
	for i, a := range attrs {

		newSpecs[i] = newInst.AddAttribute(a)
	}
	// Adding the class attribute
	newInst.AddClassAttribute(attrs[classAttrIndex])

	// Allocate space
	nRows := df.NRows()
	newInst.Extend(df.NRows())

	// Write the data based on DataType
	for i := 0; i < nRows; i++ {
		for j := range names {
			col := df.Series[j]

			var val string
			switch v := col.Value(i).(type) {
			case string:
				val = v
			case int64:
				val = strconv.FormatInt(v, 10)
			case float64:
				val = fmt.Sprintf("%f", v)
			case float32:
				val = fmt.Sprintf("%f", v)
			}

			newInst.Set(newSpecs[j], i, newSpecs[j].GetAttribute().GetSysValFromString(val))
		}

	}

	return newInst
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"math"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"

	"msrl.com/hacks/saseat"
)

var (
	guestFlag = flag.String("guests", "", "CSV file of guest names")
	prefFlag  = flag.String("prefs", "", "CSV file of preferences")
	tableFlag = flag.String("tables", "", "comma-separated list of table sizes")
)

func main() {
	rand.Seed(time.Now().UnixNano())

	flag.Parse()
	if *guestFlag == "" || *prefFlag == "" || *tableFlag == "" {
		fmt.Fprintln(os.Stderr, "all flags are required")
		os.Exit(2)
	}

	// Load guests file.
	f, err := os.Open(*guestFlag)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	guests, err := saseat.ReadGuests(f)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Load prefs file.
	f, err = os.Open(*prefFlag)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	prefs, err := saseat.ReadPrefs(f)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if err = prefs.CheckGuests(guests); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Create tables, packing the guests to them in random order.
	var tables []saseat.Table
	perm := rand.Perm(len(guests))
	seated := 0
	for _, s := range strings.Split(*tableFlag, ",") {
		capacity, err := strconv.ParseInt(s, 0, 10)
		if err != nil {
			fmt.Fprintln(os.Stderr, "bad table capacity %q: %v", s, err)
			os.Exit(1)
		}
		if capacity <= 0 || capacity%2 != 0 {
			fmt.Fprintln(os.Stderr, "only positive even table sizes supported")
			os.Exit(1)
		}
		t := saseat.NewTable(int(capacity))
		for i := 0; i < int(capacity/2) && seated < len(guests); i++ {
			t.Left[i] = guests[perm[seated]]
			seated++
		}
		for i := 0; i < int(capacity/2) && seated < len(guests); i++ {
			t.Right[i] = guests[perm[seated]]
			seated++
		}
		t.Rescore(prefs)
		tables = append(tables, t)
	}
	if seated != len(guests) {
		fmt.Fprintf(os.Stderr, "seats for only %v of %v guests", seated, len(guests))
		os.Exit(1)
	}

	// Let's anneal!
	temp := 250.0
	reported := time.Now()
	iter := 1
	for ; ; iter++ {
		// Cooling.
		if iter%1000000 == 0 {
			temp *= 0.98
		}

		if time.Now().Sub(reported) > 1*time.Second {
			report(tables)
			fmt.Printf("Iteration %d, temperature %.1f\n\n\n", iter, temp)
			reported = time.Now()
		}

		// Spend more time trying to optimize within tables instead of
		// swapping people around the room.
		if rand.Float64() > 0.1 {
			i := rand.Intn(len(tables))
			t := copyTable(&tables[i])
			t.Swap(&t, 2)
			t.Rescore(prefs)
			if accept(t.Score, tables[i].Score, temp) {
				tables[i] = t
			}
		} else {
			i1 := rand.Intn(len(tables))
			i2 := rand.Intn(len(tables))
			if i1 == i2 {
				continue
			}
			t1 := copyTable(&tables[i1])
			t2 := copyTable(&tables[i2])
			t1.Swap(&t2, -1)
			t1.Rescore(prefs)
			t2.Rescore(prefs)
			if accept(t1.Score+t2.Score, tables[i1].Score+tables[i2].Score, temp) {
				tables[i1] = t1
				tables[i2] = t2
			}
		}
	}

	report(tables)
}

// Makes a partial copy of a table.
func copyTable(t *saseat.Table) saseat.Table {
	tt := saseat.Table{
		Left:        make([]saseat.Guest, len(t.Left)),
		Right:       make([]saseat.Guest, len(t.Right)),
		LeftScores:  make([]float64, len(t.LeftScores)),
		RightScores: make([]float64, len(t.RightScores)),
	}
	copy(tt.Left, t.Left)
	copy(tt.Right, t.Right)
	return tt
}

// Simulated annealing acceptance function.
func accept(new, old float64, temp float64) bool {
	if new >= old {
		return true
	}
	return math.Exp((new-old)/temp) > rand.Float64()
}

func report(tables []saseat.Table) {
	fmt.Printf("----------------------------------------\n\n")
	var Σ float64
	for _, t := range tables {
		Σ += t.Score
	}
	for i, t := range tables {
		printTable(i+1, t)
	}
	fmt.Printf("Score %.0f\n\n", Σ)
}

func printTable(n int, t saseat.Table) {
	fmt.Printf("Table %d -- subtotal %.0f; table %.0f\n\n", n, t.Score, t.TableScore)
	for i := 0; i < len(t.Left); i++ {
		fmt.Printf("%5.0f %-30s  %5.0f %-30s\n",
			t.LeftScores[i], t.Left[i].Name, t.RightScores[i], t.Right[i].Name)
	}
	fmt.Printf("\n\n")
}
<commit_msg>Squashed commit of the following:<commit_after>// Copyright 2015 Michael Shields
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"math"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"

	"msrl.com/hacks/saseat"
)

var (
	guestFlag = flag.String("guests", "", "CSV file of guest names")
	prefFlag  = flag.String("prefs", "", "CSV file of preferences")
	tableFlag = flag.String("tables", "", "comma-separated list of table sizes")
)

func main() {
	rand.Seed(time.Now().UnixNano())

	flag.Parse()
	if *guestFlag == "" || *prefFlag == "" || *tableFlag == "" {
		fmt.Fprintln(os.Stderr, "all flags are required")
		os.Exit(2)
	}

	// Load guests file.
	f, err := os.Open(*guestFlag)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	guests, err := saseat.ReadGuests(f)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Load prefs file.
	f, err = os.Open(*prefFlag)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	prefs, err := saseat.ReadPrefs(f)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if err = prefs.CheckGuests(guests); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// Create tables, packing the guests to them in random order.
	var tables []saseat.Table
	perm := rand.Perm(len(guests))
	seated := 0
	for _, s := range strings.Split(*tableFlag, ",") {
		capacity, err := strconv.ParseInt(s, 0, 10)
		if err != nil {
			fmt.Fprintln(os.Stderr, "bad table capacity %q: %v", s, err)
			os.Exit(1)
		}
		if capacity <= 0 || capacity%2 != 0 {
			fmt.Fprintln(os.Stderr, "only positive even table sizes supported")
			os.Exit(1)
		}
		t := saseat.NewTable(int(capacity))
		for i := 0; i < int(capacity/2) && seated < len(guests); i++ {
			t.Left[i] = guests[perm[seated]]
			seated++
		}
		for i := 0; i < int(capacity/2) && seated < len(guests); i++ {
			t.Right[i] = guests[perm[seated]]
			seated++
		}
		t.Rescore(prefs)
		tables = append(tables, t)
	}
	if seated != len(guests) {
		fmt.Fprintf(os.Stderr, "seats for only %v of %v guests", seated, len(guests))
		os.Exit(1)
	}

	// Let's anneal!
	temp := 250.0
	reported := time.Now()
	iter := 1
	for ; ; iter++ {
		// Cooling.
		if iter%1000000 == 0 {
			temp *= 0.99
		}

		if time.Now().Sub(reported) > 1*time.Second {
			report(tables)
			fmt.Printf("Iteration %d, temperature %.1f\n\n\n", iter, temp)
			reported = time.Now()
		}

		// Spend more time trying to optimize within tables instead of
		// swapping people around the room.
		if rand.Float64() > 0.1 {
			i := rand.Intn(len(tables))
			t := copyTable(&tables[i])
			t.Swap(&t, 2)
			t.Rescore(prefs)
			if accept(t.Score, tables[i].Score, temp) {
				tables[i] = t
			}
		} else {
			i1 := rand.Intn(len(tables))
			i2 := rand.Intn(len(tables))
			if i1 == i2 {
				continue
			}
			t1 := copyTable(&tables[i1])
			t2 := copyTable(&tables[i2])
			t1.Swap(&t2, -1)
			t1.Rescore(prefs)
			t2.Rescore(prefs)
			if accept(t1.Score+t2.Score, tables[i1].Score+tables[i2].Score, temp) {
				tables[i1] = t1
				tables[i2] = t2
			}
		}
	}

	report(tables)
}

// Makes a partial copy of a table.
func copyTable(t *saseat.Table) saseat.Table {
	tt := saseat.Table{
		Left:        make([]saseat.Guest, len(t.Left)),
		Right:       make([]saseat.Guest, len(t.Right)),
		LeftScores:  make([]float64, len(t.LeftScores)),
		RightScores: make([]float64, len(t.RightScores)),
	}
	copy(tt.Left, t.Left)
	copy(tt.Right, t.Right)
	return tt
}

// Simulated annealing acceptance function.
func accept(new, old float64, temp float64) bool {
	if new >= old {
		return true
	}
	return math.Exp((new-old)/temp) > rand.Float64()
}

func report(tables []saseat.Table) {
	fmt.Printf("----------------------------------------\n\n")
	var Σ float64
	for _, t := range tables {
		Σ += t.Score
	}
	for i, t := range tables {
		printTable(i+1, t)
	}
	fmt.Printf("Score %.0f\n\n", Σ)
}

func printTable(n int, t saseat.Table) {
	fmt.Printf("Table %d -- subtotal %.0f; table %.0f\n\n", n, t.Score, t.TableScore)
	for i := 0; i < len(t.Left); i++ {
		fmt.Printf("%5.0f %-30s  %5.0f %-30s\n",
			t.LeftScores[i], t.Left[i].Name, t.RightScores[i], t.Right[i].Name)
	}
	fmt.Printf("\n\n")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"

	"github.com/dave/jennifer/jen"
)

var (
	in  = flag.String("in", ".", "folder to create bindings from")
	out = flag.String("out", "bindings", "output file name")
)

type Binding struct {
	ClassName       string
	ClassMethods    []*ast.FuncDecl
	InstanceMethods []*ast.FuncDecl
}

func (Binding) New() {

}

func main() {
	flag.Parse()

	fs := token.NewFileSet()
	buff, err := ioutil.ReadFile(*in)
	if err != nil {
		log.Fatal(err)
	}

	f, err := parser.ParseFile(fs, *in, string(buff), parser.AllErrors)
	if err != nil {
		log.Fatal(err)
	}

	var binding Binding

	ast.Inspect(f, func(n ast.Node) bool {
		switch n := n.(type) {
		case *ast.FuncDecl:
			if n.Recv != nil {
				// class or instance?
				r := n.Recv.List[0]
				r.Type.

				// class
				if r.Names == nil {

				} else {
					// instance
				}
				if n.Recv.List[0].Type {
					binding.ClassMethods = append(binding.ClassMethods, n)
				}
			}
		case *ast.TypeSpec:
			binding.ClassName = n.Name.Name

		}

		return true
	})
	log.Printf("%+v", binding)
	o := jen.NewFile(*out)

	o.Func().Id("main").Params().Block(jen.Qual("log", "Println").Call(jen.Lit("Hello world")))
	b := new(bytes.Buffer)
	err = o.Render(b)
	log.Println(err, b.String())
}
<commit_msg>Render basic binding functions<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"log"

	"github.com/dave/jennifer/jen"
)

var (
	in  = flag.String("in", ".", "folder to create bindings from")
	out = flag.String("out", "bindings", "output file name")
)

const (
	vmPkg = "github.com/goby-lang/goby/vm"
)

type Binding struct {
	ClassName       string
	ClassMethods    []*ast.FuncDecl
	InstanceMethods []*ast.FuncDecl
}

func (b *Binding) staticName() string {
	return fmt.Sprintf("_static%s", b.ClassName)
}

func (b *Binding) bindingName(f *ast.FuncDecl) string {
	return fmt.Sprintf("_binding_%s_%s", b.ClassName, f.Name.Name)
}

func (b *Binding) BindMethods(f *jen.File) {
	for _, c := range b.ClassMethods {
		b.BindClassMethod(f, c)
		f.Line()
	}
	for _, c := range b.InstanceMethods {
		b.BindInstanceMethod(f, c)
		f.Line()
	}
}

func (b *Binding) BindClassMethod(f *jen.File, d *ast.FuncDecl) {
	f.Func().Id(b.bindingName(d)).Call().Block()
}

func (b *Binding) BindInstanceMethod(f *jen.File, d *ast.FuncDecl) {
	s := f.Func().Id(b.bindingName(d))
	s = s.Params(jen.Id("r").Qual(vmPkg, "Object"), jen.Id("line").Id("int")).Qual(vmPkg, "Method")
	ff := jen.Func().Params(jen.Id("t").Qual(vmPkg, "Thread"), jen.Id("args").Index().Qual(vmPkg, "Object"))
	ff = ff.Qual(vmPkg, "Object")
	ff = ff.Block(
		jen.Return(nil),
	)
	s.Block(jen.Return(ff))

	// func closeDB(receiver vm.Object, sourceLine int) vm.Method {
	// 	return func(t *vm.Thread, args []vm.Object) vm.Object {
	// 	}
	// 	return nil
	// }
}

func main() {
	flag.Parse()

	fs := token.NewFileSet()
	buff, err := ioutil.ReadFile(*in)
	if err != nil {
		log.Fatal(err)
	}

	f, err := parser.ParseFile(fs, *in, string(buff), parser.AllErrors)
	if err != nil {
		log.Fatal(err)
	}

	bindings := make(map[string]*Binding)

	ast.Inspect(f, func(n ast.Node) bool {
		switch n := n.(type) {
		case *ast.FuncDecl:
			if n.Recv != nil {
				// class or instance?
				r := n.Recv.List[0]
				var name string
				switch t := r.Type.(type) {
				case *ast.Ident:
					name = t.Name

				case *ast.StarExpr:
					name = t.X.(*ast.Ident).Name
				}

				b, ok := bindings[name]
				if !ok {
					b := new(Binding)
					b.ClassName = name
					bindings[name] = b
				}

				// class
				if r.Names == nil {
					b.ClassMethods = append(b.ClassMethods, n)
				} else {
					b.InstanceMethods = append(b.InstanceMethods, n)
				}
			}
		case *ast.TypeSpec:
			bindings[n.Name.Name] = &Binding{
				ClassName: n.Name.Name,
			}

		}

		return true
	})
	o := jen.NewFile(*out)

	for _, x := range bindings {
		x.BindMethods(o)
	}

	var b bytes.Buffer
	err = o.Render(&b)
	log.Println(err, b.String())
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

const helpText = `Usage: %[1]s [options] <ident> <source file> [-- <C flags>]

ident is used as the stem of all generated Go types and functions, and
must be a valid Go identifier.

source is a single C file that is compiled using the specified compiler
(usually some version of clang).

You can pass options to the compiler by appending them after a '--' argument
or by supplying -cflags. Flags passed as arguments take precedence
over flags passed via -cflags. Additionally, the program expands quotation
marks in -cflags. This means that -cflags 'foo "bar baz"' is passed to the
compiler as two arguments "foo" and "bar baz".

The program expects GOPACKAGE to be set in the environment, and should be invoked
via go generate. The generated files are written to the current directory.

Options:

`

// Targets understood by bpf2go.
//
// Targets without a Linux string can't be used directly and are only included
// for the generic bpf, bpfel, bpfeb targets.
var targetByGoArch = map[string]target{
	"386":         {"bpfel", "x86"},
	"amd64":       {"bpfel", "x86"},
	"amd64p32":    {"bpfel", ""},
	"arm":         {"bpfel", "arm"},
	"arm64":       {"bpfel", "arm64"},
	"mipsle":      {"bpfel", ""},
	"mips64le":    {"bpfel", ""},
	"mips64p32le": {"bpfel", ""},
	"ppc64le":     {"bpfel", "powerpc"},
	"riscv64":     {"bpfel", ""},
	"armbe":       {"bpfeb", "arm"},
	"arm64be":     {"bpfeb", "arm64"},
	"mips":        {"bpfeb", ""},
	"mips64":      {"bpfeb", ""},
	"mips64p32":   {"bpfeb", ""},
	"ppc64":       {"bpfeb", "powerpc"},
	"s390":        {"bpfeb", "s390"},
	"s390x":       {"bpfeb", "s390"},
	"sparc":       {"bpfeb", "sparc"},
	"sparc64":     {"bpfeb", "sparc"},
}

func run(stdout io.Writer, pkg, outputDir string, args []string) (err error) {
	b2g := bpf2go{
		stdout:    stdout,
		pkg:       pkg,
		outputDir: outputDir,
	}

	fs := flag.NewFlagSet("bpf2go", flag.ContinueOnError)
	fs.StringVar(&b2g.cc, "cc", "clang", "`binary` used to compile C to BPF")
	flagCFlags := fs.String("cflags", "", "flags passed to the compiler, may contain quoted arguments")
	fs.StringVar(&b2g.tags, "tags", "", "list of Go build tags to include in generated files")
	flagTarget := fs.String("target", "bpfel,bpfeb", "clang target to compile for")
	fs.StringVar(&b2g.makeBase, "makebase", "", "write make compatible depinfo files relative to `directory`")

	fs.SetOutput(stdout)
	fs.Usage = func() {
		fmt.Fprintf(fs.Output(), helpText, fs.Name())
		fs.PrintDefaults()
		fmt.Fprintln(fs.Output())
		printTargets(fs.Output())
	}
	if err := fs.Parse(args); errors.Is(err, flag.ErrHelp) {
		return nil
	} else if err != nil {
		return err
	}

	if b2g.pkg == "" {
		return errors.New("missing package, are you running via go generate?")
	}

	if b2g.cc == "" {
		return errors.New("no compiler specified")
	}

	args, cFlags := splitCFlagsFromArgs(fs.Args())

	if *flagCFlags != "" {
		splitCFlags, err := splitArguments(*flagCFlags)
		if err != nil {
			return err
		}

		// Command line arguments take precedence over C flags
		// from the flag.
		cFlags = append(splitCFlags, cFlags...)
	}

	for _, cFlag := range cFlags {
		if strings.HasPrefix(cFlag, "-M") {
			return fmt.Errorf("use -makebase instead of %q", cFlag)
		}
	}

	b2g.cFlags = cFlags[:len(cFlags):len(cFlags)]

	if len(args) < 2 {
		return errors.New("expected at least two arguments")
	}

	b2g.ident = args[0]
	if !token.IsIdentifier(b2g.ident) {
		return fmt.Errorf("%q is not a valid identifier", b2g.ident)
	}

	input := args[1]
	if _, err := os.Stat(input); os.IsNotExist(err) {
		return fmt.Errorf("file %s doesn't exist", input)
	} else if err != nil {
		return fmt.Errorf("state %s: %s", input, err)
	}

	b2g.sourceFile, err = filepath.Abs(input)
	if err != nil {
		return err
	}

	if b2g.makeBase != "" {
		b2g.makeBase, err = filepath.Abs(b2g.makeBase)
		if err != nil {
			return err
		}
	}

	if strings.ContainsRune(b2g.tags, '\n') {
		return fmt.Errorf("-tags mustn't contain new line characters")
	}

	targetArches := strings.Split(*flagTarget, ",")
	if len(targetArches) == 0 {
		return fmt.Errorf("no targets specified")
	}

	targets, err := collectTargets(targetArches)
	if errors.Is(err, errInvalidTarget) {
		printTargets(stdout)
		fmt.Fprintln(stdout)
		return err
	}
	if err != nil {
		return err
	}

	for target, arches := range targets {
		if err := b2g.convert(target, arches); err != nil {
			return err
		}
	}

	return nil
}

type bpf2go struct {
	stdout io.Writer
	// Absolute path to a .c file.
	sourceFile string
	// Absolute path to a directory where .go are written
	outputDir string
	// Valid go package name.
	pkg string
	// Valid go identifier.
	ident string
	// C compiler.
	cc string
	// C flags passed to the compiler.
	cFlags []string
	// Go tags included in the .go
	tags string
	// Base directory of the Makefile. Enables outputting make-style dependencies
	// in .d files.
	makeBase string
}

func (b2g *bpf2go) convert(tgt target, arches []string) (err error) {
	removeOnError := func(f *os.File) {
		if err != nil {
			os.Remove(f.Name())
		}
		f.Close()
	}

	stem := fmt.Sprintf("%s_%s", strings.ToLower(b2g.ident), tgt.clang)
	if tgt.linux != "" {
		stem = fmt.Sprintf("%s_%s_%s", strings.ToLower(b2g.ident), tgt.clang, tgt.linux)
	}

	objFileName := filepath.Join(b2g.outputDir, stem+".o")

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	var tags []string
	if len(arches) > 0 {
		tags = append(tags, strings.Join(arches, " "))
	}
	if b2g.tags != "" {
		tags = append(tags, b2g.tags)
	}

	cFlags := make([]string, len(b2g.cFlags))
	copy(cFlags, b2g.cFlags)
	if tgt.linux != "" {
		cFlags = append(cFlags, "-D__TARGET_ARCH_"+tgt.linux)
	}

	var dep bytes.Buffer
	err = compile(compileArgs{
		cc:     b2g.cc,
		cFlags: cFlags,
		target: tgt.clang,
		dir:    cwd,
		source: b2g.sourceFile,
		dest:   objFileName,
		dep:    &dep,
	})
	if err != nil {
		return err
	}

	fmt.Fprintln(b2g.stdout, "Compiled", objFileName)

	// Write out generated go
	goFileName := filepath.Join(b2g.outputDir, stem+".go")
	goFile, err := os.Create(goFileName)
	if err != nil {
		return err
	}
	defer removeOnError(goFile)

	obj, err := os.Open(objFileName)
	if err != nil {
		return err
	}
	defer obj.Close()

	err = writeCommon(writeArgs{
		pkg:   b2g.pkg,
		ident: b2g.ident,
		tags:  tags,
		obj:   objFileName,
		out:   goFile,
	})
	if err != nil {
		return fmt.Errorf("can't write %s: %s", goFileName, err)
	}

	fmt.Fprintln(b2g.stdout, "Wrote", goFileName)

	if b2g.makeBase == "" {
		return
	}

	deps, err := parseDependencies(cwd, &dep)
	if err != nil {
		return fmt.Errorf("can't read dependency information: %s", err)
	}

	// There is always at least a dependency for the main file.
	deps[0].file = goFileName
	depFile, err := adjustDependencies(b2g.makeBase, deps)
	if err != nil {
		return fmt.Errorf("can't adjust dependency information: %s", err)
	}

	depFileName := goFileName + ".d"
	if err := os.WriteFile(depFileName, depFile, 0666); err != nil {
		return fmt.Errorf("can't write dependency file: %s", err)
	}

	fmt.Fprintln(b2g.stdout, "Wrote", depFileName)
	return nil
}

type target struct {
	clang string
	linux string
}

func printTargets(w io.Writer) {
	var arches []string
	for arch, archTarget := range targetByGoArch {
		if archTarget.linux == "" {
			continue
		}
		arches = append(arches, arch)
	}
	sort.Strings(arches)

	fmt.Fprint(w, "Supported targets:\n")
	fmt.Fprint(w, "\tbpf\n\tbpfel\n\tbpfeb\n")
	for _, arch := range arches {
		fmt.Fprintf(w, "\t%s\n", arch)
	}
}

var errInvalidTarget = errors.New("unsupported target")

func collectTargets(targets []string) (map[target][]string, error) {
	result := make(map[target][]string)
	for _, tgt := range targets {
		switch tgt {
		case "bpf", "bpfel", "bpfeb":
			var goarches []string
			for arch, archTarget := range targetByGoArch {
				if archTarget.clang == tgt {
					// Include tags for all goarches that have the same endianness.
					goarches = append(goarches, arch)
				}
			}
			sort.Strings(goarches)
			result[target{tgt, ""}] = goarches

		default:
			archTarget, ok := targetByGoArch[tgt]
			if !ok || archTarget.linux == "" {
				return nil, fmt.Errorf("%q: %w", tgt, errInvalidTarget)
			}

			var goarches []string
			for goarch, lt := range targetByGoArch {
				if lt == archTarget {
					// Include tags for all goarches that have the same
					// target.
					goarches = append(goarches, goarch)
				}
			}

			sort.Strings(goarches)
			result[archTarget] = goarches
		}
	}

	return result, nil
}

func main() {
	outputDir, err := os.Getwd()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}

	if err := run(os.Stdout, os.Getenv("GOPACKAGE"), outputDir, os.Args[1:]); err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}
}
<commit_msg>cmd/bpf2go: remove unused open file<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

const helpText = `Usage: %[1]s [options] <ident> <source file> [-- <C flags>]

ident is used as the stem of all generated Go types and functions, and
must be a valid Go identifier.

source is a single C file that is compiled using the specified compiler
(usually some version of clang).

You can pass options to the compiler by appending them after a '--' argument
or by supplying -cflags. Flags passed as arguments take precedence
over flags passed via -cflags. Additionally, the program expands quotation
marks in -cflags. This means that -cflags 'foo "bar baz"' is passed to the
compiler as two arguments "foo" and "bar baz".

The program expects GOPACKAGE to be set in the environment, and should be invoked
via go generate. The generated files are written to the current directory.

Options:

`

// Targets understood by bpf2go.
//
// Targets without a Linux string can't be used directly and are only included
// for the generic bpf, bpfel, bpfeb targets.
var targetByGoArch = map[string]target{
	"386":         {"bpfel", "x86"},
	"amd64":       {"bpfel", "x86"},
	"amd64p32":    {"bpfel", ""},
	"arm":         {"bpfel", "arm"},
	"arm64":       {"bpfel", "arm64"},
	"mipsle":      {"bpfel", ""},
	"mips64le":    {"bpfel", ""},
	"mips64p32le": {"bpfel", ""},
	"ppc64le":     {"bpfel", "powerpc"},
	"riscv64":     {"bpfel", ""},
	"armbe":       {"bpfeb", "arm"},
	"arm64be":     {"bpfeb", "arm64"},
	"mips":        {"bpfeb", ""},
	"mips64":      {"bpfeb", ""},
	"mips64p32":   {"bpfeb", ""},
	"ppc64":       {"bpfeb", "powerpc"},
	"s390":        {"bpfeb", "s390"},
	"s390x":       {"bpfeb", "s390"},
	"sparc":       {"bpfeb", "sparc"},
	"sparc64":     {"bpfeb", "sparc"},
}

func run(stdout io.Writer, pkg, outputDir string, args []string) (err error) {
	b2g := bpf2go{
		stdout:    stdout,
		pkg:       pkg,
		outputDir: outputDir,
	}

	fs := flag.NewFlagSet("bpf2go", flag.ContinueOnError)
	fs.StringVar(&b2g.cc, "cc", "clang", "`binary` used to compile C to BPF")
	flagCFlags := fs.String("cflags", "", "flags passed to the compiler, may contain quoted arguments")
	fs.StringVar(&b2g.tags, "tags", "", "list of Go build tags to include in generated files")
	flagTarget := fs.String("target", "bpfel,bpfeb", "clang target to compile for")
	fs.StringVar(&b2g.makeBase, "makebase", "", "write make compatible depinfo files relative to `directory`")

	fs.SetOutput(stdout)
	fs.Usage = func() {
		fmt.Fprintf(fs.Output(), helpText, fs.Name())
		fs.PrintDefaults()
		fmt.Fprintln(fs.Output())
		printTargets(fs.Output())
	}
	if err := fs.Parse(args); errors.Is(err, flag.ErrHelp) {
		return nil
	} else if err != nil {
		return err
	}

	if b2g.pkg == "" {
		return errors.New("missing package, are you running via go generate?")
	}

	if b2g.cc == "" {
		return errors.New("no compiler specified")
	}

	args, cFlags := splitCFlagsFromArgs(fs.Args())

	if *flagCFlags != "" {
		splitCFlags, err := splitArguments(*flagCFlags)
		if err != nil {
			return err
		}

		// Command line arguments take precedence over C flags
		// from the flag.
		cFlags = append(splitCFlags, cFlags...)
	}

	for _, cFlag := range cFlags {
		if strings.HasPrefix(cFlag, "-M") {
			return fmt.Errorf("use -makebase instead of %q", cFlag)
		}
	}

	b2g.cFlags = cFlags[:len(cFlags):len(cFlags)]

	if len(args) < 2 {
		return errors.New("expected at least two arguments")
	}

	b2g.ident = args[0]
	if !token.IsIdentifier(b2g.ident) {
		return fmt.Errorf("%q is not a valid identifier", b2g.ident)
	}

	input := args[1]
	if _, err := os.Stat(input); os.IsNotExist(err) {
		return fmt.Errorf("file %s doesn't exist", input)
	} else if err != nil {
		return fmt.Errorf("state %s: %s", input, err)
	}

	b2g.sourceFile, err = filepath.Abs(input)
	if err != nil {
		return err
	}

	if b2g.makeBase != "" {
		b2g.makeBase, err = filepath.Abs(b2g.makeBase)
		if err != nil {
			return err
		}
	}

	if strings.ContainsRune(b2g.tags, '\n') {
		return fmt.Errorf("-tags mustn't contain new line characters")
	}

	targetArches := strings.Split(*flagTarget, ",")
	if len(targetArches) == 0 {
		return fmt.Errorf("no targets specified")
	}

	targets, err := collectTargets(targetArches)
	if errors.Is(err, errInvalidTarget) {
		printTargets(stdout)
		fmt.Fprintln(stdout)
		return err
	}
	if err != nil {
		return err
	}

	for target, arches := range targets {
		if err := b2g.convert(target, arches); err != nil {
			return err
		}
	}

	return nil
}

type bpf2go struct {
	stdout io.Writer
	// Absolute path to a .c file.
	sourceFile string
	// Absolute path to a directory where .go are written
	outputDir string
	// Valid go package name.
	pkg string
	// Valid go identifier.
	ident string
	// C compiler.
	cc string
	// C flags passed to the compiler.
	cFlags []string
	// Go tags included in the .go
	tags string
	// Base directory of the Makefile. Enables outputting make-style dependencies
	// in .d files.
	makeBase string
}

func (b2g *bpf2go) convert(tgt target, arches []string) (err error) {
	removeOnError := func(f *os.File) {
		if err != nil {
			os.Remove(f.Name())
		}
		f.Close()
	}

	stem := fmt.Sprintf("%s_%s", strings.ToLower(b2g.ident), tgt.clang)
	if tgt.linux != "" {
		stem = fmt.Sprintf("%s_%s_%s", strings.ToLower(b2g.ident), tgt.clang, tgt.linux)
	}

	objFileName := filepath.Join(b2g.outputDir, stem+".o")

	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	var tags []string
	if len(arches) > 0 {
		tags = append(tags, strings.Join(arches, " "))
	}
	if b2g.tags != "" {
		tags = append(tags, b2g.tags)
	}

	cFlags := make([]string, len(b2g.cFlags))
	copy(cFlags, b2g.cFlags)
	if tgt.linux != "" {
		cFlags = append(cFlags, "-D__TARGET_ARCH_"+tgt.linux)
	}

	var dep bytes.Buffer
	err = compile(compileArgs{
		cc:     b2g.cc,
		cFlags: cFlags,
		target: tgt.clang,
		dir:    cwd,
		source: b2g.sourceFile,
		dest:   objFileName,
		dep:    &dep,
	})
	if err != nil {
		return err
	}

	fmt.Fprintln(b2g.stdout, "Compiled", objFileName)

	// Write out generated go
	goFileName := filepath.Join(b2g.outputDir, stem+".go")
	goFile, err := os.Create(goFileName)
	if err != nil {
		return err
	}
	defer removeOnError(goFile)

	err = writeCommon(writeArgs{
		pkg:   b2g.pkg,
		ident: b2g.ident,
		tags:  tags,
		obj:   objFileName,
		out:   goFile,
	})
	if err != nil {
		return fmt.Errorf("can't write %s: %s", goFileName, err)
	}

	fmt.Fprintln(b2g.stdout, "Wrote", goFileName)

	if b2g.makeBase == "" {
		return
	}

	deps, err := parseDependencies(cwd, &dep)
	if err != nil {
		return fmt.Errorf("can't read dependency information: %s", err)
	}

	// There is always at least a dependency for the main file.
	deps[0].file = goFileName
	depFile, err := adjustDependencies(b2g.makeBase, deps)
	if err != nil {
		return fmt.Errorf("can't adjust dependency information: %s", err)
	}

	depFileName := goFileName + ".d"
	if err := os.WriteFile(depFileName, depFile, 0666); err != nil {
		return fmt.Errorf("can't write dependency file: %s", err)
	}

	fmt.Fprintln(b2g.stdout, "Wrote", depFileName)
	return nil
}

type target struct {
	clang string
	linux string
}

func printTargets(w io.Writer) {
	var arches []string
	for arch, archTarget := range targetByGoArch {
		if archTarget.linux == "" {
			continue
		}
		arches = append(arches, arch)
	}
	sort.Strings(arches)

	fmt.Fprint(w, "Supported targets:\n")
	fmt.Fprint(w, "\tbpf\n\tbpfel\n\tbpfeb\n")
	for _, arch := range arches {
		fmt.Fprintf(w, "\t%s\n", arch)
	}
}

var errInvalidTarget = errors.New("unsupported target")

func collectTargets(targets []string) (map[target][]string, error) {
	result := make(map[target][]string)
	for _, tgt := range targets {
		switch tgt {
		case "bpf", "bpfel", "bpfeb":
			var goarches []string
			for arch, archTarget := range targetByGoArch {
				if archTarget.clang == tgt {
					// Include tags for all goarches that have the same endianness.
					goarches = append(goarches, arch)
				}
			}
			sort.Strings(goarches)
			result[target{tgt, ""}] = goarches

		default:
			archTarget, ok := targetByGoArch[tgt]
			if !ok || archTarget.linux == "" {
				return nil, fmt.Errorf("%q: %w", tgt, errInvalidTarget)
			}

			var goarches []string
			for goarch, lt := range targetByGoArch {
				if lt == archTarget {
					// Include tags for all goarches that have the same
					// target.
					goarches = append(goarches, goarch)
				}
			}

			sort.Strings(goarches)
			result[archTarget] = goarches
		}
	}

	return result, nil
}

func main() {
	outputDir, err := os.Getwd()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}

	if err := run(os.Stdout, os.Getenv("GOPACKAGE"), outputDir, os.Args[1:]); err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os/exec"
)

var cmdDestroy = &Command{
	Run:             confirmDestroy(maybeMessage(runDestroy)),
	Usage:           "destroy <name>",
	OptionalMessage: true,
	Category:        "app",
	Short:           "destroy an app",
	NumArgs:         1,
	Long: `
Destroy destroys a heroku app. There is no going back, so be
sure you mean it. The command will prompt for confirmation, or
accept confirmation via stdin.

Example:

    $ emp destroy myapp
    warning: This will destroy myapp and its add-ons. Please type "myapp" to continue:
    Destroyed myapp.

    $ echo myapp | emp destroy myapp
    Destroyed myapp.
`,
}

func confirmDestroy(action func(cmd *Command, args []string)) func(cmd *Command, args []string) {
	return func(cmd *Command, args []string) {
		if len(args) != 1 {
			cmd.PrintUsage()
			os.Exit(2)
		}

		appname := args[0]
		warning := fmt.Sprintf("This will destroy %s and its add-ons. Please type %q to continue:", appname, appname)
		mustConfirm(warning, appname)
		action(cmd, args)
	}
}

func runDestroy(cmd *Command, args []string) {
	message := getMessage()
	appname := args[0]

	must(client.AppDelete(appname, message))
	log.Printf("Destroyed %s.", appname)
	remotes, _ := gitRemotes()
	for remote, remoteApp := range remotes {
		if appname == remoteApp {
			exec.Command("git", "remote", "rm", remote).Run()
		}
	}
}
<commit_msg>fix typo<commit_after>package main

import (
	"fmt"
	"log"
	"os/exec"
)

var cmdDestroy = &Command{
	Run:             confirmDestroy(maybeMessage(runDestroy)),
	Usage:           "destroy <name>",
	OptionalMessage: true,
	Category:        "app",
	Short:           "destroy an app",
	NumArgs:         1,
	Long: `
Destroy destroys a heroku app. There is no going back, so be
sure you mean it. The command will prompt for confirmation, or
accept confirmation via stdin.

Example:

    $ emp destroy myapp
    warning: This will destroy myapp and its add-ons. Please type "myapp" to continue:
    Destroyed myapp.

    $ echo myapp | emp destroy myapp
    Destroyed myapp.
`,
}

func confirmDestroy(action func(cmd *Command, args []string)) func(cmd *Command, args []string) {
	return func(cmd *Command, args []string) {
		cmd.AssertNumArgsCorrect(args)

		appname := args[0]
		warning := fmt.Sprintf("This will destroy %s and its add-ons. Please type %q to continue:", appname, appname)
		mustConfirm(warning, appname)
		action(cmd, args)
	}
}

func runDestroy(cmd *Command, args []string) {
	message := getMessage()
	appname := args[0]

	must(client.AppDelete(appname, message))
	log.Printf("Destroyed %s.", appname)
	remotes, _ := gitRemotes()
	for remote, remoteApp := range remotes {
		if appname == remoteApp {
			exec.Command("git", "remote", "rm", remote).Run()
		}
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path"

	"github.com/exoscale/egoscale"
	"github.com/spf13/cobra"
)

// sshCmd represents the ssh command
var sshCmd = &cobra.Command{
	Use:   "ssh <vm name | id>",
	Short: "SSH into a virtual machine instance",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return cmd.Usage()
		}

		ipv6, err := cmd.Flags().GetBool("ipv6")
		if err != nil {
			return err
		}

		isInfo, err := cmd.Flags().GetBool("info")
		if err != nil {
			return err
		}

		isConnectionSTR, err := cmd.Flags().GetBool("print")
		if err != nil {
			return err
		}

		info, err := getSSHInfo(args[0], ipv6)
		if err != nil {
			return err
		}

		if isConnectionSTR {
			return printSSHConnectSTR(info)
		}

		if isInfo {
			printSSHInfo(info)
			return nil
		}
		return connectSSH(info)
	},
}

type sshInfo struct {
	sshKeys  string
	userName string
	ip       *net.IP
	vmName   string
	vmID     string
}

func getSSHInfo(name string, isIpv6 bool) (*sshInfo, error) {
	vm, err := getVMWithNameOrID(cs, name)
	if err != nil {
		return nil, err
	}

	sshKeyPath := path.Join(gConfigFolder, "instances", vm.ID, "id_rsa")

	if _, err := os.Stat(sshKeyPath); os.IsNotExist(err) {
		sshKeyPath = "Default ssh keypair not found"
	}

	nic := vm.DefaultNic()
	if nic == nil {
		return nil, fmt.Errorf("this instance %q has no default NIC", vm.ID)
	}

	vmIP := vm.IP()

	if isIpv6 {
		if nic.IP6Address == nil {
			return nil, fmt.Errorf("missing IPv6 address on the instance %q", vm.ID)
		}
		vmIP = &nic.IP6Address
	}

	template := &egoscale.Template{ID: vm.TemplateID, IsFeatured: true, ZoneID: "1"}

	if err := cs.Get(template); err != nil {
		return nil, err
	}

	tempUser, ok := template.Details["username"]
	if !ok {
		return nil, fmt.Errorf("missing username information in Template %q", template.ID)
	}

	return &sshInfo{
		sshKeys:  sshKeyPath,
		userName: tempUser,
		ip:       vmIP,
		vmName:   vm.Name,
		vmID:     vm.ID,
	}, nil

}

func printSSHConnectSTR(info *sshInfo) error {

	if _, err := os.Stat(info.sshKeys); os.IsNotExist(err) {
		return fmt.Errorf("default ssh KeyPair not found %q infos.sshKeys", info.sshKeys)
	}

	fmt.Printf("ssh -i %s %s@%s\n", info.sshKeys, info.userName, info.ip)

	return nil
}

func printSSHInfo(info *sshInfo) {
	println("Host", info.vmName)
	println("\tHostName", info.ip.String())
	println("\tUser", info.userName)
	println("\tIdentityFile", info.sshKeys)
}

func connectSSH(cred *sshInfo) error {

	args := []string{
		"-i",
		cred.sshKeys,
		cred.userName + "@" + cred.ip.String(),
	}

	cmd := exec.Command("ssh", args...)

	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	return cmd.Run()
}

func init() {
	sshCmd.Flags().BoolP("info", "i", false, "Print SSH config information")
	sshCmd.Flags().BoolP("print", "p", false, "Print SSH command")
	sshCmd.Flags().BoolP("ipv6", "6", false, "Use IPv6 for SSH")
	RootCmd.AddCommand(sshCmd)
}
<commit_msg>Add warning on sshkey (#231)<commit_after>package cmd

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"path"

	"github.com/exoscale/egoscale"
	"github.com/spf13/cobra"
)

// sshCmd represents the ssh command
var sshCmd = &cobra.Command{
	Use:   "ssh <vm name | id>",
	Short: "SSH into a virtual machine instance",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return cmd.Usage()
		}

		ipv6, err := cmd.Flags().GetBool("ipv6")
		if err != nil {
			return err
		}

		isInfo, err := cmd.Flags().GetBool("info")
		if err != nil {
			return err
		}

		isConnectionSTR, err := cmd.Flags().GetBool("print")
		if err != nil {
			return err
		}

		info, err := getSSHInfo(args[0], ipv6)
		if err != nil {
			return err
		}

		if isConnectionSTR {
			printSSHConnectSTR(info)
			return nil
		}

		if isInfo {
			printSSHInfo(info)
			return nil
		}
		return connectSSH(info)
	},
}

type sshInfo struct {
	sshKeys  string
	userName string
	ip       net.IP
	vmName   string
	vmID     string
}

func getSSHInfo(name string, isIpv6 bool) (*sshInfo, error) {
	vm, err := getVMWithNameOrID(cs, name)
	if err != nil {
		return nil, err
	}

	sshKeyPath := path.Join(gConfigFolder, "instances", vm.ID, "id_rsa")

	nic := vm.DefaultNic()
	if nic == nil {
		return nil, fmt.Errorf("this instance %q has no default NIC", vm.ID)
	}

	vmIP := vm.IP()

	if isIpv6 {
		if nic.IP6Address == nil {
			return nil, fmt.Errorf("missing IPv6 address on the instance %q", vm.ID)
		}
		vmIP = &nic.IP6Address
	}

	if vmIP == nil {
		return nil, fmt.Errorf("no valid IP address found")
	}

	template := &egoscale.Template{ID: vm.TemplateID, IsFeatured: true, ZoneID: "1"}

	if err := cs.Get(template); err != nil {
		return nil, err
	}

	tempUser, ok := template.Details["username"]
	if !ok {
		return nil, fmt.Errorf("missing username information in Template %q", template.ID)
	}

	return &sshInfo{
		sshKeys:  sshKeyPath,
		userName: tempUser,
		ip:       *vmIP,
		vmName:   vm.Name,
		vmID:     vm.ID,
	}, nil

}

func printSSHConnectSTR(info *sshInfo) {
	sshArgs := ""

	if _, err := os.Stat(info.sshKeys); err == nil {
		sshArgs = fmt.Sprintf("-i %q ", info.sshKeys)
	}

	fmt.Printf("ssh %s%s@%s\n", sshArgs, info.userName, info.ip)
}

func printSSHInfo(info *sshInfo) {
	fmt.Println("Host", info.vmName)
	fmt.Println("\tHostName", info.ip.String())
	fmt.Println("\tUser", info.userName)
	if _, err := os.Stat(info.sshKeys); err == nil {
		fmt.Println("\tIdentityFile", info.sshKeys)
	}
}

func connectSSH(info *sshInfo) error {

	args := make([]string, 0, 3)

	if _, err := os.Stat(info.sshKeys); os.IsNotExist(err) {
		log.Printf("Warning: Identity file %s not found or not accessible.", info.sshKeys)
	} else {
		args = append(args, "-i")
		args = append(args, info.sshKeys)
	}

	args = append(args, info.userName+"@"+info.ip.String())

	cmd := exec.Command("ssh", args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	return cmd.Run()
}

func init() {
	sshCmd.Flags().BoolP("info", "i", false, "Print SSH config information")
	sshCmd.Flags().BoolP("print", "p", false, "Print SSH command")
	sshCmd.Flags().BoolP("ipv6", "6", false, "Use IPv6 for SSH")
	RootCmd.AddCommand(sshCmd)
}
<|endoftext|>


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

package main

import (
	"time"

	"github.com/google/gapid/core/app/flags"
	"github.com/google/gapid/core/os/file"
)

const (
	AutoVideo VideoType = iota
	SxsVideo
	RegularVideo
	IndividualFrames
)

const (
	Json PackagesOutput = iota
	Proto
	ProtoString
	SimpleList
)

type VideoType uint8

var videoTypeNames = map[VideoType]string{
	AutoVideo:        "auto",
	SxsVideo:         "sxs",
	RegularVideo:     "regular",
	IndividualFrames: "frames",
}

func (v *VideoType) Choose(c interface{}) {
	*v = c.(VideoType)
}
func (v VideoType) String() string {
	return videoTypeNames[v]
}

type PackagesOutput uint8

var packagesOutputNames = map[PackagesOutput]string{
	Json:        "json",
	Proto:       "proto",
	ProtoString: "proto-string",
	SimpleList:  "list",
}

func (v *PackagesOutput) Choose(c interface{}) {
	*v = c.(PackagesOutput)
}
func (v PackagesOutput) String() string {
	return packagesOutputNames[v]
}

type (
	CommandFilterFlags struct {
		Context int `help:"Filter to the i'th context."`
	}
	ObservationFlags struct {
		Ranges bool `help:"if true then display the read and write ranges made by each command."`
		Data   bool `help:"if true then display the bytes read and written by each command. Implies Ranges."`
	}
	DeviceFlags struct {
		Device string `help:"Device to spawn on. One of: 'none', 'host', 'android' or <device-serial>"`
	}
	DevicesFlags struct {
		Gapis GapisFlags
	}
	GapisFlags struct {
		Profile string `help:"produce a pprof file from gapis"`
		Port    int    `help:"gapis tcp port to connect to, 0 means start new instance."`
		Args    string `help:"The arguments to be passed to gapis"`
		Token   string `help:"The auth token to use when connecting to an existing server."`
	}
	GapirFlags struct {
		DeviceFlags
		Args string `help:"The arguments to be passed to gapir"`
	}
	GapiiFlags struct {
		DeviceFlags
	}
	ReportFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		Out   string `help:"output report path"`
		CommandFilterFlags
	}
	VideoFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		FPS   int    `help:"frames per second"`
		Out   string `help:"output video path"`
		Max   struct {
			Width  int `help:"maximum video width"`
			Height int `help:"maximum video height"`
		}
		Type     VideoType `help:"type of output to produce"`
		Text     string    `help:"summary prefix (use '║' for aligned columns, '¶' for new line)"`
		Commands bool      `help:"Treat every command as its own frame"`
		Frames   struct {
			Start   int `help:"frame to start capture from"`
			Count   int `help:"number of frames after Start to capture: -1 for all frames"`
			Minimum int `help:"return error when less than this number of frames is found"`
		}
		CommandFilterFlags
	}
	DumpShadersFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		At    int `help:"command index to dump the resources after"`
	}
	DumpFlags struct {
		Gapis          GapisFlags
		Gapir          GapirFlags
		Raw            bool `help:"if true then the value of constants, instead of their names, will be dumped."`
		ShowDeviceInfo bool `help:"if true then show originating device information."`
		ShowABIInfo    bool `help:"if true then show information of the ABI used for the trace."`
		Observations   ObservationFlags
	}
	CommandsFlags struct {
		Gapis                  GapisFlags
		Gapir                  GapirFlags
		Raw                    bool   `help:"if true then the value of constants, instead of their names, will be dumped."`
		Name                   string `help:"Filter to commands and groups with the specified name."`
		MaxChildren            int    `help:"Maximum children per tree node."`
		GroupByAPI             bool   `help:"Group commands by api"`
		GroupByContext         bool   `help:"Group commands by context"`
		GroupByThread          bool   `help:"Group commands by thread"`
		GroupByDrawCall        bool   `help:"Group commands by draw call"`
		GroupByFrame           bool   `help:"Group commands by frame"`
		GroupByUserMarkers     bool   `help:"Group commands by user markers"`
		IncludeNoContextGroups bool   `help:"Include no context groups"`
		AllowIncompleteFrame   bool   `help:"Make a group for incomplete frames"`
		Observations           ObservationFlags
		CommandFilterFlags
	}
	StateFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		At    flags.U64Slice `help:"command/subcommand index to get the state after. Empty for last"`
	}
	StressTestFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
	}
	TraceFlags struct {
		Gapii GapiiFlags
		For   time.Duration `help:"duration to trace for"`
		Out   string        `help:"the file to generate"`
		Local struct {
			Port       int       `help:"capture a local program instead of using ADB"`
			App        file.Path `help:"a local program to trace"`
			Args       string    `help:"arguments to pass to the traced program"`
			WorkingDir string    `help:"working directory for the process"`
		}
		Android struct {
			Package        string `help:"the full package name"`
			Activity       string `help:"the full activity name"`
			Action         string `help:"the full action name"`
			Attach         bool   `help:"attach to running instance of the specified package"`
			Logcat         bool   `help:"print the output of logcat while tracing"`
			AdditionalArgs string `help:"additional arguments to pass to am start"`
		}
		APK     file.Path `help:"the path to an apk to install"`
		OBB     file.Path `help:"the path to an obb to install for APK"`
		Observe struct {
			Frames uint `help:"capture the framebuffer every n frames (0 to disable)"`
			Draws  uint `help:"capture the framebuffer every n draws (0 to disable)"`
		}
		Disable struct {
			PCS bool `help:"disable pre-compiled shaders"`
		}
		Record struct {
			Errors bool `help:"record device error state"`
			Inputs bool `help:"record the inputs to file"`
		}
		Clear struct {
			Cache bool `help:"clear package data before running it"`
		}
		Input struct {
			File string `help:"the file to use for recorded inputs"`
		}
		Replay struct {
			Inputs bool `help:"replay the inputs from file"`
		}
		Start struct {
			Defer bool `help:"defers the start of the trace until <enter> is pressed. Only valid for Vulkan."`
			At    struct {
				Frame int `help:"defers the start of the trace until given frame. Only valid for Vulkan. Not compatible with start-defer."`
			}
		}
		Capture struct {
			Frames int `help:"only capture the given number of frames. 0 for all"`
		}
		No struct {
			Buffer bool `help:"Do not buffer the output, this helps if the application crashes"`
		}
		API string `help:"only capture the given API valid options are gles and vulkan"`
		ADB string `help:"Path to the adb executable; leave empty to search the environment"`
	}
	PackagesFlags struct {
		DeviceFlags
		Icons       bool           `help:"if true then package icons are also dumped."`
		IconDensity float64        `help:"scale multiplier on icon density."`
		Format      PackagesOutput `help:"output format"`
		Out         string         `help:"output file, standard output if none"`
		DataHeader  string         `help:"marker to write before package data"`
		ADB         string         `help:"Path to the adb executable; leave empty to search the environment"`
	}
	ScreenshotFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		At    flags.U64Slice `help:"command/subcommand index for the screenshot. Empty for last"`
	}
	UnpackFlags struct {
		Verbose bool `help:"if true, then output will not be truncated"`
	}
)
<commit_msg>Make some gapit flags hidden.<commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"time"

	"github.com/google/gapid/core/app/flags"
	"github.com/google/gapid/core/os/file"
)

const (
	AutoVideo VideoType = iota
	SxsVideo
	RegularVideo
	IndividualFrames
)

const (
	Json PackagesOutput = iota
	Proto
	ProtoString
	SimpleList
)

type VideoType uint8

var videoTypeNames = map[VideoType]string{
	AutoVideo:        "auto",
	SxsVideo:         "sxs",
	RegularVideo:     "regular",
	IndividualFrames: "frames",
}

func (v *VideoType) Choose(c interface{}) {
	*v = c.(VideoType)
}
func (v VideoType) String() string {
	return videoTypeNames[v]
}

type PackagesOutput uint8

var packagesOutputNames = map[PackagesOutput]string{
	Json:        "json",
	Proto:       "proto",
	ProtoString: "proto-string",
	SimpleList:  "list",
}

func (v *PackagesOutput) Choose(c interface{}) {
	*v = c.(PackagesOutput)
}
func (v PackagesOutput) String() string {
	return packagesOutputNames[v]
}

type (
	CommandFilterFlags struct {
		Context int `help:"Filter to the i'th context."`
	}
	ObservationFlags struct {
		Ranges bool `help:"if true then display the read and write ranges made by each command."`
		Data   bool `help:"if true then display the bytes read and written by each command. Implies Ranges."`
	}
	DeviceFlags struct {
		Device string `help:"Device to spawn on. One of: 'none', 'host', 'android' or <device-serial>"`
	}
	DevicesFlags struct {
		Gapis GapisFlags
	}
	GapisFlags struct {
		Profile string `help:"_produce a pprof file from gapis"`
		Port    int    `help:"gapis tcp port to connect to, 0 means start new instance."`
		Args    string `help:"_The arguments to be passed to gapis"`
		Token   string `help:"_The auth token to use when connecting to an existing server."`
	}
	GapirFlags struct {
		DeviceFlags
		Args string `help:"_The arguments to be passed to gapir"`
	}
	GapiiFlags struct {
		DeviceFlags
	}
	ReportFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		Out   string `help:"output report path"`
		CommandFilterFlags
	}
	VideoFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		FPS   int    `help:"frames per second"`
		Out   string `help:"output video path"`
		Max   struct {
			Width  int `help:"maximum video width"`
			Height int `help:"maximum video height"`
		}
		Type     VideoType `help:"type of output to produce"`
		Text     string    `help:"_summary prefix (use '║' for aligned columns, '¶' for new line)"`
		Commands bool      `help:"Treat every command as its own frame"`
		Frames   struct {
			Start   int `help:"frame to start capture from"`
			Count   int `help:"number of frames after Start to capture: -1 for all frames"`
			Minimum int `help:"_return error when less than this number of frames is found"`
		}
		CommandFilterFlags
	}
	DumpShadersFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		At    int `help:"command index to dump the resources after"`
	}
	DumpFlags struct {
		Gapis          GapisFlags
		Gapir          GapirFlags
		Raw            bool `help:"if true then the value of constants, instead of their names, will be dumped."`
		ShowDeviceInfo bool `help:"if true then show originating device information."`
		ShowABIInfo    bool `help:"if true then show information of the ABI used for the trace."`
		Observations   ObservationFlags
	}
	CommandsFlags struct {
		Gapis                  GapisFlags
		Gapir                  GapirFlags
		Raw                    bool   `help:"if true then the value of constants, instead of their names, will be dumped."`
		Name                   string `help:"Filter to commands and groups with the specified name."`
		MaxChildren            int    `help:"_Maximum children per tree node."`
		GroupByAPI             bool   `help:"Group commands by api"`
		GroupByContext         bool   `help:"Group commands by context"`
		GroupByThread          bool   `help:"Group commands by thread"`
		GroupByDrawCall        bool   `help:"Group commands by draw call"`
		GroupByFrame           bool   `help:"Group commands by frame"`
		GroupByUserMarkers     bool   `help:"Group commands by user markers"`
		IncludeNoContextGroups bool   `help:"_Include no context groups"`
		AllowIncompleteFrame   bool   `help:"_Make a group for incomplete frames"`
		Observations           ObservationFlags
		CommandFilterFlags
	}
	StateFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		At    flags.U64Slice `help:"command/subcommand index to get the state after. Empty for last"`
	}
	StressTestFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
	}
	TraceFlags struct {
		Gapii GapiiFlags
		For   time.Duration `help:"duration to trace for"`
		Out   string        `help:"the file to generate"`
		Local struct {
			Port       int       `help:"capture a local program instead of using ADB"`
			App        file.Path `help:"a local program to trace"`
			Args       string    `help:"arguments to pass to the traced program"`
			WorkingDir string    `help:"working directory for the process"`
		}
		Android struct {
			Package        string `help:"the full package name"`
			Activity       string `help:"the full activity name"`
			Action         string `help:"the full action name"`
			Attach         bool   `help:"attach to running instance of the specified package"`
			Logcat         bool   `help:"print the output of logcat while tracing"`
			AdditionalArgs string `help:"additional arguments to pass to am start"`
		}
		APK     file.Path `help:"the path to an apk to install"`
		OBB     file.Path `help:"the path to an obb to install for APK"`
		Observe struct {
			Frames uint `help:"capture the framebuffer every n frames (0 to disable)"`
			Draws  uint `help:"capture the framebuffer every n draws (0 to disable)"`
		}
		Disable struct {
			PCS bool `help:"disable pre-compiled shaders"`
		}
		Record struct {
			Errors bool `help:"_record device error state"`
			Inputs bool `help:"_record the inputs to file"`
		}
		Clear struct {
			Cache bool `help:"clear package data before running it"`
		}
		Input struct {
			File string `help:"_the file to use for recorded inputs"`
		}
		Replay struct {
			Inputs bool `help:"_replay the inputs from file"`
		}
		Start struct {
			Defer bool `help:"defers the start of the trace until <enter> is pressed. Only valid for Vulkan."`
			At    struct {
				Frame int `help:"defers the start of the trace until given frame. Only valid for Vulkan. Not compatible with start-defer."`
			}
		}
		Capture struct {
			Frames int `help:"only capture the given number of frames. 0 for all"`
		}
		No struct {
			Buffer bool `help:"Do not buffer the output, this helps if the application crashes"`
		}
		API string `help:"only capture the given API valid options are gles and vulkan"`
		ADB string `help:"Path to the adb executable; leave empty to search the environment"`
	}
	PackagesFlags struct {
		DeviceFlags
		Icons       bool           `help:"if true then package icons are also dumped."`
		IconDensity float64        `help:"_scale multiplier on icon density."`
		Format      PackagesOutput `help:"output format"`
		Out         string         `help:"output file, standard output if none"`
		DataHeader  string         `help:"marker to write before package data"`
		ADB         string         `help:"Path to the adb executable; leave empty to search the environment"`
	}
	ScreenshotFlags struct {
		Gapis GapisFlags
		Gapir GapirFlags
		At    flags.U64Slice `help:"command/subcommand index for the screenshot. Empty for last"`
	}
	UnpackFlags struct {
		Verbose bool `help:"if true, then output will not be truncated"`
	}
)
<|endoftext|>