<commit_before>//
// This file is automatically generated by scripts/generate-plugins.go -- Do not edit!
//

package command

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/mitchellh/packer/packer"
	"github.com/mitchellh/packer/packer/plugin"

	amazonchrootbuilder "github.com/mitchellh/packer/builder/amazon/chroot"
	amazonebsbuilder "github.com/mitchellh/packer/builder/amazon/ebs"
	amazonebsvolumebuilder "github.com/mitchellh/packer/builder/amazon/ebsvolume"
	amazoninstancebuilder "github.com/mitchellh/packer/builder/amazon/instance"
	azurearmbuilder "github.com/mitchellh/packer/builder/azure/arm"
	cloudstackbuilder "github.com/mitchellh/packer/builder/cloudstack"
	digitaloceanbuilder "github.com/mitchellh/packer/builder/digitalocean"
	dockerbuilder "github.com/mitchellh/packer/builder/docker"
	filebuilder "github.com/mitchellh/packer/builder/file"
	googlecomputebuilder "github.com/mitchellh/packer/builder/googlecompute"
	hypervbuilder "github.com/mitchellh/packer/builder/hyperv"
	nullbuilder "github.com/mitchellh/packer/builder/null"
	oneandonebuilder "github.com/mitchellh/packer/builder/oneandone"
	openstackbuilder "github.com/mitchellh/packer/builder/openstack"
	parallelsisobuilder "github.com/mitchellh/packer/builder/parallels/iso"
	parallelspvmbuilder "github.com/mitchellh/packer/builder/parallels/pvm"
	profitbricksbuilder "github.com/mitchellh/packer/builder/profitbricks"
	qemubuilder "github.com/mitchellh/packer/builder/qemu"
	virtualboxisobuilder "github.com/mitchellh/packer/builder/virtualbox/iso"
	virtualboxovfbuilder "github.com/mitchellh/packer/builder/virtualbox/ovf"
	vmwareisobuilder "github.com/mitchellh/packer/builder/vmware/iso"
	vmwarevmxbuilder "github.com/mitchellh/packer/builder/vmware/vmx"
	amazonimportpostprocessor "github.com/mitchellh/packer/post-processor/amazon-import"
	artificepostprocessor "github.com/mitchellh/packer/post-processor/artifice"
	atlaspostprocessor "github.com/mitchellh/packer/post-processor/atlas"
	checksumpostprocessor "github.com/mitchellh/packer/post-processor/checksum"
	compresspostprocessor "github.com/mitchellh/packer/post-processor/compress"
	dockerimportpostprocessor "github.com/mitchellh/packer/post-processor/docker-import"
	dockerpushpostprocessor "github.com/mitchellh/packer/post-processor/docker-push"
	dockersavepostprocessor "github.com/mitchellh/packer/post-processor/docker-save"
	dockertagpostprocessor "github.com/mitchellh/packer/post-processor/docker-tag"
	googlecomputeexportpostprocessor "github.com/mitchellh/packer/post-processor/googlecompute-export"
	manifestpostprocessor "github.com/mitchellh/packer/post-processor/manifest"
	shelllocalpostprocessor "github.com/mitchellh/packer/post-processor/shell-local"
	vagrantpostprocessor "github.com/mitchellh/packer/post-processor/vagrant"
	vagrantcloudpostprocessor "github.com/mitchellh/packer/post-processor/vagrant-cloud"
	vspherepostprocessor "github.com/mitchellh/packer/post-processor/vsphere"
	ansibleprovisioner "github.com/mitchellh/packer/provisioner/ansible"
	ansiblelocalprovisioner "github.com/mitchellh/packer/provisioner/ansible-local"
	chefclientprovisioner "github.com/mitchellh/packer/provisioner/chef-client"
	chefsoloprovisioner "github.com/mitchellh/packer/provisioner/chef-solo"
	fileprovisioner "github.com/mitchellh/packer/provisioner/file"
	powershellprovisioner "github.com/mitchellh/packer/provisioner/powershell"
	puppetmasterlessprovisioner "github.com/mitchellh/packer/provisioner/puppet-masterless"
	puppetserverprovisioner "github.com/mitchellh/packer/provisioner/puppet-server"
	saltmasterlessprovisioner "github.com/mitchellh/packer/provisioner/salt-masterless"
	shellprovisioner "github.com/mitchellh/packer/provisioner/shell"
	shelllocalprovisioner "github.com/mitchellh/packer/provisioner/shell-local"
	windowsrestartprovisioner "github.com/mitchellh/packer/provisioner/windows-restart"
	windowsshellprovisioner "github.com/mitchellh/packer/provisioner/windows-shell"
)

type PluginCommand struct {
	Meta
}

var Builders = map[string]packer.Builder{
	"amazon-chroot":    new(amazonchrootbuilder.Builder),
	"amazon-ebs":       new(amazonebsbuilder.Builder),
	"amazon-ebsvolume": new(amazonebsvolumebuilder.Builder),
	"amazon-instance":  new(amazoninstancebuilder.Builder),
	"azure-arm":        new(azurearmbuilder.Builder),
	"cloudstack":       new(cloudstackbuilder.Builder),
	"digitalocean":     new(digitaloceanbuilder.Builder),
	"docker":           new(dockerbuilder.Builder),
	"file":             new(filebuilder.Builder),
	"googlecompute":    new(googlecomputebuilder.Builder),
	"hyperv":   	   new(hypervbuilder.Builder),
	"null":             new(nullbuilder.Builder),
	"oneandone":        new(oneandonebuilder.Builder),
	"openstack":        new(openstackbuilder.Builder),
	"parallels-iso":    new(parallelsisobuilder.Builder),
	"parallels-pvm":    new(parallelspvmbuilder.Builder),
	"profitbricks":     new(profitbricksbuilder.Builder),
	"qemu":             new(qemubuilder.Builder),
	"virtualbox-iso":   new(virtualboxisobuilder.Builder),
	"virtualbox-ovf":   new(virtualboxovfbuilder.Builder),
	"vmware-iso":       new(vmwareisobuilder.Builder),
	"vmware-vmx":       new(vmwarevmxbuilder.Builder),
}

var Provisioners = map[string]packer.Provisioner{
	"ansible":           new(ansibleprovisioner.Provisioner),
	"ansible-local":     new(ansiblelocalprovisioner.Provisioner),
	"chef-client":       new(chefclientprovisioner.Provisioner),
	"chef-solo":         new(chefsoloprovisioner.Provisioner),
	"file":              new(fileprovisioner.Provisioner),
	"powershell":        new(powershellprovisioner.Provisioner),
	"puppet-masterless": new(puppetmasterlessprovisioner.Provisioner),
	"puppet-server":     new(puppetserverprovisioner.Provisioner),
	"salt-masterless":   new(saltmasterlessprovisioner.Provisioner),
	"shell":             new(shellprovisioner.Provisioner),
	"shell-local":       new(shelllocalprovisioner.Provisioner),
	"windows-restart":   new(windowsrestartprovisioner.Provisioner),
	"windows-shell":     new(windowsshellprovisioner.Provisioner),
}

var PostProcessors = map[string]packer.PostProcessor{
	"amazon-import":        new(amazonimportpostprocessor.PostProcessor),
	"artifice":             new(artificepostprocessor.PostProcessor),
	"atlas":                new(atlaspostprocessor.PostProcessor),
	"checksum":             new(checksumpostprocessor.PostProcessor),
	"compress":             new(compresspostprocessor.PostProcessor),
	"docker-import":        new(dockerimportpostprocessor.PostProcessor),
	"docker-push":          new(dockerpushpostprocessor.PostProcessor),
	"docker-save":          new(dockersavepostprocessor.PostProcessor),
	"docker-tag":           new(dockertagpostprocessor.PostProcessor),
	"googlecompute-export": new(googlecomputeexportpostprocessor.PostProcessor),
	"manifest":             new(manifestpostprocessor.PostProcessor),
	"shell-local":          new(shelllocalpostprocessor.PostProcessor),
	"vagrant":              new(vagrantpostprocessor.PostProcessor),
	"vagrant-cloud":        new(vagrantcloudpostprocessor.PostProcessor),
	"vsphere":              new(vspherepostprocessor.PostProcessor),
}

var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner)-(.+)")

func (c *PluginCommand) Run(args []string) int {
	// This is an internal call (users should not call this directly) so we're
	// not going to do much input validation. If there's a problem we'll often
	// just crash. Error handling should be added to facilitate debugging.
	log.Printf("args: %#v", args)
	if len(args) != 1 {
		c.Ui.Error("Wrong number of args")
		return 1
	}

	// Plugin will match something like "packer-builder-amazon-ebs"
	parts := pluginRegexp.FindStringSubmatch(args[0])
	if len(parts) != 3 {
		c.Ui.Error(fmt.Sprintf("Error parsing plugin argument [DEBUG]: %#v", parts))
		return 1
	}
	pluginType := parts[1] // capture group 1 (builder|post-processor|provisioner)
	pluginName := parts[2] // capture group 2 (.+)

	server, err := plugin.Server()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error starting plugin server: %s", err))
		return 1
	}

	switch pluginType {
	case "builder":
		builder, found := Builders[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load builder: %s", pluginName))
			return 1
		}
		server.RegisterBuilder(builder)
	case "provisioner":
		provisioner, found := Provisioners[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load provisioner: %s", pluginName))
			return 1
		}
		server.RegisterProvisioner(provisioner)
	case "post-processor":
		postProcessor, found := PostProcessors[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load post-processor: %s", pluginName))
			return 1
		}
		server.RegisterPostProcessor(postProcessor)
	}

	server.Serve()

	return 0
}

func (*PluginCommand) Help() string {
	helpText := `
Usage: packer plugin PLUGIN

  Runs an internally-compiled version of a plugin from the packer binary.

  NOTE: this is an internal command and you should not call it yourself.
`

	return strings.TrimSpace(helpText)
}

func (c *PluginCommand) Synopsis() string {
	return "internal plugin command"
}
<commit_msg>Must point to iso hyperv plugin<commit_after>//
// This file is automatically generated by scripts/generate-plugins.go -- Do not edit!
//

