<commit_before>package mesh

import (
	"fmt"
	"math/rand"
	"net"
	"time"
	"unicode"
)

const (
	initialInterval = 2 * time.Second
	maxInterval     = 6 * time.Minute
	resetAfter      = 1 * time.Minute
)

type peerAddrs map[string]*net.TCPAddr

// ConnectionMaker initiates and manages connections to peers.
type connectionMaker struct {
	ourself     *localPeer
	peers       *Peers
	localAddr   string
	port        int
	discovery   bool
	targets     map[string]*target
	connections map[Connection]struct{}
	directPeers peerAddrs
	actionChan  chan<- connectionMakerAction
	logger      Logger
}

// TargetState describes the connection state of a remote target.
type targetState int

const (
	targetWaiting targetState = iota
	targetAttempting
	targetConnected
	targetSuspended
)

// Information about an address where we may find a peer.
type target struct {
	state       targetState
	lastError   error         // reason for disconnection last time
	tryAfter    time.Time     // next time to try this address
	tryInterval time.Duration // retry delay on next failure
}

// The actor closure used by ConnectionMaker. If an action returns true, the
// ConnectionMaker will check the state of its targets, and reconnect to
// relevant candidates.
type connectionMakerAction func() bool

// newConnectionMaker returns a usable ConnectionMaker, seeded with
// peers, making outbound connections from localAddr, and listening on
// port. If discovery is true, ConnectionMaker will attempt to
// initiate new connections with peers it's not directly connected to.
func newConnectionMaker(ourself *localPeer, peers *Peers, localAddr string, port int, discovery bool, logger Logger) *connectionMaker {
	actionChan := make(chan connectionMakerAction, ChannelSize)
	cm := &connectionMaker{
		ourself:     ourself,
		peers:       peers,
		localAddr:   localAddr,
		port:        port,
		discovery:   discovery,
		directPeers: peerAddrs{},
		targets:     make(map[string]*target),
		connections: make(map[Connection]struct{}),
		actionChan:  actionChan,
		logger:      logger,
	}
	go cm.queryLoop(actionChan)
	return cm
}

// InitiateConnections creates new connections to the provided peers,
// specified in host:port format. If replace is true, any existing direct
// peers are forgotten.
//
// TODO(pb): Weave Net invokes router.ConnectionMaker.InitiateConnections;
// it may be better to provide that on Router directly.
func (cm *connectionMaker) InitiateConnections(peers []string, replace bool) []error {
	errors := []error{}
	addrs := peerAddrs{}
	for _, peer := range peers {
		host, port, err := net.SplitHostPort(peer)
		if err != nil {
			host = peer
			port = "0" // we use that as an indication that "no port was supplied"
		}
		if !isAlnum(port) {
			errors = append(errors, fmt.Errorf("invalid peer name %q, should just be host[:port]", peer))
		} else if addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%s", host, port)); err != nil {
			errors = append(errors, err)
		} else {
			addrs[peer] = addr
		}
	}
	cm.actionChan <- func() bool {
		if replace {
			cm.directPeers = peerAddrs{}
		}
		for peer, addr := range addrs {
			cm.directPeers[peer] = addr
			// curtail any existing reconnect interval
			if target, found := cm.targets[cm.completeAddr(*addr)]; found {
				target.nextTryNow()
			}
		}
		return true
	}
	return errors
}

func isAlnum(s string) bool {
	for _, c := range s {
		if !unicode.In(c, unicode.Letter, unicode.Digit) {
			return false
		}
	}
	return true
}

// ForgetConnections removes direct connections to the provided peers,
// specified in host:port format.
//
// TODO(pb): Weave Net invokes router.ConnectionMaker.ForgetConnections;
// it may be better to provide that on Router directly.
func (cm *connectionMaker) ForgetConnections(peers []string) {
	cm.actionChan <- func() bool {
		for _, peer := range peers {
			delete(cm.directPeers, peer)
		}
		return false
	}
}

// Targets takes a snapshot of the targets (direct peers),
// either just the ones we are still trying, or all of them.
// Note these are the same things that InitiateConnections and ForgetConnections talks about,
// but a method to retrieve 'Connections' would obviously return the current connections.
func (cm *connectionMaker) Targets(activeOnly bool) []string {
	resultChan := make(chan []string, 0)
	cm.actionChan <- func() bool {
		var slice []string
		for peer := range cm.directPeers {
			if activeOnly {
				if target, ok := cm.targets[peer]; ok && target.tryAfter.IsZero() {
					continue
				}
			}
			slice = append(slice, peer)
		}
		resultChan <- slice
		return false
	}
	return <-resultChan
}

// connectionAborted marks the target identified by address as broken, and
// puts it in the TargetWaiting state.
func (cm *connectionMaker) connectionAborted(address string, err error) {
	cm.actionChan <- func() bool {
		target := cm.targets[address]
		target.state = targetWaiting
		target.lastError = err
		target.nextTryLater()
		return true
	}
}

// connectionCreated registers the passed connection, and marks the target
// identified by conn.RemoteTCPAddr() as established, and puts it in the
// TargetConnected state.
func (cm *connectionMaker) connectionCreated(conn Connection) {
	cm.actionChan <- func() bool {
		cm.connections[conn] = struct{}{}
		if conn.isOutbound() {
			target := cm.targets[conn.remoteTCPAddress()]
			target.state = targetConnected
		}
		return false
	}
}

// connectionTerminated unregisters the passed connection, and marks the
// target identified by conn.RemoteTCPAddr() as Waiting.
func (cm *connectionMaker) connectionTerminated(conn Connection, err error) {
	cm.actionChan <- func() bool {
		delete(cm.connections, conn)
		if conn.isOutbound() {
			target := cm.targets[conn.remoteTCPAddress()]
			target.state = targetWaiting
			target.lastError = err
			switch {
			case err == errConnectToSelf:
				target.nextTryNever()
			case time.Now().After(target.tryAfter.Add(resetAfter)):
				target.nextTryNow()
			default:
				target.nextTryLater()
			}
		}
		return true
	}
}

// refresh sends a no-op action into the ConnectionMaker, purely so that the
// ConnectionMaker will check the state of its targets and reconnect to
// relevant candidates.
func (cm *connectionMaker) refresh() {
	cm.actionChan <- func() bool { return true }
}

func (cm *connectionMaker) queryLoop(actionChan <-chan connectionMakerAction) {
	timer := time.NewTimer(maxDuration)
	run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) }
	for {
		select {
		case action := <-actionChan:
			if action() {
				run()
			}
		case <-timer.C:
			run()
		}
	}
}

func (cm *connectionMaker) completeAddr(addr net.TCPAddr) string {
	if addr.Port == 0 {
		addr.Port = cm.port
	}
	return addr.String()
}

func (cm *connectionMaker) checkStateAndAttemptConnections() time.Duration {
	var (
		validTarget  = make(map[string]struct{})
		directTarget = make(map[string]struct{})
	)
	ourConnectedPeers, ourConnectedTargets, ourInboundIPs := cm.ourConnections()

	addTarget := func(address string) {
		if _, connected := ourConnectedTargets[address]; connected {
			return
		}
		validTarget[address] = struct{}{}
		if _, found := cm.targets[address]; found {
			return
		}
		tgt := &target{state: targetWaiting}
		tgt.nextTryNow()
		cm.targets[address] = tgt
	}

	// Add direct targets that are not connected
	for _, addr := range cm.directPeers {
		attempt := true
		if addr.Port == 0 {
			// If a peer was specified w/o a port, then we do not
			// attempt to connect to it if we have any inbound
			// connections from that IP.
			if _, connected := ourInboundIPs[addr.IP.String()]; connected {
				attempt = false
			}
		}
		address := cm.completeAddr(*addr)
		directTarget[address] = struct{}{}
		if attempt {
			addTarget(address)
		}
	}

	// Add targets for peers that someone else is connected to, but we
	// aren't
	if cm.discovery {
		cm.addPeerTargets(ourConnectedPeers, addTarget)
	}

	return cm.connectToTargets(validTarget, directTarget)
}

func (cm *connectionMaker) ourConnections() (peerNameSet, map[string]struct{}, map[string]struct{}) {
	var (
		ourConnectedPeers   = make(peerNameSet)
		ourConnectedTargets = make(map[string]struct{})
		ourInboundIPs       = make(map[string]struct{})
	)
	for conn := range cm.connections {
		address := conn.remoteTCPAddress()
		ourConnectedPeers[conn.Remote().Name] = struct{}{}
		ourConnectedTargets[address] = struct{}{}
		if conn.isOutbound() {
			continue
		}
		if ip, _, err := net.SplitHostPort(address); err == nil { // should always succeed
			ourInboundIPs[ip] = struct{}{}
		}
	}
	return ourConnectedPeers, ourConnectedTargets, ourInboundIPs
}

func (cm *connectionMaker) addPeerTargets(ourConnectedPeers peerNameSet, addTarget func(string)) {
	cm.peers.forEach(func(peer *Peer) {
		if peer == cm.ourself.Peer {
			return
		}
		// Modifying peer.connections requires a write lock on Peers,
		// and since we are holding a read lock (due to the ForEach),
		// access without locking the peer is safe.
		for otherPeer, conn := range peer.connections {
			if otherPeer == cm.ourself.Name {
				continue
			}
			if _, connected := ourConnectedPeers[otherPeer]; connected {
				continue
			}
			address := conn.remoteTCPAddress()
			if conn.isOutbound() {
				addTarget(address)
			} else if ip, _, err := net.SplitHostPort(address); err == nil {
				// There is no point connecting to the (likely
				// ephemeral) remote port of an inbound connection
				// that some peer has. Let's try to connect on the
				// weave port instead.
				addTarget(fmt.Sprintf("%s:%d", ip, cm.port))
			}
		}
	})
}

func (cm *connectionMaker) connectToTargets(validTarget map[string]struct{}, directTarget map[string]struct{}) time.Duration {
	now := time.Now() // make sure we catch items just added
	after := maxDuration
	for address, target := range cm.targets {
		if target.state != targetWaiting && target.state != targetSuspended {
			continue
		}
		if _, valid := validTarget[address]; !valid {
			// Not valid: suspend reconnects if direct peer,
			// otherwise forget this target entirely
			if _, direct := directTarget[address]; direct {
				target.state = targetSuspended
			} else {
				delete(cm.targets, address)
			}
			continue
		}
		if target.tryAfter.IsZero() {
			continue
		}
		target.state = targetWaiting
		switch duration := target.tryAfter.Sub(now); {
		case duration <= 0:
			target.state = targetAttempting
			_, isCmdLineTarget := directTarget[address]
			go cm.attemptConnection(address, isCmdLineTarget)
		case duration < after:
			after = duration
		}
	}
	return after
}

func (cm *connectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	cm.logger.Printf("->[%s] attempting connection", address)
	if err := cm.ourself.createConnection(cm.localAddr, address, acceptNewPeer, cm.logger); err != nil {
		cm.logger.Printf("->[%s] error during connection attempt: %v", address, err)
		cm.connectionAborted(address, err)
	}
}

func (t *target) nextTryNever() {
	t.tryAfter = time.Time{}
	t.tryInterval = maxInterval
}

func (t *target) nextTryNow() {
	t.tryAfter = time.Now()
	t.tryInterval = initialInterval
}

// The delay at the nth retry is a random value in the range
// [i-i/2,i+i/2], where i = InitialInterval * 1.5^(n-1).
func (t *target) nextTryLater() {
	t.tryAfter = time.Now().Add(t.tryInterval/2 + time.Duration(rand.Int63n(int64(t.tryInterval))))
	t.tryInterval = t.tryInterval * 3 / 2
	if t.tryInterval > maxInterval {
		t.tryInterval = maxInterval
	}
}
<commit_msg>Recompute targets immediately after a 'Forget'<commit_after>package mesh

import (
	"fmt"
	"math/rand"
	"net"
	"time"
	"unicode"
)

const (
	initialInterval = 2 * time.Second
	maxInterval     = 6 * time.Minute
	resetAfter      = 1 * time.Minute
)

type peerAddrs map[string]*net.TCPAddr

// ConnectionMaker initiates and manages connections to peers.
type connectionMaker struct {
	ourself     *localPeer
	peers       *Peers
	localAddr   string
	port        int
	discovery   bool
	targets     map[string]*target
	connections map[Connection]struct{}
	directPeers peerAddrs
	actionChan  chan<- connectionMakerAction
	logger      Logger
}

// TargetState describes the connection state of a remote target.
type targetState int

const (
	targetWaiting targetState = iota
	targetAttempting
	targetConnected
	targetSuspended
)

