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

// dhclient sets up DHCP.
//
// Synopsis:
//     dhclient [OPTIONS...]
//
// Options:
//     -timeout:  lease timeout in seconds
//     -renewals: number of DHCP renewals before exiting
//     -verbose:  verbose output
package main

import (
	"bytes"
	"crypto/rand"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"time"

	"github.com/d2g/dhcp4"
	"github.com/d2g/dhcp4client"
	"github.com/vishvananda/netlink"
)

const (
	defaultIface = "eth0"
	// slop is the slop in our lease time.
	slop = 10 * time.Second
)

var (
	leasetimeout = flag.Int("timeout", 600, "Lease timeout in seconds")
	renewals     = flag.Int("renewals", 2, "Number of DHCP renewals before exiting")
	verbose      = flag.Bool("verbose", false, "Verbose output")
	debug        = func(string, ...interface{}) {}
)

func dhclient(ifname string, numRenewals int, timeout time.Duration) error {
	var err error

	// if timeout is < 10 seconds, it's too short.
	if timeout < slop {
		timeout = 2 * slop
		log.Printf("increased log timeout to %s", timeout)
	}

	n, err := ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/address", ifname))
	if err != nil {
		return fmt.Errorf("cannot get mac for %v: %v", ifname, err)
	}

	// This is truly amazing but /sys appends newlines to all this data.
	n = bytes.TrimSpace(n)
	mac, err := net.ParseMAC(string(n))
	if err != nil {
		return fmt.Errorf("mac error: %v", err)
	}

	iface, err := netlink.LinkByName(ifname)
	if err != nil {
		return fmt.Errorf("%s: netlink.LinkByName failed: %v", ifname, err)
	}

	if err := netlink.LinkSetUp(iface); err != nil {
		return fmt.Errorf("%v: %v can't make it up: %v", ifname, iface, err)
	}

	conn, err := dhcp4client.NewPacketSock(iface.Attrs().Index)
	if err != nil {
		return fmt.Errorf("client conection generation: %v", err)
	}

	client, err := dhcp4client.New(dhcp4client.HardwareAddr(mac), dhcp4client.Connection(conn), dhcp4client.Timeout(timeout))
	if err != nil {
		return fmt.Errorf("error: %v", err)
	}

	var packet dhcp4.Packet
	for i := 0; i < numRenewals+1; i++ {
		debug("Start getting or renewing lease")

		var success bool
		if packet == nil {
			success, packet, err = client.Request()
		} else {
			success, packet, err = client.Renew(packet)
		}
		if err != nil {
			networkError, ok := err.(*net.OpError)
			if ok && networkError.Timeout() {
				return fmt.Errorf("%s: could not find DHCP server", mac)
			}
			return fmt.Errorf("%s: error: %v", mac, err)
		}

		debug("Success on %s: %v\n", mac, success)
		debug("Packet: %v\n", packet)
		debug("Lease is %v seconds\n", packet.Secs())

		if !success {
			return fmt.Errorf("%s: we didn't sucessfully get a DHCP lease.", mac)
		}
		debug("IP Received: %v\n", packet.YIAddr().String())

		// We got here because we got a good packet.
		o := packet.ParseOptions()

		netmask, ok := o[dhcp4.OptionSubnetMask]
		if ok {
			log.Printf("OptionSubnetMask is %v\n", netmask)
		} else {
			// If they did not offer a subnet mask, we
			// choose the most restrictive option, namely,
			// our IP address.  This could happen on,
			// e.g., a point to point link.
			netmask = packet.YIAddr()
		}

		dst := &netlink.Addr{IPNet: &net.IPNet{IP: packet.YIAddr(), Mask: netmask}, Label: ""}
		// Add the address to the iface.
		if err := netlink.AddrAdd(iface, dst); err != nil {
			if os.IsExist(err) {
				return fmt.Errorf("add %v to %v: %v", dst, n, err)
			}
		}

		if gwData, ok := o[dhcp4.OptionRouter]; ok {
			log.Printf("router %v", gwData)
			routerName := net.IP(gwData).String()
			debug("routerName %v", routerName)
			r := &netlink.Route{
				Dst:       &net.IPNet{IP: packet.GIAddr(), Mask: netmask},
				LinkIndex: iface.Attrs().Index,
				Gw:        packet.GIAddr(),
			}

			if err := netlink.RouteReplace(r); err != nil {
				return fmt.Errorf("%s: add %s: %v", ifname, r.String(), routerName)
			}
		}

		// We can not assume the server will give us any grace time. So
		// sleep for just a tiny bit less than the minimum.
		time.Sleep(timeout - slop)
	}
	return nil
}

func main() {
	flag.Parse()
	if *verbose {
		debug = log.Printf
	}

	// if we boot quickly enough, the random number generator
	// may not be ready, and the dhcp package panics in that case.
	// Worse, /dev/urandom, which the Go package falls back to,
	// might not be there. Still worse, the Go package is "sticky"
	// in that once it decides to use /dev/urandom, it won't go back,
	// even if the system call would subsequently work.
	// You're screwed. Exit.
	// Wouldn't it be nice if we could just do the blocking system
	// call? But that comes with its own giant set of headaches.
	// Maybe we'll end up in a loop, sleeping, and just running
	// ourselves.
	if n, err := rand.Read([]byte{0}); err != nil || n != 1 {
		log.Fatalf("We're sorry, the random number generator is not up. Please file a ticket")
	}

	iList := []string{defaultIface}
	if len(flag.Args()) > 0 {
		iList = flag.Args()
	}

	done := make(chan error)
	for _, iface := range iList {
		go func(iface string) {
			done <- dhclient(iface, *renewals, time.Duration(*leasetimeout)*time.Second)
		}(iface)
	}

	// Wait for all goroutines to finish.
	for range iList {
		if err := <-done; err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
}
<commit_msg>Enabled infinite renewal from dhclient<commit_after>// Copyright 2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// dhclient sets up DHCP.
//
// Synopsis:
//     dhclient [OPTIONS...]
//
// Options:
//     -timeout:  lease timeout in seconds
//     -renewals: number of DHCP renewals before exiting
//     -verbose:  verbose output
package main

import (
	"bytes"
	"crypto/rand"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"time"

	"github.com/d2g/dhcp4"
	"github.com/d2g/dhcp4client"
	"github.com/vishvananda/netlink"
)

const (
	defaultIface = "eth0"
	// slop is the slop in our lease time.
	slop = 10 * time.Second
)

var (
	leasetimeout = flag.Int("timeout", 600, "Lease timeout in seconds")
	renewals     = flag.Int("renewals", -1, "Number of DHCP renewals before exiting")
	verbose      = flag.Bool("verbose", false, "Verbose output")
	debug        = func(string, ...interface{}) {}
)

func dhclient(ifname string, numRenewals int, timeout time.Duration) error {
	var err error

	// if timeout is < 10 seconds, it's too short.
	if timeout < slop {
		timeout = 2 * slop
		log.Printf("increased log timeout to %s", timeout)
	}

	n, err := ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/address", ifname))
	if err != nil {
		return fmt.Errorf("cannot get mac for %v: %v", ifname, err)
	}

	// This is truly amazing but /sys appends newlines to all this data.
	n = bytes.TrimSpace(n)
	mac, err := net.ParseMAC(string(n))
	if err != nil {
		return fmt.Errorf("mac error: %v", err)
	}

	iface, err := netlink.LinkByName(ifname)
	if err != nil {
		return fmt.Errorf("%s: netlink.LinkByName failed: %v", ifname, err)
	}

	if err := netlink.LinkSetUp(iface); err != nil {
		return fmt.Errorf("%v: %v can't make it up: %v", ifname, iface, err)
	}

	conn, err := dhcp4client.NewPacketSock(iface.Attrs().Index)
	if err != nil {
		return fmt.Errorf("client conection generation: %v", err)
	}

	client, err := dhcp4client.New(dhcp4client.HardwareAddr(mac), dhcp4client.Connection(conn), dhcp4client.Timeout(timeout))
	if err != nil {
		return fmt.Errorf("error: %v", err)
	}

	var packet dhcp4.Packet
	for i := 0; numRenewals < 0 || i < numRenewals+1; i++ {
		debug("Start getting or renewing lease")

		var success bool
		if packet == nil {
			success, packet, err = client.Request()
		} else {
			success, packet, err = client.Renew(packet)
		}
		if err != nil {
			networkError, ok := err.(*net.OpError)
			if ok && networkError.Timeout() {
				return fmt.Errorf("%s: could not find DHCP server", mac)
			}
			return fmt.Errorf("%s: error: %v", mac, err)
		}

		debug("Success on %s: %v\n", mac, success)
		debug("Packet: %v\n", packet)
		debug("Lease is %v seconds\n", packet.Secs())

		if !success {
			return fmt.Errorf("%s: we didn't sucessfully get a DHCP lease.", mac)
		}
		debug("IP Received: %v\n", packet.YIAddr().String())

		// We got here because we got a good packet.
		o := packet.ParseOptions()

		netmask, ok := o[dhcp4.OptionSubnetMask]
		if ok {
			log.Printf("OptionSubnetMask is %v\n", netmask)
		} else {
			// If they did not offer a subnet mask, we
			// choose the most restrictive option, namely,
			// our IP address.  This could happen on,
			// e.g., a point to point link.
			netmask = packet.YIAddr()
		}

		dst := &netlink.Addr{IPNet: &net.IPNet{IP: packet.YIAddr(), Mask: netmask}, Label: ""}
		// Add the address to the iface.
		if err := netlink.AddrAdd(iface, dst); err != nil {
			if os.IsExist(err) {
				return fmt.Errorf("add %v to %v: %v", dst, n, err)
			}
		}

		if gwData, ok := o[dhcp4.OptionRouter]; ok {
			log.Printf("router %v", gwData)
			routerName := net.IP(gwData).String()
			debug("routerName %v", routerName)
			r := &netlink.Route{
				Dst:       &net.IPNet{IP: packet.GIAddr(), Mask: netmask},
				LinkIndex: iface.Attrs().Index,
				Gw:        packet.GIAddr(),
			}

			if err := netlink.RouteReplace(r); err != nil {
				return fmt.Errorf("%s: add %s: %v", ifname, r.String(), routerName)
			}
		}

		// We can not assume the server will give us any grace time. So
		// sleep for just a tiny bit less than the minimum.
		time.Sleep(timeout - slop)
	}
	return nil
}

func main() {
	flag.Parse()
	if *verbose {
		debug = log.Printf
	}

	// if we boot quickly enough, the random number generator
	// may not be ready, and the dhcp package panics in that case.
	// Worse, /dev/urandom, which the Go package falls back to,
	// might not be there. Still worse, the Go package is "sticky"
	// in that once it decides to use /dev/urandom, it won't go back,
	// even if the system call would subsequently work.
	// You're screwed. Exit.
	// Wouldn't it be nice if we could just do the blocking system
	// call? But that comes with its own giant set of headaches.
	// Maybe we'll end up in a loop, sleeping, and just running
	// ourselves.
	if n, err := rand.Read([]byte{0}); err != nil || n != 1 {
		log.Fatalf("We're sorry, the random number generator is not up. Please file a ticket")
	}

	iList := []string{defaultIface}
	if len(flag.Args()) > 0 {
		iList = flag.Args()
	}

	done := make(chan error)
	for _, iface := range iList {
		go func(iface string) {
			done <- dhclient(iface, *renewals, time.Duration(*leasetimeout)*time.Second)
		}(iface)
	}

	// Wait for all goroutines to finish.
	for range iList {
		if err := <-done; err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
}
<|endoftext|>


<commit_before>package collector

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/google/gnxi/utils/xpath"
	"github.com/openconfig/gnmi/proto/gnmi"
)

// SubscriptionConfig //
type SubscriptionConfig struct {
	Name              string        `mapstructure:"name,omitempty"`
	Models            []string      `mapstructure:"models,omitempty"`
	Prefix            string        `mapstructure:"prefix,omitempty"`
	Paths             []string      `mapstructure:"paths,omitempty"`
	Mode              string        `mapstructure:"mode,omitempty"`
	StreamMode        string        `mapstructure:"stream-mode,omitempty"`
	Encoding          string        `mapstructure:"encoding,omitempty"`
	Qos               uint32        `mapstructure:"qos,omitempty"`
	SampleInterval    time.Duration `mapstructure:"sample-interval,omitempty"`
	HeartbeatInterval time.Duration `mapstructure:"heartbeat-interval,omitempty"`
	SuppressRedundant bool          `mapstructure:"suppress-redundant,omitempty"`
	UpdatesOnly       bool          `mapstructure:"updates-only,omitempty"`
}

// String //
func (sc *SubscriptionConfig) String() string {
	b, err := json.Marshal(sc)
	if err != nil {
		return ""
	}
	return string(b)
}

func (sc *SubscriptionConfig) setDefaults() error {
	if len(sc.Paths) == 0 {
		return fmt.Errorf("missing path(s) in subscription '%s'", sc.Name)
	}
	if sc.Mode == "" {
		sc.Mode = "STREAM"
	}
	if sc.Mode == "STREAM" && sc.StreamMode == "" {
		sc.StreamMode = "TARGET_DEFINED"
	}
	if sc.Encoding == "" {
		sc.Encoding = "JSON"
	}
	if sc.Qos == 0 {
		sc.Qos = 20
	}
	if sc.StreamMode == "SAMPLE" && sc.SampleInterval == 0 {
		sc.SampleInterval = 10 * time.Second
	}
	return nil
}

// CreateSubscribeRequest validates the SubscriptionConfig and creates gnmi.SubscribeRequest
func (sc *SubscriptionConfig) CreateSubscribeRequest() (*gnmi.SubscribeRequest, error) {
	if err := sc.setDefaults(); err != nil {
		return nil, err
	}
	gnmiPrefix, err := xpath.ToGNMIPath(sc.Prefix)
	if err != nil {
		return nil, fmt.Errorf("prefix parse error: %v", err)
	}
	encodingVal, ok := gnmi.Encoding_value[strings.Replace(strings.ToUpper(sc.Encoding), "-", "_", -1)]
	if !ok {
		return nil, fmt.Errorf("subscription '%s' invalid encoding type '%s'", sc.Name, sc.Encoding)
	}
	modeVal, ok := gnmi.SubscriptionList_Mode_value[strings.ToUpper(sc.Mode)]
	if !ok {
		return nil, fmt.Errorf("subscription '%s' invalid subscription list type '%s'", sc.Name, sc.Mode)
	}
	qos := &gnmi.QOSMarking{Marking: sc.Qos}

	subscriptions := make([]*gnmi.Subscription, len(sc.Paths))
	for i, p := range sc.Paths {
		gnmiPath, err := xpath.ToGNMIPath(strings.TrimSpace(p))
		if err != nil {
			return nil, fmt.Errorf("path '%s' parse error: %v", p, err)
		}
		subscriptions[i] = &gnmi.Subscription{Path: gnmiPath}
		switch gnmi.SubscriptionList_Mode(modeVal) {
		case gnmi.SubscriptionList_STREAM:
			mode, ok := gnmi.SubscriptionMode_value[strings.Replace(strings.ToUpper(sc.StreamMode), "-", "_", -1)]
			if !ok {
				return nil, fmt.Errorf("invalid streamed subscription mode %s", sc.Mode)
			}
			subscriptions[i].Mode = gnmi.SubscriptionMode(mode)
			switch gnmi.SubscriptionMode(mode) {
			case gnmi.SubscriptionMode_ON_CHANGE:
				subscriptions[i].HeartbeatInterval = uint64(sc.HeartbeatInterval.Nanoseconds())
			case gnmi.SubscriptionMode_SAMPLE, gnmi.SubscriptionMode_TARGET_DEFINED:
				subscriptions[i].SampleInterval = uint64(sc.SampleInterval.Nanoseconds())
				subscriptions[i].SuppressRedundant = sc.SuppressRedundant
				if subscriptions[i].SuppressRedundant {
					subscriptions[i].HeartbeatInterval = uint64(sc.HeartbeatInterval.Nanoseconds())
				}
			}
		}
	}
	models := make([]*gnmi.ModelData, 0, len(sc.Models))
	for _, m := range sc.Models {
		models = append(models, &gnmi.ModelData{Name: m})
	}
	return &gnmi.SubscribeRequest{
		Request: &gnmi.SubscribeRequest_Subscribe{
			Subscribe: &gnmi.SubscriptionList{
				Prefix:       gnmiPrefix,
				Mode:         gnmi.SubscriptionList_Mode(modeVal),
				Encoding:     gnmi.Encoding(encodingVal),
				Subscription: subscriptions,
				Qos:          qos,
				UpdatesOnly:  sc.UpdatesOnly,
				UseModels:    models,
			},
		},
	}, nil
}

// SubscribeResponse //
type SubscribeResponse struct {
	SubscriptionName string
	Response         *gnmi.SubscribeResponse
}
<commit_msg>support origin in path and prefix for subscribeRequest creation<commit_after>package collector

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/openconfig/gnmi/proto/gnmi"
)