package command

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/mitchellh/packer/packer"
	"github.com/mitchellh/packer/packer/plugin"

	amazonchrootbuilder "github.com/mitchellh/packer/builder/amazon/chroot"
	amazonebsbuilder "github.com/mitchellh/packer/builder/amazon/ebs"
	amazonebsvolumebuilder "github.com/mitchellh/packer/builder/amazon/ebsvolume"
	amazoninstancebuilder "github.com/mitchellh/packer/builder/amazon/instance"
	azurearmbuilder "github.com/mitchellh/packer/builder/azure/arm"
	cloudstackbuilder "github.com/mitchellh/packer/builder/cloudstack"
	digitaloceanbuilder "github.com/mitchellh/packer/builder/digitalocean"
	dockerbuilder "github.com/mitchellh/packer/builder/docker"
	filebuilder "github.com/mitchellh/packer/builder/file"
	googlecomputebuilder "github.com/mitchellh/packer/builder/googlecompute"
	hypervbuilder "github.com/mitchellh/packer/builder/hyperv/iso"
	nullbuilder "github.com/mitchellh/packer/builder/null"
	oneandonebuilder "github.com/mitchellh/packer/builder/oneandone"
	openstackbuilder "github.com/mitchellh/packer/builder/openstack"
	parallelsisobuilder "github.com/mitchellh/packer/builder/parallels/iso"
	parallelspvmbuilder "github.com/mitchellh/packer/builder/parallels/pvm"
	profitbricksbuilder "github.com/mitchellh/packer/builder/profitbricks"
	qemubuilder "github.com/mitchellh/packer/builder/qemu"
	virtualboxisobuilder "github.com/mitchellh/packer/builder/virtualbox/iso"
	virtualboxovfbuilder "github.com/mitchellh/packer/builder/virtualbox/ovf"
	vmwareisobuilder "github.com/mitchellh/packer/builder/vmware/iso"
	vmwarevmxbuilder "github.com/mitchellh/packer/builder/vmware/vmx"
	amazonimportpostprocessor "github.com/mitchellh/packer/post-processor/amazon-import"
	artificepostprocessor "github.com/mitchellh/packer/post-processor/artifice"
	atlaspostprocessor "github.com/mitchellh/packer/post-processor/atlas"
	checksumpostprocessor "github.com/mitchellh/packer/post-processor/checksum"
	compresspostprocessor "github.com/mitchellh/packer/post-processor/compress"
	dockerimportpostprocessor "github.com/mitchellh/packer/post-processor/docker-import"
	dockerpushpostprocessor "github.com/mitchellh/packer/post-processor/docker-push"
	dockersavepostprocessor "github.com/mitchellh/packer/post-processor/docker-save"
	dockertagpostprocessor "github.com/mitchellh/packer/post-processor/docker-tag"
	googlecomputeexportpostprocessor "github.com/mitchellh/packer/post-processor/googlecompute-export"
	manifestpostprocessor "github.com/mitchellh/packer/post-processor/manifest"
	shelllocalpostprocessor "github.com/mitchellh/packer/post-processor/shell-local"
	vagrantpostprocessor "github.com/mitchellh/packer/post-processor/vagrant"
	vagrantcloudpostprocessor "github.com/mitchellh/packer/post-processor/vagrant-cloud"
	vspherepostprocessor "github.com/mitchellh/packer/post-processor/vsphere"
	ansibleprovisioner "github.com/mitchellh/packer/provisioner/ansible"
	ansiblelocalprovisioner "github.com/mitchellh/packer/provisioner/ansible-local"
	chefclientprovisioner "github.com/mitchellh/packer/provisioner/chef-client"
	chefsoloprovisioner "github.com/mitchellh/packer/provisioner/chef-solo"
	fileprovisioner "github.com/mitchellh/packer/provisioner/file"
	powershellprovisioner "github.com/mitchellh/packer/provisioner/powershell"
	puppetmasterlessprovisioner "github.com/mitchellh/packer/provisioner/puppet-masterless"
	puppetserverprovisioner "github.com/mitchellh/packer/provisioner/puppet-server"
	saltmasterlessprovisioner "github.com/mitchellh/packer/provisioner/salt-masterless"
	shellprovisioner "github.com/mitchellh/packer/provisioner/shell"
	shelllocalprovisioner "github.com/mitchellh/packer/provisioner/shell-local"
	windowsrestartprovisioner "github.com/mitchellh/packer/provisioner/windows-restart"
	windowsshellprovisioner "github.com/mitchellh/packer/provisioner/windows-shell"
)

type PluginCommand struct {
	Meta
}

var Builders = map[string]packer.Builder{
	"amazon-chroot":    new(amazonchrootbuilder.Builder),
	"amazon-ebs":       new(amazonebsbuilder.Builder),
	"amazon-ebsvolume": new(amazonebsvolumebuilder.Builder),
	"amazon-instance":  new(amazoninstancebuilder.Builder),
	"azure-arm":        new(azurearmbuilder.Builder),
	"cloudstack":       new(cloudstackbuilder.Builder),
	"digitalocean":     new(digitaloceanbuilder.Builder),
	"docker":           new(dockerbuilder.Builder),
	"file":             new(filebuilder.Builder),
	"googlecompute":    new(googlecomputebuilder.Builder),
	"hyperv-iso":      new(hypervbuilder.Builder),
	"null":             new(nullbuilder.Builder),
	"oneandone":        new(oneandonebuilder.Builder),
	"openstack":        new(openstackbuilder.Builder),
	"parallels-iso":    new(parallelsisobuilder.Builder),
	"parallels-pvm":    new(parallelspvmbuilder.Builder),
	"profitbricks":     new(profitbricksbuilder.Builder),
	"qemu":             new(qemubuilder.Builder),
	"virtualbox-iso":   new(virtualboxisobuilder.Builder),
	"virtualbox-ovf":   new(virtualboxovfbuilder.Builder),
	"vmware-iso":       new(vmwareisobuilder.Builder),
	"vmware-vmx":       new(vmwarevmxbuilder.Builder),
}

var Provisioners = map[string]packer.Provisioner{
	"ansible":           new(ansibleprovisioner.Provisioner),
	"ansible-local":     new(ansiblelocalprovisioner.Provisioner),
	"chef-client":       new(chefclientprovisioner.Provisioner),
	"chef-solo":         new(chefsoloprovisioner.Provisioner),
	"file":              new(fileprovisioner.Provisioner),
	"powershell":        new(powershellprovisioner.Provisioner),
	"puppet-masterless": new(puppetmasterlessprovisioner.Provisioner),
	"puppet-server":     new(puppetserverprovisioner.Provisioner),
	"salt-masterless":   new(saltmasterlessprovisioner.Provisioner),
	"shell":             new(shellprovisioner.Provisioner),
	"shell-local":       new(shelllocalprovisioner.Provisioner),
	"windows-restart":   new(windowsrestartprovisioner.Provisioner),
	"windows-shell":     new(windowsshellprovisioner.Provisioner),
}

var PostProcessors = map[string]packer.PostProcessor{
	"amazon-import":        new(amazonimportpostprocessor.PostProcessor),
	"artifice":             new(artificepostprocessor.PostProcessor),
	"atlas":                new(atlaspostprocessor.PostProcessor),
	"checksum":             new(checksumpostprocessor.PostProcessor),
	"compress":             new(compresspostprocessor.PostProcessor),
	"docker-import":        new(dockerimportpostprocessor.PostProcessor),
	"docker-push":          new(dockerpushpostprocessor.PostProcessor),
	"docker-save":          new(dockersavepostprocessor.PostProcessor),
	"docker-tag":           new(dockertagpostprocessor.PostProcessor),
	"googlecompute-export": new(googlecomputeexportpostprocessor.PostProcessor),
	"manifest":             new(manifestpostprocessor.PostProcessor),
	"shell-local":          new(shelllocalpostprocessor.PostProcessor),
	"vagrant":              new(vagrantpostprocessor.PostProcessor),
	"vagrant-cloud":        new(vagrantcloudpostprocessor.PostProcessor),
	"vsphere":              new(vspherepostprocessor.PostProcessor),
}

var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner)-(.+)")

func (c *PluginCommand) Run(args []string) int {
	// This is an internal call (users should not call this directly) so we're
	// not going to do much input validation. If there's a problem we'll often
	// just crash. Error handling should be added to facilitate debugging.
	log.Printf("args: %#v", args)
	if len(args) != 1 {
		c.Ui.Error("Wrong number of args")
		return 1
	}

	// Plugin will match something like "packer-builder-amazon-ebs"
	parts := pluginRegexp.FindStringSubmatch(args[0])
	if len(parts) != 3 {
		c.Ui.Error(fmt.Sprintf("Error parsing plugin argument [DEBUG]: %#v", parts))
		return 1
	}
	pluginType := parts[1] // capture group 1 (builder|post-processor|provisioner)
	pluginName := parts[2] // capture group 2 (.+)

	server, err := plugin.Server()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error starting plugin server: %s", err))
		return 1
	}

	switch pluginType {
	case "builder":
		builder, found := Builders[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load builder: %s", pluginName))
			return 1
		}
		server.RegisterBuilder(builder)
	case "provisioner":
		provisioner, found := Provisioners[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load provisioner: %s", pluginName))
			return 1
		}
		server.RegisterProvisioner(provisioner)
	case "post-processor":
		postProcessor, found := PostProcessors[pluginName]
		if !found {
			c.Ui.Error(fmt.Sprintf("Could not load post-processor: %s", pluginName))
			return 1
		}
		server.RegisterPostProcessor(postProcessor)
	}

	server.Serve()

	return 0
}

func (*PluginCommand) Help() string {
	helpText := `
Usage: packer plugin PLUGIN

  Runs an internally-compiled version of a plugin from the packer binary.

  NOTE: this is an internal command and you should not call it yourself.
`

	return strings.TrimSpace(helpText)
}

func (c *PluginCommand) Synopsis() string {
	return "internal plugin command"
}
<|endoftext|>


<commit_before>package cluster

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

func Test_SingleJoinOK(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			t.Fatalf("Client did not use POST")
		}
		w.WriteHeader(http.StatusOK)
	}))
	defer ts.Close()

	j, err := Join([]string{ts.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts.URL)
	}
}

func Test_SingleJoinFail(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
	}))
	defer ts.Close()

	_, err := Join([]string{ts.URL}, "127.0.0.1:9090", true)
	if err == nil {
		t.Fatalf("expected error when joining bad node")
	}
}

func Test_DoubleJoinOK(t *testing.T) {
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts1.Close()
	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts2.Close()

	j, err := Join([]string{ts1.URL, ts2.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts1.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts1.URL)
	}
}

func Test_DoubleJoinOKSecondNode(t *testing.T) {
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
	}))
	defer ts1.Close()
	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts2.Close()

	j, err := Join([]string{ts1.URL, ts2.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts2.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts2.URL)
	}
}

func Test_DoubleJoinOKSecondNodeRedirect(t *testing.T) {
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts1.Close()
	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, fmt.Sprintf("%s%s", ts1.URL, "/join"), http.StatusMovedPermanently)
	}))
	defer ts2.Close()

	j, err := Join([]string{ts2.URL, ts1.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts1.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts2.URL)
	}
}
<commit_msg>Tweak redirect join test<commit_after>package cluster

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
)

func Test_SingleJoinOK(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			t.Fatalf("Client did not use POST")
		}
		w.WriteHeader(http.StatusOK)
	}))
	defer ts.Close()

	j, err := Join([]string{ts.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts.URL)
	}
}

func Test_SingleJoinFail(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
	}))
	defer ts.Close()

	_, err := Join([]string{ts.URL}, "127.0.0.1:9090", true)
	if err == nil {
		t.Fatalf("expected error when joining bad node")
	}
}

func Test_DoubleJoinOK(t *testing.T) {
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts1.Close()
	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts2.Close()

	j, err := Join([]string{ts1.URL, ts2.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts1.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts1.URL)
	}
}

func Test_DoubleJoinOKSecondNode(t *testing.T) {
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusBadRequest)
	}))
	defer ts1.Close()
	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts2.Close()

	j, err := Join([]string{ts1.URL, ts2.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts2.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts2.URL)
	}
}

func Test_DoubleJoinOKSecondNodeRedirect(t *testing.T) {
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	}))
	defer ts1.Close()
	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, fmt.Sprintf("%s%s", ts1.URL, "/join"), http.StatusMovedPermanently)
	}))
	defer ts2.Close()

	j, err := Join([]string{ts2.URL}, "127.0.0.1:9090", true)
	if err != nil {
		t.Fatalf("failed to join a single node: %s", err.Error())
	}
	if j != ts1.URL+"/join" {
		t.Fatalf("node joined using wrong endpoint, exp: %s, got: %s", j, ts2.URL)
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"github.com/github/hub/utils"
	"os"
	"path/filepath"
	"strings"
)

var cmdAlias = &Command{
	Run:   alias,
	Usage: "alias [-s] [SHELL]",
	Short: "Show shell instructions for wrapping git",
	Long: `Shows shell instructions for wrapping git. If given, SHELL specifies the
type of shell; otherwise defaults to the value of SHELL environment
variable. With -s, outputs shell script suitable for eval.
`,
}

var flagAliasScript bool

func init() {
	cmdAlias.Flag.BoolVarP(&flagAliasScript, "script", "s", false, "SCRIPT")
	CmdRunner.Use(cmdAlias)
}