// Information about an address where we may find a peer.
type target struct {
	state       targetState
	lastError   error         // reason for disconnection last time
	tryAfter    time.Time     // next time to try this address
	tryInterval time.Duration // retry delay on next failure
}

// The actor closure used by ConnectionMaker. If an action returns true, the
// ConnectionMaker will check the state of its targets, and reconnect to
// relevant candidates.
type connectionMakerAction func() bool

// newConnectionMaker returns a usable ConnectionMaker, seeded with
// peers, making outbound connections from localAddr, and listening on
// port. If discovery is true, ConnectionMaker will attempt to
// initiate new connections with peers it's not directly connected to.
func newConnectionMaker(ourself *localPeer, peers *Peers, localAddr string, port int, discovery bool, logger Logger) *connectionMaker {
	actionChan := make(chan connectionMakerAction, ChannelSize)
	cm := &connectionMaker{
		ourself:     ourself,
		peers:       peers,
		localAddr:   localAddr,
		port:        port,
		discovery:   discovery,
		directPeers: peerAddrs{},
		targets:     make(map[string]*target),
		connections: make(map[Connection]struct{}),
		actionChan:  actionChan,
		logger:      logger,
	}
	go cm.queryLoop(actionChan)
	return cm
}

// InitiateConnections creates new connections to the provided peers,
// specified in host:port format. If replace is true, any existing direct
// peers are forgotten.
//
// TODO(pb): Weave Net invokes router.ConnectionMaker.InitiateConnections;
// it may be better to provide that on Router directly.
func (cm *connectionMaker) InitiateConnections(peers []string, replace bool) []error {
	errors := []error{}
	addrs := peerAddrs{}
	for _, peer := range peers {
		host, port, err := net.SplitHostPort(peer)
		if err != nil {
			host = peer
			port = "0" // we use that as an indication that "no port was supplied"
		}
		if !isAlnum(port) {
			errors = append(errors, fmt.Errorf("invalid peer name %q, should just be host[:port]", peer))
		} else if addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%s", host, port)); err != nil {
			errors = append(errors, err)
		} else {
			addrs[peer] = addr
		}
	}
	cm.actionChan <- func() bool {
		if replace {
			cm.directPeers = peerAddrs{}
		}
		for peer, addr := range addrs {
			cm.directPeers[peer] = addr
			// curtail any existing reconnect interval
			if target, found := cm.targets[cm.completeAddr(*addr)]; found {
				target.nextTryNow()
			}
		}
		return true
	}
	return errors
}

func isAlnum(s string) bool {
	for _, c := range s {
		if !unicode.In(c, unicode.Letter, unicode.Digit) {
			return false
		}
	}
	return true
}

// ForgetConnections removes direct connections to the provided peers,
// specified in host:port format.
//
// TODO(pb): Weave Net invokes router.ConnectionMaker.ForgetConnections;
// it may be better to provide that on Router directly.
func (cm *connectionMaker) ForgetConnections(peers []string) {
	cm.actionChan <- func() bool {
		for _, peer := range peers {
			delete(cm.directPeers, peer)
		}
		return true
	}
}

// Targets takes a snapshot of the targets (direct peers),
// either just the ones we are still trying, or all of them.
// Note these are the same things that InitiateConnections and ForgetConnections talks about,
// but a method to retrieve 'Connections' would obviously return the current connections.
func (cm *connectionMaker) Targets(activeOnly bool) []string {
	resultChan := make(chan []string, 0)
	cm.actionChan <- func() bool {
		var slice []string
		for peer := range cm.directPeers {
			if activeOnly {
				if target, ok := cm.targets[peer]; ok && target.tryAfter.IsZero() {
					continue
				}
			}
			slice = append(slice, peer)
		}
		resultChan <- slice
		return false
	}
	return <-resultChan
}

// connectionAborted marks the target identified by address as broken, and
// puts it in the TargetWaiting state.
func (cm *connectionMaker) connectionAborted(address string, err error) {
	cm.actionChan <- func() bool {
		target := cm.targets[address]
		target.state = targetWaiting
		target.lastError = err
		target.nextTryLater()
		return true
	}
}

// connectionCreated registers the passed connection, and marks the target
// identified by conn.RemoteTCPAddr() as established, and puts it in the
// TargetConnected state.
func (cm *connectionMaker) connectionCreated(conn Connection) {
	cm.actionChan <- func() bool {
		cm.connections[conn] = struct{}{}
		if conn.isOutbound() {
			target := cm.targets[conn.remoteTCPAddress()]
			target.state = targetConnected
		}
		return false
	}
}

// connectionTerminated unregisters the passed connection, and marks the
// target identified by conn.RemoteTCPAddr() as Waiting.
func (cm *connectionMaker) connectionTerminated(conn Connection, err error) {
	cm.actionChan <- func() bool {
		delete(cm.connections, conn)
		if conn.isOutbound() {
			target := cm.targets[conn.remoteTCPAddress()]
			target.state = targetWaiting
			target.lastError = err
			switch {
			case err == errConnectToSelf:
				target.nextTryNever()
			case time.Now().After(target.tryAfter.Add(resetAfter)):
				target.nextTryNow()
			default:
				target.nextTryLater()
			}
		}
		return true
	}
}

// refresh sends a no-op action into the ConnectionMaker, purely so that the
// ConnectionMaker will check the state of its targets and reconnect to
// relevant candidates.
func (cm *connectionMaker) refresh() {
	cm.actionChan <- func() bool { return true }
}

func (cm *connectionMaker) queryLoop(actionChan <-chan connectionMakerAction) {
	timer := time.NewTimer(maxDuration)
	run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) }
	for {
		select {
		case action := <-actionChan:
			if action() {
				run()
			}
		case <-timer.C:
			run()
		}
	}
}

func (cm *connectionMaker) completeAddr(addr net.TCPAddr) string {
	if addr.Port == 0 {
		addr.Port = cm.port
	}
	return addr.String()
}

func (cm *connectionMaker) checkStateAndAttemptConnections() time.Duration {
	var (
		validTarget  = make(map[string]struct{})
		directTarget = make(map[string]struct{})
	)
	ourConnectedPeers, ourConnectedTargets, ourInboundIPs := cm.ourConnections()

	addTarget := func(address string) {
		if _, connected := ourConnectedTargets[address]; connected {
			return
		}
		validTarget[address] = struct{}{}
		if _, found := cm.targets[address]; found {
			return
		}
		tgt := &target{state: targetWaiting}
		tgt.nextTryNow()
		cm.targets[address] = tgt
	}

	// Add direct targets that are not connected
	for _, addr := range cm.directPeers {
		attempt := true
		if addr.Port == 0 {
			// If a peer was specified w/o a port, then we do not
			// attempt to connect to it if we have any inbound
			// connections from that IP.
			if _, connected := ourInboundIPs[addr.IP.String()]; connected {
				attempt = false
			}
		}
		address := cm.completeAddr(*addr)
		directTarget[address] = struct{}{}
		if attempt {
			addTarget(address)
		}
	}

	// Add targets for peers that someone else is connected to, but we
	// aren't
	if cm.discovery {
		cm.addPeerTargets(ourConnectedPeers, addTarget)
	}

	return cm.connectToTargets(validTarget, directTarget)
}

func (cm *connectionMaker) ourConnections() (peerNameSet, map[string]struct{}, map[string]struct{}) {
	var (
		ourConnectedPeers   = make(peerNameSet)
		ourConnectedTargets = make(map[string]struct{})
		ourInboundIPs       = make(map[string]struct{})
	)
	for conn := range cm.connections {
		address := conn.remoteTCPAddress()
		ourConnectedPeers[conn.Remote().Name] = struct{}{}
		ourConnectedTargets[address] = struct{}{}
		if conn.isOutbound() {
			continue
		}
		if ip, _, err := net.SplitHostPort(address); err == nil { // should always succeed
			ourInboundIPs[ip] = struct{}{}
		}
	}
	return ourConnectedPeers, ourConnectedTargets, ourInboundIPs
}

func (cm *connectionMaker) addPeerTargets(ourConnectedPeers peerNameSet, addTarget func(string)) {
	cm.peers.forEach(func(peer *Peer) {
		if peer == cm.ourself.Peer {
			return
		}
		// Modifying peer.connections requires a write lock on Peers,
		// and since we are holding a read lock (due to the ForEach),
		// access without locking the peer is safe.
		for otherPeer, conn := range peer.connections {
			if otherPeer == cm.ourself.Name {
				continue
			}
			if _, connected := ourConnectedPeers[otherPeer]; connected {
				continue
			}
			address := conn.remoteTCPAddress()
			if conn.isOutbound() {
				addTarget(address)
			} else if ip, _, err := net.SplitHostPort(address); err == nil {
				// There is no point connecting to the (likely
				// ephemeral) remote port of an inbound connection
				// that some peer has. Let's try to connect on the
				// weave port instead.
				addTarget(fmt.Sprintf("%s:%d", ip, cm.port))
			}
		}
	})
}

func (cm *connectionMaker) connectToTargets(validTarget map[string]struct{}, directTarget map[string]struct{}) time.Duration {
	now := time.Now() // make sure we catch items just added
	after := maxDuration
	for address, target := range cm.targets {
		if target.state != targetWaiting && target.state != targetSuspended {
			continue
		}
		if _, valid := validTarget[address]; !valid {
			// Not valid: suspend reconnects if direct peer,
			// otherwise forget this target entirely
			if _, direct := directTarget[address]; direct {
				target.state = targetSuspended
			} else {
				delete(cm.targets, address)
			}
			continue
		}
		if target.tryAfter.IsZero() {
			continue
		}
		target.state = targetWaiting
		switch duration := target.tryAfter.Sub(now); {
		case duration <= 0:
			target.state = targetAttempting
			_, isCmdLineTarget := directTarget[address]
			go cm.attemptConnection(address, isCmdLineTarget)
		case duration < after:
			after = duration
		}
	}
	return after
}

func (cm *connectionMaker) attemptConnection(address string, acceptNewPeer bool) {
	cm.logger.Printf("->[%s] attempting connection", address)
	if err := cm.ourself.createConnection(cm.localAddr, address, acceptNewPeer, cm.logger); err != nil {
		cm.logger.Printf("->[%s] error during connection attempt: %v", address, err)
		cm.connectionAborted(address, err)
	}
}

func (t *target) nextTryNever() {
	t.tryAfter = time.Time{}
	t.tryInterval = maxInterval
}

func (t *target) nextTryNow() {
	t.tryAfter = time.Now()
	t.tryInterval = initialInterval
}

// The delay at the nth retry is a random value in the range
// [i-i/2,i+i/2], where i = InitialInterval * 1.5^(n-1).
func (t *target) nextTryLater() {
	t.tryAfter = time.Now().Add(t.tryInterval/2 + time.Duration(rand.Int63n(int64(t.tryInterval))))
	t.tryInterval = t.tryInterval * 3 / 2
	if t.tryInterval > maxInterval {
		t.tryInterval = maxInterval
	}
}
<|endoftext|>


<commit_before>/*** Copyright (c) 2016, University of Florida Research Foundation, Inc. ***
 *** For more information please refer to the LICENSE.md file            ***/

package gorods

// #include "wrapper.h"
import "C"

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strings"
	"unsafe"
)

// Collection structs contain information about single collections in an iRods zone.
type Collection struct {
	Path        string
	Name        string
	DataObjects []interface{}
	MetaCol MetaCollection
	Con         *Connection
	Col         *Collection
	Recursive   bool

	chandle C.int
}

type Collections []*Collection

// Exists checks to see if a collection exists in the slice
// and returns true or false
func (colls Collections) Exists(path string) bool {
	if c := colls.Find(path); c != nil {
		return true
	}

	return false
}

// Find gets a collection from the slice and returns nil if one is not found.
// Both the collection name and path can be used as input.
func (colls Collections) Find(path string) *Collection {
	if path[len(path)-1] == '/' {
		path = path[:len(path)-1]
	}

	for i, col := range colls {
		if col.Path == path || col.Name == path {
			return colls[i]
		}
	}

	return nil
}

// FindRecursive acts just like Find, but also searches sub collections recursively.
// If the collection was not explicitly loaded recursively, only the first level of sub collections will be searched.
func (colls Collections) FindRecursive(path string) *Collection {
	if path[len(path)-1] == '/' {
		path = path[:len(path)-1]
	}

	for i, col := range colls {
		if col.Path == path || col.Name == path {
			return colls[i]
		}

		if col.Recursive {
			// Use Collections() since we already loaded everything
			if subCol := col.Collections().FindRecursive(path); subCol != nil {
				return subCol
			}
		} else {
			// Use DataObjects so we don't load new collections
			var filtered Collections

			for n, obj := range col.DataObjects {
				if reflect.TypeOf(obj).String() == "*gorods.Collection" {
					filtered = append(filtered, col.DataObjects[n].(*Collection))
				}
			}

			if subCol := filtered.FindRecursive(path); subCol != nil {
				return subCol
			}
		}
	}

	return nil
}