// SubscriptionConfig //
type SubscriptionConfig struct {
	Name              string        `mapstructure:"name,omitempty"`
	Models            []string      `mapstructure:"models,omitempty"`
	Prefix            string        `mapstructure:"prefix,omitempty"`
	Paths             []string      `mapstructure:"paths,omitempty"`
	Mode              string        `mapstructure:"mode,omitempty"`
	StreamMode        string        `mapstructure:"stream-mode,omitempty"`
	Encoding          string        `mapstructure:"encoding,omitempty"`
	Qos               uint32        `mapstructure:"qos,omitempty"`
	SampleInterval    time.Duration `mapstructure:"sample-interval,omitempty"`
	HeartbeatInterval time.Duration `mapstructure:"heartbeat-interval,omitempty"`
	SuppressRedundant bool          `mapstructure:"suppress-redundant,omitempty"`
	UpdatesOnly       bool          `mapstructure:"updates-only,omitempty"`
}

// String //
func (sc *SubscriptionConfig) String() string {
	b, err := json.Marshal(sc)
	if err != nil {
		return ""
	}
	return string(b)
}

func (sc *SubscriptionConfig) setDefaults() error {
	if len(sc.Paths) == 0 {
		return fmt.Errorf("missing path(s) in subscription '%s'", sc.Name)
	}
	if sc.Mode == "" {
		sc.Mode = "STREAM"
	}
	if sc.Mode == "STREAM" && sc.StreamMode == "" {
		sc.StreamMode = "TARGET_DEFINED"
	}
	if sc.Encoding == "" {
		sc.Encoding = "JSON"
	}
	if sc.Qos == 0 {
		sc.Qos = 20
	}
	if sc.StreamMode == "SAMPLE" && sc.SampleInterval == 0 {
		sc.SampleInterval = 10 * time.Second
	}
	return nil
}

// CreateSubscribeRequest validates the SubscriptionConfig and creates gnmi.SubscribeRequest
func (sc *SubscriptionConfig) CreateSubscribeRequest() (*gnmi.SubscribeRequest, error) {
	if err := sc.setDefaults(); err != nil {
		return nil, err
	}
	gnmiPrefix, err := ParsePath(sc.Prefix)
	if err != nil {
		return nil, fmt.Errorf("prefix parse error: %v", err)
	}
	encodingVal, ok := gnmi.Encoding_value[strings.Replace(strings.ToUpper(sc.Encoding), "-", "_", -1)]
	if !ok {
		return nil, fmt.Errorf("subscription '%s' invalid encoding type '%s'", sc.Name, sc.Encoding)
	}
	modeVal, ok := gnmi.SubscriptionList_Mode_value[strings.ToUpper(sc.Mode)]
	if !ok {
		return nil, fmt.Errorf("subscription '%s' invalid subscription list type '%s'", sc.Name, sc.Mode)
	}
	qos := &gnmi.QOSMarking{Marking: sc.Qos}

	subscriptions := make([]*gnmi.Subscription, len(sc.Paths))
	for i, p := range sc.Paths {
		gnmiPath, err := ParsePath(strings.TrimSpace(p))
		if err != nil {
			return nil, fmt.Errorf("path '%s' parse error: %v", p, err)
		}
		subscriptions[i] = &gnmi.Subscription{Path: gnmiPath}
		switch gnmi.SubscriptionList_Mode(modeVal) {
		case gnmi.SubscriptionList_STREAM:
			mode, ok := gnmi.SubscriptionMode_value[strings.Replace(strings.ToUpper(sc.StreamMode), "-", "_", -1)]
			if !ok {
				return nil, fmt.Errorf("invalid streamed subscription mode %s", sc.Mode)
			}
			subscriptions[i].Mode = gnmi.SubscriptionMode(mode)
			switch gnmi.SubscriptionMode(mode) {
			case gnmi.SubscriptionMode_ON_CHANGE:
				subscriptions[i].HeartbeatInterval = uint64(sc.HeartbeatInterval.Nanoseconds())
			case gnmi.SubscriptionMode_SAMPLE, gnmi.SubscriptionMode_TARGET_DEFINED:
				subscriptions[i].SampleInterval = uint64(sc.SampleInterval.Nanoseconds())
				subscriptions[i].SuppressRedundant = sc.SuppressRedundant
				if subscriptions[i].SuppressRedundant {
					subscriptions[i].HeartbeatInterval = uint64(sc.HeartbeatInterval.Nanoseconds())
				}
			}
		}
	}
	models := make([]*gnmi.ModelData, 0, len(sc.Models))
	for _, m := range sc.Models {
		models = append(models, &gnmi.ModelData{Name: m})
	}
	return &gnmi.SubscribeRequest{
		Request: &gnmi.SubscribeRequest_Subscribe{
			Subscribe: &gnmi.SubscriptionList{
				Prefix:       gnmiPrefix,
				Mode:         gnmi.SubscriptionList_Mode(modeVal),
				Encoding:     gnmi.Encoding(encodingVal),
				Subscription: subscriptions,
				Qos:          qos,
				UpdatesOnly:  sc.UpdatesOnly,
				UseModels:    models,
			},
		},
	}, nil
}

// SubscribeResponse //
type SubscribeResponse struct {
	SubscriptionName string
	Response         *gnmi.SubscribeResponse
}
<|endoftext|>


<commit_before>package command

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"runtime"
	"sync"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/otto/app"
	"github.com/hashicorp/otto/helper/semaphore"
	"github.com/hashicorp/otto/otto"
	"github.com/hashicorp/otto/plugin"
	"github.com/kardianos/osext"
)

// PluginGlob is the glob pattern used to find plugins.
const PluginGlob = "otto-plugin-*"

// PluginManager is responsible for discovering and starting plugins.
//
// Plugin cleanup is done out in the main package: we just defer
// plugin.CleanupClients in main itself.
type PluginManager struct {
	// PluginDirs are the directories where plugins can be found.
	// Any plugins with the same types found later (higher index) will
	// override earlier (lower index) directories.
	PluginDirs []string

	// PluginMap is the map of availabile built-in plugins
	PluginMap plugin.ServeMuxMap

	plugins []*Plugin
}

// Plugin is a single plugin that has been loaded.
type Plugin struct {
	// Path and Args are the method used to invocate this plugin.
	// These are the only two values that need to be set manually. Once
	// these are set, call Load to load the plugin.
	Path string   `json:"path,omitempty"`
	Args []string `json:"args"`

	// Builtin will be set to true by the PluginManager if this plugin
	// represents a built-in plugin. If it does, then Path above has
	// no affect, we always use the current executable.
	Builtin bool `json:"builtin"`

	// The fields below are loaded as part of the Load() call and should
	// not be set manually, but can be accessed after Load.
	App     app.Factory `json:"-"`
	AppMeta *app.Meta   `json:"-"`

	used bool
}

// Load loads the plugin specified by the Path and instantiates the
// other fields on this structure.
func (p *Plugin) Load() error {
	// If it is builtin, then we always use our own path
	path := p.Path
	if p.Builtin {
		path = pluginExePath
	}

	// Create the plugin client to communicate with the process
	pluginClient := plugin.NewClient(&plugin.ClientConfig{
		Cmd:     exec.Command(path, p.Args...),
		Managed: true,
	})

	// Request the client
	client, err := pluginClient.Client()
	if err != nil {
		return err
	}

	// Get the app implementation
	appImpl, err := client.App()
	if err != nil {
		return err
	}
	if c, ok := appImpl.(io.Closer); ok {
		defer c.Close()
	}

	p.AppMeta, err = appImpl.Meta()
	if err != nil {
		return err
	}

	// Create a custom factory that when called marks the plugin as used
	p.used = false
	p.App = func() (app.App, error) {
		p.used = true
		return client.App()
	}

	return nil
}