func alias(command *Command, args *Args) {
	var shell string
	if args.ParamsSize() > 0 {
		shell = args.FirstParam()
	} else {
		shell = os.Getenv("SHELL")
	}

	if shell == "" {
		utils.Check(fmt.Errorf("Unknown shell"))
	}

	shells := []string{"bash", "zsh", "sh", "ksh", "csh", "fish"}
	shell = filepath.Base(shell)
	var validShell bool
	for _, s := range shells {
		if s == shell {
			validShell = true
			break
		}
	}

	if !validShell {
		err := fmt.Errorf("hub alias: unsupported shell\nsupported shells: %s", strings.Join(shells, " "))
		utils.Check(err)
	}

	if flagAliasScript {
		fmt.Println("alias git=hub")
	} else {
		var profile string
		switch shell {
		case "bash":
			profile = "~/.bash_profile"
		case "zsh":
			profile = "~/.zshrc"
		case "ksh":
			profile = "~/.profile"
		case "fish":
			profile = "~/.config/fish/config.fish"
		default:
			profile = "your profile"
		}

		msg := fmt.Sprintf("# Wrap git automatically by adding the following to %s:\n", profile)
		fmt.Println(msg)

		var eval string
		if shell == "fish" {
			eval = `eval (hub alias -s)`
		} else {
			eval = `eval "$(hub alias -s)"`
		}
		fmt.Println(eval)
	}

	os.Exit(0)
}
<commit_msg>Support tcsh.<commit_after>package commands

import (
	"fmt"
	"github.com/github/hub/utils"
	"os"
	"path/filepath"
	"strings"
)

var cmdAlias = &Command{
	Run:   alias,
	Usage: "alias [-s] [SHELL]",
	Short: "Show shell instructions for wrapping git",
	Long: `Shows shell instructions for wrapping git. If given, SHELL specifies the
type of shell; otherwise defaults to the value of SHELL environment
variable. With -s, outputs shell script suitable for eval.
`,
}

var flagAliasScript bool

func init() {
	cmdAlias.Flag.BoolVarP(&flagAliasScript, "script", "s", false, "SCRIPT")
	CmdRunner.Use(cmdAlias)
}