// String shows the contents of the collection. D = DataObj, C = Collection. Sample output:
//
// 	Collection: /tempZone/home/admin/gorods
// 		D: build.sh
// 		C: bin
// 		C: pkg
// 		C: src
func (obj *Collection) String() string {
	str := fmt.Sprintf("Collection: %v\n", obj.Path)

	for _, o := range obj.DataObjs() {
		str += fmt.Sprintf("\tD: %v\n", o.Name)
	}

	for _, o := range obj.Collections() {
		str += fmt.Sprintf("\tC: %v\n", o.Name)
	}

	return str
}

// NewCollection initializes collection from *C.collEnt_t. This is used internally in the gorods package, maybe it should be lowercased?
func NewCollection(data *C.collEnt_t, acol *Collection) *Collection {

	col := new(Collection)

	col.Col = acol
	col.Con = col.Col.Con
	col.Path = C.GoString(data.collName)

	pathSlice := strings.Split(col.Path, "/")

	col.Name = pathSlice[len(pathSlice)-1]

	if acol.Recursive {
		col.Recursive = true
		col.Init()
	}

	return col
}

// GetCollection initializes specified collection located at startPath using gorods.Connection.
// Could be considered alias of Connection.Collection()
func GetCollection(startPath string, recursive bool, con *Connection) *Collection {
	col := new(Collection)

	col.Con = con
	col.Path = startPath
	col.Recursive = recursive

	if col.Path[len(col.Path)-1] == '/' {
		col.Path = col.Path[:len(col.Path)-1]
	}

	pathSlice := strings.Split(col.Path, "/")
	col.Name = pathSlice[len(pathSlice)-1]

	if col.Recursive {
		col.Init()
	}

	return col
}

// Init opens and reads collection information from iRods if the handle isn't set
func (col *Collection) Init() *Collection {
	// If connection hasn't been opened, do it!
	if int(col.chandle) == 0 {
		col.Open()
		col.ReadCollection()
	}

	return col
}

// Attribute gets specific metadata AVU triple for Collection
func (col *Collection) Attribute(attr string) *Meta {
	col.Init()

	return col.Meta().Get(attr)
}

// Meta returns collection of all metadata AVU triples for Collection
func (col *Collection) Meta() MetaCollection {
	col.Init()

	if col.MetaCol == nil {
		col.MetaCol = NewMetaCollection(CollectionType, col.Name, filepath.Dir(col.Path), col.Con.ccon)
	}

	return col.MetaCol
}

// Open connects to iRods and sets the handle for Collection
// Usually called by Collection.Init()
func (col *Collection) Open() *Collection {
	var errMsg *C.char

	path := C.CString(col.Path)

	defer C.free(unsafe.Pointer(path))

	if status := C.gorods_open_collection(path, &col.chandle, col.Con.ccon, &errMsg); status != 0 {
		panic(fmt.Sprintf("iRods Open Collection Failed: %v, %v", col.Path, C.GoString(errMsg)))
	}

	return col
}

// Close closes the Collection connection and resets the handle
func (col *Collection) Close() *Collection {
	var errMsg *C.char

	if status := C.gorods_close_collection(col.chandle, col.Con.ccon, &errMsg); status != 0 {
		panic(fmt.Sprintf("iRods Close Collection Failed: %v, %v", col.Path, C.GoString(errMsg)))
	}

	col.chandle = C.int(0)

	return col
}

// Reads data into col.DataObjects
func (col *Collection) ReadCollection() {

	// Init C varaibles
	var (
		err     *C.char
		arr     *C.collEnt_t
		arrSize C.int
	)

	// Read data objs from collection
	C.gorods_read_collection(col.Con.ccon, col.chandle, &arr, &arrSize, &err)

	// Get result length
	arrLen := int(arrSize)

	unsafeArr := unsafe.Pointer(arr)
	defer C.free(unsafeArr)

	// Convert C array to slice, backed by arr *C.collEnt_t
	slice := (*[1 << 30]C.collEnt_t)(unsafeArr)[:arrLen:arrLen]

	col.DataObjects = make([]interface{}, 0)

	for i, _ := range slice {
		obj := &slice[i]

		isCollection := (obj.objType != C.DATA_OBJ_T)

		if isCollection {
			col.DataObjects = append(col.DataObjects, NewCollection(obj, col))
		} else {
			col.DataObjects = append(col.DataObjects, NewDataObj(obj, col))

			// Strings only in DataObj types
			C.free(unsafe.Pointer(obj.dataName))
			C.free(unsafe.Pointer(obj.dataId))
			C.free(unsafe.Pointer(obj.chksum))
			C.free(unsafe.Pointer(obj.dataType))
			C.free(unsafe.Pointer(obj.resource))
			C.free(unsafe.Pointer(obj.rescGrp))
			C.free(unsafe.Pointer(obj.phyPath))
		}

		// String in both object types
		C.free(unsafe.Pointer(obj.ownerName))
		C.free(unsafe.Pointer(obj.collName))
		C.free(unsafe.Pointer(obj.createTime))
		C.free(unsafe.Pointer(obj.modifyTime))

	}

	col.Close()
}

func (col *Collection) DataObjs() DataObjs {
	col.Init()

	var response DataObjs

	for i, obj := range col.DataObjects {
		if reflect.TypeOf(obj).String() == "*gorods.DataObj" {
			response = append(response, col.DataObjects[i].(*DataObj))
		}
	}

	return response
}

func (col *Collection) Collections() Collections {
	col.Init()

	var response Collections

	for i, obj := range col.DataObjects {
		if reflect.TypeOf(obj).String() == "*gorods.Collection" {
			response = append(response, col.DataObjects[i].(*Collection))
		}
	}

	return response
}

func (col *Collection) Put(localFile string) *DataObj {
	col.Init()

	data, err := ioutil.ReadFile(localFile)
	if err != nil {
		panic(fmt.Sprintf("Can't read file for Put(): %v", localFile))
	}

	fileName := filepath.Base(localFile)

	newFile := CreateDataObj(DataObjOptions{
		Name:  fileName,
		Size:  int64(len(data)),
		Mode:  0750,
		Force: true,
	}, col)

	newFile.Write(data)

	return newFile
}

func (col *Collection) Add(dataObj interface{}) *Collection {
	col.Init()

	col.DataObjects = append(col.DataObjects, dataObj)

	return col
}

func (col *Collection) All() []interface{} {
	col.Init()

	return col.DataObjects
}

func (col *Collection) Both() (DataObjs, Collections) {
	return col.DataObjs(), col.Collections()
}

func (col *Collection) Exists(path string) bool {
	return col.DataObjs().Exists(path) || col.Collections().Exists(path)
}

func (col *Collection) Find(path string) interface{} {
	if d := col.DataObjs().Find(path); d != nil {
		return d
	}

	if c := col.Collections().Find(path); c != nil {
		return c
	}

	return nil
}

func (col *Collection) Cd(path string) *Collection {
	return col.Collections().Find(path)
}

func (col *Collection) Get(path string) *DataObj {
	return col.DataObjs().Find(path)
}
<commit_msg>Added comments for godoc documentation. refs #4322<commit_after>/*** Copyright (c) 2016, University of Florida Research Foundation, Inc. ***
 *** For more information please refer to the LICENSE.md file            ***/

package gorods

// #include "wrapper.h"
import "C"

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strings"
	"unsafe"
)

// Collection structs contain information about single collections in an iRods zone.
type Collection struct {
	Path        string
	Name        string
	DataObjects []interface{}
	MetaCol MetaCollection
	Con         *Connection
	Col         *Collection
	Recursive   bool

	chandle C.int
}

type Collections []*Collection

// Exists checks to see if a collection exists in the slice
// and returns true or false
func (colls Collections) Exists(path string) bool {
	if c := colls.Find(path); c != nil {
		return true
	}

	return false
}

// Find gets a collection from the slice and returns nil if one is not found.
// Both the collection name and path can be used as input.
func (colls Collections) Find(path string) *Collection {
	if path[len(path)-1] == '/' {
		path = path[:len(path)-1]
	}

	for i, col := range colls {
		if col.Path == path || col.Name == path {
			return colls[i]
		}
	}

	return nil
}

// FindRecursive acts just like Find, but also searches sub collections recursively.
// If the collection was not explicitly loaded recursively, only the first level of sub collections will be searched.
func (colls Collections) FindRecursive(path string) *Collection {
	if path[len(path)-1] == '/' {
		path = path[:len(path)-1]
	}

	for i, col := range colls {
		if col.Path == path || col.Name == path {
			return colls[i]
		}

		if col.Recursive {
			// Use Collections() since we already loaded everything
			if subCol := col.Collections().FindRecursive(path); subCol != nil {
				return subCol
			}
		} else {
			// Use DataObjects so we don't load new collections
			var filtered Collections

			for n, obj := range col.DataObjects {
				if reflect.TypeOf(obj).String() == "*gorods.Collection" {
					filtered = append(filtered, col.DataObjects[n].(*Collection))
				}
			}

			if subCol := filtered.FindRecursive(path); subCol != nil {
				return subCol
			}
		}
	}

	return nil
}

// String shows the contents of the collection.
//
// D = DataObj
//
// C = Collection
//
// Sample output:
//
// 	Collection: /tempZone/home/admin/gorods
// 		D: build.sh
// 		C: bin
// 		C: pkg
// 		C: src
func (obj *Collection) String() string {
	str := fmt.Sprintf("Collection: %v\n", obj.Path)

	for _, o := range obj.DataObjs() {
		str += fmt.Sprintf("\tD: %v\n", o.Name)
	}

	for _, o := range obj.Collections() {
		str += fmt.Sprintf("\tC: %v\n", o.Name)
	}

	return str
}

// NewCollection initializes collection from *C.collEnt_t. This is used internally in the gorods package, maybe it should be lowercased?
func NewCollection(data *C.collEnt_t, acol *Collection) *Collection {

	col := new(Collection)

	col.Col = acol
	col.Con = col.Col.Con
	col.Path = C.GoString(data.collName)

	pathSlice := strings.Split(col.Path, "/")

	col.Name = pathSlice[len(pathSlice)-1]

	if acol.Recursive {
		col.Recursive = true
		col.Init()
	}

	return col
}

// GetCollection initializes specified collection located at startPath using gorods.Connection.
// Could be considered alias of Connection.Collection()
func GetCollection(startPath string, recursive bool, con *Connection) *Collection {
	col := new(Collection)

	col.Con = con
	col.Path = startPath
	col.Recursive = recursive

	if col.Path[len(col.Path)-1] == '/' {
		col.Path = col.Path[:len(col.Path)-1]
	}

	pathSlice := strings.Split(col.Path, "/")
	col.Name = pathSlice[len(pathSlice)-1]

	if col.Recursive {
		col.Init()
	}

	return col
}

// Init opens and reads collection information from iRods if the handle isn't set
func (col *Collection) Init() *Collection {
	// If connection hasn't been opened, do it!
	if int(col.chandle) == 0 {
		col.Open()
		col.ReadCollection()
	}

	return col
}

// Attribute gets specific metadata AVU triple for Collection
func (col *Collection) Attribute(attr string) *Meta {
	col.Init()

	return col.Meta().Get(attr)
}

// Meta returns collection of all metadata AVU triples for Collection
func (col *Collection) Meta() MetaCollection {
	col.Init()

	if col.MetaCol == nil {
		col.MetaCol = NewMetaCollection(CollectionType, col.Name, filepath.Dir(col.Path), col.Con.ccon)
	}

	return col.MetaCol
}

// Open connects to iRods and sets the handle for Collection.
// Usually called by Collection.Init()
func (col *Collection) Open() *Collection {
	var errMsg *C.char

	path := C.CString(col.Path)

	defer C.free(unsafe.Pointer(path))

	if status := C.gorods_open_collection(path, &col.chandle, col.Con.ccon, &errMsg); status != 0 {
		panic(fmt.Sprintf("iRods Open Collection Failed: %v, %v", col.Path, C.GoString(errMsg)))
	}

	return col
}