// Used tracks whether or not this plugin was used or not. You can call
// this after compilation on each plugin to determine what plugin
// was used.
func (p *Plugin) Used() bool {
	return p.used
}

func (p *Plugin) String() string {
	path := p.Path
	if p.Builtin {
		path = "<builtin>"
	}

	return fmt.Sprintf("%s %v", path, p.Args)
}

// ConfigureCore configures the Otto core configuration with the loaded
// plugin data.
func (m *PluginManager) ConfigureCore(core *otto.CoreConfig) error {
	if core.Apps == nil {
		core.Apps = make(map[app.Tuple]app.Factory)
	}

	for _, p := range m.Plugins() {
		for _, tuple := range p.AppMeta.Tuples {
			core.Apps[tuple] = p.App
		}
	}

	return nil
}

// Plugins returns the loaded plugins.
func (m *PluginManager) Plugins() []*Plugin {
	return m.plugins
}

// Discover will find all the available plugin binaries. Each time this
// is called it will override any previously discovered plugins.
func (m *PluginManager) Discover() error {
	result := make([]*Plugin, 0, 20)

	if !testingMode {
		// First we add all the builtin plugins which we get by executing ourself
		for k, _ := range m.PluginMap {
			result = append(result, &Plugin{
				Args:    []string{"plugin-builtin", k},
				Builtin: true,
			})
		}
	}

	for _, dir := range m.PluginDirs {
		log.Printf("[DEBUG] Looking for plugins in: %s", dir)
		paths, err := plugin.Discover(PluginGlob, dir)
		if err != nil {
			return fmt.Errorf(
				"Error discovering plugins in %s: %s", dir, err)
		}

		for _, path := range paths {
			result = append(result, &Plugin{
				Path: path,
			})
		}
	}

	// Log it
	for _, r := range result {
		log.Printf("[DEBUG] Detected plugin: %s", r)
	}

	// Save our result
	m.plugins = result

	return nil
}

// StoreUsed will persist the used plugins into a file. LoadUsed can
// then be called to load the plugins that were used only, making plugin
// loading much more efficient.
func (m *PluginManager) StoreUsed(path string) error {
	// Get the used plugins
	plugins := make([]*Plugin, 0, 2)
	for _, p := range m.Plugins() {
		if p.Used() {
			plugins = append(plugins, p)
		}
	}

	// Write the used plugins to the given path as JSON
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()

	enc := json.NewEncoder(f)
	return enc.Encode(&usedPluginWrapper{
		Version: usedPluginVersion,
		Plugins: plugins,
	})
}

// LoadUsed will load the plugins in the given used file that was saved
// with StoreUsed.
func (m *PluginManager) LoadUsed(path string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}

	var wrapper usedPluginWrapper
	dec := json.NewDecoder(f)
	err = dec.Decode(&wrapper)
	f.Close()
	if err != nil {
		return err
	}

	if wrapper.Version > usedPluginVersion {
		return fmt.Errorf(
			"Couldn't load used plugins because the format of the stored\n" +
				"metadata is newer than this version of Otto knows how to read.\n\n" +
				"This is usually caused by a newer version of Otto compiling an\n" +
				"environment. Please use a later version of Otto to read this.")
	}

	m.plugins = wrapper.Plugins
	return m.LoadAll()
}

// LoadAll will launch every plugin and add it to the CoreConfig given.
func (m *PluginManager) LoadAll() error {
	// If we've never loaded plugin paths, then let's discover those first
	if m.Plugins() == nil {
		if err := m.Discover(); err != nil {
			return err
		}
	}

	// Go through each plugin path and load single
	var merr error
	var merrLock sync.Mutex
	var wg sync.WaitGroup
	sema := semaphore.New(runtime.NumCPU())
	for _, plugin := range m.Plugins() {
		wg.Add(1)
		go func(plugin *Plugin) {
			defer wg.Done()

			sema.Acquire()
			defer sema.Release()

			if err := plugin.Load(); err != nil {
				merrLock.Lock()
				defer merrLock.Unlock()
				merr = multierror.Append(merr, fmt.Errorf(
					"Error loading plugin %s: %s",
					plugin.Path, err))
			}
		}(plugin)
	}

	// Wait for all the plugins to load
	wg.Wait()

	return merr
}

// usedPluginVersion is the current version of the used plugin format
// that we understand. We can increment and handle older versions as we go.
const usedPluginVersion int = 1

type usedPluginWrapper struct {
	Version int       `json:"version"`
	Plugins []*Plugin `json:"plugins"`
}

// pluginExePath is our own path. We cache this so we only have to calculate
// it once.
var pluginExePath string

func init() {
	var err error
	pluginExePath, err = osext.Executable()
	if err != nil {
		panic(err)
	}
}
<commit_msg>command: reverse the order of detected plugins for proper priority<commit_after>package command

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"runtime"
	"sync"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/otto/app"
	"github.com/hashicorp/otto/helper/semaphore"
	"github.com/hashicorp/otto/otto"
	"github.com/hashicorp/otto/plugin"
	"github.com/kardianos/osext"
)

// PluginGlob is the glob pattern used to find plugins.
const PluginGlob = "otto-plugin-*"

// PluginManager is responsible for discovering and starting plugins.
//
// Plugin cleanup is done out in the main package: we just defer
// plugin.CleanupClients in main itself.
type PluginManager struct {
	// PluginDirs are the directories where plugins can be found.
	// Any plugins with the same types found later (higher index) will
	// override earlier (lower index) directories.
	PluginDirs []string

	// PluginMap is the map of availabile built-in plugins
	PluginMap plugin.ServeMuxMap

	plugins []*Plugin
}

// Plugin is a single plugin that has been loaded.
type Plugin struct {
	// Path and Args are the method used to invocate this plugin.
	// These are the only two values that need to be set manually. Once
	// these are set, call Load to load the plugin.
	Path string   `json:"path,omitempty"`
	Args []string `json:"args"`

	// Builtin will be set to true by the PluginManager if this plugin
	// represents a built-in plugin. If it does, then Path above has
	// no affect, we always use the current executable.
	Builtin bool `json:"builtin"`

	// The fields below are loaded as part of the Load() call and should
	// not be set manually, but can be accessed after Load.
	App     app.Factory `json:"-"`
	AppMeta *app.Meta   `json:"-"`

	used bool
}

// Load loads the plugin specified by the Path and instantiates the
// other fields on this structure.
func (p *Plugin) Load() error {
	// If it is builtin, then we always use our own path
	path := p.Path
	if p.Builtin {
		path = pluginExePath
	}

	// Create the plugin client to communicate with the process
	pluginClient := plugin.NewClient(&plugin.ClientConfig{
		Cmd:     exec.Command(path, p.Args...),
		Managed: true,
	})

	// Request the client
	client, err := pluginClient.Client()
	if err != nil {
		return err
	}

	// Get the app implementation
	appImpl, err := client.App()
	if err != nil {
		return err
	}
	if c, ok := appImpl.(io.Closer); ok {
		defer c.Close()
	}

	p.AppMeta, err = appImpl.Meta()
	if err != nil {
		return err
	}

	// Create a custom factory that when called marks the plugin as used
	p.used = false
	p.App = func() (app.App, error) {
		p.used = true
		return client.App()
	}

	return nil
}

// Used tracks whether or not this plugin was used or not. You can call
// this after compilation on each plugin to determine what plugin
// was used.
func (p *Plugin) Used() bool {
	return p.used
}

func (p *Plugin) String() string {
	path := p.Path
	if p.Builtin {
		path = "<builtin>"
	}

	return fmt.Sprintf("%s %v", path, p.Args)
}

// ConfigureCore configures the Otto core configuration with the loaded
// plugin data.
func (m *PluginManager) ConfigureCore(core *otto.CoreConfig) error {
	if core.Apps == nil {
		core.Apps = make(map[app.Tuple]app.Factory)
	}

	for _, p := range m.Plugins() {
		for _, tuple := range p.AppMeta.Tuples {
			core.Apps[tuple] = p.App
		}
	}

	return nil
}

// Plugins returns the loaded plugins.
func (m *PluginManager) Plugins() []*Plugin {
	return m.plugins
}

// Discover will find all the available plugin binaries. Each time this
// is called it will override any previously discovered plugins.
func (m *PluginManager) Discover() error {
	result := make([]*Plugin, 0, 20)

	if !testingMode {
		// First we add all the builtin plugins which we get by executing ourself
		for k, _ := range m.PluginMap {
			result = append(result, &Plugin{
				Args:    []string{"plugin-builtin", k},
				Builtin: true,
			})
		}
	}

	for _, dir := range m.PluginDirs {
		log.Printf("[DEBUG] Looking for plugins in: %s", dir)
		paths, err := plugin.Discover(PluginGlob, dir)
		if err != nil {
			return fmt.Errorf(
				"Error discovering plugins in %s: %s", dir, err)
		}

		for _, path := range paths {
			result = append(result, &Plugin{
				Path: path,
			})
		}
	}

	// Reverse the list of plugins. We do this because we want custom
	// plugins to take priority over built-in plugins, and the PluginDirs
	// ordering also defines this priority.
	for left, right := 0, len(result)-1; left < right; left, right = left+1, right-1 {
		result[left], result[right] = result[right], result[left]
	}

	// Log it
	for _, r := range result {
		log.Printf("[DEBUG] Detected plugin: %s", r)
	}

	// Save our result
	m.plugins = result

	return nil
}

// StoreUsed will persist the used plugins into a file. LoadUsed can
// then be called to load the plugins that were used only, making plugin
// loading much more efficient.
func (m *PluginManager) StoreUsed(path string) error {
	// Get the used plugins
	plugins := make([]*Plugin, 0, 2)
	for _, p := range m.Plugins() {
		if p.Used() {
			plugins = append(plugins, p)
		}
	}

	// Write the used plugins to the given path as JSON
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()

	enc := json.NewEncoder(f)
	return enc.Encode(&usedPluginWrapper{
		Version: usedPluginVersion,
		Plugins: plugins,
	})
}

// LoadUsed will load the plugins in the given used file that was saved
// with StoreUsed.
func (m *PluginManager) LoadUsed(path string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}

	var wrapper usedPluginWrapper
	dec := json.NewDecoder(f)
	err = dec.Decode(&wrapper)
	f.Close()
	if err != nil {
		return err
	}

	if wrapper.Version > usedPluginVersion {
		return fmt.Errorf(
			"Couldn't load used plugins because the format of the stored\n" +
				"metadata is newer than this version of Otto knows how to read.\n\n" +
				"This is usually caused by a newer version of Otto compiling an\n" +
				"environment. Please use a later version of Otto to read this.")
	}

	m.plugins = wrapper.Plugins
	return m.LoadAll()
}

// LoadAll will launch every plugin and add it to the CoreConfig given.
func (m *PluginManager) LoadAll() error {
	// If we've never loaded plugin paths, then let's discover those first
	if m.Plugins() == nil {
		if err := m.Discover(); err != nil {
			return err
		}
	}

	// Go through each plugin path and load single
	var merr error
	var merrLock sync.Mutex
	var wg sync.WaitGroup
	sema := semaphore.New(runtime.NumCPU())
	for _, plugin := range m.Plugins() {
		wg.Add(1)
		go func(plugin *Plugin) {
			defer wg.Done()

			sema.Acquire()
			defer sema.Release()

			if err := plugin.Load(); err != nil {
				merrLock.Lock()
				defer merrLock.Unlock()
				merr = multierror.Append(merr, fmt.Errorf(
					"Error loading plugin %s: %s",
					plugin.Path, err))
			}
		}(plugin)
	}

	// Wait for all the plugins to load
	wg.Wait()

	return merr
}

// usedPluginVersion is the current version of the used plugin format
// that we understand. We can increment and handle older versions as we go.
const usedPluginVersion int = 1