func alias(command *Command, args *Args) {
	var shell string
	if args.ParamsSize() > 0 {
		shell = args.FirstParam()
	} else {
		shell = os.Getenv("SHELL")
	}

	if shell == "" {
		utils.Check(fmt.Errorf("Unknown shell"))
	}

	shells := []string{"bash", "zsh", "sh", "ksh", "csh", "tcsh", "fish"}
	shell = filepath.Base(shell)
	var validShell bool
	for _, s := range shells {
		if s == shell {
			validShell = true
			break
		}
	}

	if !validShell {
		err := fmt.Errorf("hub alias: unsupported shell\nsupported shells: %s", strings.Join(shells, " "))
		utils.Check(err)
	}

	if flagAliasScript {
		fmt.Println("alias git=hub")
	} else {
		var profile string
		switch shell {
		case "bash":
			profile = "~/.bash_profile"
		case "zsh":
			profile = "~/.zshrc"
		case "ksh":
			profile = "~/.profile"
		case "fish":
			profile = "~/.config/fish/config.fish"
		case "tcsh":
			profile = "~/.tcshrc"
		default:
			profile = "your profile"
		}

		msg := fmt.Sprintf("# Wrap git automatically by adding the following to %s:\n", profile)
		fmt.Println(msg)

		var eval string
		if shell == "fish" {
			eval = `eval (hub alias -s)`
		} else {
			eval = `eval "$(hub alias -s)"`
		}
		fmt.Println(eval)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package commands

import (
	. "fmt"
	"io"
	"polydawn.net/docket/confl"
	"polydawn.net/docket/crocker"
	"polydawn.net/docket/dex"
	. "polydawn.net/docket/util"
)

type BuildCmdOpts struct {
	Source      string `short:"s" long:"source"      description:"Container source.      (default: graph)"`
	Destination string `short:"d" long:"destination" description:"Container destination. (default: graph)"`
	NoOp bool          `long:"noop" description:"Set the container command to /bin/true."`
}

const DefaultBuildTarget = "build"

//Transforms a container
func (opts *BuildCmdOpts) Execute(args []string) error {
	//Get configuration
	target   := GetTarget(args, DefaultBuildTarget)
	settings := confl.NewConfigLoad(".")
	config := settings.GetConfig(target)
	saveAs := settings.GetDefaultImage()
	var sourceGraph, destinationGraph *dex.Graph

	//If desired, set the command to /bin/true.
	//We'd love to not launch the container at all, but docker's export is completely broken.
	// 'docker export ubuntu' --> 'Error: No such container: ubuntu' --> :(
	if opts.NoOp {
		config.Command = []string{ "/bin/true" }
	}

	//Right now, go-flags' default announation does not appear to work when in a sub-command.
	//	Will investigate and hopefully remove this later.
	if opts.Source == "" {
		opts.Source = "graph"
	}
	if opts.Destination == "" {
		opts.Destination = "graph"
	}

	//Parse input/output URIs
	sourceScheme, sourcePath           := ParseURI(opts.Source)
	destinationScheme, destinationPath := ParseURI(opts.Destination)

	//Prepare input
	switch sourceScheme {
		case "docker":
			//TODO: check that docker has the image loaded
		case "graph":
			//Look up the graph, and clear any unwanted state
			sourceGraph = dex.NewGraph(settings.Graph)
			sourceGraph.Cleanse()
		case "file":
			//If the user did not specify an image path, set one
			if sourcePath == "" {
				sourcePath = "./image.tar"
			}
	}

	//Prepare output
	name, tag := crocker.SplitImageName(saveAs)
	switch destinationScheme {
		case "docker":
			//Nothing required here until container has ran
		case "graph":
			//Look up the graph, and clear any unwanted state
			destinationGraph = dex.NewGraph(settings.Graph)

			//Don't run extra git commands if they'd be redundant.
			//Right now, we're ignoring the destinationPath, so this will never fire.
			if sourceScheme == "graph" && sourceGraph.GetDir() != destinationGraph.GetDir() {
				destinationGraph.Cleanse()
			}
		case "file":
			//If the user did not specify an image path, set one
			if destinationPath == "" {
				destinationPath = "./image.tar"
			}

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

	//Start or connect to a docker daemon
	dock := StartDocker(settings)

	//Prepare cache
	switch sourceScheme {
		case "graph":
			//Import the latest lineage
			dock.Import(sourceGraph.Load(config.Image), config.Image, "latest")
		case "file":
			//Load image from file
			dock.ImportFromFilenameTagstring(sourcePath, config.Image)
		case "index":
			//TODO: check that docker doesn't already have the image loaded
			dock.Pull(config.Image)
	}

	//Launch the container and wait for it to finish
	container := Launch(dock, config)
	container.Wait()

	//Perform any destination operations required
	switch destinationScheme {
		//If we're not exporting to the graph, there is no commit hash from which to generate a tag.
		//	Thus the docker import will have either a static tag (from docker.toml) or the default 'latest' tag.
		case "docker":
			Println("Exporting to", name, tag)
			container.Commit(name, tag)
		case "graph":
			// Export a tar of the filesystem
			exportStreamOut, exportStreamIn := io.Pipe()
			go container.Export(exportStreamIn)

			// Commit it to the image graph
			destinationGraph.Publish(exportStreamOut, saveAs, config.Image)
		case "file":
			//Export a tar
			Println("Exporting to", destinationPath)
			container.ExportToFilename(destinationPath)
	}

	//Remove if desired
	if config.Purge {
		container.Purge()
	}

	//Stop the docker daemon if it's a child process
	dock.Slay()

	return nil
}
<commit_msg>Build command: Fixed not cleaning the graph if source is not a graph.<commit_after>package commands

import (
	. "fmt"
	"io"
	"polydawn.net/docket/confl"
	"polydawn.net/docket/crocker"
	"polydawn.net/docket/dex"
	. "polydawn.net/docket/util"
)

type BuildCmdOpts struct {
	Source      string `short:"s" long:"source"      description:"Container source.      (default: graph)"`
	Destination string `short:"d" long:"destination" description:"Container destination. (default: graph)"`
	NoOp bool          `long:"noop" description:"Set the container command to /bin/true."`
}

const DefaultBuildTarget = "build"

//Transforms a container
func (opts *BuildCmdOpts) Execute(args []string) error {
	//Get configuration
	target   := GetTarget(args, DefaultBuildTarget)
	settings := confl.NewConfigLoad(".")
	config := settings.GetConfig(target)
	saveAs := settings.GetDefaultImage()
	var sourceGraph, destinationGraph *dex.Graph

	//If desired, set the command to /bin/true.
	//We'd love to not launch the container at all, but docker's export is completely broken.
	// 'docker export ubuntu' --> 'Error: No such container: ubuntu' --> :(
	if opts.NoOp {
		config.Command = []string{ "/bin/true" }
	}

	//Right now, go-flags' default announation does not appear to work when in a sub-command.
	//	Will investigate and hopefully remove this later.
	if opts.Source == "" {
		opts.Source = "graph"
	}
	if opts.Destination == "" {
		opts.Destination = "graph"
	}

	//Parse input/output URIs
	sourceScheme, sourcePath           := ParseURI(opts.Source)
	destinationScheme, destinationPath := ParseURI(opts.Destination)

	//Prepare input
	switch sourceScheme {
		case "docker":
			//TODO: check that docker has the image loaded
		case "graph":
			//Look up the graph, and clear any unwanted state
			sourceGraph = dex.NewGraph(settings.Graph)
			sourceGraph.Cleanse()
		case "file":
			//If the user did not specify an image path, set one
			if sourcePath == "" {
				sourcePath = "./image.tar"
			}
	}

	//Prepare output
	name, tag := crocker.SplitImageName(saveAs)
	switch destinationScheme {
		case "docker":
			//Nothing required here until container has ran
		case "graph":
			//Look up the graph, and clear any unwanted state
			destinationGraph = dex.NewGraph(settings.Graph)

			//Cleanse the graph unless it'd be redundant.
			if !(sourceScheme == "graph" && sourceGraph.GetDir() != destinationGraph.GetDir()) {
				destinationGraph.Cleanse()
			}
		case "file":
			//If the user did not specify an image path, set one
			if destinationPath == "" {
				destinationPath = "./image.tar"
			}

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

	//Start or connect to a docker daemon
	dock := StartDocker(settings)

	//Prepare cache
	switch sourceScheme {
		case "graph":
			//Import the latest lineage
			dock.Import(sourceGraph.Load(config.Image), config.Image, "latest")
		case "file":
			//Load image from file
			dock.ImportFromFilenameTagstring(sourcePath, config.Image)
		case "index":
			//TODO: check that docker doesn't already have the image loaded
			dock.Pull(config.Image)
	}

	//Launch the container and wait for it to finish
	container := Launch(dock, config)
	container.Wait()

	//Perform any destination operations required
	switch destinationScheme {
		//If we're not exporting to the graph, there is no commit hash from which to generate a tag.
		//	Thus the docker import will have either a static tag (from docker.toml) or the default 'latest' tag.
		case "docker":
			Println("Exporting to", name, tag)
			container.Commit(name, tag)
		case "graph":
			// Export a tar of the filesystem
			exportStreamOut, exportStreamIn := io.Pipe()
			go container.Export(exportStreamIn)

			// Commit it to the image graph
			destinationGraph.Publish(exportStreamOut, saveAs, config.Image)
		case "file":
			//Export a tar
			Println("Exporting to", destinationPath)
			container.ExportToFilename(destinationPath)
	}

	//Remove if desired
	if config.Purge {
		container.Purge()
	}

	//Stop the docker daemon if it's a child process
	dock.Slay()

	return nil
}
<|endoftext|>


<commit_before>package commands

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	service "github.com/ayufan/golang-kardianos-service"
	"github.com/codegangsta/cli"

	log "github.com/Sirupsen/logrus"

	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/sentry"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/service"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/network"
)

type RunCommand struct {
	configOptions
	network common.Network
	healthHelper

	buildsHelper buildsHelper

	ServiceName      string `short:"n" long:"service" description:"Use different names for different services"`
	WorkingDirectory string `short:"d" long:"working-directory" description:"Specify custom working directory"`
	User             string `short:"u" long:"user" description:"Use specific user to execute shell scripts"`
	Syslog           bool   `long:"syslog" description:"Log to syslog"`

	sentryLogHook sentry.LogHook

	// abortBuilds is used to abort running builds
	abortBuilds chan os.Signal

	// runSignal is used to abort current operation (scaling workers, waiting for config)
	runSignal chan os.Signal

	// reloadSignal is used to trigger forceful config reload
	reloadSignal chan os.Signal

	// stopSignals is to catch a signals notified to process: SIGTERM, SIGQUIT, Interrupt, Kill
	stopSignals chan os.Signal

	// stopSignal is used to preserve the signal that was used to stop the process
	// In case this is SIGQUIT it makes to finish all buids
	stopSignal os.Signal

	// runFinished is used to notify that Run() did finish
	runFinished chan bool
}

func (mr *RunCommand) log() *log.Entry {
	return log.WithField("builds", len(mr.buildsHelper.builds))
}

func (mr *RunCommand) feedRunner(runner *common.RunnerConfig, runners chan *common.RunnerConfig) {
	if !mr.isHealthy(runner.UniqueID()) {
		return
	}

	runners <- runner
}

func (mr *RunCommand) feedRunners(runners chan *common.RunnerConfig) {
	for mr.stopSignal == nil {
		mr.log().Debugln("Feeding runners to channel")
		config := mr.config

		// If no runners wait full interval to test again
		if len(config.Runners) == 0 {
			time.Sleep(config.GetCheckInterval())
			continue
		}

		interval := config.GetCheckInterval() / time.Duration(len(config.Runners))

		// Feed runner with waiting exact amount of time
		for _, runner := range config.Runners {
			mr.feedRunner(runner, runners)
			time.Sleep(interval)
		}
	}
}

func (mr *RunCommand) processRunner(id int, runner *common.RunnerConfig, runners chan *common.RunnerConfig) (err error) {
	provider := common.GetExecutor(runner.Executor)
	if provider == nil {
		return
	}

	context, err := provider.Acquire(runner)
	if err != nil {
		log.Warningln("Failed to update executor", runner.Executor, "for", runner.ShortDescription(), err)
		return
	}
	defer provider.Release(runner, context)

	// Acquire build slot
	if !mr.buildsHelper.acquire(runner) {
		return
	}
	defer mr.buildsHelper.release(runner)

	// Receive a new build
	buildData, healthy := mr.network.GetBuild(*runner)
	mr.makeHealthy(runner.UniqueID(), healthy)
	if buildData == nil {
		return
	}

	// Make sure to always close output
	buildCredentials := &common.BuildCredentials{
		ID:    buildData.ID,
		Token: buildData.Token,
	}
	trace := mr.network.ProcessBuild(*runner, buildCredentials)
	defer trace.Fail(err)

	// Create a new build
	build := &common.Build{
		GetBuildResponse: *buildData,
		Runner:           runner,
		ExecutorData:     context,
		SystemInterrupt:  mr.abortBuilds,
	}

	// Add build to list of builds to assign numbers
	mr.buildsHelper.addBuild(build)
	defer mr.buildsHelper.removeBuild(build)

	// Process the same runner by different worker again
	// to speed up taking the builds
	select {
	case runners <- runner:
		mr.log().WithField("runner", runner.ShortDescription()).Debugln("Requeued the runner")

	default:
		mr.log().WithField("runner", runner.ShortDescription()).Debugln("Failed to requeue the runner: ")
	}

	// Process a build
	return build.Run(mr.config, trace)
}

func (mr *RunCommand) processRunners(id int, stopWorker chan bool, runners chan *common.RunnerConfig) {
	mr.log().WithField("worker", id).Debugln("Starting worker")
	for mr.stopSignal == nil {
		select {
		case runner := <-runners:
			mr.processRunner(id, runner, runners)

			// force GC cycle after processing build
			runtime.GC()

		case <-stopWorker:
			mr.log().WithField("worker", id).Debugln("Stopping worker")
			return
		}
	}
	<-stopWorker
}

func (mr *RunCommand) startWorkers(startWorker chan int, stopWorker chan bool, runners chan *common.RunnerConfig) {
	for mr.stopSignal == nil {
		id := <-startWorker
		go mr.processRunners(id, stopWorker, runners)
	}
}

func (mr *RunCommand) loadConfig() error {
	err := mr.configOptions.loadConfig()
	if err != nil {
		return err
	}

	// pass user to execute scripts as specific user
	if mr.User != "" {
		mr.config.User = mr.User
	}

	mr.healthy = nil
	mr.log().Println("Config loaded:", helpers.ToYAML(mr.config))

	// initialize sentry
	if mr.config.SentryDSN != nil {
		var err error
		mr.sentryLogHook, err = sentry.NewLogHook(*mr.config.SentryDSN)
		if err != nil {
			mr.log().WithError(err).Errorln("Sentry failure")
		}
	} else {
		mr.sentryLogHook = sentry.LogHook{}
	}

	return nil
}

func (mr *RunCommand) checkConfig() (err error) {
	info, err := os.Stat(mr.ConfigFile)
	if err != nil {
		return err
	}

	if !mr.config.ModTime.Before(info.ModTime()) {
		return nil
	}

	err = mr.loadConfig()
	if err != nil {
		mr.log().Errorln("Failed to load config", err)
		// don't reload the same file
		mr.config.ModTime = info.ModTime()
		return
	}
	return nil
}

func (mr *RunCommand) Start(s service.Service) error {
	mr.abortBuilds = make(chan os.Signal)
	mr.runSignal = make(chan os.Signal, 1)
	mr.reloadSignal = make(chan os.Signal, 1)
	mr.runFinished = make(chan bool, 1)
	mr.stopSignals = make(chan os.Signal)
	mr.log().Println("Starting multi-runner from", mr.ConfigFile, "...")

	userModeWarning(false)

	if len(mr.WorkingDirectory) > 0 {
		err := os.Chdir(mr.WorkingDirectory)
		if err != nil {
			return err
		}
	}

	err := mr.loadConfig()
	if err != nil {
		return err
	}

	// Start should not block. Do the actual work async.
	go mr.Run()

	return nil
}

func (mr *RunCommand) updateWorkers(currentWorkers, workerIndex *int, startWorker chan int, stopWorker chan bool) os.Signal {
	buildLimit := mr.config.Concurrent

	for *currentWorkers > buildLimit {
		select {
		case stopWorker <- true:
		case signaled := <-mr.runSignal:
			return signaled
		}
		*currentWorkers--
	}

	for *currentWorkers < buildLimit {
		select {
		case startWorker <- *workerIndex:
		case signaled := <-mr.runSignal:
			return signaled
		}
		*currentWorkers++
		*workerIndex++
	}

	return nil
}

func (mr *RunCommand) updateConfig() os.Signal {
	select {
	case <-time.After(common.ReloadConfigInterval * time.Second):
		err := mr.checkConfig()
		if err != nil {
			mr.log().Errorln("Failed to load config", err)
		}

	case <-mr.reloadSignal:
		err := mr.loadConfig()
		if err != nil {
			mr.log().Errorln("Failed to load config", err)
		}

	case signaled := <-mr.runSignal:
		return signaled
	}
	return nil
}

func (mr *RunCommand) runWait() {
	mr.log().Debugln("Waiting for stop signal")

	// Save the stop signal and exit to execute Stop()
	mr.stopSignal = <-mr.stopSignals
}

func (mr *RunCommand) Run() {
	runners := make(chan *common.RunnerConfig)
	go mr.feedRunners(runners)

	signal.Notify(mr.stopSignals, syscall.SIGQUIT, syscall.SIGTERM, os.Interrupt, os.Kill)
	signal.Notify(mr.reloadSignal, syscall.SIGHUP)

	startWorker := make(chan int)
	stopWorker := make(chan bool)
	go mr.startWorkers(startWorker, stopWorker, runners)

	currentWorkers := 0
	workerIndex := 0

	for mr.stopSignal == nil {
		signaled := mr.updateWorkers(&currentWorkers, &workerIndex, startWorker, stopWorker)
		if signaled != nil {
			break
		}

		signaled = mr.updateConfig()
		if signaled != nil {
			break
		}
	}

	// Wait for workers to shutdown
	for currentWorkers > 0 {
		stopWorker <- true
		currentWorkers--
	}
	mr.log().Println("All workers stopped. Can exit now")
	mr.runFinished <- true
}

func (mr *RunCommand) interruptRun() {
	// Pump interrupt signal
	for {
		mr.runSignal <- mr.stopSignal
	}
}

func (mr *RunCommand) abortAllBuilds() {
	// Pump signal to abort all current builds
	for {
		mr.abortBuilds <- mr.stopSignal
	}
}

func (mr *RunCommand) handleGracefulShutdown() error {
	// We wait till we have a SIGQUIT
	for mr.stopSignal == syscall.SIGQUIT {
		mr.log().Warningln("Requested quit, waiting for builds to finish")

		// Wait for other signals to finish builds
		select {
		case mr.stopSignal = <-mr.stopSignals:
		// We received a new signal

		case <-mr.runFinished:
			// Everything finished we can exit now
			return nil
		}
	}

	return fmt.Errorf("received: %v", mr.stopSignal)
}

func (mr *RunCommand) handleShutdown() error {
	mr.log().Warningln("Requested service stop:", mr.stopSignal)

	go mr.abortAllBuilds()

	// Wait for graceful shutdown or abort after timeout
	for {
		select {
		case mr.stopSignal = <-mr.stopSignals:
			return fmt.Errorf("forced exit: %v", mr.stopSignal)

		case <-time.After(common.ShutdownTimeout * time.Second):
			return errors.New("shutdown timedout")

		case <-mr.runFinished:
			// Everything finished we can exit now
			return nil
		}
	}
}

func (mr *RunCommand) Stop(s service.Service) (err error) {
	go mr.interruptRun()
	err = mr.handleGracefulShutdown()
	if err == nil {
		return
	}
	err = mr.handleShutdown()
	return
}

func (mr *RunCommand) Execute(context *cli.Context) {
	svcConfig := &service.Config{
		Name:        mr.ServiceName,
		DisplayName: mr.ServiceName,
		Description: defaultDescription,
		Arguments:   []string{"run"},
		Option: service.KeyValue{
			"RunWait": mr.runWait,
		},
	}

	service, err := service_helpers.New(mr, svcConfig)
	if err != nil {
		log.Fatalln(err)
	}

	if mr.Syslog {
		log.SetFormatter(new(log.TextFormatter))
		logger, err := service.SystemLogger(nil)
		if err == nil {
			log.AddHook(&ServiceLogHook{logger, log.InfoLevel})
		} else {
			log.Errorln(err)
		}
	}

	log.AddHook(&mr.sentryLogHook)

	err = service.Run()
	if err != nil {
		log.Fatalln(err)
	}
}

func init() {
	common.RegisterCommand2("run", "run multi runner service", &RunCommand{
		ServiceName: defaultServiceName,
		network:     &network.GitLabClient{},
	})
}
<commit_msg>Remove configuration dump from Runner's logs<commit_after>package commands

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"

	service "github.com/ayufan/golang-kardianos-service"
	"github.com/codegangsta/cli"

	log "github.com/Sirupsen/logrus"

	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/sentry"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/service"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/network"
)

type RunCommand struct {
	configOptions
	network common.Network
	healthHelper

	buildsHelper buildsHelper

	ServiceName      string `short:"n" long:"service" description:"Use different names for different services"`
	WorkingDirectory string `short:"d" long:"working-directory" description:"Specify custom working directory"`
	User             string `short:"u" long:"user" description:"Use specific user to execute shell scripts"`
	Syslog           bool   `long:"syslog" description:"Log to syslog"`

	sentryLogHook sentry.LogHook

	// abortBuilds is used to abort running builds
	abortBuilds chan os.Signal

	// runSignal is used to abort current operation (scaling workers, waiting for config)
	runSignal chan os.Signal

	// reloadSignal is used to trigger forceful config reload
	reloadSignal chan os.Signal

	// stopSignals is to catch a signals notified to process: SIGTERM, SIGQUIT, Interrupt, Kill
	stopSignals chan os.Signal

	// stopSignal is used to preserve the signal that was used to stop the process
	// In case this is SIGQUIT it makes to finish all buids
	stopSignal os.Signal

	// runFinished is used to notify that Run() did finish
	runFinished chan bool
}

func (mr *RunCommand) log() *log.Entry {
	return log.WithField("builds", len(mr.buildsHelper.builds))
}

func (mr *RunCommand) feedRunner(runner *common.RunnerConfig, runners chan *common.RunnerConfig) {
	if !mr.isHealthy(runner.UniqueID()) {
		return
	}

	runners <- runner
}

func (mr *RunCommand) feedRunners(runners chan *common.RunnerConfig) {
	for mr.stopSignal == nil {
		mr.log().Debugln("Feeding runners to channel")
		config := mr.config

		// If no runners wait full interval to test again
		if len(config.Runners) == 0 {
			time.Sleep(config.GetCheckInterval())
			continue
		}

		interval := config.GetCheckInterval() / time.Duration(len(config.Runners))

		// Feed runner with waiting exact amount of time
		for _, runner := range config.Runners {
			mr.feedRunner(runner, runners)
			time.Sleep(interval)
		}
	}
}

func (mr *RunCommand) processRunner(id int, runner *common.RunnerConfig, runners chan *common.RunnerConfig) (err error) {
	provider := common.GetExecutor(runner.Executor)
	if provider == nil {
		return
	}

	context, err := provider.Acquire(runner)
	if err != nil {
		log.Warningln("Failed to update executor", runner.Executor, "for", runner.ShortDescription(), err)
		return
	}
	defer provider.Release(runner, context)

	// Acquire build slot
	if !mr.buildsHelper.acquire(runner) {
		return
	}
	defer mr.buildsHelper.release(runner)

	// Receive a new build
	buildData, healthy := mr.network.GetBuild(*runner)
	mr.makeHealthy(runner.UniqueID(), healthy)
	if buildData == nil {
		return
	}

	// Make sure to always close output
	buildCredentials := &common.BuildCredentials{
		ID:    buildData.ID,
		Token: buildData.Token,
	}
	trace := mr.network.ProcessBuild(*runner, buildCredentials)
	defer trace.Fail(err)

	// Create a new build
	build := &common.Build{
		GetBuildResponse: *buildData,
		Runner:           runner,
		ExecutorData:     context,
		SystemInterrupt:  mr.abortBuilds,
	}

	// Add build to list of builds to assign numbers
	mr.buildsHelper.addBuild(build)
	defer mr.buildsHelper.removeBuild(build)

	// Process the same runner by different worker again
	// to speed up taking the builds
	select {
	case runners <- runner:
		mr.log().WithField("runner", runner.ShortDescription()).Debugln("Requeued the runner")

	default:
		mr.log().WithField("runner", runner.ShortDescription()).Debugln("Failed to requeue the runner: ")
	}

	// Process a build
	return build.Run(mr.config, trace)
}

func (mr *RunCommand) processRunners(id int, stopWorker chan bool, runners chan *common.RunnerConfig) {
	mr.log().WithField("worker", id).Debugln("Starting worker")
	for mr.stopSignal == nil {
		select {
		case runner := <-runners:
			mr.processRunner(id, runner, runners)

			// force GC cycle after processing build
			runtime.GC()

		case <-stopWorker:
			mr.log().WithField("worker", id).Debugln("Stopping worker")
			return
		}
	}
	<-stopWorker
}

func (mr *RunCommand) startWorkers(startWorker chan int, stopWorker chan bool, runners chan *common.RunnerConfig) {
	for mr.stopSignal == nil {
		id := <-startWorker
		go mr.processRunners(id, stopWorker, runners)
	}
}

func (mr *RunCommand) loadConfig() error {
	err := mr.configOptions.loadConfig()
	if err != nil {
		return err
	}

	// pass user to execute scripts as specific user
	if mr.User != "" {
		mr.config.User = mr.User
	}

	mr.healthy = nil
	mr.log().Println("Configuration loaded")
	mr.log().Debugln(helpers.ToYAML(mr.config))

	// initialize sentry
	if mr.config.SentryDSN != nil {
		var err error
		mr.sentryLogHook, err = sentry.NewLogHook(*mr.config.SentryDSN)
		if err != nil {
			mr.log().WithError(err).Errorln("Sentry failure")
		}
	} else {
		mr.sentryLogHook = sentry.LogHook{}
	}

	return nil
}

func (mr *RunCommand) checkConfig() (err error) {
	info, err := os.Stat(mr.ConfigFile)
	if err != nil {
		return err
	}

	if !mr.config.ModTime.Before(info.ModTime()) {
		return nil
	}

	err = mr.loadConfig()
	if err != nil {
		mr.log().Errorln("Failed to load config", err)
		// don't reload the same file
		mr.config.ModTime = info.ModTime()
		return
	}
	return nil
}

func (mr *RunCommand) Start(s service.Service) error {
	mr.abortBuilds = make(chan os.Signal)
	mr.runSignal = make(chan os.Signal, 1)
	mr.reloadSignal = make(chan os.Signal, 1)
	mr.runFinished = make(chan bool, 1)
	mr.stopSignals = make(chan os.Signal)
	mr.log().Println("Starting multi-runner from", mr.ConfigFile, "...")

	userModeWarning(false)

	if len(mr.WorkingDirectory) > 0 {
		err := os.Chdir(mr.WorkingDirectory)
		if err != nil {
			return err
		}
	}

	err := mr.loadConfig()
	if err != nil {
		return err
	}

	// Start should not block. Do the actual work async.
	go mr.Run()

	return nil
}

func (mr *RunCommand) updateWorkers(currentWorkers, workerIndex *int, startWorker chan int, stopWorker chan bool) os.Signal {
	buildLimit := mr.config.Concurrent

	for *currentWorkers > buildLimit {
		select {
		case stopWorker <- true:
		case signaled := <-mr.runSignal:
			return signaled
		}
		*currentWorkers--
	}

	for *currentWorkers < buildLimit {
		select {
		case startWorker <- *workerIndex:
		case signaled := <-mr.runSignal:
			return signaled
		}
		*currentWorkers++
		*workerIndex++
	}

	return nil
}

func (mr *RunCommand) updateConfig() os.Signal {
	select {
	case <-time.After(common.ReloadConfigInterval * time.Second):
		err := mr.checkConfig()
		if err != nil {
			mr.log().Errorln("Failed to load config", err)
		}

	case <-mr.reloadSignal:
		err := mr.loadConfig()
		if err != nil {
			mr.log().Errorln("Failed to load config", err)
		}

	case signaled := <-mr.runSignal:
		return signaled
	}
	return nil
}

func (mr *RunCommand) runWait() {
	mr.log().Debugln("Waiting for stop signal")

	// Save the stop signal and exit to execute Stop()
	mr.stopSignal = <-mr.stopSignals
}

func (mr *RunCommand) Run() {
	runners := make(chan *common.RunnerConfig)
	go mr.feedRunners(runners)

	signal.Notify(mr.stopSignals, syscall.SIGQUIT, syscall.SIGTERM, os.Interrupt, os.Kill)
	signal.Notify(mr.reloadSignal, syscall.SIGHUP)

	startWorker := make(chan int)
	stopWorker := make(chan bool)
	go mr.startWorkers(startWorker, stopWorker, runners)

	currentWorkers := 0
	workerIndex := 0

	for mr.stopSignal == nil {
		signaled := mr.updateWorkers(&currentWorkers, &workerIndex, startWorker, stopWorker)
		if signaled != nil {
			break
		}

		signaled = mr.updateConfig()
		if signaled != nil {
			break
		}
	}

	// Wait for workers to shutdown
	for currentWorkers > 0 {
		stopWorker <- true
		currentWorkers--
	}
	mr.log().Println("All workers stopped. Can exit now")
	mr.runFinished <- true
}

func (mr *RunCommand) interruptRun() {
	// Pump interrupt signal
	for {
		mr.runSignal <- mr.stopSignal
	}
}

func (mr *RunCommand) abortAllBuilds() {
	// Pump signal to abort all current builds
	for {
		mr.abortBuilds <- mr.stopSignal
	}
}

func (mr *RunCommand) handleGracefulShutdown() error {
	// We wait till we have a SIGQUIT
	for mr.stopSignal == syscall.SIGQUIT {
		mr.log().Warningln("Requested quit, waiting for builds to finish")

		// Wait for other signals to finish builds
		select {
		case mr.stopSignal = <-mr.stopSignals:
		// We received a new signal

		case <-mr.runFinished:
			// Everything finished we can exit now
			return nil
		}
	}

	return fmt.Errorf("received: %v", mr.stopSignal)
}

func (mr *RunCommand) handleShutdown() error {
	mr.log().Warningln("Requested service stop:", mr.stopSignal)

	go mr.abortAllBuilds()

	// Wait for graceful shutdown or abort after timeout
	for {
		select {
		case mr.stopSignal = <-mr.stopSignals:
			return fmt.Errorf("forced exit: %v", mr.stopSignal)

		case <-time.After(common.ShutdownTimeout * time.Second):
			return errors.New("shutdown timedout")

		case <-mr.runFinished:
			// Everything finished we can exit now
			return nil
		}
	}
}

func (mr *RunCommand) Stop(s service.Service) (err error) {
	go mr.interruptRun()
	err = mr.handleGracefulShutdown()
	if err == nil {
		return
	}
	err = mr.handleShutdown()
	return
}

func (mr *RunCommand) Execute(context *cli.Context) {
	svcConfig := &service.Config{
		Name:        mr.ServiceName,
		DisplayName: mr.ServiceName,
		Description: defaultDescription,
		Arguments:   []string{"run"},
		Option: service.KeyValue{
			"RunWait": mr.runWait,
		},
	}

	service, err := service_helpers.New(mr, svcConfig)
	if err != nil {
		log.Fatalln(err)
	}

	if mr.Syslog {
		log.SetFormatter(new(log.TextFormatter))
		logger, err := service.SystemLogger(nil)
		if err == nil {
			log.AddHook(&ServiceLogHook{logger, log.InfoLevel})
		} else {
			log.Errorln(err)
		}
	}

	log.AddHook(&mr.sentryLogHook)

	err = service.Run()
	if err != nil {
		log.Fatalln(err)
	}
}

func init() {
	common.RegisterCommand2("run", "run multi runner service", &RunCommand{
		ServiceName: defaultServiceName,
		network:     &network.GitLabClient{},
	})
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io"
	"net"
	"os"

	"github.com/moul/advanced-ssh-config/vendor/github.com/codegangsta/cli"

	"github.com/moul/advanced-ssh-config/config"
)

func cmdProxy(c *cli.Context) {
	if len(c.Args()) < 1 {
		os.Exit(1)
	}

	dest := c.Args()[0]

	conf, err := config.Open()
	if err != nil {
		panic(err)
	}

	// Get host configuration
	host, err := conf.GetHost(dest)
	if err != nil {
		panic(err)
	}

	// Dial
	var port uint
	if c.Int("port") > 0 {
		port = uint(c.Int("port"))
	} else {
		port = host.Port
	}
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host.Host, port))
	if err != nil {
		panic(err)
	}

	defer conn.Close()

	fmt.Fprintf(os.Stderr, "Connected to %s:%d\n", host.Host, host.Port)

	// Create Stdio pipes
	go io.Copy(conn, os.Stdin)
	go io.Copy(os.Stdout, conn)
	_, err = io.Copy(os.Stderr, conn)
	if err != nil {
		panic(err)
	}

	return
}
<commit_msg>Checking io.Copy errors<commit_after>package commands