// Close closes the Collection connection and resets the handle
func (col *Collection) Close() *Collection {
	var errMsg *C.char

	if status := C.gorods_close_collection(col.chandle, col.Con.ccon, &errMsg); status != 0 {
		panic(fmt.Sprintf("iRods Close Collection Failed: %v, %v", col.Path, C.GoString(errMsg)))
	}

	col.chandle = C.int(0)

	return col
}

// ReadCollection reads data into col.DataObjects field
func (col *Collection) ReadCollection() {

	// Init C varaibles
	var (
		err     *C.char
		arr     *C.collEnt_t
		arrSize C.int
	)

	// Read data objs from collection
	C.gorods_read_collection(col.Con.ccon, col.chandle, &arr, &arrSize, &err)

	// Get result length
	arrLen := int(arrSize)

	unsafeArr := unsafe.Pointer(arr)
	defer C.free(unsafeArr)

	// Convert C array to slice, backed by arr *C.collEnt_t
	slice := (*[1 << 30]C.collEnt_t)(unsafeArr)[:arrLen:arrLen]

	col.DataObjects = make([]interface{}, 0)

	for i, _ := range slice {
		obj := &slice[i]

		isCollection := (obj.objType != C.DATA_OBJ_T)

		if isCollection {
			col.DataObjects = append(col.DataObjects, NewCollection(obj, col))
		} else {
			col.DataObjects = append(col.DataObjects, NewDataObj(obj, col))

			// Strings only in DataObj types
			C.free(unsafe.Pointer(obj.dataName))
			C.free(unsafe.Pointer(obj.dataId))
			C.free(unsafe.Pointer(obj.chksum))
			C.free(unsafe.Pointer(obj.dataType))
			C.free(unsafe.Pointer(obj.resource))
			C.free(unsafe.Pointer(obj.rescGrp))
			C.free(unsafe.Pointer(obj.phyPath))
		}

		// String in both object types
		C.free(unsafe.Pointer(obj.ownerName))
		C.free(unsafe.Pointer(obj.collName))
		C.free(unsafe.Pointer(obj.createTime))
		C.free(unsafe.Pointer(obj.modifyTime))

	}

	col.Close()
}

// DataObjs returns only the data objects contained within the collection
func (col *Collection) DataObjs() DataObjs {
	col.Init()

	var response DataObjs

	for i, obj := range col.DataObjects {
		if reflect.TypeOf(obj).String() == "*gorods.DataObj" {
			response = append(response, col.DataObjects[i].(*DataObj))
		}
	}

	return response
}

// Collections returns only the collections contained within the collection
func (col *Collection) Collections() Collections {
	col.Init()

	var response Collections

	for i, obj := range col.DataObjects {
		if reflect.TypeOf(obj).String() == "*gorods.Collection" {
			response = append(response, col.DataObjects[i].(*Collection))
		}
	}

	return response
}

// Put adds a local file to the remote iRods collection
func (col *Collection) Put(localFile string) *DataObj {
	col.Init()

	data, err := ioutil.ReadFile(localFile)
	if err != nil {
		panic(fmt.Sprintf("Can't read file for Put(): %v", localFile))
	}

	fileName := filepath.Base(localFile)

	newFile := CreateDataObj(DataObjOptions{
		Name:  fileName,
		Size:  int64(len(data)),
		Mode:  0750,
		Force: true,
	}, col)

	newFile.Write(data)

	return newFile
}

func (col *Collection) Add(dataObj interface{}) *Collection {
	col.Init()

	col.DataObjects = append(col.DataObjects, dataObj)

	return col
}

func (col *Collection) All() []interface{} {
	col.Init()

	return col.DataObjects
}

func (col *Collection) Both() (DataObjs, Collections) {
	return col.DataObjs(), col.Collections()
}

func (col *Collection) Exists(path string) bool {
	return col.DataObjs().Exists(path) || col.Collections().Exists(path)
}

func (col *Collection) Find(path string) interface{} {
	if d := col.DataObjs().Find(path); d != nil {
		return d
	}

	if c := col.Collections().Find(path); c != nil {
		return c
	}

	return nil
}

func (col *Collection) Cd(path string) *Collection {
	return col.Collections().Find(path)
}

func (col *Collection) Get(path string) *DataObj {
	return col.DataObjs().Find(path)
}
<|endoftext|>


<commit_before>package multipartutil

import (
	"net/http"
	"net/url"

	"github.com/grokify/gotilla/net/httputilmore"
)

type FileInfo struct {
	ParamName string
	Filepath  string
}

// NewRequestFileUpload returns a `*http.Request` for making a
// request using multipart/form-data. It supports simple strings
// and files. For more complex field requirements such as JSON
// body parts that require Content-Type headers and Base64
// encoding, use MultipartBuilder directly.
func NewRequestFileUpload(method, url string, params url.Values, files []FileInfo) (*http.Request, error) {
	mb := NewMultipartBuilder()
	err := mb.WriteURLValues(params)
	if err != nil {
		return nil, err
	}
	for _, file := range files {
		err := mb.WriteFilePathPlus(file.ParamName, file.Filepath, true)
		if err != nil {
			return nil, err
		}
	}
	err = mb.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, url, mb.Buffer)
	if err != nil {
		return nil, err
	}
	req.Header.Set(httputilmore.HeaderContentType, mb.ContentType())
	return req, nil
}
<commit_msg>update multipartutil<commit_after>package multipartutil

import (
	"net/http"
	"net/url"

	"github.com/grokify/gotilla/net/httputilmore"
)

// FileInfo represents a file for uploading.
type FileInfo struct {
	MIMEPartName string
	Filepath     string
}

// NewRequestFileUpload returns a `*http.Request` for making a
// request using multipart/form-data. It supports simple strings
// and files. For more complex field requirements such as JSON
// body parts that require Content-Type headers and Base64
// encoding, use MultipartBuilder directly.
func NewRequestFileUpload(method, url string, params url.Values, files []FileInfo) (*http.Request, error) {
	mb := NewMultipartBuilder()
	err := mb.WriteURLValues(params)
	if err != nil {
		return nil, err
	}
	for _, file := range files {
		err := mb.WriteFilePathPlus(file.MIMEPartName, file.Filepath, true)
		if err != nil {
			return nil, err
		}
	}
	err = mb.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, url, mb.Buffer)
	if err != nil {
		return nil, err
	}
	req.Header.Set(httputilmore.HeaderContentType, mb.ContentType())
	return req, nil
}
<|endoftext|>


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

// A minimal example of how to include Prometheus instrumentation.
package main