type usedPluginWrapper struct {
	Version int       `json:"version"`
	Plugins []*Plugin `json:"plugins"`
}

// pluginExePath is our own path. We cache this so we only have to calculate
// it once.
var pluginExePath string

func init() {
	var err error
	pluginExePath, err = osext.Executable()
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"time"

	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/git-lfs/git-lfs/progress"
	"github.com/git-lfs/git-lfs/tasklog"
	"github.com/git-lfs/git-lfs/tq"
	"github.com/rubyist/tracerx"
	"github.com/spf13/cobra"
)

var (
	fetchRecentArg bool
	fetchAllArg    bool
	fetchPruneArg  bool
)

func getIncludeExcludeArgs(cmd *cobra.Command) (include, exclude *string) {
	includeFlag := cmd.Flag("include")
	excludeFlag := cmd.Flag("exclude")
	if includeFlag.Changed {
		include = &includeArg
	}
	if excludeFlag.Changed {
		exclude = &excludeArg
	}

	return
}

func fetchCommand(cmd *cobra.Command, args []string) {
	requireInRepo()

	var refs []*git.Ref

	if len(args) > 0 {
		// Remote is first arg
		if err := cfg.SetValidRemote(args[0]); err != nil {
			Exit("Invalid remote name %q: %s", args[0], err)
		}
	}

	if len(args) > 1 {
		resolvedrefs, err := git.ResolveRefs(args[1:])
		if err != nil {
			Panic(err, "Invalid ref argument: %v", args[1:])
		}
		refs = resolvedrefs
	} else if !fetchAllArg {
		ref, err := git.CurrentRef()
		if err != nil {
			Panic(err, "Could not fetch")
		}
		refs = []*git.Ref{ref}
	}

	success := true
	gitscanner := lfs.NewGitScanner(nil)
	defer gitscanner.Close()

	include, exclude := getIncludeExcludeArgs(cmd)
	fetchPruneCfg := lfs.NewFetchPruneConfig(cfg.Git)

	if fetchAllArg {
		if fetchRecentArg || len(args) > 1 {
			Exit("Cannot combine --all with ref arguments or --recent")
		}
		if include != nil || exclude != nil {
			Exit("Cannot combine --all with --include or --exclude")
		}
		if len(cfg.FetchIncludePaths()) > 0 || len(cfg.FetchExcludePaths()) > 0 {
			Print("Ignoring global include / exclude paths to fulfil --all")
		}
		success = fetchAll()

	} else { // !all
		filter := buildFilepathFilter(cfg, include, exclude)

		// Fetch refs sequentially per arg order; duplicates in later refs will be ignored
		for _, ref := range refs {
			Print("Fetching %v", ref.Name)
			s := fetchRef(ref.Sha, filter)
			success = success && s
		}

		if fetchRecentArg || fetchPruneCfg.FetchRecentAlways {
			s := fetchRecent(fetchPruneCfg, refs, filter)
			success = success && s
		}
	}

	if fetchPruneArg {
		verify := fetchPruneCfg.PruneVerifyRemoteAlways
		// no dry-run or verbose options in fetch, assume false
		prune(fetchPruneCfg, verify, false, false)
	}

	if !success {
		c := getAPIClient()
		e := c.Endpoints.Endpoint("download", cfg.Remote())
		Exit("error: failed to fetch some objects from '%s'", e.Url)
	}
}

func pointersToFetchForRef(ref string, filter *filepathfilter.Filter) ([]*lfs.WrappedPointer, error) {
	var pointers []*lfs.WrappedPointer
	var multiErr error
	tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err != nil {
			if multiErr != nil {
				multiErr = fmt.Errorf("%v\n%v", multiErr, err)
			} else {
				multiErr = err
			}
			return
		}

		pointers = append(pointers, p)
	})

	tempgitscanner.Filter = filter

	if err := tempgitscanner.ScanTree(ref); err != nil {
		return nil, err
	}

	tempgitscanner.Close()
	return pointers, multiErr
}

// Fetch all binaries for a given ref (that we don't have already)
func fetchRef(ref string, filter *filepathfilter.Filter) bool {
	pointers, err := pointersToFetchForRef(ref, filter)
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}
	return fetchAndReportToChan(pointers, filter, nil)
}

// Fetch all previous versions of objects from since to ref (not including final state at ref)
// So this will fetch all the '-' sides of the diff from since to ref
func fetchPreviousVersions(ref string, since time.Time, filter *filepathfilter.Filter) bool {
	var pointers []*lfs.WrappedPointer

	tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err != nil {
			Panic(err, "Could not scan for Git LFS previous versions")
			return
		}

		pointers = append(pointers, p)
	})

	tempgitscanner.Filter = filter

	if err := tempgitscanner.ScanPreviousVersions(ref, since, nil); err != nil {
		ExitWithError(err)
	}

	tempgitscanner.Close()
	return fetchAndReportToChan(pointers, filter, nil)
}

// Fetch recent objects based on config
func fetchRecent(fetchconf lfs.FetchPruneConfig, alreadyFetchedRefs []*git.Ref, filter *filepathfilter.Filter) bool {
	if fetchconf.FetchRecentRefsDays == 0 && fetchconf.FetchRecentCommitsDays == 0 {
		return true
	}

	ok := true
	// Make a list of what unique commits we've already fetched for to avoid duplicating work
	uniqueRefShas := make(map[string]string, len(alreadyFetchedRefs))
	for _, ref := range alreadyFetchedRefs {
		uniqueRefShas[ref.Sha] = ref.Name
	}
	// First find any other recent refs
	if fetchconf.FetchRecentRefsDays > 0 {
		Print("Fetching recent branches within %v days", fetchconf.FetchRecentRefsDays)
		refsSince := time.Now().AddDate(0, 0, -fetchconf.FetchRecentRefsDays)
		refs, err := git.RecentBranches(refsSince, fetchconf.FetchRecentRefsIncludeRemotes, cfg.Remote())
		if err != nil {
			Panic(err, "Could not scan for recent refs")
		}
		for _, ref := range refs {
			// Don't fetch for the same SHA twice
			if prevRefName, ok := uniqueRefShas[ref.Sha]; ok {
				if ref.Name != prevRefName {
					tracerx.Printf("Skipping fetch for %v, already fetched via %v", ref.Name, prevRefName)
				}
			} else {
				uniqueRefShas[ref.Sha] = ref.Name
				Print("Fetching %v", ref.Name)
				k := fetchRef(ref.Sha, filter)
				ok = ok && k
			}
		}
	}
	// For every unique commit we've fetched, check recent commits too
	if fetchconf.FetchRecentCommitsDays > 0 {
		for commit, refName := range uniqueRefShas {
			// We measure from the last commit at the ref
			summ, err := git.GetCommitSummary(commit)
			if err != nil {
				Error("Couldn't scan commits at %v: %v", refName, err)
				continue
			}
			Print("Fetching changes within %v days of %v", fetchconf.FetchRecentCommitsDays, refName)
			commitsSince := summ.CommitDate.AddDate(0, 0, -fetchconf.FetchRecentCommitsDays)
			k := fetchPreviousVersions(commit, commitsSince, filter)
			ok = ok && k
		}

	}
	return ok
}

func fetchAll() bool {
	pointers := scanAll()
	Print("Fetching objects...")
	return fetchAndReportToChan(pointers, nil, nil)
}

func scanAll() []*lfs.WrappedPointer {
	// This could be a long process so use the chan version & report progress
	Print("Scanning for all objects ever referenced...")
	logger := tasklog.NewLogger(OutputWriter)
	spinner := progress.NewSpinner()
	logger.Enqueue(spinner)
	var numObjs int64

	// use temp gitscanner to collect pointers
	var pointers []*lfs.WrappedPointer
	var multiErr error
	tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err != nil {
			if multiErr != nil {
				multiErr = fmt.Errorf("%v\n%v", multiErr, err)
			} else {
				multiErr = err
			}
			return
		}

		numObjs++
		spinner.Spinf("%d objects found", numObjs)
		pointers = append(pointers, p)
	})

	if err := tempgitscanner.ScanAll(nil); err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	tempgitscanner.Close()

	if multiErr != nil {
		Panic(multiErr, "Could not scan for Git LFS files")
	}

	spinner.Finish("%d objects found", numObjs)
	return pointers
}

// Fetch and report completion of each OID to a channel (optional, pass nil to skip)
// Returns true if all completed with no errors, false if errors were written to stderr/log
func fetchAndReportToChan(allpointers []*lfs.WrappedPointer, filter *filepathfilter.Filter, out chan<- *lfs.WrappedPointer) bool {
	ready, pointers, meter := readyAndMissingPointers(allpointers, filter)
	q := newDownloadQueue(
		getTransferManifestOperationRemote("download", cfg.Remote()),
		cfg.Remote(), tq.WithProgress(meter),
	)

	if out != nil {
		// If we already have it, or it won't be fetched
		// report it to chan immediately to support pull/checkout
		for _, p := range ready {
			out <- p
		}

		dlwatch := q.Watch()

		go func() {
			// fetch only reports single OID, but OID *might* be referenced by multiple
			// WrappedPointers if same content is at multiple paths, so map oid->slice
			oidToPointers := make(map[string][]*lfs.WrappedPointer, len(pointers))
			for _, pointer := range pointers {
				plist := oidToPointers[pointer.Oid]
				oidToPointers[pointer.Oid] = append(plist, pointer)
			}

			for t := range dlwatch {
				plist, ok := oidToPointers[t.Oid]
				if !ok {
					continue
				}
				for _, p := range plist {
					out <- p
				}
			}
			close(out)
		}()
	}

	for _, p := range pointers {
		tracerx.Printf("fetch %v [%v]", p.Name, p.Oid)

		q.Add(downloadTransfer(p))
	}

	processQueue := time.Now()
	q.Wait()
	tracerx.PerformanceSince("process queue", processQueue)

	ok := true
	for _, err := range q.Errors() {
		ok = false
		FullError(err)
	}
	return ok
}

func readyAndMissingPointers(allpointers []*lfs.WrappedPointer, filter *filepathfilter.Filter) ([]*lfs.WrappedPointer, []*lfs.WrappedPointer, *progress.ProgressMeter) {
	logger := tasklog.NewLogger(os.Stdout)
	meter := buildProgressMeter(false)
	logger.Enqueue(meter)

	seen := make(map[string]bool, len(allpointers))
	missing := make([]*lfs.WrappedPointer, 0, len(allpointers))
	ready := make([]*lfs.WrappedPointer, 0, len(allpointers))

	for _, p := range allpointers {
		// no need to download the same object multiple times
		if seen[p.Oid] {
			continue
		}

		seen[p.Oid] = true

		// no need to download objects that exist locally already
		lfs.LinkOrCopyFromReference(cfg, p.Oid, p.Size)
		if cfg.LFSObjectExists(p.Oid, p.Size) {
			ready = append(ready, p)
			continue
		}

		missing = append(missing, p)
		meter.Add(p.Size)
	}

	return ready, missing, meter
}

func init() {
	RegisterCommand("fetch", fetchCommand, func(cmd *cobra.Command) {
		cmd.Flags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
		cmd.Flags().StringVarP(&excludeArg, "exclude", "X", "", "Exclude a list of paths")
		cmd.Flags().BoolVarP(&fetchRecentArg, "recent", "r", false, "Fetch recent refs & commits")
		cmd.Flags().BoolVarP(&fetchAllArg, "all", "a", false, "Fetch all LFS files ever referenced")
		cmd.Flags().BoolVarP(&fetchPruneArg, "prune", "p", false, "After fetching, prune old data")
	})
}
<commit_msg>commands/fetch: unify formatting within fetch<commit_after>package commands

import (
	"fmt"
	"os"
	"time"

	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/git-lfs/git-lfs/progress"
	"github.com/git-lfs/git-lfs/tasklog"
	"github.com/git-lfs/git-lfs/tq"
	"github.com/rubyist/tracerx"
	"github.com/spf13/cobra"
)

var (
	fetchRecentArg bool
	fetchAllArg    bool
	fetchPruneArg  bool
)

func getIncludeExcludeArgs(cmd *cobra.Command) (include, exclude *string) {
	includeFlag := cmd.Flag("include")
	excludeFlag := cmd.Flag("exclude")
	if includeFlag.Changed {
		include = &includeArg
	}
	if excludeFlag.Changed {
		exclude = &excludeArg
	}

	return
}