import (
	"fmt"
	"io"
	"net"
	"os"

	"github.com/moul/advanced-ssh-config/vendor/github.com/codegangsta/cli"

	"github.com/moul/advanced-ssh-config/config"
)

func cmdProxy(c *cli.Context) {
	if len(c.Args()) < 1 {
		os.Exit(1)
	}

	dest := c.Args()[0]

	conf, err := config.Open()
	if err != nil {
		panic(err)
	}

	// Get host configuration
	host, err := conf.GetHost(dest)
	if err != nil {
		panic(err)
	}

	// Dial
	var port uint
	if c.Int("port") > 0 {
		port = uint(c.Int("port"))
	} else {
		port = host.Port
	}
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host.Host, port))
	if err != nil {
		panic(err)
	}

	defer conn.Close()

	fmt.Fprintf(os.Stderr, "Connected to %s:%d\n", host.Host, host.Port)

	// Create Stdio pipes
	go func() {
		_, err := io.Copy(conn, os.Stdin)
		if err != nil {
			panic(err)
		}
	}()
	go func() {
		_, err := io.Copy(os.Stderr, conn)
		if err != nil {
			panic(err)
		}
	}()
	_, err = io.Copy(os.Stdout, conn)
	if err != nil {
		panic(err)
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/util"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/urfave/cli"
	"net"
	"strings"
)