import (
	"flag"
	"log"
	"net/http"

	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")

func main() {
	flag.Parse()
	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>Update simple example to use custom registry<commit_after>// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A minimal example of how to include Prometheus instrumentation.
package main

import (
	"flag"
	"log"
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

var addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")

func main() {
	flag.Parse()

	// Create non-global registry.
	reg := prometheus.NewRegistry()

	// Expose /metrics HTTP endpoint using the created custom registry.
	http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ant0ine/go-json-rest"
	"net/http"
)

type User struct {
	Id   string
	Name string
	Posts  string
}

func GetUser(w *rest.ResponseWriter, req *rest.Request) {
	params := map[string][]string {"userId": []string{ req.PathParam("id") }}
	url := req.UriForWithParams("/posts/exports", params)
	user := User{
		Id:   req.PathParam("id"),
		Name: "Antoine",
		Posts: url.String(),
	}
	w.WriteJson(&user)
}

func main() {
	handler := rest.ResourceHandler{}
	handler.SetRoutes(
		rest.Route{"GET", "/users/:id", GetUser},
	)
	http.ListenAndServe(":8080", &handler)
}
<commit_msg>Docstring for this example<commit_after>/* The minimal example from the documentation

The Curl Demo:

        curl -i http://127.0.0.1:8080/users/123

*/
package main

import (
	"github.com/ant0ine/go-json-rest"
	"net/http"
)

type User struct {
	Id   string
	Name string
	Posts  string
}

func GetUser(w *rest.ResponseWriter, req *rest.Request) {
	params := map[string][]string {"userId": []string{ req.PathParam("id") }}
	url := req.UriForWithParams("/posts/exports", params)
	user := User{
		Id:   req.PathParam("id"),
		Name: "Antoine",
		Posts: url.String(),
	}
	w.WriteJson(&user)
}

func main() {
	handler := rest.ResourceHandler{}
	handler.SetRoutes(
		rest.Route{"GET", "/users/:id", GetUser},
	)
	http.ListenAndServe(":8080", &handler)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package commands

import (
	"errors"
	"flag"
	"fmt"
	"github.com/google/git-appraise/repository"
	"github.com/google/git-appraise/review"
	"github.com/google/git-appraise/review/comment"
)

var acceptFlagSet = flag.NewFlagSet("accept", flag.ExitOnError)

var (
	acceptMessage = acceptFlagSet.String("m", "", "Message to attach to the review")
)

// acceptReview adds an LGTM comment to the current code review.
func acceptReview(args []string) error {
	acceptFlagSet.Parse(args)

	r, err := review.GetCurrent()
	if err != nil {
		return fmt.Errorf("Failed to load the current review: %v\n", err)
	}
	if r == nil {
		return errors.New("There is no current review.")
	}

	acceptedCommit := repository.GetCommitHash(r.Request.ReviewRef)
	location := comment.Location{
		Commit: acceptedCommit,
	}
	resolved := true
	c := comment.New(*acceptMessage)
	c.Location = &location
	c.Resolved = &resolved
	return r.AddComment(c)
}

// acceptCmd defines the "accept" subcommand.
var acceptCmd = &Command{
	Usage: func(arg0 string) {
		fmt.Printf("Usage: %s accept <option>...\n\nOptions:\n", arg0)
		acceptFlagSet.PrintDefaults()
	},
	RunMethod: func(args []string) error {
		return acceptReview(args)
	},
}
<commit_msg>Added the ability to accept an arbitrary review given the corresponding hash<commit_after>/*
Copyright 2015 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package commands

import (
	"errors"
	"flag"
	"fmt"
	"github.com/google/git-appraise/repository"
	"github.com/google/git-appraise/review"
	"github.com/google/git-appraise/review/comment"
)

var acceptFlagSet = flag.NewFlagSet("accept", flag.ExitOnError)

var (
	acceptMessage = acceptFlagSet.String("m", "", "Message to attach to the review")
)

// acceptReview adds an LGTM comment to the current code review.
func acceptReview(args []string) error {
	acceptFlagSet.Parse(args)
	args = acceptFlagSet.Args()

	var r *review.Review
	var err error
	if len(args) > 1 {
		return errors.New("Only accepting a single review is supported.")
	}

	if len(args) == 1 {
		r = review.Get(args[0])
	} else {
		r, err = review.GetCurrent()
	}

	if err != nil {
		return fmt.Errorf("Failed to load the review: %v\n", err)
	}
	if r == nil {
		return errors.New("There is no matching review.")
	}

	var acceptedCommit string
	if r.Submitted {
		acceptedCommit = r.Revision
	} else {
		// TODO(ojarjur): This will fail if the user has not fetched the
		// review ref into their local repo. In that case, we should run
		// ls-remote on each of the remote repos until we find a maching
		// ref, and then use that ref's commit.
		acceptedCommit = repository.GetCommitHash(r.Request.ReviewRef)
	}
	location := comment.Location{
		Commit: acceptedCommit,
	}
	resolved := true
	c := comment.New(*acceptMessage)
	c.Location = &location
	c.Resolved = &resolved
	return r.AddComment(c)
}

// acceptCmd defines the "accept" subcommand.
var acceptCmd = &Command{
	Usage: func(arg0 string) {
		fmt.Printf("Usage: %s accept <option>... (<commit>)\n\nOptions:\n", arg0)
		acceptFlagSet.PrintDefaults()
	},
	RunMethod: func(args []string) error {
		return acceptReview(args)
	},
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"context"
	"os"
	"io/ioutil"
	"os/user"
	"path"

	"github.com/urfave/cli"
	"github.com/cbegin/graven/domain"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"gopkg.in/yaml.v2"
	"github.com/bgentry/speakeasy"
	"github.com/cbegin/graven/util"
	"strings"
)

type ConfigMap map[string]map[string]string
type Validator func(stdout, stderr string) error

var DeployCommand = cli.Command{
	Name: "deploy",
	Usage:       "Deploys artifacts to a repository",
	Action: deploy,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "login",
			Usage: "Prompts for repo login credentials.",
		},
	},
}

func deploy(c *cli.Context) error {
	project, err := domain.FindProject()
	if err != nil {
		return err
	}

	if err := verifyRepoState(project); err != nil {
		return err
	}

	if c.Bool("login") {
		return loginToGithub()
	}

	if err := pkg(c); err != nil {
		return err
	}

	return deployToGithub(project)
}

func loginToGithub() error {
	token, err := readSecret("Please type or paste a github token (will not echo): ")
	config, err := readConfig()
	if err != nil {
		config = ConfigMap{}
	}
	config["github"] = map[string]string{}
	config["github"]["token"] = token
	err = writeConfig(config)
	if err != nil {
		return fmt.Errorf("Error writing configuration file. %v", err)
	}
	return nil
}

func deployToGithub(project *domain.Project) error {

	gh, ctx, err := authenticate()
	if err != nil {
		return err
	}

	repo, ok := project.Repositories["github"]
	if !ok {
		return fmt.Errorf("Sorry, could not find gihub repo configuration")
	}

	ownerName := repo["owner"]
	repoName := repo["repo"]

	tagName := fmt.Sprintf("v%s", project.Version)
	releaseName := tagName
	release := &github.RepositoryRelease{
		TagName: &tagName,
		Name: &releaseName,
	}

	release, _, err = gh.Repositories.CreateRelease(ctx, ownerName, repoName, release)
	if err != nil {
		return err
	}
	fmt.Printf("Created release %v/%v:%v\n", ownerName, repoName, *release.Name)

	for _, a := range project.Artifacts {
		filename := a.ArtifactFile(project)
		sourceFile, err := os.Open(project.TargetPath(filename))
		if err != nil {
			return err
		}
		opts := &github.UploadOptions{
			Name: filename,
		}
		_, _, err = gh.Repositories.UploadReleaseAsset(ctx, ownerName, repoName, *release.ID, opts, sourceFile)
		if err != nil {
			return err
		}
		fmt.Printf("Uploaded %v/%v/%v\n", ownerName, repoName, filename)
	}

	return err
}

func authenticate() (*github.Client, context.Context, error) {
	config, err := readConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("Error reading configuration (try: deploy --login): %v", err)
	}

	ctx := context.Background()
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: config["github"]["token"]},
	)
	tc := oauth2.NewClient(ctx, ts)

	client := github.NewClient(tc)

	return client, ctx, nil
}

func readSecret(prompt string) (string, error) {
	password, err := speakeasy.Ask(prompt)
	if err != nil {
		return "", fmt.Errorf("Error reading secret from terminal: %v", err)
	}
	return password, nil
}

func readConfig() (ConfigMap, error) {
	usr, err := user.Current()
	if err != nil {
		return nil, err
	}
	file, err := os.Open(path.Join(usr.HomeDir, ".graven.yaml"))
	if err != nil {
		return nil, err
	}
	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}
	config := ConfigMap{}
	err = yaml.Unmarshal(bytes, config)
	if err != nil {
		return nil, err
	}
	return config, nil
}

func writeConfig(config ConfigMap) (error) {
	usr, err := user.Current()
	if err != nil {
		return err
	}
	bytes, err := yaml.Marshal(config)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path.Join(usr.HomeDir, ".graven.yaml"), bytes, 0600)
	if err != nil {
		return err
	}

	return nil
}

func verifyRepoState(project *domain.Project) error {
	remoteName := "origin"
	branchName := "master"

	// Check if on expected branch (e.g. master)
	if err := verifyGitState(func(stdout, stderr string) error {
		actualBranch := strings.TrimSpace(stdout)
		if actualBranch != branchName {
			return fmt.Errorf("Expected to be on branch %v but found branch %v", branchName, actualBranch)
		}
		return nil
	}, project, "rev-parse", "--abbrev-ref", "HEAD"); err != nil {
		return err
	}

	// Ensure no uncommitted changes
	if err := verifyGitState(func(stdout, stderr string) error {
		if strings.TrimSpace(stdout) != "" || strings.TrimSpace(stderr) != "" {
			return fmt.Errorf("Cannot deploy with uncommitted changes.")
		}
		return nil
	}, project, "status", "--porcelain"); err != nil {
		return err
	}

	// Check if changes exist on server
	if err := verifyGitState(func(stdout, stderr string) error {
		lineCount := len(strings.Split(strings.TrimSpace(stderr), "\n"))
		if lineCount > 2 {
			return fmt.Errorf("Changes were detected on the server for this branch.")
		}
		return nil
	}, project, "fetch", "--dry-run", remoteName, branchName); err != nil {
		return err
	}

	// Check if local changes are pushed
	if err := verifyGitState(func(stdout, stderr string) error {
		fmt.Println(stdout)

		return nil
	}, project, "rev-parse", branchName, fmt.Sprintf("%v/%v", remoteName, branchName)); err != nil {
		return err
	}

	return fmt.Errorf("Testing...")
}

func verifyGitState(validator Validator, project *domain.Project, args... string) error {
	sout, serr, err := util.RunCommand(project.ProjectPath(), nil, "git", args...)
	if err != nil {
		return fmt.Errorf("ERROR running Git command: %v\n", err)
	}
	return validator(sout, serr)
}<commit_msg>intermediate commit while working on git validation<commit_after>package commands

import (
	"fmt"
	"context"
	"os"
	"io/ioutil"
	"os/user"
	"path"

	"github.com/urfave/cli"
	"github.com/cbegin/graven/domain"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	"gopkg.in/yaml.v2"
	"github.com/bgentry/speakeasy"
	"github.com/cbegin/graven/util"
	"strings"
)

type ConfigMap map[string]map[string]string
type Validator func(stdout, stderr string) error

var DeployCommand = cli.Command{
	Name: "deploy",
	Usage:       "Deploys artifacts to a repository",
	Action: deploy,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "login",
			Usage: "Prompts for repo login credentials.",
		},
	},
}

func deploy(c *cli.Context) error {
	project, err := domain.FindProject()
	if err != nil {
		return err
	}

	if err := verifyRepoState(project); err != nil {
		return err
	}

	if c.Bool("login") {
		return loginToGithub()
	}

	if err := pkg(c); err != nil {
		return err
	}

	return deployToGithub(project)
}

func loginToGithub() error {
	token, err := readSecret("Please type or paste a github token (will not echo): ")
	config, err := readConfig()
	if err != nil {
		config = ConfigMap{}
	}
	config["github"] = map[string]string{}
	config["github"]["token"] = token
	err = writeConfig(config)
	if err != nil {
		return fmt.Errorf("Error writing configuration file. %v", err)
	}
	return nil
}

func deployToGithub(project *domain.Project) error {

	gh, ctx, err := authenticate()
	if err != nil {
		return err
	}

	repo, ok := project.Repositories["github"]
	if !ok {
		return fmt.Errorf("Sorry, could not find gihub repo configuration")
	}

	ownerName := repo["owner"]
	repoName := repo["repo"]

	tagName := fmt.Sprintf("v%s", project.Version)
	releaseName := tagName
	release := &github.RepositoryRelease{
		TagName: &tagName,
		Name: &releaseName,
	}

	release, _, err = gh.Repositories.CreateRelease(ctx, ownerName, repoName, release)
	if err != nil {
		return err
	}
	fmt.Printf("Created release %v/%v:%v\n", ownerName, repoName, *release.Name)

	for _, a := range project.Artifacts {
		filename := a.ArtifactFile(project)
		sourceFile, err := os.Open(project.TargetPath(filename))
		if err != nil {
			return err
		}
		opts := &github.UploadOptions{
			Name: filename,
		}
		_, _, err = gh.Repositories.UploadReleaseAsset(ctx, ownerName, repoName, *release.ID, opts, sourceFile)
		if err != nil {
			return err
		}
		fmt.Printf("Uploaded %v/%v/%v\n", ownerName, repoName, filename)
	}

	return err
}

func authenticate() (*github.Client, context.Context, error) {
	config, err := readConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("Error reading configuration (try: deploy --login): %v", err)
	}

	ctx := context.Background()
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: config["github"]["token"]},
	)
	tc := oauth2.NewClient(ctx, ts)

	client := github.NewClient(tc)

	return client, ctx, nil
}

func readSecret(prompt string) (string, error) {
	password, err := speakeasy.Ask(prompt)
	if err != nil {
		return "", fmt.Errorf("Error reading secret from terminal: %v", err)
	}
	return password, nil
}

func readConfig() (ConfigMap, error) {
	usr, err := user.Current()
	if err != nil {
		return nil, err
	}
	file, err := os.Open(path.Join(usr.HomeDir, ".graven.yaml"))
	if err != nil {
		return nil, err
	}
	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}
	config := ConfigMap{}
	err = yaml.Unmarshal(bytes, config)
	if err != nil {
		return nil, err
	}
	return config, nil
}

func writeConfig(config ConfigMap) (error) {
	usr, err := user.Current()
	if err != nil {
		return err
	}
	bytes, err := yaml.Marshal(config)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path.Join(usr.HomeDir, ".graven.yaml"), bytes, 0600)
	if err != nil {
		return err
	}

	return nil
}

func verifyRepoState(project *domain.Project) error {
	remoteName := "origin"
	branchName := "master"

	// Check if on expected branch (e.g. master)
	if err := verifyGitState(func(stdout, stderr string) error {
		actualBranch := strings.TrimSpace(stdout)
		if actualBranch != branchName {
			return fmt.Errorf("Expected to be on branch %v but found branch %v", branchName, actualBranch)
		}
		return nil
	}, project, "rev-parse", "--abbrev-ref", "HEAD"); err != nil {
		return err
	}

	// Ensure no uncommitted changes
	if err := verifyGitState(func(stdout, stderr string) error {
		if strings.TrimSpace(stdout) != "" || strings.TrimSpace(stderr) != "" {
			return fmt.Errorf("Cannot deploy with uncommitted changes.")
		}
		return nil
	}, project, "status", "--porcelain"); err != nil {
		return err
	}

	// Check if changes exist on server
	if err := verifyGitState(func(stdout, stderr string) error {
		lineCount := len(strings.Split(strings.TrimSpace(stderr), "\n"))
		if lineCount > 2 {
			return fmt.Errorf("Changes were detected on the server for this branch.")
		}
		return nil
	}, project, "fetch", "--dry-run", remoteName, branchName); err != nil {
		return err
	}

	// Check if local changes are pushed
	if err := verifyGitState(func(stdout, stderr string) error {
		parts := strings.Split(strings.TrimSpace(stdout), "\n")
		if strings.TrimSpace(parts[0]) != strings.TrimSpace(parts[1]) {
			return fmt.Errorf("Not all local changes have been pushed to the server.")
		}
		return nil
	}, project, "rev-parse", branchName, fmt.Sprintf("%v/%v", remoteName, branchName)); err != nil {
		return err
	}

	return fmt.Errorf("Testing...")
}

func verifyGitState(validator Validator, project *domain.Project, args... string) error {
	sout, serr, err := util.RunCommand(project.ProjectPath(), nil, "git", args...)
	if err != nil {
		return fmt.Errorf("ERROR running Git command: %v\n", err)
	}
	return validator(sout, serr)
}<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"strings"

	"github.com/daidokoro/qaz/log"
	"github.com/daidokoro/qaz/repo"
	"github.com/daidokoro/qaz/utils"

	stks "github.com/daidokoro/qaz/stacks"

	"github.com/spf13/cobra"
)

// stack management commands, ie. deploy, terminate, update

var (
	// deploy command
	deployCmd = &cobra.Command{
		Use:   "deploy",
		Short: "Deploys stack(s) to AWS",
		Example: strings.Join([]string{
			"qaz deploy stack -c path/to/config",
			"qaz deploy -c path/to/config -t stack::s3://bucket/key",
			"qaz deploy -c path/to/config -t stack::path/to/template",
			"qaz deploy -c path/to/config -t stack::http://someurl",
			"qaz deploy -c path/to/config -t stack::lambda:{some:json}@lambda_function",
		}, "\n"),
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			err := Configure(run.cfgSource, run.cfgRaw)
			utils.HandleError(err)

			run.stacks = make(map[string]string)

			// Add run.stacks based on [templates] Flags
			for _, src := range run.tplSources {
				s, source, err := utils.GetSource(src)
				utils.HandleError(err)
				if _, ok := stacks.Get(s); !ok {
					utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
				}
				stacks.MustGet(s).Source = source
				stacks.MustGet(s).Actioned = true
			}

			// Add all stacks with defined sources if actioned
			if run.all {
				stacks.Range(func(_ string, s *stks.Stack) bool {
					s.Actioned = true
					return true
				})
			}

			// Add run.stacks based on Args
			if len(args) > 0 && !run.all {
				for _, s := range args {
					if _, ok := stacks.Get(s); !ok {
						utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
					}
					stacks.MustGet(s).Actioned = true
				}
			}

			// run gentimeParser
			stacks.Range(func(_ string, s *stks.Stack) bool {
				if !s.Actioned {
					return true
				}
				if err := s.GenTimeParser(); err != nil {
					utils.HandleError(err)
				}
				return true
			})

			// Deploy Stacks
			stks.DeployHandler(&stacks)

		},
	}

	// git-deploy command
	gitDeployCmd = &cobra.Command{
		Use:     "git-deploy [git-repo]",
		Short:   "Deploy project from Git repository",
		Example: "qaz git-deploy https://github.com/cfn-deployable/simplevpc --user me",
		PreRun:  initialise,
		Run: func(cmd *cobra.Command, args []string) {

			// check args
			if len(args) < 1 {
				fmt.Println("Please specify git repo...")
				return
			}

			repo, err := repo.NewRepo(args[0], run.gituser, run.gitrsa)
			utils.HandleError(err)

			// Passing repo to the global var
			gitrepo = *repo

			// add repo
			stks.Git = &gitrepo

			if out, ok := repo.Files[run.cfgSource]; ok {
				repo.Config = out
			}

			log.Debug("Repo Files:")
			for k := range repo.Files {
				log.Debug(k)
			}

			err = Configure(run.cfgSource, repo.Config)
			utils.HandleError(err)

			//create set actioned stacks
			stacks.Range(func(_ string, s *stks.Stack) bool {
				s.Actioned = true
				utils.HandleError(s.GenTimeParser())
				return true
			})

			// Deploy Stacks
			stks.DeployHandler(&stacks)

		},
	}

	// update command
	updateCmd = &cobra.Command{
		Use:   "update",
		Short: "Updates a given stack",
		Example: strings.Join([]string{
			"qaz update -c path/to/config -t stack::path/to/template",
			"qaz update -c path/to/config -t stack::s3://bucket/key",
			"qaz update -c path/to/config -t stack::http://someurl",
			"qaz deploy -c path/to/config -t stack::lambda:{some:json}@lambda_function",
		}, "\n"),
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			var s string
			var source string

			err := Configure(run.cfgSource, run.cfgRaw)
			if err != nil {
				utils.HandleError(err)
				return
			}

			switch {

			case run.tplSource != "":
				s, source, err = utils.GetSource(run.tplSource)
				utils.HandleError(err)

			case len(args) > 0:
				s = args[0]
				if _, ok := stacks.Get(s); !ok {
					utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
				}
			}

			// check stack exists
			if _, ok := stacks.Get(s); !ok {
				utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
			}

			if source != "" {
				stacks.MustGet(s).Source = source
			}

			utils.HandleError(stacks.MustGet(s).GenTimeParser())
			utils.HandleError(stacks.MustGet(s).Update())
		},
	}

	// terminate command
	terminateCmd = &cobra.Command{
		Use:    "terminate [stacks]",
		Short:  "Terminates stacks",
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) < 1 && !run.all {
				log.Warn("No stack specified for termination")
				return
			}

			err := Configure(run.cfgSource, "")
			utils.HandleError(err)

			// select actioned stacks
			for _, s := range args {
				if _, ok := stacks.Get(s); !ok {
					utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
				}
				stacks.MustGet(s).Actioned = true
			}

			// action stacks if all
			if run.all {
				stacks.Range(func(_ string, s *stks.Stack) bool {
					s.Actioned = true
					return true
				})
			}

			// Terminate Stacks
			stks.TerminateHandler(&stacks)
		},
	}
)
<commit_msg>updated repo.NewRepo to idiomatic repo.New<commit_after>package commands

import (
	"fmt"
	"strings"

	"github.com/daidokoro/qaz/log"
	"github.com/daidokoro/qaz/repo"
	"github.com/daidokoro/qaz/utils"

	stks "github.com/daidokoro/qaz/stacks"

	"github.com/spf13/cobra"
)

// stack management commands, ie. deploy, terminate, update

var (
	// deploy command
	deployCmd = &cobra.Command{
		Use:   "deploy",
		Short: "Deploys stack(s) to AWS",
		Example: strings.Join([]string{
			"qaz deploy stack -c path/to/config",
			"qaz deploy -c path/to/config -t stack::s3://bucket/key",
			"qaz deploy -c path/to/config -t stack::path/to/template",
			"qaz deploy -c path/to/config -t stack::http://someurl",
			"qaz deploy -c path/to/config -t stack::lambda:{some:json}@lambda_function",
		}, "\n"),
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			err := Configure(run.cfgSource, run.cfgRaw)
			utils.HandleError(err)

			run.stacks = make(map[string]string)

			// Add run.stacks based on [templates] Flags
			for _, src := range run.tplSources {
				s, source, err := utils.GetSource(src)
				utils.HandleError(err)
				if _, ok := stacks.Get(s); !ok {
					utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
				}
				stacks.MustGet(s).Source = source
				stacks.MustGet(s).Actioned = true
			}

			// Add all stacks with defined sources if actioned
			if run.all {
				stacks.Range(func(_ string, s *stks.Stack) bool {
					s.Actioned = true
					return true
				})
			}

			// Add run.stacks based on Args
			if len(args) > 0 && !run.all {
				for _, s := range args {
					if _, ok := stacks.Get(s); !ok {
						utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
					}
					stacks.MustGet(s).Actioned = true
				}
			}

			// run gentimeParser
			stacks.Range(func(_ string, s *stks.Stack) bool {
				if !s.Actioned {
					return true
				}
				if err := s.GenTimeParser(); err != nil {
					utils.HandleError(err)
				}
				return true
			})

			// Deploy Stacks
			stks.DeployHandler(&stacks)

		},
	}

	// git-deploy command
	gitDeployCmd = &cobra.Command{
		Use:     "git-deploy [git-repo]",
		Short:   "Deploy project from Git repository",
		Example: "qaz git-deploy https://github.com/cfn-deployable/simplevpc --user me",
		PreRun:  initialise,
		Run: func(cmd *cobra.Command, args []string) {

			// check args
			if len(args) < 1 {
				fmt.Println("Please specify git repo...")
				return
			}

			repo, err := repo.New(args[0], run.gituser, run.gitrsa)
			utils.HandleError(err)

			// Passing repo to the global var
			gitrepo = *repo

			// add repo
			stks.Git = &gitrepo

			if out, ok := repo.Files[run.cfgSource]; ok {
				repo.Config = out
			}

			log.Debug("Repo Files:")
			for k := range repo.Files {
				log.Debug(k)
			}

			err = Configure(run.cfgSource, repo.Config)
			utils.HandleError(err)

			//create set actioned stacks
			stacks.Range(func(_ string, s *stks.Stack) bool {
				s.Actioned = true
				utils.HandleError(s.GenTimeParser())
				return true
			})

			// Deploy Stacks
			stks.DeployHandler(&stacks)

		},
	}

	// update command
	updateCmd = &cobra.Command{
		Use:   "update",
		Short: "Updates a given stack",
		Example: strings.Join([]string{
			"qaz update -c path/to/config -t stack::path/to/template",
			"qaz update -c path/to/config -t stack::s3://bucket/key",
			"qaz update -c path/to/config -t stack::http://someurl",
			"qaz deploy -c path/to/config -t stack::lambda:{some:json}@lambda_function",
		}, "\n"),
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			var s string
			var source string

			err := Configure(run.cfgSource, run.cfgRaw)
			if err != nil {
				utils.HandleError(err)
				return
			}

			switch {

			case run.tplSource != "":
				s, source, err = utils.GetSource(run.tplSource)
				utils.HandleError(err)

			case len(args) > 0:
				s = args[0]
				if _, ok := stacks.Get(s); !ok {
					utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
				}
			}

			// check stack exists
			if _, ok := stacks.Get(s); !ok {
				utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
			}

			if source != "" {
				stacks.MustGet(s).Source = source
			}

			utils.HandleError(stacks.MustGet(s).GenTimeParser())
			utils.HandleError(stacks.MustGet(s).Update())
		},
	}

	// terminate command
	terminateCmd = &cobra.Command{
		Use:    "terminate [stacks]",
		Short:  "Terminates stacks",
		PreRun: initialise,
		Run: func(cmd *cobra.Command, args []string) {

			if len(args) < 1 && !run.all {
				log.Warn("No stack specified for termination")
				return
			}

			err := Configure(run.cfgSource, "")
			utils.HandleError(err)

			// select actioned stacks
			for _, s := range args {
				if _, ok := stacks.Get(s); !ok {
					utils.HandleError(fmt.Errorf("stacks [%s] not found in config", s))
				}
				stacks.MustGet(s).Actioned = true
			}

			// action stacks if all
			if run.all {
				stacks.Range(func(_ string, s *stks.Stack) bool {
					s.Actioned = true
					return true
				})
			}

			// Terminate Stacks
			stks.TerminateHandler(&stacks)
		},
	}
)
<|endoftext|>


<commit_before>package executor

import (
	"fmt"
	"os/exec"
	"reflect"

	"github.com/JulzDiverse/aviator"
	"github.com/pkg/errors"
	"github.com/starkandwayne/goutils/ansi"
)

type FlyExecutor struct{}

func (e FlyExecutor) Command(cfg interface{}) (*exec.Cmd, error) {
	fly, ok := cfg.(aviator.Fly)
	if !ok {
		return &exec.Cmd{}, errors.New(ansi.Sprintf("@R{Type Assertion failed! Cannot assert %s to %s}", reflect.TypeOf(cfg), "aviator.Fly"))
	}

	var args []string
	if fly.ValidatePipeline {
		args = []string{"validate-pipeline", "-c", fly.Config}

		if fly.Strict {
			args = append(args, "--strict")
		}

	} else if fly.FormatPipeline {
		args = []string{"format-pipeline", "-c", fly.Config}

		if fly.Write {
			args = append(args, "--write")
		}

	} else {
		args = []string{
			"-t", fly.Target, "set-pipeline", "-p", fly.Name, "-c", fly.Config,
		}

		for _, v := range fly.Vars {
			args = append(args, "-l", v)
		}

		for k, v := range fly.Var {
			args = append(args, "-v", fmt.Sprintf("%s=%s", k, v))
		}

		if fly.NonInteractive {
			args = append(args, "-n")
		}
	}

	return exec.Command("fly", args...), nil
}

func (e FlyExecutor) Execute(cmd *exec.Cmd, cfg interface{}) error {
	fly, ok := cfg.(aviator.Fly)
	if !ok {
		return errors.New(ansi.Sprintf("@R{Type Assertion failed! Cannot assert %s to %s}", reflect.TypeOf(cfg), "aviator.Fly"))
	}

	err := execCmd(cmd)
	if err != nil {
		return err
	}

	if fly.Expose {
		args := []string{"-t", fly.Target, "expose-pipeline", "-p", fly.Name}
		cmd = exec.Command("fly", args...)
		err := execCmd(cmd)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Hide pipelines unless exposed<commit_after>package executor

import (
	"fmt"
	"os/exec"
	"reflect"

	"github.com/JulzDiverse/aviator"
	"github.com/pkg/errors"
	"github.com/starkandwayne/goutils/ansi"
)

type FlyExecutor struct{}

func (e FlyExecutor) Command(cfg interface{}) (*exec.Cmd, error) {
	fly, ok := cfg.(aviator.Fly)
	if !ok {
		return &exec.Cmd{}, errors.New(ansi.Sprintf("@R{Type Assertion failed! Cannot assert %s to %s}", reflect.TypeOf(cfg), "aviator.Fly"))
	}

	var args []string
	if fly.ValidatePipeline {
		args = []string{"validate-pipeline", "-c", fly.Config}

		if fly.Strict {
			args = append(args, "--strict")
		}

	} else if fly.FormatPipeline {
		args = []string{"format-pipeline", "-c", fly.Config}

		if fly.Write {
			args = append(args, "--write")
		}

	} else {
		args = []string{
			"-t", fly.Target, "set-pipeline", "-p", fly.Name, "-c", fly.Config,
		}

		for _, v := range fly.Vars {
			args = append(args, "-l", v)
		}

		for k, v := range fly.Var {
			args = append(args, "-v", fmt.Sprintf("%s=%s", k, v))
		}

		if fly.NonInteractive {
			args = append(args, "-n")
		}
	}

	return exec.Command("fly", args...), nil
}

func (e FlyExecutor) Execute(cmd *exec.Cmd, cfg interface{}) error {
	fly, ok := cfg.(aviator.Fly)
	if !ok {
		return errors.New(ansi.Sprintf("@R{Type Assertion failed! Cannot assert %s to %s}", reflect.TypeOf(cfg), "aviator.Fly"))
	}

	err := execCmd(cmd)
	if err != nil {
		return err
	}

	if fly.Expose {
		args := []string{"-t", fly.Target, "expose-pipeline", "-p", fly.Name}
		cmd = exec.Command("fly", args...)
		err := execCmd(cmd)
		if err != nil {
			return err
		}
	} else {
		args := []string{"-t", fly.Target, "hide-pipeline", "-p", fly.Name}
		cmd = exec.Command("fly", args...)
		err := execCmd(cmd)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package commands

//Helper struct holds all the state & shared functionality you need to run a hroot command.

import (
	. "fmt"
	"time"
	"polydawn.net/hroot/conf"
	"polydawn.net/hroot/crocker"
	"polydawn.net/hroot/dex"
	. "polydawn.net/hroot/util"
	guitarconf "polydawn.net/guitar/conf"
)

//Holds everything needed to load/save docker images
type ImagePath struct {
	scheme string    //URI scheme
	path   string    //URI path
	graph *dex.Graph //Graph (if desired)
}

//Holds everything needed to run a hroot command
type Hroot struct {
	//Source and destination URIs
	source    ImagePath
	dest      ImagePath

	//Docker instance
	dock      *crocker.Dock

	//Container instance
	container *crocker.Container

	//Configuration
	folders  conf.Folders
	image    conf.Image
	settings conf.Container
	launchImage     string //Stored separately so we don't modify config if needed later for export.
}

//Create a hroot struct
func LoadHroot(args []string, defaultTarget, sourceURI, destURI string) *Hroot {
	//If there was no target specified, override it
	target   := GetTarget(args, defaultTarget)

	//Load toml parser
	parser := &conf.TomlConfigParser{}

	//Parse config file
	configuration, folders := conf.LoadConfigurationFromDisk(".", parser)
	config := configuration.Targets[target]

	//Hroot struct
	d := &Hroot {
		folders:     *folders,
		image:       configuration.Image,
		settings:    config,
		launchImage: configuration.Image.Name, //Stored separately (see above)
	}

	//Parse input URI
	sourceScheme, sourcePath := ParseURI(sourceURI)
	d.source = ImagePath {
		scheme: sourceScheme,
		path:   sourcePath,
	}

	//If there's a destination URI, parse that as well
	if destURI != "" {
		destScheme, destPath     := ParseURI(destURI)

		d.dest = ImagePath {
			scheme: destScheme,
			path:   destPath,
		}
	}

	//Image name required
	if d.launchImage == "" {
		ExitGently("No image name specified.")
	}

	//Specifying a command in the settings section has confusing implications
	if len(configuration.Settings.Command) > 0 {
		ExitGently("Cannot specify a command in settings; instead, put them in a target!")
	}

	return d
}

//Prepare the hroot input
func (d *Hroot) PrepareInput() {

	//If you're using an index key with a non-index source, or upstream key with index source, reject.
	//Runs here (not LoadHroot) so commands have a chance to change settings.
	if d.source.scheme == "index" && d.image.Index == "" {
		ExitGently("You asked to pull from the index but have no index key configured.")
	} else if d.source.scheme != "index" && d.image.Upstream == "" {
		ExitGently("You asked to pull from the index but have no index key configured.")
	}

	switch d.source.scheme {
		case "graph":
			//Look up the graph, and clear any unwanted state
			d.source.graph = dex.NewGraph(d.folders.Graph)
			Println("Opening source repository")
		case "file":
			//If the user did not specify an image path, set one
			if d.source.path == "" {
				d.source.path = "./image.tar"
			}
		case "index":
			//If pulling from the index, use the index key instead (protect URL namespace from docker)
			d.launchImage = d.image.Index
	}
}

//Prepare the hroot output
func (d *Hroot) PrepareOutput() {
	switch d.dest.scheme {
		case "graph":
			//Look up the graph, and clear any unwanted state
			d.dest.graph = dex.NewGraph(d.folders.Graph)

			//If the user's git config isn't ready, we want to tell them *before* building.
			if !d.dest.graph.IsConfigReady() {
				ExitGently("\n" +
					"Git could not find a user name & email."                 + "\n"   +
					"You'll need to set up git with the following commands:"  + "\n\n" +
					"git config --global user.email \"you@example.com\""      + "\n"   +
					"git config --global user.name \"Your Name\"")
			}

			//Cleanse the graph unless it'd be redundant.
			Println("Opening destination repository")
		case "file":
			//If the user did not specify an image path, set one
			if d.dest.path == "" {
				d.dest.path = "./image.tar"
			}

			//If the user is insane and wants to overwrite his source tar, stop him.
			//	Not at all robust (absolute paths? what are those? etc)
			if d.source.scheme == "file" && d.source.path == d.dest.path {
				ExitGently("Tar location is same for source and destination:", d.source.path)
			}
		case "index":
			ExitGently("Destination", d.dest.scheme, "is not supported yet.")
	}
}

//Connects to the docker daemon
func (d *Hroot) StartDocker(socketURI string) {
	d.dock = crocker.Dial(socketURI)
}

//Behavior when docker cache has the image
func (d *Hroot) prepareCacheWithImage(image string) {
	switch d.source.scheme {
		case "graph":
			Println("Docker already has", image, "loaded, not importing from graph.")
		case "file":
			Println(
				"\n"   + "Warning: your docker cache already has " + image + " loaded." +
				"\n"   + "Importing will overwrite the saved image." +
				"\n\n" + "Continuing in 10 seconds, hit Ctrl-C to cancel..")
			time.Sleep(time.Second * 10)
		case "index":
			Println(
				"\n"   + "Warning: your docker cache already has " + d.image.Index + " loaded." +
				"\n"   + "Pulling from the index may modify the saved image." +
				"\n\n" + "Continuing in 10 seconds, hit Ctrl-C to cancel...")
			time.Sleep(time.Second * 10)
	}
}

//Behavior when docker cache doesn't have the image
func (d *Hroot) prepareCacheWithoutImage(image string) {
	switch d.source.scheme {
		case "docker":
			//Can't continue; specified docker as source and it doesn't have it
			ExitGently("Docker does not have", image, "loaded.")
		case "graph":
			d.source.graph.Load(
				image,
				&dex.GraphLoadRequest_Image{
					Dock: d.dock,
					ImageName: image,
				},
			)
	}
}

//Prepare the docker cache
func (d *Hroot) PrepareCache() {
	image := d.launchImage

	//Behavior based on if the docker cache already has an image
	if d.dock.CheckCache(image) {
		d.prepareCacheWithImage(image)
	} else {
		d.prepareCacheWithoutImage(image)
	}

	//Now that the docker cache has the image, run normal behavior
	//Both these actions take place unconditionally, but warn the user if the cache is hot.
	switch d.source.scheme  {
		case "file":
			d.dock.ImportFromFilenameTagstring(d.source.path, image) //Load image from file
		case "index":
			d.dock.Pull(d.image.Index)
	}
}

//Lanuch the container and wait for it to complete
func (d *Hroot) Launch() {
	Println("Launching container.")
	c := d.settings

	//Map the struct values to crocker function params
	d.container = crocker.Launch(d.dock, d.launchImage, c.Command, c.Attach, c.Privileged, c.Folder, c.DNS, c.Mounts, c.Ports, c.Environment)

	//Wait for container
	d.container.Wait()
}

//Prepare the hroot export
func (d *Hroot) ExportBuild(forceEpoch bool) error {
	switch d.dest.scheme {
		case "graph":
			Println("Committing to graph...")

			//Don't give ancestor name to graph publish if source was not the graph.
			ancestor := d.image.Upstream
			if d.source.scheme != "graph" {
				ancestor = ""
			}

			d.dest.graph.Publish(
				d.image.Name,
				ancestor,
				&dex.GraphStoreRequest_Container{
					Container: d.container,
					Settings: guitarconf.Settings{
						Epoch: forceEpoch,
					},
				},
			)
		case "file":
			//Export a tar
			Println("Exporting to", d.dest.path)
			d.container.ExportToFilename(d.dest.path)
	}

	//Commit the image name to the docker cache.
	//	This is so if you run:
	//		hroot build -s index  -d graph --noop
	//		hroot build -s docker -d graph
	//	Docker will already know about your (much cooler) image name :)
	name, tag := crocker.SplitImageName(d.image.Name)
	Println("Exporting to docker cache:", name, tag)
	d.container.Commit(name, tag)

	return nil
}

//Clean up after ourselves
func (d *Hroot) Cleanup() {
	//Remove the container from cache if desired
	if d.settings.Purge {
		d.container.Purge()
	}

	//Close the docker connection
	d.dock.Close()
}
<commit_msg>Correct exit message<commit_after>package commands

//Helper struct holds all the state & shared functionality you need to run a hroot command.

import (
	. "fmt"
	"time"
	"polydawn.net/hroot/conf"
	"polydawn.net/hroot/crocker"
	"polydawn.net/hroot/dex"
	. "polydawn.net/hroot/util"
	guitarconf "polydawn.net/guitar/conf"
)

//Holds everything needed to load/save docker images
type ImagePath struct {
	scheme string    //URI scheme
	path   string    //URI path
	graph *dex.Graph //Graph (if desired)
}

//Holds everything needed to run a hroot command
type Hroot struct {
	//Source and destination URIs
	source    ImagePath
	dest      ImagePath

	//Docker instance
	dock      *crocker.Dock

	//Container instance
	container *crocker.Container

	//Configuration
	folders  conf.Folders
	image    conf.Image
	settings conf.Container
	launchImage     string //Stored separately so we don't modify config if needed later for export.
}

//Create a hroot struct
func LoadHroot(args []string, defaultTarget, sourceURI, destURI string) *Hroot {
	//If there was no target specified, override it
	target   := GetTarget(args, defaultTarget)

	//Load toml parser
	parser := &conf.TomlConfigParser{}

	//Parse config file
	configuration, folders := conf.LoadConfigurationFromDisk(".", parser)
	config := configuration.Targets[target]

	//Hroot struct
	d := &Hroot {
		folders:     *folders,
		image:       configuration.Image,
		settings:    config,
		launchImage: configuration.Image.Name, //Stored separately (see above)
	}

	//Parse input URI
	sourceScheme, sourcePath := ParseURI(sourceURI)
	d.source = ImagePath {
		scheme: sourceScheme,
		path:   sourcePath,
	}

	//If there's a destination URI, parse that as well
	if destURI != "" {
		destScheme, destPath     := ParseURI(destURI)

		d.dest = ImagePath {
			scheme: destScheme,
			path:   destPath,
		}
	}

	//Image name required
	if d.launchImage == "" {
		ExitGently("No image name specified.")
	}

	//Specifying a command in the settings section has confusing implications
	if len(configuration.Settings.Command) > 0 {
		ExitGently("Cannot specify a command in settings; instead, put them in a target!")
	}

	return d
}

//Prepare the hroot input
func (d *Hroot) PrepareInput() {

	//If you're using an index key with a non-index source, or upstream key with index source, reject.
	//Runs here (not LoadHroot) so commands have a chance to change settings.
	if d.source.scheme == "index" && d.image.Index == "" {
		ExitGently("You asked to pull from the index but have no index key configured.")
	} else if d.source.scheme != "index" && d.image.Upstream == "" {
		ExitGently("You asked to run from from", d.source.scheme, "but have no upstream key configured.")
	}

	switch d.source.scheme {
		case "graph":
			//Look up the graph, and clear any unwanted state
			d.source.graph = dex.NewGraph(d.folders.Graph)
			Println("Opening source repository")
		case "file":
			//If the user did not specify an image path, set one
			if d.source.path == "" {
				d.source.path = "./image.tar"
			}
		case "index":
			//If pulling from the index, use the index key instead (protect URL namespace from docker)
			d.launchImage = d.image.Index
	}
}

//Prepare the hroot output
func (d *Hroot) PrepareOutput() {
	switch d.dest.scheme {
		case "graph":
			//Look up the graph, and clear any unwanted state
			d.dest.graph = dex.NewGraph(d.folders.Graph)

			//If the user's git config isn't ready, we want to tell them *before* building.
			if !d.dest.graph.IsConfigReady() {
				ExitGently("\n" +
					"Git could not find a user name & email."                 + "\n"   +
					"You'll need to set up git with the following commands:"  + "\n\n" +
					"git config --global user.email \"you@example.com\""      + "\n"   +
					"git config --global user.name \"Your Name\"")
			}

			//Cleanse the graph unless it'd be redundant.
			Println("Opening destination repository")
		case "file":
			//If the user did not specify an image path, set one
			if d.dest.path == "" {
				d.dest.path = "./image.tar"
			}

			//If the user is insane and wants to overwrite his source tar, stop him.
			//	Not at all robust (absolute paths? what are those? etc)
			if d.source.scheme == "file" && d.source.path == d.dest.path {
				ExitGently("Tar location is same for source and destination:", d.source.path)
			}
		case "index":
			ExitGently("Destination", d.dest.scheme, "is not supported yet.")
	}
}

//Connects to the docker daemon
func (d *Hroot) StartDocker(socketURI string) {
	d.dock = crocker.Dial(socketURI)
}

//Behavior when docker cache has the image
func (d *Hroot) prepareCacheWithImage(image string) {
	switch d.source.scheme {
		case "graph":
			Println("Docker already has", image, "loaded, not importing from graph.")
		case "file":
			Println(
				"\n"   + "Warning: your docker cache already has " + image + " loaded." +
				"\n"   + "Importing will overwrite the saved image." +
				"\n\n" + "Continuing in 10 seconds, hit Ctrl-C to cancel..")
			time.Sleep(time.Second * 10)
		case "index":
			Println(
				"\n"   + "Warning: your docker cache already has " + d.image.Index + " loaded." +
				"\n"   + "Pulling from the index may modify the saved image." +
				"\n\n" + "Continuing in 10 seconds, hit Ctrl-C to cancel...")
			time.Sleep(time.Second * 10)
	}
}

//Behavior when docker cache doesn't have the image
func (d *Hroot) prepareCacheWithoutImage(image string) {
	switch d.source.scheme {
		case "docker":
			//Can't continue; specified docker as source and it doesn't have it
			ExitGently("Docker does not have", image, "loaded.")
		case "graph":
			d.source.graph.Load(
				image,
				&dex.GraphLoadRequest_Image{
					Dock: d.dock,
					ImageName: image,
				},
			)
	}
}

//Prepare the docker cache
func (d *Hroot) PrepareCache() {
	image := d.launchImage

	//Behavior based on if the docker cache already has an image
	if d.dock.CheckCache(image) {
		d.prepareCacheWithImage(image)
	} else {
		d.prepareCacheWithoutImage(image)
	}

	//Now that the docker cache has the image, run normal behavior
	//Both these actions take place unconditionally, but warn the user if the cache is hot.
	switch d.source.scheme  {
		case "file":
			d.dock.ImportFromFilenameTagstring(d.source.path, image) //Load image from file
		case "index":
			d.dock.Pull(d.image.Index)
	}
}

//Lanuch the container and wait for it to complete
func (d *Hroot) Launch() {
	Println("Launching container.")
	c := d.settings

	//Map the struct values to crocker function params
	d.container = crocker.Launch(d.dock, d.launchImage, c.Command, c.Attach, c.Privileged, c.Folder, c.DNS, c.Mounts, c.Ports, c.Environment)

	//Wait for container
	d.container.Wait()
}

//Prepare the hroot export
func (d *Hroot) ExportBuild(forceEpoch bool) error {
	switch d.dest.scheme {
		case "graph":
			Println("Committing to graph...")

			//Don't give ancestor name to graph publish if source was not the graph.
			ancestor := d.image.Upstream
			if d.source.scheme != "graph" {
				ancestor = ""
			}

			d.dest.graph.Publish(
				d.image.Name,
				ancestor,
				&dex.GraphStoreRequest_Container{
					Container: d.container,
					Settings: guitarconf.Settings{
						Epoch: forceEpoch,
					},
				},
			)
		case "file":
			//Export a tar
			Println("Exporting to", d.dest.path)
			d.container.ExportToFilename(d.dest.path)
	}

	//Commit the image name to the docker cache.
	//	This is so if you run:
	//		hroot build -s index  -d graph --noop
	//		hroot build -s docker -d graph
	//	Docker will already know about your (much cooler) image name :)
	name, tag := crocker.SplitImageName(d.image.Name)
	Println("Exporting to docker cache:", name, tag)
	d.container.Commit(name, tag)

	return nil
}

//Clean up after ourselves
func (d *Hroot) Cleanup() {
	//Remove the container from cache if desired
	if d.settings.Purge {
		d.container.Purge()
	}

	//Close the docker connection
	d.dock.Close()
}
<|endoftext|>


<commit_before>/*

LICENSE:  MIT
Author:   sine
Email:    sinerwr@gmail.com

*/

package controller

import (
	"encoding/json"
	// "fmt"
	// "github.com/getsentry/raven-go"
	"golang.org/x/net/context"
	"net/http"

	"github.com/SiCo-Ops/Pb"
	"github.com/SiCo-Ops/dao/grpc"
	// "github.com/SiCo-Ops/dao/mongo"
	// "github.com/SiCo-Ops/public"
)

type AssetTemplate struct {
	PrivateToken AuthenticationToken `json:"token"`
	Name         string              `json:"name"`
	Param        map[string]string   `json:"param"`
}

func AssetCreateTemplate(rw http.ResponseWriter, req *http.Request) {
	v := AssetTemplate{}
	if data, ok := ValidatePostData(rw, req); ok {
		json.Unmarshal(data, &v)
	} else {
		return
	}
	in := &pb.AssetTemplateCall{}
	if config.AAAEnable && !AAAValidateToken(v.PrivateToken.ID, v.PrivateToken.Signature) {
		rsp, _ := json.Marshal(ResponseErrmsg(2))
		httprsp(rw, rsp)
		return
	}
	in.Id = v.PrivateToken.ID
	in.Name = v.Name
	in.Param = v.Param
	cc := rpc.RPCConn(RPCAddr["Be"])
	defer cc.Close()
	c := pb.NewAssetClient(cc)
	res, _ := c.CreateTemplateRPC(context.Background(), in)
	if res.Code == 0 {
		rsp, _ := json.Marshal(&ResponseData{0, "Success add template"})
		httprsp(rw, rsp)
		return
	}
	rsp, _ := json.Marshal(res)
	httprsp(rw, rsp)
	return
}

// func Asset_synchronize(rw http.ResponseWriter, req *http.Request) {
// 	cloud := GetRouteName(req, "cloud")
// 	bsns := GetRouteName(req, "bsns")
// 	if !AuthBsns(cloud, bsns) {
// 		rsp, _ := json.Marshal(&ResponseData{Code: 2, Data: "Cloud not support yet ,damn"})
// 		httprsp(rw, rsp)
// 		return
// 	}

// 	data, ok := AuthPostData(rw, req)
// 	if !ok {
// 		return
// 	}
// 	v := &Cloud_Req{}
// 	json.Unmarshal(data, v)

// 	/*
// 		Control need AAA server to get Cloud id & key
// 	*/
// 	if needAAA {
// 		cloud_id, cloud_key = AAA_GetThirdKey(cloud, v.Auth.Id, v.Auth.Signature, v.Name)
// 		if cloud_id == "" {
// 			rsp, _ := json.Marshal(&ResponseData{2, "AAA failed"})
// 			httprsp(rw, rsp)
// 			return
// 		}
// 	} else {
// 		cloud_id = v.Auth.Id
// 		cloud_key = v.Auth.Signature
// 	}

// 	in := &pb.CloudRequest{Bsns: bsns, Action: "list_ins", Region: v.Region, CloudId: cloud_id, CloudKey: cloud_key}
// 	in.Params["Limit"] = "1"
// 	res, ok := Cloud_CommonCall(in, "qcloud")
// 	if res.Code == 0 {
// 		v := make(map[string]interface{})
// 		json.Unmarshal(res.Data, &v)
// 		var count int
// 		if bsns == "cvm" {
// 			totalcount, ok := v["Response"].(map[string]interface{})["TotalCount"].(float64)
// 			if ok {
// 				count = int(totalcount)
// 			}
// 		} else {
// 			totalcount, ok := v["totalCount"].(string)
// 			if ok {
// 				count = public.Atoi(totalcount)
// 			}
// 		}

// 		var looptime int
// 		if count%100 == 0 {
// 			looptime = count / 100
// 		} else {
// 			looptime = count/100 + 1
// 		}
// 		in.Params["Limit"] = "100"
// 		for i := 0; i < looptime; i++ {
// 			in.Params["Offset"] = public.Itoa(i * 100)
// 			fmt.Println(in)
// 		}
// 	}
// 	rsp, _ := json.Marshal(&Cloud_Res{Code: 2, Msg: res.Msg})
// 	httprsp(rw, rsp)

// 	// collectionName := "asset."
// }
<commit_msg>fix_asset_rename_AssetService<commit_after>/*

LICENSE:  MIT
Author:   sine
Email:    sinerwr@gmail.com

*/

package controller

import (
	"encoding/json"
	// "fmt"
	// "github.com/getsentry/raven-go"
	"golang.org/x/net/context"
	"net/http"

	"github.com/SiCo-Ops/Pb"
	"github.com/SiCo-Ops/dao/grpc"
	// "github.com/SiCo-Ops/dao/mongo"
	// "github.com/SiCo-Ops/public"
)

type AssetTemplate struct {
	PrivateToken AuthenticationToken `json:"token"`
	Name         string              `json:"name"`
	Param        map[string]string   `json:"param"`
}

func AssetCreateTemplate(rw http.ResponseWriter, req *http.Request) {
	v := AssetTemplate{}
	if data, ok := ValidatePostData(rw, req); ok {
		json.Unmarshal(data, &v)
	} else {
		return
	}
	in := &pb.AssetTemplateCall{}
	if config.AAAEnable && !AAAValidateToken(v.PrivateToken.ID, v.PrivateToken.Signature) {
		rsp, _ := json.Marshal(ResponseErrmsg(2))
		httprsp(rw, rsp)
		return
	}
	in.Id = v.PrivateToken.ID
	in.Name = v.Name
	in.Param = v.Param
	cc := rpc.RPCConn(RPCAddr["Be"])
	defer cc.Close()
	c := pb.NewAssetServiceClient(cc)
	res, _ := c.CreateTemplateRPC(context.Background(), in)
	if res.Code == 0 {
		rsp, _ := json.Marshal(&ResponseData{0, "Success add template"})
		httprsp(rw, rsp)
		return
	}
	rsp, _ := json.Marshal(res)
	httprsp(rw, rsp)
	return
}

// func Asset_synchronize(rw http.ResponseWriter, req *http.Request) {
// 	cloud := GetRouteName(req, "cloud")
// 	bsns := GetRouteName(req, "bsns")
// 	if !AuthBsns(cloud, bsns) {
// 		rsp, _ := json.Marshal(&ResponseData{Code: 2, Data: "Cloud not support yet ,damn"})
// 		httprsp(rw, rsp)
// 		return
// 	}

// 	data, ok := AuthPostData(rw, req)
// 	if !ok {
// 		return
// 	}
// 	v := &Cloud_Req{}
// 	json.Unmarshal(data, v)

// 	/*
// 		Control need AAA server to get Cloud id & key
// 	*/
// 	if needAAA {
// 		cloud_id, cloud_key = AAA_GetThirdKey(cloud, v.Auth.Id, v.Auth.Signature, v.Name)
// 		if cloud_id == "" {
// 			rsp, _ := json.Marshal(&ResponseData{2, "AAA failed"})
// 			httprsp(rw, rsp)
// 			return
// 		}
// 	} else {
// 		cloud_id = v.Auth.Id
// 		cloud_key = v.Auth.Signature
// 	}

// 	in := &pb.CloudRequest{Bsns: bsns, Action: "list_ins", Region: v.Region, CloudId: cloud_id, CloudKey: cloud_key}
// 	in.Params["Limit"] = "1"
// 	res, ok := Cloud_CommonCall(in, "qcloud")
// 	if res.Code == 0 {
// 		v := make(map[string]interface{})
// 		json.Unmarshal(res.Data, &v)
// 		var count int
// 		if bsns == "cvm" {
// 			totalcount, ok := v["Response"].(map[string]interface{})["TotalCount"].(float64)
// 			if ok {
// 				count = int(totalcount)
// 			}
// 		} else {
// 			totalcount, ok := v["totalCount"].(string)
// 			if ok {
// 				count = public.Atoi(totalcount)
// 			}
// 		}

// 		var looptime int
// 		if count%100 == 0 {
// 			looptime = count / 100
// 		} else {
// 			looptime = count/100 + 1
// 		}
// 		in.Params["Limit"] = "100"
// 		for i := 0; i < looptime; i++ {
// 			in.Params["Offset"] = public.Itoa(i * 100)
// 			fmt.Println(in)
// 		}
// 	}
// 	rsp, _ := json.Marshal(&Cloud_Res{Code: 2, Msg: res.Msg})
// 	httprsp(rw, rsp)

// 	// collectionName := "asset."
// }
<|endoftext|>