func fetchCommand(cmd *cobra.Command, args []string) {
	requireInRepo()

	var refs []*git.Ref

	if len(args) > 0 {
		// Remote is first arg
		if err := cfg.SetValidRemote(args[0]); err != nil {
			Exit("Invalid remote name %q: %s", args[0], err)
		}
	}

	if len(args) > 1 {
		resolvedrefs, err := git.ResolveRefs(args[1:])
		if err != nil {
			Panic(err, "Invalid ref argument: %v", args[1:])
		}
		refs = resolvedrefs
	} else if !fetchAllArg {
		ref, err := git.CurrentRef()
		if err != nil {
			Panic(err, "Could not fetch")
		}
		refs = []*git.Ref{ref}
	}

	success := true
	gitscanner := lfs.NewGitScanner(nil)
	defer gitscanner.Close()

	include, exclude := getIncludeExcludeArgs(cmd)
	fetchPruneCfg := lfs.NewFetchPruneConfig(cfg.Git)

	if fetchAllArg {
		if fetchRecentArg || len(args) > 1 {
			Exit("Cannot combine --all with ref arguments or --recent")
		}
		if include != nil || exclude != nil {
			Exit("Cannot combine --all with --include or --exclude")
		}
		if len(cfg.FetchIncludePaths()) > 0 || len(cfg.FetchExcludePaths()) > 0 {
			Print("Ignoring global include / exclude paths to fulfil --all")
		}
		success = fetchAll()

	} else { // !all
		filter := buildFilepathFilter(cfg, include, exclude)

		// Fetch refs sequentially per arg order; duplicates in later refs will be ignored
		for _, ref := range refs {
			Print("fetch: Fetching reference %s", ref.Name)
			s := fetchRef(ref.Sha, filter)
			success = success && s
		}

		if fetchRecentArg || fetchPruneCfg.FetchRecentAlways {
			s := fetchRecent(fetchPruneCfg, refs, filter)
			success = success && s
		}
	}

	if fetchPruneArg {
		verify := fetchPruneCfg.PruneVerifyRemoteAlways
		// no dry-run or verbose options in fetch, assume false
		prune(fetchPruneCfg, verify, false, false)
	}

	if !success {
		c := getAPIClient()
		e := c.Endpoints.Endpoint("download", cfg.Remote())
		Exit("error: failed to fetch some objects from '%s'", e.Url)
	}
}

func pointersToFetchForRef(ref string, filter *filepathfilter.Filter) ([]*lfs.WrappedPointer, error) {
	var pointers []*lfs.WrappedPointer
	var multiErr error
	tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err != nil {
			if multiErr != nil {
				multiErr = fmt.Errorf("%v\n%v", multiErr, err)
			} else {
				multiErr = err
			}
			return
		}

		pointers = append(pointers, p)
	})

	tempgitscanner.Filter = filter

	if err := tempgitscanner.ScanTree(ref); err != nil {
		return nil, err
	}

	tempgitscanner.Close()
	return pointers, multiErr
}

// Fetch all binaries for a given ref (that we don't have already)
func fetchRef(ref string, filter *filepathfilter.Filter) bool {
	pointers, err := pointersToFetchForRef(ref, filter)
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}
	return fetchAndReportToChan(pointers, filter, nil)
}

// Fetch all previous versions of objects from since to ref (not including final state at ref)
// So this will fetch all the '-' sides of the diff from since to ref
func fetchPreviousVersions(ref string, since time.Time, filter *filepathfilter.Filter) bool {
	var pointers []*lfs.WrappedPointer

	tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err != nil {
			Panic(err, "Could not scan for Git LFS previous versions")
			return
		}

		pointers = append(pointers, p)
	})

	tempgitscanner.Filter = filter

	if err := tempgitscanner.ScanPreviousVersions(ref, since, nil); err != nil {
		ExitWithError(err)
	}

	tempgitscanner.Close()
	return fetchAndReportToChan(pointers, filter, nil)
}

// Fetch recent objects based on config
func fetchRecent(fetchconf lfs.FetchPruneConfig, alreadyFetchedRefs []*git.Ref, filter *filepathfilter.Filter) bool {
	if fetchconf.FetchRecentRefsDays == 0 && fetchconf.FetchRecentCommitsDays == 0 {
		return true
	}

	ok := true
	// Make a list of what unique commits we've already fetched for to avoid duplicating work
	uniqueRefShas := make(map[string]string, len(alreadyFetchedRefs))
	for _, ref := range alreadyFetchedRefs {
		uniqueRefShas[ref.Sha] = ref.Name
	}
	// First find any other recent refs
	if fetchconf.FetchRecentRefsDays > 0 {
		Print("fetch: Fetching recent branches within %v days", fetchconf.FetchRecentRefsDays)
		refsSince := time.Now().AddDate(0, 0, -fetchconf.FetchRecentRefsDays)
		refs, err := git.RecentBranches(refsSince, fetchconf.FetchRecentRefsIncludeRemotes, cfg.Remote())
		if err != nil {
			Panic(err, "Could not scan for recent refs")
		}
		for _, ref := range refs {
			// Don't fetch for the same SHA twice
			if prevRefName, ok := uniqueRefShas[ref.Sha]; ok {
				if ref.Name != prevRefName {
					tracerx.Printf("Skipping fetch for %v, already fetched via %v", ref.Name, prevRefName)
				}
			} else {
				uniqueRefShas[ref.Sha] = ref.Name
				Print("fetch: Fetching reference %s", ref.Name)
				k := fetchRef(ref.Sha, filter)
				ok = ok && k
			}
		}
	}
	// For every unique commit we've fetched, check recent commits too
	if fetchconf.FetchRecentCommitsDays > 0 {
		for commit, refName := range uniqueRefShas {
			// We measure from the last commit at the ref
			summ, err := git.GetCommitSummary(commit)
			if err != nil {
				Error("Couldn't scan commits at %v: %v", refName, err)
				continue
			}
			Print("fetch: Fetching changes within %v days of %v", fetchconf.FetchRecentCommitsDays, refName)
			commitsSince := summ.CommitDate.AddDate(0, 0, -fetchconf.FetchRecentCommitsDays)
			k := fetchPreviousVersions(commit, commitsSince, filter)
			ok = ok && k
		}

	}
	return ok
}

func fetchAll() bool {
	pointers := scanAll()
	Print("fetch: Fetching all references...")
	return fetchAndReportToChan(pointers, nil, nil)
}

func scanAll() []*lfs.WrappedPointer {
	// This could be a long process so use the chan version & report progress
	task := tasklog.NewSimpleTask()
	logger := tasklog.NewLogger(OutputWriter)
	logger.Enqueue(task)
	var numObjs int64

	// use temp gitscanner to collect pointers
	var pointers []*lfs.WrappedPointer
	var multiErr error
	tempgitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err != nil {
			if multiErr != nil {
				multiErr = fmt.Errorf("%v\n%v", multiErr, err)
			} else {
				multiErr = err
			}
			return
		}

		numObjs++
		task.Logf("fetch: %d object(s) found", numObjs)
		pointers = append(pointers, p)
	})

	if err := tempgitscanner.ScanAll(nil); err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	tempgitscanner.Close()

	if multiErr != nil {
		Panic(multiErr, "Could not scan for Git LFS files")
	}

	task.Complete()
	return pointers
}

// Fetch and report completion of each OID to a channel (optional, pass nil to skip)
// Returns true if all completed with no errors, false if errors were written to stderr/log
func fetchAndReportToChan(allpointers []*lfs.WrappedPointer, filter *filepathfilter.Filter, out chan<- *lfs.WrappedPointer) bool {
	ready, pointers, meter := readyAndMissingPointers(allpointers, filter)
	q := newDownloadQueue(
		getTransferManifestOperationRemote("download", cfg.Remote()),
		cfg.Remote(), tq.WithProgress(meter),
	)

	if out != nil {
		// If we already have it, or it won't be fetched
		// report it to chan immediately to support pull/checkout
		for _, p := range ready {
			out <- p
		}

		dlwatch := q.Watch()

		go func() {
			// fetch only reports single OID, but OID *might* be referenced by multiple
			// WrappedPointers if same content is at multiple paths, so map oid->slice
			oidToPointers := make(map[string][]*lfs.WrappedPointer, len(pointers))
			for _, pointer := range pointers {
				plist := oidToPointers[pointer.Oid]
				oidToPointers[pointer.Oid] = append(plist, pointer)
			}

			for t := range dlwatch {
				plist, ok := oidToPointers[t.Oid]
				if !ok {
					continue
				}
				for _, p := range plist {
					out <- p
				}
			}
			close(out)
		}()
	}

	for _, p := range pointers {
		tracerx.Printf("fetch %v [%v]", p.Name, p.Oid)

		q.Add(downloadTransfer(p))
	}

	processQueue := time.Now()
	q.Wait()
	tracerx.PerformanceSince("process queue", processQueue)

	ok := true
	for _, err := range q.Errors() {
		ok = false
		FullError(err)
	}
	return ok
}

func readyAndMissingPointers(allpointers []*lfs.WrappedPointer, filter *filepathfilter.Filter) ([]*lfs.WrappedPointer, []*lfs.WrappedPointer, *progress.ProgressMeter) {
	logger := tasklog.NewLogger(os.Stdout)
	meter := buildProgressMeter(false)
	logger.Enqueue(meter)

	seen := make(map[string]bool, len(allpointers))
	missing := make([]*lfs.WrappedPointer, 0, len(allpointers))
	ready := make([]*lfs.WrappedPointer, 0, len(allpointers))

	for _, p := range allpointers {
		// no need to download the same object multiple times
		if seen[p.Oid] {
			continue
		}

		seen[p.Oid] = true

		// no need to download objects that exist locally already
		lfs.LinkOrCopyFromReference(cfg, p.Oid, p.Size)
		if cfg.LFSObjectExists(p.Oid, p.Size) {
			ready = append(ready, p)
			continue
		}

		missing = append(missing, p)
		meter.Add(p.Size)
	}

	return ready, missing, meter
}

func init() {
	RegisterCommand("fetch", fetchCommand, func(cmd *cobra.Command) {
		cmd.Flags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
		cmd.Flags().StringVarP(&excludeArg, "exclude", "X", "", "Exclude a list of paths")
		cmd.Flags().BoolVarP(&fetchRecentArg, "recent", "r", false, "Fetch recent refs & commits")
		cmd.Flags().BoolVarP(&fetchAllArg, "all", "a", false, "Fetch all LFS files ever referenced")
		cmd.Flags().BoolVarP(&fetchPruneArg, "prune", "p", false, "After fetching, prune old data")
	})
}
<|endoftext|>


<commit_before>package search

import (
	"github.com/catorpilor/leetcode/utils"
)

func RecoverTree(root *utils.TreeNode) []int {
	if root == nil {
		return nil
	}
	if root.Left == nil && root.Right == nil {
		return utils.LevelOrderTravesal(root)
	}
	// inorder travesal
	// recursion so bset or normal space complex is O(lgN) and worst case is O(N)
	var first, second, prev *utils.TreeNode
	traverse(root, &first, &second, &prev)
	// fmt.Println(first, second)
	first.Val, second.Val = second.Val, first.Val
	return utils.LevelOrderTravesal(root)
}

func traverse(node *utils.TreeNode, first, second, prev **utils.TreeNode) {
	if node == nil {
		return
	}
	traverse(node.Left, first, second, prev)
	if *prev != nil && (*prev).Val >= node.Val {
		if *first == nil {
			*first = *prev
		}
		if *first != nil {
			*second = node
		}
	}
	*prev = node
	traverse(node.Right, first, second, prev)
}