// ProviderFunc is the function type that can be passed to With()
type ProviderFunc func(*Context) error

// With is a convenience function for making cli.Command.Actions that sets up a Context, runs all the providers, cleans up afterward and returns errors from the actions if there is one
func With(providers ...ProviderFunc) func(c *cli.Context) error {
	return func(cliContext *cli.Context) error {
		c := Context{Context: cliContext}
		err := foldProviders(&c, providers...)
		cleanup(&c)
		return err
	}
}

// cleanup resets the value of special flags between invocations of global.App.Run so that the tests pass.
// This is needed because the init() functions are only executed once during the testing cycle.
// Outside of the tests, global.App.Run is only called once before the program closes.
func cleanup(c *Context) {
	ips, ok := c.Context.Generic("ip").(*util.IPFlag)
	if ok {
		*ips = make([]net.IP, 0)
	}
	disc, ok := c.Context.Generic("disc").(*util.DiscSpecFlag)
	if ok {
		*disc = make([]brain.Disc, 0)
	}
	size, ok := c.Context.Generic("memory").(*util.SizeSpecFlag)
	if ok {
		*size = 0
	}
	server, ok := c.Context.Generic("server").(*VirtualMachineNameFlag)
	if ok {
		*server = VirtualMachineNameFlag{}
	}
	server, ok = c.Context.Generic("from").(*VirtualMachineNameFlag)
	if ok {
		*server = VirtualMachineNameFlag{}
	}
	server, ok = c.Context.Generic("to").(*VirtualMachineNameFlag)
	if ok {
		*server = VirtualMachineNameFlag{}
	}
	group, ok := c.Context.Generic("group").(*GroupNameFlag)
	if ok {
		*group = GroupNameFlag{}
	}
}

// foldProviders runs all the providers with the given context, stopping if there's an error
func foldProviders(c *Context, providers ...ProviderFunc) (err error) {
	for _, provider := range providers {
		err = provider(c)
		if err != nil {
			return
		}
	}
	return
}

// OptionalArgs takes a list of flag names. For each flag name it attempts to read the next arg and set the flag with the corresponding name.
// for instance:
// OptionalArgs("server", "disc", "size")
// will attempt to read 3 arguments, setting the "server" flag to the first, "disc" to the 2nd, "size" to the third.
func OptionalArgs(args ...string) ProviderFunc {
	return func(c *Context) error {
		for _, name := range args {
			value, err := c.NextArg()
			if err != nil {
				// if c.NextArg errors that means there aren't more arguments
				// so we just return nil - returning an error would stop the execution of the action.
				return nil
			}
			err = c.Context.Set(name, value)
			if err != nil {
				return err
			}
		}
		return nil
	}
}

// JoinArgs is like OptionalArgs, but reads up to n arguments joined with spaces and sets the one named flag.
// if n is not set, reads all the remaining arguments.
func JoinArgs(flagName string, n ...int) ProviderFunc {
	return func(c *Context) (err error) {
		toRead := len(c.Args())
		if len(n) > 0 {
			toRead = n[0]
		}

		value := make([]string, 0, toRead)
		for i := 0; i < toRead; i++ {
			arg, err := c.NextArg()
			if err != nil {
				// don't return the error - just means we ran out of arguments to slurp
				break
			}
			value = append(value, arg)
		}
		err = c.Context.Set(flagName, strings.Join(value, " "))
		return

	}
}

func isIn(needle string, haystack []string) bool {
	for _, str := range haystack {
		if needle == str {
			return true
		}
	}
	return false
}

func flagValueIsOK(c *Context, flag cli.Flag) bool {
	switch realFlag := flag.(type) {
	case cli.GenericFlag:
		switch value := realFlag.Value.(type) {
		case *VirtualMachineNameFlag:
			return value.VirtualMachine != "" && value.Group != "" && value.Account != ""
		case *GroupNameFlag:
			return value.Group != "" && value.Account != ""
		case *AccountNameFlag:
			return *value != ""
		case *util.SizeSpecFlag:
			return *value != 0
		case *PrivilegeFlag:
			return value.Username != "" && value.Level != ""
		}
	case cli.StringFlag:
		return c.String(realFlag.Name) != ""
	case cli.IntFlag:
		return c.Int(realFlag.Name) != 0
	}
	return true
}

// RequiredFlags makes sure that the named flags are not their zero-values.
// (or that VirtualMachineName / GroupName flags have the full complement of values needed)
func RequiredFlags(flagNames ...string) ProviderFunc {
	return func(c *Context) (err error) {
		for _, flag := range c.Context.Command.Flags {
			if isIn(flag.GetName(), flagNames) && !flagValueIsOK(c, flag) {
				return fmt.Errorf("--%s not set (or should not be blank/zero)", flag.GetName())
			}
		}
		return nil
	}
}

// AccountProvider gets an account name from a flag, then the account details from the API, then stitches it to the context
func AccountProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		err = AuthProvider(c)
		if err != nil {
			return
		}
		c.Account, err = global.Client.GetAccount(c.String(flagName))
		return
	}
}

// AuthProvider makes sure authentication has been successfully completed, attempting it if necessary.
func AuthProvider(c *Context) (err error) {
	if !c.Authed {
		err = EnsureAuth()
		if err != nil {
			return
		}
	}
	c.Authed = true
	return
}

// DiscProvider gets a VirtualMachineName from a flag and a disc from another, then gets the named Disc from the brain and attaches it to the Context.
func DiscProvider(vmFlagName, discFlagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.Group != nil {
			return
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}

		vmName := c.VirtualMachineName(vmFlagName)
		discLabel := c.String(discFlagName)
		c.Disc, err = global.Client.GetDisc(&vmName, discLabel)
		return
	}
}

// DefinitionsProvider gets the Definitions from the brain and attaches them to the Context.
func DefinitionsProvider(c *Context) (err error) {
	if c.Definitions != nil {
		return
	}
	c.Definitions, err = global.Client.ReadDefinitions()
	return
}

// GroupProvider gets a GroupName from a flag, then gets the named Group from the brain and attaches it to the Context.
func GroupProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.Group != nil {
			return
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}

		groupName := c.GroupName(flagName)
		c.Group, err = global.Client.GetGroup(&groupName)
		return
	}
}

// normalisePrivilegeLevel makes sure the level provided is actually a valid PrivilegeLevel and provides a couple of aliases.
func normalisePrivilegeLevel(l brain.PrivilegeLevel) (level brain.PrivilegeLevel, ok bool) {
	level = brain.PrivilegeLevel(strings.ToLower(string(l)))
	switch level {
	case "cluster_admin", "account_admin", "group_admin", "vm_admin", "vm_console":
		ok = true
	case "server_admin", "server_console":
		level = brain.PrivilegeLevel(strings.Replace(string(level), "server", "vm", 1))
		ok = true
	case "console":
		level = "vm_console"
		ok = true
	}
	return
}

// PrivilegeProvider gets the named PrivilegeFlag from the context, then resolves its target to an ID if needed to create a brain.Privilege, then attaches that to the context
func PrivilegeProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		pf := c.PrivilegeFlag(flagName)
		level, ok := normalisePrivilegeLevel(pf.Level)
		if !ok && !c.Bool("force") {
			return fmt.Errorf("Unexpected privilege level '%s' - expecting account_admin, group_admin, vm_admin or vm_console")
		}
		c.Privilege = brain.Privilege{
			Username: pf.Username,
			Level:    level,
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}
		switch strings.SplitN(string(c.Privilege.Level), "_", 2)[0] {
		case "vm":
			var vm *brain.VirtualMachine
			vm, err = global.Client.GetVirtualMachine(pf.VirtualMachineName)
			c.Privilege.VirtualMachineID = vm.ID
		case "group":
			var group *brain.Group
			group, err = global.Client.GetGroup(pf.GroupName)
			c.Privilege.GroupID = group.ID
		case "account":
			var acc *lib.Account
			acc, err = global.Client.GetAccount(pf.AccountName)
			c.Privilege.AccountID = acc.BrainID
		}
		return
	}
}

// UserProvider gets a username from the given flag, then gets the corresponding User from the brain, and attaches it to the Context.
func UserProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.User != nil {
			return
		}
		user := c.String(flagName)
		if user != "" {
			user = global.Config.GetIgnoreErr("user")
		}
		if err = AuthProvider(c); err != nil {
			return
		}
		c.User, err = global.Client.GetUser(user)
		return
	}
}

// VirtualMachineProvider gets a VirtualMachineName from a flag, then gets the named VirtualMachine from the brain and attaches it to the Context.
func VirtualMachineProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.VirtualMachine != nil {
			return
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}
		vmName := c.VirtualMachineName(flagName)
		c.VirtualMachine, err = global.Client.GetVirtualMachine(&vmName)
		return
	}
}
<commit_msg>Fix fmt.Errorf in with.go<commit_after>package main

import (
	"fmt"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/util"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/urfave/cli"
	"net"
	"strings"
)

// ProviderFunc is the function type that can be passed to With()
type ProviderFunc func(*Context) error

// With is a convenience function for making cli.Command.Actions that sets up a Context, runs all the providers, cleans up afterward and returns errors from the actions if there is one
func With(providers ...ProviderFunc) func(c *cli.Context) error {
	return func(cliContext *cli.Context) error {
		c := Context{Context: cliContext}
		err := foldProviders(&c, providers...)
		cleanup(&c)
		return err
	}
}

// cleanup resets the value of special flags between invocations of global.App.Run so that the tests pass.
// This is needed because the init() functions are only executed once during the testing cycle.
// Outside of the tests, global.App.Run is only called once before the program closes.
func cleanup(c *Context) {
	ips, ok := c.Context.Generic("ip").(*util.IPFlag)
	if ok {
		*ips = make([]net.IP, 0)
	}
	disc, ok := c.Context.Generic("disc").(*util.DiscSpecFlag)
	if ok {
		*disc = make([]brain.Disc, 0)
	}
	size, ok := c.Context.Generic("memory").(*util.SizeSpecFlag)
	if ok {
		*size = 0
	}
	server, ok := c.Context.Generic("server").(*VirtualMachineNameFlag)
	if ok {
		*server = VirtualMachineNameFlag{}
	}
	server, ok = c.Context.Generic("from").(*VirtualMachineNameFlag)
	if ok {
		*server = VirtualMachineNameFlag{}
	}
	server, ok = c.Context.Generic("to").(*VirtualMachineNameFlag)
	if ok {
		*server = VirtualMachineNameFlag{}
	}
	group, ok := c.Context.Generic("group").(*GroupNameFlag)
	if ok {
		*group = GroupNameFlag{}
	}
}

// foldProviders runs all the providers with the given context, stopping if there's an error
func foldProviders(c *Context, providers ...ProviderFunc) (err error) {
	for _, provider := range providers {
		err = provider(c)
		if err != nil {
			return
		}
	}
	return
}

// OptionalArgs takes a list of flag names. For each flag name it attempts to read the next arg and set the flag with the corresponding name.
// for instance:
// OptionalArgs("server", "disc", "size")
// will attempt to read 3 arguments, setting the "server" flag to the first, "disc" to the 2nd, "size" to the third.
func OptionalArgs(args ...string) ProviderFunc {
	return func(c *Context) error {
		for _, name := range args {
			value, err := c.NextArg()
			if err != nil {
				// if c.NextArg errors that means there aren't more arguments
				// so we just return nil - returning an error would stop the execution of the action.
				return nil
			}
			err = c.Context.Set(name, value)
			if err != nil {
				return err
			}
		}
		return nil
	}
}

// JoinArgs is like OptionalArgs, but reads up to n arguments joined with spaces and sets the one named flag.
// if n is not set, reads all the remaining arguments.
func JoinArgs(flagName string, n ...int) ProviderFunc {
	return func(c *Context) (err error) {
		toRead := len(c.Args())
		if len(n) > 0 {
			toRead = n[0]
		}

		value := make([]string, 0, toRead)
		for i := 0; i < toRead; i++ {
			arg, err := c.NextArg()
			if err != nil {
				// don't return the error - just means we ran out of arguments to slurp
				break
			}
			value = append(value, arg)
		}
		err = c.Context.Set(flagName, strings.Join(value, " "))
		return

	}
}

func isIn(needle string, haystack []string) bool {
	for _, str := range haystack {
		if needle == str {
			return true
		}
	}
	return false
}

func flagValueIsOK(c *Context, flag cli.Flag) bool {
	switch realFlag := flag.(type) {
	case cli.GenericFlag:
		switch value := realFlag.Value.(type) {
		case *VirtualMachineNameFlag:
			return value.VirtualMachine != "" && value.Group != "" && value.Account != ""
		case *GroupNameFlag:
			return value.Group != "" && value.Account != ""
		case *AccountNameFlag:
			return *value != ""
		case *util.SizeSpecFlag:
			return *value != 0
		case *PrivilegeFlag:
			return value.Username != "" && value.Level != ""
		}
	case cli.StringFlag:
		return c.String(realFlag.Name) != ""
	case cli.IntFlag:
		return c.Int(realFlag.Name) != 0
	}
	return true
}

// RequiredFlags makes sure that the named flags are not their zero-values.
// (or that VirtualMachineName / GroupName flags have the full complement of values needed)
func RequiredFlags(flagNames ...string) ProviderFunc {
	return func(c *Context) (err error) {
		for _, flag := range c.Context.Command.Flags {
			if isIn(flag.GetName(), flagNames) && !flagValueIsOK(c, flag) {
				return fmt.Errorf("--%s not set (or should not be blank/zero)", flag.GetName())
			}
		}
		return nil
	}
}

// AccountProvider gets an account name from a flag, then the account details from the API, then stitches it to the context
func AccountProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		err = AuthProvider(c)
		if err != nil {
			return
		}
		c.Account, err = global.Client.GetAccount(c.String(flagName))
		return
	}
}

// AuthProvider makes sure authentication has been successfully completed, attempting it if necessary.
func AuthProvider(c *Context) (err error) {
	if !c.Authed {
		err = EnsureAuth()
		if err != nil {
			return
		}
	}
	c.Authed = true
	return
}

// DiscProvider gets a VirtualMachineName from a flag and a disc from another, then gets the named Disc from the brain and attaches it to the Context.
func DiscProvider(vmFlagName, discFlagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.Group != nil {
			return
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}

		vmName := c.VirtualMachineName(vmFlagName)
		discLabel := c.String(discFlagName)
		c.Disc, err = global.Client.GetDisc(&vmName, discLabel)
		return
	}
}

// DefinitionsProvider gets the Definitions from the brain and attaches them to the Context.
func DefinitionsProvider(c *Context) (err error) {
	if c.Definitions != nil {
		return
	}
	c.Definitions, err = global.Client.ReadDefinitions()
	return
}

// GroupProvider gets a GroupName from a flag, then gets the named Group from the brain and attaches it to the Context.
func GroupProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.Group != nil {
			return
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}

		groupName := c.GroupName(flagName)
		c.Group, err = global.Client.GetGroup(&groupName)
		return
	}
}

// normalisePrivilegeLevel makes sure the level provided is actually a valid PrivilegeLevel and provides a couple of aliases.
func normalisePrivilegeLevel(l brain.PrivilegeLevel) (level brain.PrivilegeLevel, ok bool) {
	level = brain.PrivilegeLevel(strings.ToLower(string(l)))
	switch level {
	case "cluster_admin", "account_admin", "group_admin", "vm_admin", "vm_console":
		ok = true
	case "server_admin", "server_console":
		level = brain.PrivilegeLevel(strings.Replace(string(level), "server", "vm", 1))
		ok = true
	case "console":
		level = "vm_console"
		ok = true
	}
	return
}

// PrivilegeProvider gets the named PrivilegeFlag from the context, then resolves its target to an ID if needed to create a brain.Privilege, then attaches that to the context
func PrivilegeProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		pf := c.PrivilegeFlag(flagName)
		level, ok := normalisePrivilegeLevel(pf.Level)
		if !ok && !c.Bool("force") {
			return fmt.Errorf("Unexpected privilege level '%s' - expecting account_admin, group_admin, vm_admin or vm_console", pf.Level)
		}
		c.Privilege = brain.Privilege{
			Username: pf.Username,
			Level:    level,
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}
		switch strings.SplitN(string(c.Privilege.Level), "_", 2)[0] {
		case "vm":
			var vm *brain.VirtualMachine
			vm, err = global.Client.GetVirtualMachine(pf.VirtualMachineName)
			c.Privilege.VirtualMachineID = vm.ID
		case "group":
			var group *brain.Group
			group, err = global.Client.GetGroup(pf.GroupName)
			c.Privilege.GroupID = group.ID
		case "account":
			var acc *lib.Account
			acc, err = global.Client.GetAccount(pf.AccountName)
			c.Privilege.AccountID = acc.BrainID
		}
		return
	}
}

// UserProvider gets a username from the given flag, then gets the corresponding User from the brain, and attaches it to the Context.
func UserProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.User != nil {
			return
		}
		user := c.String(flagName)
		if user != "" {
			user = global.Config.GetIgnoreErr("user")
		}
		if err = AuthProvider(c); err != nil {
			return
		}
		c.User, err = global.Client.GetUser(user)
		return
	}
}

// VirtualMachineProvider gets a VirtualMachineName from a flag, then gets the named VirtualMachine from the brain and attaches it to the Context.
func VirtualMachineProvider(flagName string) ProviderFunc {
	return func(c *Context) (err error) {
		if c.VirtualMachine != nil {
			return
		}
		err = AuthProvider(c)
		if err != nil {
			return
		}
		vmName := c.VirtualMachineName(flagName)
		c.VirtualMachine, err = global.Client.GetVirtualMachine(&vmName)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"image/png"
	"math/rand"
	"os"
	"time"

	"github.com/iopred/comicgen"
)

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

	c, _ := comicgen.NewComicGen("arial")

	i, _ := c.MakeComic(&comicgen.Script{
		Messages: []*comicgen.Message{
			{
				Speaker: 0,
				Text:    "Hello World!",
			},
			{
				Speaker: 1,
				Text:    "🌝",
			},
			{
				Speaker: 1,
				Text:    "Typing indicators are the best 🌝",
			},
			{
				Speaker: 0,
				Text:    "This is a story all about how my life got flip-turned upside down and I liked to take a minute and sit right there and tell you how I became the prince of a town called Bel Air",
			},
		},
		Author: "iopred",
		Avatars: map[int]string{
			0: "https://avatars0.githubusercontent.com/u/1529218?v=3&s=460",
		},
	})

	f, _ := os.Create("comic.png")

	w := bufio.NewWriter(f)

	png.Encode(w, i)

	w.Flush()
}
<commit_msg>Fix example.<commit_after>package main

import (
	"bufio"
	"image/png"
	"math/rand"
	"os"
	"time"

	"github.com/iopred/comicgen"
)

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

	c := comicgen.NewComicGen("arial")

	i, _ := c.MakeComic(&comicgen.Script{
		Messages: []*comicgen.Message{
			{
				Speaker: 0,
				Text:    "Hello World!",
			},
			{
				Speaker: 1,
				Text:    "🌝",
			},
			{
				Speaker: 1,
				Text:    "Typing indicators are the best 🌝",
			},
			{
				Speaker: 0,
				Text:    "This is a story all about how my life got flip-turned upside down and I liked to take a minute and sit right there and tell you how I became the prince of a town called Bel Air",
			},
		},
		Author: "iopred",
		Avatars: map[int]string{
			0: "https://avatars0.githubusercontent.com/u/1529218?v=3&s=460",
		},
	})

	f, _ := os.Create("comic.png")

	w := bufio.NewWriter(f)

	png.Encode(w, i)

	w.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/cli/command/commands"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
	opts := cliflags.NewClientOptions()
	var flags *pflag.FlagSet

	cmd := &cobra.Command{
		Use:              "docker [OPTIONS] COMMAND [ARG...]",
		Short:            "A self-sufficient runtime for containers",
		SilenceUsage:     true,
		SilenceErrors:    true,
		TraverseChildren: true,
		Args:             noArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			if opts.Version {
				showVersion()
				return nil
			}
			return dockerCli.ShowHelp(cmd, args)
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// daemon command is special, we redirect directly to another binary
			if cmd.Name() == "daemon" {
				return nil
			}
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			return dockerCli.Initialize(opts)
		},
	}
	cli.SetupRootCommand(cmd)

	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
		if dockerCli.Client() == nil {
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			dockerCli.Initialize(opts)
		}

		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())

		if err := ccmd.Help(); err != nil {
			ccmd.Println(err)
		}
	})

	flags = cmd.Flags()
	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
	opts.Common.InstallFlags(flags)

	cmd.SetOutput(dockerCli.Out())
	cmd.AddCommand(newDaemonCommand())
	commands.AddCommands(cmd, dockerCli)

	return cmd
}

func noArgs(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return nil
	}
	return fmt.Errorf(
		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}

func dockerPreRun(opts *cliflags.ClientOptions) {
	cliflags.SetLogLevel(opts.Common.LogLevel)

	if opts.ConfigDir != "" {
		cliconfig.SetConfigDir(opts.ConfigDir)
	}

	if opts.Common.Debug {
		utils.EnableDebug()
	}
}