func RecoverTree2(root *utils.TreeNode) []int {
	// morris traversal
	if root == nil {
		return nil
	}
	if root.Left == nil && root.Right == nil {
		return []int{root.Val}
	}
	var first, second, prev, cur *utils.TreeNode
	cur = root
	for cur != nil {
		if cur.Left == nil {
			if prev != nil && prev.Val >= cur.Val {
				if first == nil {
					first = prev
				}
				if first != nil {
					second = cur
				}
			}
			prev = cur
			cur = cur.Right
		} else {
			predecessor := cur.Left
			for predecessor.Right != cur && predecessor.Right != nil {
				predecessor = predecessor.Right
			}
			// node := preInorder(cur)
			if predecessor.Right == nil {
				predecessor.Right = cur
				cur = cur.Left
			} else {
				predecessor.Right = nil
				if prev != nil && prev.Val >= cur.Val {
					if first == nil {
						first = prev
					}
					if first != nil {
						second = cur
					}
				}
				prev = cur
				cur = cur.Right
			}
		}
	}
	first.Val, second.Val = second.Val, first.Val
	return utils.LevelOrderTravesal(root)
}

// preInorder returns a previous n for node in the inorder traversal
func preInorder(node *utils.TreeNode) *utils.TreeNode {
	n := node.Left
	for n.Right != node && n.Right != nil {
		n = n.Right
	}
	return n
}
<commit_msg>simplified version<commit_after>package search

import (
	"github.com/catorpilor/leetcode/utils"
)

func RecoverTree(root *utils.TreeNode) []int {
	if root == nil {
		return nil
	}
	if root.Left == nil && root.Right == nil {
		return utils.LevelOrderTravesal(root)
	}
	// inorder travesal
	// recursion so bset or normal space complex is O(lgN) and worst case is O(N)
	var first, second, prev *utils.TreeNode
	traverse(root, &first, &second, &prev)
	// fmt.Println(first, second)
	first.Val, second.Val = second.Val, first.Val
	return utils.LevelOrderTravesal(root)
}

func traverse(node *utils.TreeNode, first, second, prev **utils.TreeNode) {
	if node == nil {
		return
	}
	traverse(node.Left, first, second, prev)
	if *prev != nil && (*prev).Val >= node.Val {
		if *first == nil {
			*first = *prev
		}
		if *first != nil {
			*second = node
		}
	}
	*prev = node
	traverse(node.Right, first, second, prev)
}

func RecoverTree2(root *utils.TreeNode) []int {
	// morris traversal
	var first, second, prev, cur *utils.TreeNode
	cur = root
	for cur != nil {
		if cur.Left == nil {
			if prev != nil && prev.Val >= cur.Val {
				if first == nil {
					first = prev
				}
				second = cur
			}
			prev = cur
			cur = cur.Right
		} else {
			predecessor := preInorder(cur)
			if predecessor.Right == nil {
				predecessor.Right = cur
				cur = cur.Left
			} else {
				predecessor.Right = nil
				if prev != nil && prev.Val >= cur.Val {
					if first == nil {
						first = prev
					}
					second = cur
				}
				prev = cur
				cur = cur.Right
			}
		}
	}
	if first != nil && second != nil {
		first.Val, second.Val = second.Val, first.Val
	}
	return utils.LevelOrderTravesal(root)
}

// preInorder returns a previous n for node in the inorder traversal
func preInorder(node *utils.TreeNode) *utils.TreeNode {
	n := node.Left
	for n.Right != node && n.Right != nil {
		n = n.Right
	}
	return n
}
<|endoftext|>


<commit_before>package workload

import (
	"fmt"
	"math/rand"
	"strconv"

	"github.com/couchbaselabs/gateload/api"
)

// the existing doc iterator

// func DocIterator(start, end int, size int, channel string) <-chan api.Doc {
// 	ch := make(chan api.Doc)
// 	go func() {
// 		for i := start; i < end; i++ {
// 			docid := Hash(strconv.FormatInt(int64(i), 10))
// 			rev := Hash(strconv.FormatInt(int64(i*i), 10))
// 			doc := api.Doc{
// 				Id:        docid,
// 				Rev:       fmt.Sprintf("1-%s", rev),
// 				Channels:  []string{channel},
// 				Data:      map[string]string{docid: RandString(docid, size)},
// 				Revisions: map[string]interface{}{"ids": []string{rev}, "start": 1},
// 			}
// 			ch <- doc
// 		}
// 		close(ch)
// 	}()
// 	return ch
// }

type DocSizeDistributionElement struct {
	Prob    int
	MinSize int
	MaxSize int
}

type DocSizeDistribution []*DocSizeDistributionElement

type DocSizeGenerator struct {
	cutoffs []int
	dist    DocSizeDistribution
}

func NewDocSizeGenerator(dist DocSizeDistribution) (*DocSizeGenerator, error) {
	rv := DocSizeGenerator{
		dist:    dist,
		cutoffs: make([]int, len(dist)),
	}

	var total int = 0

	for i, distelem := range dist {
		rv.cutoffs[i] = total + distelem.Prob - 1
		total += distelem.Prob
	}
	if total != 100 {
		return nil, fmt.Errorf("document distribution probabilities must sum to 100")
	}
	return &rv, nil
}

func (dsg *DocSizeGenerator) NextDocSize() int {

	whichDist := int(rand.Int31n(100))
	for i, cutoff := range dsg.cutoffs {
		if whichDist <= cutoff {
			dist := dsg.dist[i]
			return int(rand.Float64()*float64(dist.MaxSize-dist.MinSize)) + dist.MinSize
		}
	}

	return 0
}

func DocIterator(start, end int, dsg *DocSizeGenerator, channel string) <-chan api.Doc {
	ch := make(chan api.Doc)
	go func() {
		for i := start; i < end; i++ {
			docid := Hash(strconv.FormatInt(int64(i), 10))
			rev := Hash(strconv.FormatInt(int64(i*i), 10))
			doc := api.Doc{
				Id:        docid,
				Rev:       fmt.Sprintf("1-%s", rev),
				Channels:  []string{channel},
				Data:      map[string]string{docid: RandString(docid, dsg.NextDocSize())},
				Revisions: map[string]interface{}{"ids": []string{rev}, "start": 1},
			}
			ch <- doc
		}
		close(ch)
	}()
	return ch
}
<commit_msg>removing commented out code<commit_after>package workload

import (
	"fmt"
	"math/rand"
	"strconv"

	"github.com/couchbaselabs/gateload/api"
)

type DocSizeDistributionElement struct {
	Prob    int
	MinSize int
	MaxSize int
}

type DocSizeDistribution []*DocSizeDistributionElement

type DocSizeGenerator struct {
	cutoffs []int
	dist    DocSizeDistribution
}

func NewDocSizeGenerator(dist DocSizeDistribution) (*DocSizeGenerator, error) {
	rv := DocSizeGenerator{
		dist:    dist,
		cutoffs: make([]int, len(dist)),
	}

	var total int = 0

	for i, distelem := range dist {
		rv.cutoffs[i] = total + distelem.Prob - 1
		total += distelem.Prob
	}
	if total != 100 {
		return nil, fmt.Errorf("document distribution probabilities must sum to 100")
	}
	return &rv, nil
}

func (dsg *DocSizeGenerator) NextDocSize() int {

	whichDist := int(rand.Int31n(100))
	for i, cutoff := range dsg.cutoffs {
		if whichDist <= cutoff {
			dist := dsg.dist[i]
			return int(rand.Float64()*float64(dist.MaxSize-dist.MinSize)) + dist.MinSize
		}
	}

	return 0
}

func DocIterator(start, end int, dsg *DocSizeGenerator, channel string) <-chan api.Doc {
	ch := make(chan api.Doc)
	go func() {
		for i := start; i < end; i++ {
			docid := Hash(strconv.FormatInt(int64(i), 10))
			rev := Hash(strconv.FormatInt(int64(i*i), 10))
			doc := api.Doc{
				Id:        docid,
				Rev:       fmt.Sprintf("1-%s", rev),
				Channels:  []string{channel},
				Data:      map[string]string{docid: RandString(docid, dsg.NextDocSize())},
				Revisions: map[string]interface{}{"ids": []string{rev}, "start": 1},
			}
			ch <- doc
		}
		close(ch)
	}()
	return ch
}
<|endoftext|>


<commit_before>package session

import "context"

type sessionKey int

const (
	idSessionKey sessionKey = iota
	inboundSessionKey
	outboundSessionKey
	contentSessionKey
	MuxPreferedSessionKey
)

// ContextWithID returns a new context with the given ID.
func ContextWithID(ctx context.Context, id ID) context.Context {
	return context.WithValue(ctx, idSessionKey, id)
}

// IDFromContext returns ID in this context, or 0 if not contained.
func IDFromContext(ctx context.Context) ID {
	if id, ok := ctx.Value(idSessionKey).(ID); ok {
		return id
	}
	return 0
}

func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
	return context.WithValue(ctx, inboundSessionKey, inbound)
}

func InboundFromContext(ctx context.Context) *Inbound {
	if inbound, ok := ctx.Value(inboundSessionKey).(*Inbound); ok {
		return inbound
	}
	return nil
}

func ContextWithOutbound(ctx context.Context, outbound *Outbound) context.Context {
	return context.WithValue(ctx, outboundSessionKey, outbound)
}

func OutboundFromContext(ctx context.Context) *Outbound {
	if outbound, ok := ctx.Value(outboundSessionKey).(*Outbound); ok {
		return outbound
	}
	return nil
}

func ContextWithContent(ctx context.Context, content *Content) context.Context {
	return context.WithValue(ctx, contentSessionKey, content)
}

func ContentFromContext(ctx context.Context) *Content {
	if content, ok := ctx.Value(contentSessionKey).(*Content); ok {
		return content
	}
	return nil
}

// ContextWithMuxPrefered returns a new context with the given bool
func ContextWithMuxPrefered(ctx context.Context, forced bool) context.Context {
	return context.WithValue(ctx, MuxPreferedSessionKey, forced)
}

// MuxPreferedFromContext returns value in this context, or false if not contained.
func MuxPreferedFromContext(ctx context.Context) bool {
	if val, ok := ctx.Value(MuxPreferedSessionKey).(bool); ok {
		return val
	}
	return false
}
<commit_msg>fix session key unexported<commit_after>package session

import "context"

type sessionKey int

const (
	idSessionKey sessionKey = iota
	inboundSessionKey
	outboundSessionKey
	contentSessionKey
	muxPreferedSessionKey
)

// ContextWithID returns a new context with the given ID.
func ContextWithID(ctx context.Context, id ID) context.Context {
	return context.WithValue(ctx, idSessionKey, id)
}

// IDFromContext returns ID in this context, or 0 if not contained.
func IDFromContext(ctx context.Context) ID {
	if id, ok := ctx.Value(idSessionKey).(ID); ok {
		return id
	}
	return 0
}

func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
	return context.WithValue(ctx, inboundSessionKey, inbound)
}

func InboundFromContext(ctx context.Context) *Inbound {
	if inbound, ok := ctx.Value(inboundSessionKey).(*Inbound); ok {
		return inbound
	}
	return nil
}

func ContextWithOutbound(ctx context.Context, outbound *Outbound) context.Context {
	return context.WithValue(ctx, outboundSessionKey, outbound)
}

func OutboundFromContext(ctx context.Context) *Outbound {
	if outbound, ok := ctx.Value(outboundSessionKey).(*Outbound); ok {
		return outbound
	}
	return nil
}

func ContextWithContent(ctx context.Context, content *Content) context.Context {
	return context.WithValue(ctx, contentSessionKey, content)
}

func ContentFromContext(ctx context.Context) *Content {
	if content, ok := ctx.Value(contentSessionKey).(*Content); ok {
		return content
	}
	return nil
}

// ContextWithMuxPrefered returns a new context with the given bool
func ContextWithMuxPrefered(ctx context.Context, forced bool) context.Context {
	return context.WithValue(ctx, muxPreferedSessionKey, forced)
}

// MuxPreferedFromContext returns value in this context, or false if not contained.
func MuxPreferedFromContext(ctx context.Context) bool {
	if val, ok := ctx.Value(muxPreferedSessionKey).(bool); ok {
		return val
	}
	return false
}
<|endoftext|>


<commit_before>package world