func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		// hide experimental flags
		if !hasExperimental {
			if _, ok := f.Annotations["experimental"]; ok {
				f.Hidden = true
			}
		}

		// hide flags not supported by the server
		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
			f.Hidden = true
		}

	})

	for _, subcmd := range cmd.Commands() {
		// hide experimental subcommands
		if !hasExperimental {
			if _, ok := subcmd.Tags["experimental"]; ok {
				subcmd.Hidden = true
			}
		}

		// hide subcommands not supported by the server
		if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
			subcmd.Hidden = true
		}
	}
}
<commit_msg>error on cli when trying to use experimental feature with non experimental daemon<commit_after>package main

import (
	"errors"
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/cli/command/commands"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
	opts := cliflags.NewClientOptions()
	var flags *pflag.FlagSet

	cmd := &cobra.Command{
		Use:              "docker [OPTIONS] COMMAND [ARG...]",
		Short:            "A self-sufficient runtime for containers",
		SilenceUsage:     true,
		SilenceErrors:    true,
		TraverseChildren: true,
		Args:             noArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			if opts.Version {
				showVersion()
				return nil
			}
			return dockerCli.ShowHelp(cmd, args)
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// daemon command is special, we redirect directly to another binary
			if cmd.Name() == "daemon" {
				return nil
			}
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			if err := dockerCli.Initialize(opts); err != nil {
				return err
			}
			return isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())
		},
	}
	cli.SetupRootCommand(cmd)

	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
		if dockerCli.Client() == nil { // when using --help, PersistenPreRun is not called, so initialization is needed.
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			dockerCli.Initialize(opts)
		}

		if err := isSupported(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()); err != nil {
			ccmd.Println(err)
			return
		}

		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())

		if err := ccmd.Help(); err != nil {
			ccmd.Println(err)
		}
	})

	flags = cmd.Flags()
	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
	opts.Common.InstallFlags(flags)

	cmd.SetOutput(dockerCli.Out())
	cmd.AddCommand(newDaemonCommand())
	commands.AddCommands(cmd, dockerCli)

	return cmd
}

func noArgs(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return nil
	}
	return fmt.Errorf(
		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}

func dockerPreRun(opts *cliflags.ClientOptions) {
	cliflags.SetLogLevel(opts.Common.LogLevel)

	if opts.ConfigDir != "" {
		cliconfig.SetConfigDir(opts.ConfigDir)
	}

	if opts.Common.Debug {
		utils.EnableDebug()
	}
}

func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		// hide experimental flags
		if !hasExperimental {
			if _, ok := f.Annotations["experimental"]; ok {
				f.Hidden = true
			}
		}

		// hide flags not supported by the server
		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
			f.Hidden = true
		}

	})

	for _, subcmd := range cmd.Commands() {
		// hide experimental subcommands
		if !hasExperimental {
			if _, ok := subcmd.Tags["experimental"]; ok {
				subcmd.Hidden = true
			}
		}

		// hide subcommands not supported by the server
		if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
			subcmd.Hidden = true
		}
	}
}

func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool) error {
	if !hasExperimental {
		if _, ok := cmd.Tags["experimental"]; ok {
			return errors.New("only supported with experimental daemon")
		}
	}

	if cmdVersion, ok := cmd.Tags["version"]; ok && versions.LessThan(clientVersion, cmdVersion) {
		return fmt.Errorf("only supported with daemon version >= %s", cmdVersion)
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/exercism/cli/config"
	"github.com/stretchr/testify/assert"
)

const payloadTemplate = `
{
	"solution": {
		"id": "bogus-id",
		"user": {
			"handle": "alice",
			"is_requester": true
		},
		"exercise": {
			"id": "bogus-exercise",
			"instructions_url": "http://example.com/bogus-exercise",
			"auto_approve": false,
			"track": {
				"id": "bogus-track",
				"language": "Bogus Language"
			}
		},
		"file_download_base_url": "%s",
		"files": [
		"%s",
		"%s",
		"%s"
		],
		"iteration": {
			"submitted_at": "2017-08-21t10:11:12.130z"
		}
	}
}
`

func TestDownload(t *testing.T) {
	oldOut := Out
	oldErr := Err
	Out = ioutil.Discard
	Err = ioutil.Discard
	defer func() {
		Out = oldOut
		Err = oldErr
	}()

	cmdTest := &CommandTest{
		Cmd:    downloadCmd,
		InitFn: initDownloadCmd,
		Args:   []string{"fakeapp", "download", "--exercise=bogus-exercise"},
	}
	cmdTest.Setup(t)
	defer cmdTest.Teardown(t)

	mockServer := makeMockServer()
	defer mockServer.Close()

	err := writeFakeUserConfigSettings(cmdTest.TmpDir, mockServer.URL)
	assert.NoError(t, err)

	testCases := []struct {
		desc     string
		path     string
		contents string
	}{
		{
			desc:     "It should download a file.",
			path:     filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", "file-1.txt"),
			contents: "this is file 1",
		},
		{
			desc:     "It should download a file in a subdir.",
			path:     filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", "subdir", "file-2.txt"),
			contents: "this is file 2",
		},
		{
			desc:     "It creates the .solution.json file.",
			path:     filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", ".solution.json"),
			contents: `{"track":"bogus-track","exercise":"bogus-exercise","id":"bogus-id","url":"","handle":"alice","is_requester":true,"auto_approve":false}`,
		},
	}

	cmdTest.App.Execute()

	for _, tc := range testCases {
		t.Run(tc.desc, func(t *testing.T) {
			b, err := ioutil.ReadFile(tc.path)
			assert.NoError(t, err)
			assert.Equal(t, tc.contents, string(b))
		})
	}

	path := filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", "file-3.txt")
	_, err = os.Lstat(path)
	assert.True(t, os.IsNotExist(err), "It should not write the file if empty.")
}

func writeFakeUserConfigSettings(tmpDirPath, serverURL string) error {
	userCfg := config.NewEmptyUserConfig()
	userCfg.Workspace = tmpDirPath
	userCfg.APIBaseURL = serverURL
	return userCfg.Write()
}

func makeMockServer() *httptest.Server {
	mux := http.NewServeMux()
	server := httptest.NewServer(mux)

	path1 := "file-1.txt"
	mux.HandleFunc("/"+path1, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "this is file 1")
	})

	path2 := "subdir/file-2.txt"
	mux.HandleFunc("/"+path2, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "this is file 2")
	})

	path3 := "file-3.txt"
	mux.HandleFunc("/"+path3, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "")
	})

	payloadBody := fmt.Sprintf(payloadTemplate, server.URL+"/", path1, path2, path3)
	mux.HandleFunc("/solutions/latest", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, payloadBody)
	})

	return server

}

func TestDownloadArgs(t *testing.T) {
	tests := []struct {
		args          []string
		expectedError string
	}{
		{
			args:          []string{"bogus"}, // providing just an exercise slug without the flag
			expectedError: "need an --exercise name or a solution --uuid",
		},
		{
			args:          []string{""}, // providing no args
			expectedError: "need an --exercise name or a solution --uuid",
		},
	}

	for _, test := range tests {
		cmdTest := &CommandTest{
			Cmd:    downloadCmd,
			InitFn: initDownloadCmd,
			Args:   append([]string{"fakeapp", "download"}, test.args...),
		}
		cmdTest.Setup(t)
		defer cmdTest.Teardown(t)
		err := cmdTest.App.Execute()

		assert.EqualError(t, err, test.expectedError)
	}
}
<commit_msg>Silence test errors for download command<commit_after>package cmd

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/exercism/cli/config"
	"github.com/stretchr/testify/assert"
)

const payloadTemplate = `
{
	"solution": {
		"id": "bogus-id",
		"user": {
			"handle": "alice",
			"is_requester": true
		},
		"exercise": {
			"id": "bogus-exercise",
			"instructions_url": "http://example.com/bogus-exercise",
			"auto_approve": false,
			"track": {
				"id": "bogus-track",
				"language": "Bogus Language"
			}
		},
		"file_download_base_url": "%s",
		"files": [
		"%s",
		"%s",
		"%s"
		],
		"iteration": {
			"submitted_at": "2017-08-21t10:11:12.130z"
		}
	}
}
`

func TestDownload(t *testing.T) {
	oldOut := Out
	oldErr := Err
	Out = ioutil.Discard
	Err = ioutil.Discard
	defer func() {
		Out = oldOut
		Err = oldErr
	}()

	cmdTest := &CommandTest{
		Cmd:    downloadCmd,
		InitFn: initDownloadCmd,
		Args:   []string{"fakeapp", "download", "--exercise=bogus-exercise"},
	}
	cmdTest.Setup(t)
	defer cmdTest.Teardown(t)

	mockServer := makeMockServer()
	defer mockServer.Close()

	err := writeFakeUserConfigSettings(cmdTest.TmpDir, mockServer.URL)
	assert.NoError(t, err)

	testCases := []struct {
		desc     string
		path     string
		contents string
	}{
		{
			desc:     "It should download a file.",
			path:     filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", "file-1.txt"),
			contents: "this is file 1",
		},
		{
			desc:     "It should download a file in a subdir.",
			path:     filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", "subdir", "file-2.txt"),
			contents: "this is file 2",
		},
		{
			desc:     "It creates the .solution.json file.",
			path:     filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", ".solution.json"),
			contents: `{"track":"bogus-track","exercise":"bogus-exercise","id":"bogus-id","url":"","handle":"alice","is_requester":true,"auto_approve":false}`,
		},
	}

	cmdTest.App.Execute()

	for _, tc := range testCases {
		t.Run(tc.desc, func(t *testing.T) {
			b, err := ioutil.ReadFile(tc.path)
			assert.NoError(t, err)
			assert.Equal(t, tc.contents, string(b))
		})
	}

	path := filepath.Join(cmdTest.TmpDir, "bogus-track", "bogus-exercise", "file-3.txt")
	_, err = os.Lstat(path)
	assert.True(t, os.IsNotExist(err), "It should not write the file if empty.")
}

func writeFakeUserConfigSettings(tmpDirPath, serverURL string) error {
	userCfg := config.NewEmptyUserConfig()
	userCfg.Workspace = tmpDirPath
	userCfg.APIBaseURL = serverURL
	return userCfg.Write()
}

func makeMockServer() *httptest.Server {
	mux := http.NewServeMux()
	server := httptest.NewServer(mux)

	path1 := "file-1.txt"
	mux.HandleFunc("/"+path1, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "this is file 1")
	})

	path2 := "subdir/file-2.txt"
	mux.HandleFunc("/"+path2, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "this is file 2")
	})

	path3 := "file-3.txt"
	mux.HandleFunc("/"+path3, func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "")
	})

	payloadBody := fmt.Sprintf(payloadTemplate, server.URL+"/", path1, path2, path3)
	mux.HandleFunc("/solutions/latest", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, payloadBody)
	})

	return server

}

func TestDownloadArgs(t *testing.T) {
	tests := []struct {
		args          []string
		expectedError string
	}{
		{
			args:          []string{"bogus"}, // providing just an exercise slug without the flag
			expectedError: "need an --exercise name or a solution --uuid",
		},
		{
			args:          []string{""}, // providing no args
			expectedError: "need an --exercise name or a solution --uuid",
		},
	}

	for _, test := range tests {
		cmdTest := &CommandTest{
			Cmd:    downloadCmd,
			InitFn: initDownloadCmd,
			Args:   append([]string{"fakeapp", "download"}, test.args...),
		}
		cmdTest.Setup(t)
		cmdTest.App.SetOutput(ioutil.Discard)
		defer cmdTest.Teardown(t)
		err := cmdTest.App.Execute()

		assert.EqualError(t, err, test.expectedError)
	}
}
<|endoftext|>