func (z *Zone) Path(start *Tile, end *Tile, stopEarly bool) [][2]uint8 {
	queue := []*Tile{start}
	from := map[*Tile]*Tile{start: nil}
	closest := start
	sx, sy := start.Position()
	ex, ey := end.Position()
	distance := (int(sx)-int(ex))*(int(sx)-int(ex)) + (int(sy)-int(ey))*(int(sy)-int(ey))

	for len(queue) != 0 {
		t := queue[0]
		queue = queue[1:]
		if t.Blocked() {
			continue
		}
		if t == end {
			if stopEarly {
				return z.constructPath(from, from[end])
			}
			return z.constructPath(from, end)
		}
		x, y := t.Position()
		d := (int(x)-int(ex))*(int(x)-int(ex)) + (int(y)-int(ey))*(int(y)-int(ey))
		if d < distance {
			closest = t
			distance = d
		}
		if x > 0 {
			next := t.Zone().Tile(x-1, y)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
		if x < 255 {
			next := t.Zone().Tile(x+1, y)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
		if y > 0 {
			next := t.Zone().Tile(x, y-1)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
		if y < 255 {
			next := t.Zone().Tile(x, y+1)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
	}

	return z.constructPath(from, closest)
}

func (z *Zone) constructPath(from map[*Tile]*Tile, end *Tile) [][2]uint8 {
	var path [][2]uint8

	for end != nil {
		x, y := end.Position()
		path = append(path, [2]uint8{x, y})
		end = from[end]
	}

	// reverse the slice
	for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
		path[i], path[j] = path[j], path[i]
	}

	return path
}
<commit_msg>restore the ability to move away from a blocked space<commit_after>package world

func (z *Zone) Path(start *Tile, end *Tile, stopEarly bool) [][2]uint8 {
	queue := []*Tile{start}
	from := map[*Tile]*Tile{start: nil}
	closest := start
	sx, sy := start.Position()
	ex, ey := end.Position()
	distance := (int(sx)-int(ex))*(int(sx)-int(ex)) + (int(sy)-int(ey))*(int(sy)-int(ey))

	for len(queue) != 0 {
		t := queue[0]
		queue = queue[1:]
		if t != start && t.Blocked() {
			continue
		}
		if t == end {
			if stopEarly {
				return z.constructPath(from, from[end])
			}
			return z.constructPath(from, end)
		}
		x, y := t.Position()
		d := (int(x)-int(ex))*(int(x)-int(ex)) + (int(y)-int(ey))*(int(y)-int(ey))
		if d < distance {
			closest = t
			distance = d
		}
		if x > 0 {
			next := t.Zone().Tile(x-1, y)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
		if x < 255 {
			next := t.Zone().Tile(x+1, y)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
		if y > 0 {
			next := t.Zone().Tile(x, y-1)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
		if y < 255 {
			next := t.Zone().Tile(x, y+1)
			if _, ok := from[next]; !ok {
				from[next] = t
				queue = append(queue, next)
			}
		}
	}

	return z.constructPath(from, closest)
}

func (z *Zone) constructPath(from map[*Tile]*Tile, end *Tile) [][2]uint8 {
	var path [][2]uint8

	for end != nil {
		x, y := end.Position()
		path = append(path, [2]uint8{x, y})
		end = from[end]
	}

	// reverse the slice
	for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
		path[i], path[j] = path[j], path[i]
	}

	return path
}
<|endoftext|>


<commit_before>package service

import (
	"fmt"
	"log"

	"potato/utils"
	"time"

	"gopkg.in/gomail.v2"
)

type Email struct {
	msgQueue chan *gomail.Message
}

type Message struct {
	From    string `json:"from"`
	TO      string `json:"to" binding:"required"`
	Cc      string `json:"cc"`
	Subject string `json:"subject" binding:"required"`
	Body    string `json:"body" binding:"required"`
}

func initEmail() *Email {
	email := &Email{}
	email.msgQueue = make(chan *gomail.Message)
	email.sendMessage()
	return email
}

func (e Email) Send(rawMsg Message) {
	msg := e.initMessage(rawMsg)
	e.msgQueue <- msg
}

func (e Email) initMessage(rawMsg Message) *gomail.Message {
	msg := gomail.NewMessage()
	if rawMsg.From == "" {
		msg.SetHeader("From", utils.Cfg.FromEmail)
	} else {
		msg.SetHeader("From", rawMsg.From)
	}
	msg.SetHeader("To", rawMsg.TO)
	msg.SetAddressHeader("Cc", rawMsg.Cc, "")
	msg.SetHeader("Subject", rawMsg.Subject)
	msg.SetBody("text/html", rawMsg.Body)
	//	msg.SetHeader("To", "1247920356@qq.com")
	//	msg.SetHeader("Subject", "subject")
	//	msg.SetBody("text/html", "hahahha")
	return msg
}

/*
发送邮箱核心服务, 支持并行发送
*/
func (email Email) sendMessage() {
	dialer := gomail.NewDialer(utils.Cfg.EmailHost, utils.Cfg.Port, utils.Cfg.Username, utils.Cfg.Password)
	var sendCloser gomail.SendCloser
	ticket := utils.NewTicket()
	open := false
	for {
		select {
		case msg, ok := <-email.msgQueue:
			if !ok {
				return
			}
			if !open {
				if sendCloser, err := dialer.Dial(); err != nil {
					panic(err)
				}
				open = true
			}
			ticket.Done()
			go func() {
				defer ticket.Add()
				if err := gomail.Send(sendCloser, msg); err != nil {
					log.Print(err)
				}
			}()
		case <-time.After(30 * time.Second):
			if open {
				if err := sendCloser.Close(); err != nil {
					panic(err)
				}
				open = false
			}
		}
	}
}
<commit_msg>修复bug<commit_after>package service

import (
	"fmt"
	"log"

	"potato/utils"
	"time"

	"gopkg.in/gomail.v2"
)

type Email struct {
	msgQueue chan *gomail.Message
}

type Message struct {
	TO      string `json:"to" binding:"required"`
	Cc      string `json:"cc"`
	Subject string `json:"subject" binding:"required"`
	Body    string `json:"body" binding:"required"`
}

func initEmail() *Email {
	email := &Email{}
	email.msgQueue = make(chan *gomail.Message)
	email.sendMessage()
	return email
}

func (e Email) Send(rawMsg Message) {
	msg := e.initMessage(rawMsg)
	e.msgQueue <- msg
}

func (e Email) initMessage(rawMsg Message) *gomail.Message {
	msg := gomail.NewMessage()
	if rawMsg.From == "" {
		msg.SetHeader("From", utils.Cfg.FromEmail)
	} else {
		msg.SetHeader("From", rawMsg.From)
	}
	msg.SetHeader("To", rawMsg.TO)
	msg.SetAddressHeader("Cc", rawMsg.Cc, "")
	msg.SetHeader("Subject", rawMsg.Subject)
	msg.SetBody("text/html", rawMsg.Body)
	//	msg.SetHeader("To", "1247920356@qq.com")
	//	msg.SetHeader("Subject", "subject")
	//	msg.SetBody("text/html", "hahahha")
	return msg
}

/*
发送邮箱核心服务, 支持并行发送，该方法负责发送每封邮件内容不想同的邮件
*/
func (email Email) sendMessage() {
	dialer := gomail.NewDialer(utils.Cfg.EmailHost, utils.Cfg.Port, utils.Cfg.Username, utils.Cfg.Password)
	var sendCloser gomail.SendCloser
	ticket := utils.NewTicket()
	open := false
	for {
		select {
		case msg, ok := <-email.msgQueue:
			if !ok {
				return
			}
			if !open {
				if sendCloser, err := dialer.Dial(); err != nil {
					panic(err)
				}
				open = true
			}
			ticket.Done()
			go func() {
				defer ticket.Add()
				if err := gomail.Send(sendCloser, msg); err != nil {
					log.Print(err)
				}
			}()
		case <-time.After(30 * time.Second):
			if open {
				if err := sendCloser.Close(); err != nil {
					panic(err)
				}
				open = false
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path"
	"strconv"
	"strings"

	"gopkg.in/op/go-logging.v1"
	"gopkg.in/yaml.v2"
)

var log = logging.MustGetLogger("wormhole")
var format = logging.MustStringFormatter(
	"%{color}%{time:15:04:05.000} %{shortfunc} %{level:.5s} %{id:03x}%{color:reset} >> %{message}",
)

type Error interface {
	Error() string
}

type WormholeConfig struct {
	Port    int               `yaml:"port,omitempty"`
	Mapping map[string]string `yaml:"mapping"`
	Editors map[string]string `yaml:"editors"`
}

func (this *WormholeConfig) GetPort() int {
	if 0 == this.Port {
		return 5115
	}

	return this.Port
}

func main() {

	// Setup logging
	logbackend := logging.NewLogBackend(os.Stdout, "", 0)
	logbackendformatter := logging.NewBackendFormatter(logbackend, format)
	logging.SetBackend(logbackendformatter)

	// Read config
	log.Info("Parsing wormhole configuration ...")
	var config WormholeConfig

	source, err := ioutil.ReadFile(path.Join(os.Getenv("HOME"), ".wormhole.yml"))
	if err != nil {
		log.Fatal(err)
	}

	err = yaml.Unmarshal(source, &config)
	if err != nil {
		log.Fatal(err)
	}
	log.Debug("Configuration: %v", config)

	// Start main
	log.Info("Wormhole server starting ...")

	l, err := net.Listen("tcp4", ":"+strconv.Itoa(config.GetPort()))
	if err != nil {
		log.Fatal(err)
	}

	log.Info("Listening at " + l.Addr().String())

	defer l.Close()
	for {
		// Wait for connection
		conn, err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}

		log.Debug("Received connection from %s", conn.RemoteAddr().String())

		// Handle connection
		go handleConnection(conn)
	}
}

func handleConnection(c net.Conn) {
	defer c.Close()

	line, err := bufio.NewReader(c).ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}

	writer := bufio.NewWriter(c)

	log.Debug("[%s] %s", c.RemoteAddr().String(), line)
	resp, err := handleLine(c, line)

	if err != nil {
		writer.WriteString("Err ")
		writer.WriteString(err.Error())
	} else {
		writer.WriteString("Ok ")
		writer.WriteString(resp)
	}

	writer.Flush()
}

func handleLine(c net.Conn, line string) (resp string, err Error) {
	parts := strings.Split(strings.TrimSpace(line), " ")

	log.Debug("Extracted parts %s", parts)
	if len(parts) < 2 {
		log.Debug("Too little parts, quit.")
		return "", errors.New("Too few words, expected at least 2.")
	}

	switch parts[0] {
	case "EDIT":
		return handleCommandEdit(parts[1:])

	case "SHELL":
		return handleCommandShell(parts[1:])

	case "EXPLORE":
		return handleCommandExplore(parts[1:])

	case "START":
		return handleCommandStart(parts[1:])
	}

	return "", errors.New("Unknown command, expected one of [EDIT, SHELL, EXPLORE, START]")
}

func handleCommandEdit(parts []string) (resp string, err Error) {
	log.Info("EDIT", parts)
	return "OK", nil
}

func handleCommandStart(parts []string) (resp string, err Error) {
	log.Info("START", parts)
	return "OK", nil
}

func handleCommandExplore(parts []string) (resp string, err Error) {
	log.Info("EXPLORE", parts)
	return "OK", nil
}

func handleCommandShell(parts []string) (resp string, err Error) {
	log.Info("SHELL", parts)
	return "OK", nil
}
<commit_msg>Execute external program, 1st try<commit_after>package main

import (
	"bufio"
	"errors"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"

	"gopkg.in/op/go-logging.v1"
	"gopkg.in/yaml.v2"
)

type Error interface {
	Error() string
}

type WormholeConfig struct {
	Port    int               `yaml:"port,omitempty"`
	Mapping map[string]string `yaml:"mapping"`
	Editors map[string]string `yaml:"editors"`
}

func (this *WormholeConfig) GetPort() int {
	if 0 == this.Port {
		return 5115
	}

	return this.Port
}

var log = logging.MustGetLogger("wormhole")
var format = logging.MustStringFormatter(
	"%{color}%{time:15:04:05.000} %{shortfunc} %{level:.5s} %{id:03x}%{color:reset} >> %{message}",
)
var config WormholeConfig

func main() {

	// Setup logging
	logbackend := logging.NewLogBackend(os.Stdout, "", 0)
	logbackendformatter := logging.NewBackendFormatter(logbackend, format)
	logging.SetBackend(logbackendformatter)

	// Read config
	log.Info("Parsing wormhole configuration ...")
	source, err := ioutil.ReadFile(path.Join(os.Getenv("HOME"), ".wormhole.yml"))
	if err != nil {
		log.Fatal(err)
	}

	err = yaml.Unmarshal(source, &config)
	if err != nil {
		log.Fatal(err)
	}
	log.Debug("Configuration: %v", config)

	// Start main
	log.Info("Wormhole server starting ...")

	l, err := net.Listen("tcp4", ":"+strconv.Itoa(config.GetPort()))
	if err != nil {
		log.Fatal(err)
	}

	log.Info("Listening at " + l.Addr().String())

	defer l.Close()
	for {
		// Wait for connection
		conn, err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}

		log.Debug("Received connection from %s", conn.RemoteAddr().String())

		// Handle connection
		go handleConnection(conn)
	}
}

func handleConnection(c net.Conn) {
	defer c.Close()

	line, err := bufio.NewReader(c).ReadString('\n')
	if err != nil {
		log.Fatal(err)
	}

	writer := bufio.NewWriter(c)

	log.Debug("[%s] %s", c.RemoteAddr().String(), line)
	resp, err := handleLine(c, line)

	if err != nil {
		writer.WriteString("[ERR] ")
		writer.WriteString(err.Error())
	} else {
		writer.WriteString("[OK]")
		writer.WriteString(resp)
	}

	writer.Flush()
}

func handleLine(c net.Conn, line string) (resp string, err Error) {
	parts := strings.Split(strings.TrimSpace(line), " ")

	log.Debug("Extracted parts %s", parts)
	if len(parts) < 2 {
		log.Debug("Too little parts, quit.")
		return "", errors.New("Too few words, expected at least 2.")
	}

	switch parts[0] {
	case "INVOKE":
		return handleInvocation(parts[1:])
	}

	return "", errors.New("Unknown command, expected one of [EDIT, SHELL, EXPLORE, START]")
}

func handleInvocation(parts []string) (resp string, err Error) {
	log.Info("Invoking ", parts)

	go executeCommand("/bin/sleep", "10")
	return "OK", nil
}

func executeCommand(executable string, args ...string) (err Error) {
	cmd := exec.Command(executable, args...)

	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Error(err.Error())
		return err
	}

	// cmd.StdoutPipe().close()
	// cmd.StderrPipe().close()
	// cmd.StdinPipe().close()

	if err := cmd.Start(); err != nil {
		log.Error(err.Error())
		return err
	}

	log.Info("Started '%s' w/ PID %d", executable, cmd.Process.Pid)

	cmd.Wait()

	log.Info("PID %d has quit.", cmd.Process.Pid)

	return nil
}
<|endoftext|>


<commit_before>package azurerm

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

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func init() {
	resource.AddTestSweepers("azurerm_resource_group", &resource.Sweeper{
		Name: "azurerm_resource_group",
		F:    testSweepResourceGroups,
	})
}

func testSweepResourceGroups(region string) error {
	armClient, err := buildConfigForSweepers()
	if err != nil {
		return err
	}

	client := (*armClient).resourceGroupClient

	log.Printf("Retrieving the Resource Groups..")
	results, err := client.List("", nil)
	if err != nil {
		return fmt.Errorf("Error Listing on Resource Groups: %+v", err)
	}

	for _, profile := range *results.Value {
		if !shouldSweepAcceptanceTestResource(*profile.Name, *profile.Location, region) {
			continue
		}

		resourceId, err := parseAzureResourceID(*profile.ID)
		if err != nil {
			return err
		}

		name := resourceId.ResourceGroup

		log.Printf("Deleting Resource Group %q", name)
		deleteResponse, error := client.Delete(name, make(chan struct{}))
		err = <-error
		resp := <-deleteResponse
		if err != nil {
			if utils.ResponseWasNotFound(resp) {
				return nil
			}

			return err
		}
	}

	return nil
}

func TestAccAzureRMResourceGroup_basic(t *testing.T) {
	ri := acctest.RandInt()
	config := testAccAzureRMResourceGroup_basic(ri, testLocation())

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testCheckAzureRMResourceGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: config,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists("azurerm_resource_group.test"),
				),
			},
		},
	})
}

func TestAccAzureRMResourceGroup_disappears(t *testing.T) {
	resourceName := "azurerm_resource_group.test"
	ri := acctest.RandInt()
	config := testAccAzureRMResourceGroup_basic(ri, testLocation())

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testCheckAzureRMResourceGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: config,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists(resourceName),
					testCheckAzureRMResourceGroupDisappears(resourceName),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func TestAccAzureRMResourceGroup_withTags(t *testing.T) {
	resourceName := "azurerm_resource_group.test"
	ri := acctest.RandInt()
	location := testLocation()
	preConfig := testAccAzureRMResourceGroup_withTags(ri, location)
	postConfig := testAccAzureRMResourceGroup_withTagsUpdated(ri, location)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testCheckAzureRMResourceGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: preConfig,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "tags.%", "2"),
					resource.TestCheckResourceAttr(resourceName, "tags.environment", "Production"),
					resource.TestCheckResourceAttr(resourceName, "tags.cost_center", "MSFT"),
				),
			},
			{
				Config: postConfig,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
					resource.TestCheckResourceAttr(resourceName, "tags.environment", "staging"),
				),
			},
		},
	})
}

func testCheckAzureRMResourceGroupExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// Ensure we have enough information in state to look up in API
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		resourceGroup := rs.Primary.Attributes["name"]

		// Ensure resource group exists in API
		conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient

		resp, err := conn.Get(resourceGroup)
		if err != nil {
			return fmt.Errorf("Bad: Get on resourceGroupClient: %+v", err)
		}

		if resp.StatusCode == http.StatusNotFound {
			return fmt.Errorf("Bad: Virtual Network %q (resource group: %q) does not exist", name, resourceGroup)
		}

		return nil
	}
}

func testCheckAzureRMResourceGroupDisappears(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// Ensure we have enough information in state to look up in API
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		resourceGroup := rs.Primary.Attributes["name"]

		// Ensure resource group exists in API
		conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient

		_, error := conn.Delete(resourceGroup, make(chan struct{}))
		err := <-error
		if err != nil {
			return fmt.Errorf("Bad: Delete on resourceGroupClient: %+v", err)
		}

		return nil
	}
}

func testCheckAzureRMResourceGroupDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "azurerm_resource_group" {
			continue
		}

		resourceGroup := rs.Primary.ID

		resp, err := conn.Get(resourceGroup)
		if err != nil {
			return nil
		}

		if resp.StatusCode != http.StatusNotFound {
			return fmt.Errorf("Resource Group still exists:\n%#v", resp.Properties)
		}
	}

	return nil
}

func testAccAzureRMResourceGroup_basic(rInt int, location string) string {
	return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
    name = "acctestRG-%d"
    location = "%s"
}
`, rInt, location)
}

func testAccAzureRMResourceGroup_withTags(rInt int, location string) string {
	return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
    name = "acctestRG-%d"
    location = "%s"

    tags {
	environment = "Production"
	cost_center = "MSFT"
    }
}
`, rInt, location)
}

func testAccAzureRMResourceGroup_withTagsUpdated(rInt int, location string) string {
	return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
    name = "acctestRG-%d"
    location = "%s"

    tags {
	environment = "staging"
    }
}
`, rInt, location)
}
<commit_msg>Fixing the Resource Group sweeper<commit_after>package azurerm

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

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func init() {
	resource.AddTestSweepers("azurerm_resource_group", &resource.Sweeper{
		Name: "azurerm_resource_group",
		F:    testSweepResourceGroups,
	})
}

func testSweepResourceGroups(region string) error {
	armClient, err := buildConfigForSweepers()
	if err != nil {
		return err
	}

	client := (*armClient).resourceGroupClient

	log.Printf("Retrieving the Resource Groups..")
	results, err := client.List("", utils.Int32(int32(1000)))
	if err != nil {
		return fmt.Errorf("Error Listing on Resource Groups: %+v", err)
	}

	for _, profile := range *results.Value {
		if !shouldSweepAcceptanceTestResource(*profile.Name, *profile.Location, region) {
			continue
		}

		resourceId, err := parseAzureResourceID(*profile.ID)
		if err != nil {
			return err
		}

		name := resourceId.ResourceGroup

		log.Printf("Deleting Resource Group %q", name)
		deleteResponse, deleteErr := client.Delete(name, make(chan struct{}))
		resp := <-deleteResponse
		err = <-deleteErr
		if err != nil {
			if utils.ResponseWasNotFound(resp) {
				continue
			}

			return err
		}
	}

	return nil
}

func TestAccAzureRMResourceGroup_basic(t *testing.T) {
	ri := acctest.RandInt()
	config := testAccAzureRMResourceGroup_basic(ri, testLocation())

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testCheckAzureRMResourceGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: config,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists("azurerm_resource_group.test"),
				),
			},
		},
	})
}

func TestAccAzureRMResourceGroup_disappears(t *testing.T) {
	resourceName := "azurerm_resource_group.test"
	ri := acctest.RandInt()
	config := testAccAzureRMResourceGroup_basic(ri, testLocation())

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testCheckAzureRMResourceGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: config,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists(resourceName),
					testCheckAzureRMResourceGroupDisappears(resourceName),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func TestAccAzureRMResourceGroup_withTags(t *testing.T) {
	resourceName := "azurerm_resource_group.test"
	ri := acctest.RandInt()
	location := testLocation()
	preConfig := testAccAzureRMResourceGroup_withTags(ri, location)
	postConfig := testAccAzureRMResourceGroup_withTagsUpdated(ri, location)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testCheckAzureRMResourceGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: preConfig,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "tags.%", "2"),
					resource.TestCheckResourceAttr(resourceName, "tags.environment", "Production"),
					resource.TestCheckResourceAttr(resourceName, "tags.cost_center", "MSFT"),
				),
			},
			{
				Config: postConfig,
				Check: resource.ComposeTestCheckFunc(
					testCheckAzureRMResourceGroupExists(resourceName),
					resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
					resource.TestCheckResourceAttr(resourceName, "tags.environment", "staging"),
				),
			},
		},
	})
}

func testCheckAzureRMResourceGroupExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// Ensure we have enough information in state to look up in API
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		resourceGroup := rs.Primary.Attributes["name"]

		// Ensure resource group exists in API
		conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient

		resp, err := conn.Get(resourceGroup)
		if err != nil {
			return fmt.Errorf("Bad: Get on resourceGroupClient: %+v", err)
		}

		if resp.StatusCode == http.StatusNotFound {
			return fmt.Errorf("Bad: Virtual Network %q (resource group: %q) does not exist", name, resourceGroup)
		}

		return nil
	}
}

func testCheckAzureRMResourceGroupDisappears(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// Ensure we have enough information in state to look up in API
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		resourceGroup := rs.Primary.Attributes["name"]

		// Ensure resource group exists in API
		conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient

		_, error := conn.Delete(resourceGroup, make(chan struct{}))
		err := <-error
		if err != nil {
			return fmt.Errorf("Bad: Delete on resourceGroupClient: %+v", err)
		}

		return nil
	}
}

func testCheckAzureRMResourceGroupDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*ArmClient).resourceGroupClient

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "azurerm_resource_group" {
			continue
		}

		resourceGroup := rs.Primary.ID

		resp, err := conn.Get(resourceGroup)
		if err != nil {
			return nil
		}

		if resp.StatusCode != http.StatusNotFound {
			return fmt.Errorf("Resource Group still exists:\n%#v", resp.Properties)
		}
	}

	return nil
}

func testAccAzureRMResourceGroup_basic(rInt int, location string) string {
	return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
    name = "acctestRG-%d"
    location = "%s"
}
`, rInt, location)
}

func testAccAzureRMResourceGroup_withTags(rInt int, location string) string {
	return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
    name = "acctestRG-%d"
    location = "%s"

    tags {
	environment = "Production"
	cost_center = "MSFT"
    }
}
`, rInt, location)
}

func testAccAzureRMResourceGroup_withTagsUpdated(rInt int, location string) string {
	return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
    name = "acctestRG-%d"
    location = "%s"

    tags {
	environment = "staging"
    }
}
`, rInt, location)
}
<|endoftext|>