<commit_before>package resource

import (
	"bytes"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/weaveworks/flux"
	"github.com/weaveworks/flux/cluster/kubernetes/testfiles"
	"github.com/weaveworks/flux/resource"
)

// for convenience
func base(source, kind, namespace, name string) baseObject {
	b := baseObject{source: source, Kind: kind}
	b.Meta.Namespace = namespace
	b.Meta.Name = name
	return b
}

func TestParseEmpty(t *testing.T) {
	doc := ``

	objs, err := ParseMultidoc([]byte(doc), "test")
	if err != nil {
		t.Error(err)
	}
	if len(objs) != 0 {
		t.Errorf("expected empty set; got %#v", objs)
	}
}

func TestParseSome(t *testing.T) {
	docs := `---
kind: Deployment
metadata:
  name: b-deployment
  namespace: b-namespace
---
kind: Deployment
metadata:
  name: a-deployment
`
	objs, err := ParseMultidoc([]byte(docs), "test")
	if err != nil {
		t.Error(err)
	}

	objA := base("test", "Deployment", "", "a-deployment")
	objB := base("test", "Deployment", "b-namespace", "b-deployment")
	expected := map[string]resource.Resource{
		objA.ResourceID().String(): &Deployment{baseObject: objA},
		objB.ResourceID().String(): &Deployment{baseObject: objB},
	}

	for id, obj := range expected {
		// Remove the bytes, so we can compare
		if !reflect.DeepEqual(obj, debyte(objs[id])) {
			t.Errorf("At %+v expected:\n%#v\ngot:\n%#v", id, obj, objs[id])
		}
	}
}

func TestParseSomeWithComment(t *testing.T) {
	docs := `# some random comment
---
kind: Deployment
metadata:
  name: b-deployment
  namespace: b-namespace
---
kind: Deployment
metadata:
  name: a-deployment
`
	objs, err := ParseMultidoc([]byte(docs), "test")
	if err != nil {
		t.Error(err)
	}

	objA := base("test", "Deployment", "", "a-deployment")
	objB := base("test", "Deployment", "b-namespace", "b-deployment")
	expected := map[string]resource.Resource{
		objA.ResourceID().String(): &Deployment{baseObject: objA},
		objB.ResourceID().String(): &Deployment{baseObject: objB},
	}
	expectedL := len(expected)

	if len(objs) != expectedL {
		t.Errorf("expected %d objects from yaml source\n%s\n, got result: %d", expectedL, docs, len(objs))
	}

	for id, obj := range expected {
		// Remove the bytes, so we can compare
		if !reflect.DeepEqual(obj, debyte(objs[id])) {
			t.Errorf("At %+v expected:\n%#v\ngot:\n%#v", id, obj, objs[id])
		}
	}
}

func TestParseSomeLong(t *testing.T) {
	doc := `---
kind: ConfigMap
metadata:
  name: bigmap
data:
  bigdata: |
`
	buffer := bytes.NewBufferString(doc)
	line := "    The quick brown fox jumps over the lazy dog.\n"
	for buffer.Len()+len(line) < 1024*1024 {
		buffer.WriteString(line)
	}

	_, err := ParseMultidoc(buffer.Bytes(), "test")
	if err != nil {
		t.Error(err)
	}
}

func TestParseBoundaryMarkers(t *testing.T) {
	doc := `---
kind: ConfigMap
metadata:
  name: bigmap
---
...
---
...
---
...
---
...
`
	buffer := bytes.NewBufferString(doc)

	resources, err := ParseMultidoc(buffer.Bytes(), "test")
	assert.NoError(t, err)
	assert.Len(t, resources, 1)
}

func TestParseCronJob(t *testing.T) {
	doc := `---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  namespace: default
  name: weekly-curl-homepage
spec:
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: weekly-curl-homepage
            image: centos:7 # Has curl installed by default
`
	objs, err := ParseMultidoc([]byte(doc), "test")
	assert.NoError(t, err)

	obj, ok := objs["default:cronjob/weekly-curl-homepage"]
	assert.True(t, ok)
	cj, ok := obj.(*CronJob)
	assert.True(t, ok)

	containers := cj.Spec.JobTemplate.Spec.Template.Spec.Containers
	if assert.Len(t, containers, 1) {
		assert.Equal(t, "centos:7", containers[0].Image)
		assert.Equal(t, "weekly-curl-homepage", containers[0].Name)
	}
}

func TestUnmarshalList(t *testing.T) {
	doc := `---
kind: List
metadata:
  name: list
items:
- kind: Deployment
  metadata:
    name: foo
    namespace: ns
- kind: Service
  metadata:
    name: bar
    namespace: ns
`
	res, err := unmarshalObject("", []byte(doc))
	if err != nil {
		t.Fatal(err)
	}
	list, ok := res.(*List)
	if !ok {
		t.Fatal("did not parse as a list")
	}
	if len(list.Items) != 2 {
		t.Fatalf("expected two items, got %+v", list.Items)
	}
	for i, id := range []flux.ResourceID{
		flux.MustParseResourceID("ns:deployment/foo"),
		flux.MustParseResourceID("ns:service/bar")} {
		if list.Items[i].ResourceID() != id {
			t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
		}
	}
}

func TestUnmarshalDeploymentList(t *testing.T) {
	doc := `---
kind: DeploymentList
metadata:
  name: list
items:
- kind: Deployment
  metadata:
    name: foo
    namespace: ns
- kind: Deployment
  metadata:
    name: bar
    namespace: ns
`
	res, err := unmarshalObject("", []byte(doc))
	if err != nil {
		t.Fatal(err)
	}
	list, ok := res.(*List)
	if !ok {
		t.Fatal("did not parse as a list")
	}
	if len(list.Items) != 2 {
		t.Fatalf("expected two items, got %+v", list.Items)
	}
	for i, id := range []flux.ResourceID{
		flux.MustParseResourceID("ns:deployment/foo"),
		flux.MustParseResourceID("ns:deployment/bar")} {
		if list.Items[i].ResourceID() != id {
			t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
		}
	}
}

func debyte(r resource.Resource) resource.Resource {
	if res, ok := r.(interface {
		debyte()
	}); ok {
		res.debyte()
	}
	return r
}

func TestLoadSome(t *testing.T) {
	dir, cleanup := testfiles.TempDir(t)
	defer cleanup()
	if err := testfiles.WriteTestFiles(dir); err != nil {
		t.Fatal(err)
	}
	objs, err := Load(dir, []string{dir})
	if err != nil {
		t.Error(err)
	}
	if len(objs) != len(testfiles.ResourceMap) {
		t.Errorf("expected %d objects from %d files, got result:\n%#v", len(testfiles.ResourceMap), len(testfiles.Files), objs)
	}
}

func TestChartTracker(t *testing.T) {
	dir, cleanup := testfiles.TempDir(t)
	defer cleanup()
	if err := testfiles.WriteTestFiles(dir); err != nil {
		t.Fatal(err)
	}

	ct, err := newChartTracker(dir)
	if err != nil {
		t.Fatal(err)
	}

	noncharts := []string{"garbage", "locked-service-deploy.yaml",
		"test", "test/test-service-deploy.yaml"}
	for _, f := range noncharts {
		fq := filepath.Join(dir, f)
		if ct.isDirChart(fq) {
			t.Errorf("%q thought to be a chart", f)
		}
		if f == "garbage" {
			continue
		}
		if m, err := Load(dir, []string{fq}); err != nil || len(m) == 0 {
			t.Errorf("Load returned 0 objs, err=%v", err)
		}
	}
	if !ct.isDirChart(filepath.Join(dir, "charts/nginx")) {
		t.Errorf("charts/nginx not recognized as chart")
	}
	if !ct.isPathInChart(filepath.Join(dir, "charts/nginx/Chart.yaml")) {
		t.Errorf("charts/nginx/Chart.yaml not recognized as in chart")
	}

	chartfiles := []string{"charts",
		"charts/nginx",
		"charts/nginx/Chart.yaml",
		"charts/nginx/values.yaml",
		"charts/nginx/templates/deployment.yaml",
	}
	for _, f := range chartfiles {
		fq := filepath.Join(dir, f)
		if m, err := Load(dir, []string{fq}); err != nil || len(m) != 0 {
			t.Errorf("%q not ignored as a chart should be", f)
		}
	}

}
<commit_msg>Add test<commit_after>package resource

import (
	"bytes"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/weaveworks/flux"
	"github.com/weaveworks/flux/cluster/kubernetes/testfiles"
	"github.com/weaveworks/flux/resource"
)

// for convenience
func base(source, kind, namespace, name string) baseObject {
	b := baseObject{source: source, Kind: kind}
	b.Meta.Namespace = namespace
	b.Meta.Name = name
	return b
}

func TestParseEmpty(t *testing.T) {
	doc := ``

	objs, err := ParseMultidoc([]byte(doc), "test")
	if err != nil {
		t.Error(err)
	}
	if len(objs) != 0 {
		t.Errorf("expected empty set; got %#v", objs)
	}
}

func TestParseSome(t *testing.T) {
	docs := `---
kind: Deployment
metadata:
  name: b-deployment
  namespace: b-namespace
---
kind: Deployment
metadata:
  name: a-deployment
`
	objs, err := ParseMultidoc([]byte(docs), "test")
	if err != nil {
		t.Error(err)
	}

	objA := base("test", "Deployment", "", "a-deployment")
	objB := base("test", "Deployment", "b-namespace", "b-deployment")
	expected := map[string]resource.Resource{
		objA.ResourceID().String(): &Deployment{baseObject: objA},
		objB.ResourceID().String(): &Deployment{baseObject: objB},
	}

	for id, obj := range expected {
		// Remove the bytes, so we can compare
		if !reflect.DeepEqual(obj, debyte(objs[id])) {
			t.Errorf("At %+v expected:\n%#v\ngot:\n%#v", id, obj, objs[id])
		}
	}
}

func TestParseSomeWithComment(t *testing.T) {
	docs := `# some random comment
---
kind: Deployment
metadata:
  name: b-deployment
  namespace: b-namespace
---
kind: Deployment
metadata:
  name: a-deployment
`
	objs, err := ParseMultidoc([]byte(docs), "test")
	if err != nil {
		t.Error(err)
	}

	objA := base("test", "Deployment", "", "a-deployment")
	objB := base("test", "Deployment", "b-namespace", "b-deployment")
	expected := map[string]resource.Resource{
		objA.ResourceID().String(): &Deployment{baseObject: objA},
		objB.ResourceID().String(): &Deployment{baseObject: objB},
	}
	expectedL := len(expected)

	if len(objs) != expectedL {
		t.Errorf("expected %d objects from yaml source\n%s\n, got result: %d", expectedL, docs, len(objs))
	}

	for id, obj := range expected {
		// Remove the bytes, so we can compare
		if !reflect.DeepEqual(obj, debyte(objs[id])) {
			t.Errorf("At %+v expected:\n%#v\ngot:\n%#v", id, obj, objs[id])
		}
	}
}

func TestParseSomeLong(t *testing.T) {
	doc := `---
kind: ConfigMap
metadata:
  name: bigmap
data:
  bigdata: |
`
	buffer := bytes.NewBufferString(doc)
	line := "    The quick brown fox jumps over the lazy dog.\n"
	for buffer.Len()+len(line) < 1024*1024 {
		buffer.WriteString(line)
	}

	_, err := ParseMultidoc(buffer.Bytes(), "test")
	if err != nil {
		t.Error(err)
	}
}

func TestParseBoundaryMarkers(t *testing.T) {
	doc := `---
kind: ConfigMap
metadata:
  name: bigmap
---
...
---
...
---
...
---
...
`
	buffer := bytes.NewBufferString(doc)

	resources, err := ParseMultidoc(buffer.Bytes(), "test")
	assert.NoError(t, err)
	assert.Len(t, resources, 1)
}

func TestParseError(t *testing.T) {
	doc := `---
kind: ConfigMap
metadata:
	name: bigmap # contains a tab at the beginning
`
	buffer := bytes.NewBufferString(doc)

	_, err := ParseMultidoc(buffer.Bytes(), "test")
	assert.Error(t, err)
}

func TestParseCronJob(t *testing.T) {
	doc := `---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  namespace: default
  name: weekly-curl-homepage
spec:
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: weekly-curl-homepage
            image: centos:7 # Has curl installed by default
`
	objs, err := ParseMultidoc([]byte(doc), "test")
	assert.NoError(t, err)

	obj, ok := objs["default:cronjob/weekly-curl-homepage"]
	assert.True(t, ok)
	cj, ok := obj.(*CronJob)
	assert.True(t, ok)

	containers := cj.Spec.JobTemplate.Spec.Template.Spec.Containers
	if assert.Len(t, containers, 1) {
		assert.Equal(t, "centos:7", containers[0].Image)
		assert.Equal(t, "weekly-curl-homepage", containers[0].Name)
	}
}

func TestUnmarshalList(t *testing.T) {
	doc := `---
kind: List
metadata:
  name: list
items:
- kind: Deployment
  metadata:
    name: foo
    namespace: ns
- kind: Service
  metadata:
    name: bar
    namespace: ns
`
	res, err := unmarshalObject("", []byte(doc))
	if err != nil {
		t.Fatal(err)
	}
	list, ok := res.(*List)
	if !ok {
		t.Fatal("did not parse as a list")
	}
	if len(list.Items) != 2 {
		t.Fatalf("expected two items, got %+v", list.Items)
	}
	for i, id := range []flux.ResourceID{
		flux.MustParseResourceID("ns:deployment/foo"),
		flux.MustParseResourceID("ns:service/bar")} {
		if list.Items[i].ResourceID() != id {
			t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
		}
	}
}

func TestUnmarshalDeploymentList(t *testing.T) {
	doc := `---
kind: DeploymentList
metadata:
  name: list
items:
- kind: Deployment
  metadata:
    name: foo
    namespace: ns
- kind: Deployment
  metadata:
    name: bar
    namespace: ns
`
	res, err := unmarshalObject("", []byte(doc))
	if err != nil {
		t.Fatal(err)
	}
	list, ok := res.(*List)
	if !ok {
		t.Fatal("did not parse as a list")
	}
	if len(list.Items) != 2 {
		t.Fatalf("expected two items, got %+v", list.Items)
	}
	for i, id := range []flux.ResourceID{
		flux.MustParseResourceID("ns:deployment/foo"),
		flux.MustParseResourceID("ns:deployment/bar")} {
		if list.Items[i].ResourceID() != id {
			t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
		}
	}
}

func debyte(r resource.Resource) resource.Resource {
	if res, ok := r.(interface {
		debyte()
	}); ok {
		res.debyte()
	}
	return r
}

func TestLoadSome(t *testing.T) {
	dir, cleanup := testfiles.TempDir(t)
	defer cleanup()
	if err := testfiles.WriteTestFiles(dir); err != nil {
		t.Fatal(err)
	}
	objs, err := Load(dir, []string{dir})
	if err != nil {
		t.Error(err)
	}
	if len(objs) != len(testfiles.ResourceMap) {
		t.Errorf("expected %d objects from %d files, got result:\n%#v", len(testfiles.ResourceMap), len(testfiles.Files), objs)
	}
}

func TestChartTracker(t *testing.T) {
	dir, cleanup := testfiles.TempDir(t)
	defer cleanup()
	if err := testfiles.WriteTestFiles(dir); err != nil {
		t.Fatal(err)
	}

	ct, err := newChartTracker(dir)
	if err != nil {
		t.Fatal(err)
	}

	noncharts := []string{"garbage", "locked-service-deploy.yaml",
		"test", "test/test-service-deploy.yaml"}
	for _, f := range noncharts {
		fq := filepath.Join(dir, f)
		if ct.isDirChart(fq) {
			t.Errorf("%q thought to be a chart", f)
		}
		if f == "garbage" {
			continue
		}
		if m, err := Load(dir, []string{fq}); err != nil || len(m) == 0 {
			t.Errorf("Load returned 0 objs, err=%v", err)
		}
	}
	if !ct.isDirChart(filepath.Join(dir, "charts/nginx")) {
		t.Errorf("charts/nginx not recognized as chart")
	}
	if !ct.isPathInChart(filepath.Join(dir, "charts/nginx/Chart.yaml")) {
		t.Errorf("charts/nginx/Chart.yaml not recognized as in chart")
	}

	chartfiles := []string{"charts",
		"charts/nginx",
		"charts/nginx/Chart.yaml",
		"charts/nginx/values.yaml",
		"charts/nginx/templates/deployment.yaml",
	}
	for _, f := range chartfiles {
		fq := filepath.Join(dir, f)
		if m, err := Load(dir, []string{fq}); err != nil || len(m) != 0 {
			t.Errorf("%q not ignored as a chart should be", f)
		}
	}

}
<|endoftext|>


<commit_before>package arguments

import (
	"fmt"
	"os"

	"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
	"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
	"sigs.k8s.io/kustomize/cmd/gorepomod/internal/utils"
)

const (
	doItFlag     = "--doIt"
	cmdPin       = "pin"
	cmdUnPin     = "unpin"
	cmdTidy      = "tidy"
	cmdList      = "list"
	cmdRelease   = "release"
	cmdUnRelease = "unrelease"
	cmdDebug     = "debug"
)

var (
	commands = []string{
		cmdPin, cmdUnPin, cmdTidy, cmdList, cmdRelease, cmdUnRelease, cmdDebug}

	// TODO: make this a PATH-like flag
	// e.g.: --excludes ".git:.idea:site:docs"
	excSlice = []string{
		".git",
		".github",
		".idea",
		"docs",
		"examples",
		"hack",
		"site",
		"releasing",
	}
)

type Command int

const (
	Tidy Command = iota
	UnPin
	Pin
	List
	Release
	UnRelease
	Debug
)

type Args struct {
	cmd               Command
	moduleName        misc.ModuleShortName
	conditionalModule misc.ModuleShortName
	version           semver.SemVer
	bump              semver.SvBump
	doIt              bool
}

func (a *Args) GetCommand() Command {
	return a.cmd
}

func (a *Args) Bump() semver.SvBump {
	return a.bump
}

func (a *Args) Version() semver.SemVer {
	return a.version
}

func (a *Args) ModuleName() misc.ModuleShortName {
	return a.moduleName
}

func (a *Args) ConditionalModule() misc.ModuleShortName {
	return a.conditionalModule
}

func (a *Args) Exclusions() (result []string) {
	// Make sure the list has no repeats.
	for k := range utils.SliceToSet(excSlice) {
		result = append(result, k)
	}
	return
}

func (a *Args) DoIt() bool {
	return a.doIt
}

type myArgs struct {
	args []string
	doIt bool
}

func (a *myArgs) next() (result string) {
	if !a.more() {
		panic("no args left")
	}
	result = a.args[0]
	a.args = a.args[1:]
	return
}

func (a *myArgs) more() bool {
	return len(a.args) > 0
}

func newArgs() *myArgs {
	result := &myArgs{}
	for _, a := range os.Args[1:] {
		if a == doItFlag {
			result.doIt = true
		} else {
			result.args = append(result.args, a)
		}
	}
	return result
}

func Parse() (result *Args, err error) {
	result = &Args{}
	clArgs := newArgs()
	result.doIt = clArgs.doIt

	result.moduleName = misc.ModuleUnknown
	result.conditionalModule = misc.ModuleUnknown
	if !clArgs.more() {
		return nil, fmt.Errorf("command needs at least one arg")
	}
	command := clArgs.next()
	switch command {
	case cmdPin:
		if !clArgs.more() {
			return nil, fmt.Errorf("pin needs a moduleName to pin")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		if clArgs.more() {
			result.version, err = semver.Parse(clArgs.next())
			if err != nil {
				return nil, err
			}
		} else {
			result.version = semver.Zero()
		}
		result.cmd = Pin
	case cmdUnPin:
		if !clArgs.more() {
			return nil, fmt.Errorf("unpin needs a moduleName to unpin")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		if clArgs.more() {
			result.conditionalModule = misc.ModuleShortName(clArgs.next())
		}
		result.cmd = UnPin
	case cmdTidy:
		result.cmd = Tidy
	case cmdList:
		result.cmd = List
	case cmdRelease:
		if !clArgs.more() {
			return nil, fmt.Errorf("specify {module} to release")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		bump := "patch"
		if clArgs.more() {
			bump = clArgs.next()
		}
		switch bump {
		case "major":
			result.bump = semver.Major
		case "minor":
			result.bump = semver.Minor
		case "patch":
			result.bump = semver.Patch
		default:
			return nil, fmt.Errorf(
				"unknown bump %s; specify one of 'major', 'minor' or 'patch'", bump)
		}
		result.cmd = Release
	case cmdUnRelease:
		if !clArgs.more() {
			return nil, fmt.Errorf("specify {module} to unrelease")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		result.cmd = UnRelease
	case cmdDebug:
		if !clArgs.more() {
			return nil, fmt.Errorf("specify {module} to debug")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		result.cmd = Debug
	default:
		return nil, fmt.Errorf(
			"unknown command %q; must be one of %v", command, commands)
	}
	if clArgs.more() {
		return nil, fmt.Errorf("unknown extra args: %v", clArgs.args)
	}
	return
}
<commit_msg>Update args.go<commit_after>package arguments

import (
	"fmt"
	"os"

	"sigs.k8s.io/kustomize/cmd/gorepomod/internal/misc"
	"sigs.k8s.io/kustomize/cmd/gorepomod/internal/semver"
	"sigs.k8s.io/kustomize/cmd/gorepomod/internal/utils"
)

const (
	doItFlag     = "--doIt"
	cmdPin       = "pin"
	cmdUnPin     = "unpin"
	cmdTidy      = "tidy"
	cmdList      = "list"
	cmdRelease   = "release"
	cmdUnRelease = "unrelease"
	cmdDebug     = "debug"
)

var (
	commands = []string{
		cmdPin, cmdUnPin, cmdTidy, cmdList, cmdRelease, cmdUnRelease, cmdDebug}

	// TODO: make this a PATH-like flag
	// e.g.: --excludes ".git:.idea:site:docs"
	excSlice = []string{
		".git",
		".github",
		".idea",
		"docs",
		"examples",
		"hack",
		"plugin",
		"releasing",
		"site",
	}
)

type Command int

const (
	Tidy Command = iota
	UnPin
	Pin
	List
	Release
	UnRelease
	Debug
)

type Args struct {
	cmd               Command
	moduleName        misc.ModuleShortName
	conditionalModule misc.ModuleShortName
	version           semver.SemVer
	bump              semver.SvBump
	doIt              bool
}

func (a *Args) GetCommand() Command {
	return a.cmd
}

func (a *Args) Bump() semver.SvBump {
	return a.bump
}

func (a *Args) Version() semver.SemVer {
	return a.version
}

func (a *Args) ModuleName() misc.ModuleShortName {
	return a.moduleName
}

func (a *Args) ConditionalModule() misc.ModuleShortName {
	return a.conditionalModule
}

func (a *Args) Exclusions() (result []string) {
	// Make sure the list has no repeats.
	for k := range utils.SliceToSet(excSlice) {
		result = append(result, k)
	}
	return
}

func (a *Args) DoIt() bool {
	return a.doIt
}

type myArgs struct {
	args []string
	doIt bool
}

func (a *myArgs) next() (result string) {
	if !a.more() {
		panic("no args left")
	}
	result = a.args[0]
	a.args = a.args[1:]
	return
}

func (a *myArgs) more() bool {
	return len(a.args) > 0
}

func newArgs() *myArgs {
	result := &myArgs{}
	for _, a := range os.Args[1:] {
		if a == doItFlag {
			result.doIt = true
		} else {
			result.args = append(result.args, a)
		}
	}
	return result
}

func Parse() (result *Args, err error) {
	result = &Args{}
	clArgs := newArgs()
	result.doIt = clArgs.doIt

	result.moduleName = misc.ModuleUnknown
	result.conditionalModule = misc.ModuleUnknown
	if !clArgs.more() {
		return nil, fmt.Errorf("command needs at least one arg")
	}
	command := clArgs.next()
	switch command {
	case cmdPin:
		if !clArgs.more() {
			return nil, fmt.Errorf("pin needs a moduleName to pin")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		if clArgs.more() {
			result.version, err = semver.Parse(clArgs.next())
			if err != nil {
				return nil, err
			}
		} else {
			result.version = semver.Zero()
		}
		result.cmd = Pin
	case cmdUnPin:
		if !clArgs.more() {
			return nil, fmt.Errorf("unpin needs a moduleName to unpin")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		if clArgs.more() {
			result.conditionalModule = misc.ModuleShortName(clArgs.next())
		}
		result.cmd = UnPin
	case cmdTidy:
		result.cmd = Tidy
	case cmdList:
		result.cmd = List
	case cmdRelease:
		if !clArgs.more() {
			return nil, fmt.Errorf("specify {module} to release")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		bump := "patch"
		if clArgs.more() {
			bump = clArgs.next()
		}
		switch bump {
		case "major":
			result.bump = semver.Major
		case "minor":
			result.bump = semver.Minor
		case "patch":
			result.bump = semver.Patch
		default:
			return nil, fmt.Errorf(
				"unknown bump %s; specify one of 'major', 'minor' or 'patch'", bump)
		}
		result.cmd = Release
	case cmdUnRelease:
		if !clArgs.more() {
			return nil, fmt.Errorf("specify {module} to unrelease")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		result.cmd = UnRelease
	case cmdDebug:
		if !clArgs.more() {
			return nil, fmt.Errorf("specify {module} to debug")
		}
		result.moduleName = misc.ModuleShortName(clArgs.next())
		result.cmd = Debug
	default:
		return nil, fmt.Errorf(
			"unknown command %q; must be one of %v", command, commands)
	}
	if clArgs.more() {
		return nil, fmt.Errorf("unknown extra args: %v", clArgs.args)
	}
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package kubeadm

const (
	DefaultServiceDNSDomain  = "cluster.local"
	DefaultServicesSubnet    = "10.12.0.0/12"
	DefaultKubernetesVersion = "v1.4.4"
	DefaultAPIBindPort       = 6443
	DefaultDiscoveryBindPort = 9898
)
<commit_msg>Change default service IP range to 10.96/12<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package kubeadm

const (
	DefaultServiceDNSDomain  = "cluster.local"
	DefaultServicesSubnet    = "10.96.0.0/12"
	DefaultKubernetesVersion = "v1.4.4"
	DefaultAPIBindPort       = 6443
	DefaultDiscoveryBindPort = 9898
)
<|endoftext|>


<commit_before>package director

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httputil"
	"time"

	"github.com/Bplotka/oidc/authorize"
	"github.com/mwitkow/go-conntrack"
	"github.com/mwitkow/go-httpwares"
	"github.com/mwitkow/go-httpwares/tags"
	"github.com/mwitkow/kedge/http/backendpool"
	"github.com/mwitkow/kedge/http/director/adhoc"
	"github.com/mwitkow/kedge/http/director/proxyreq"
	"github.com/mwitkow/kedge/http/director/router"
	"github.com/mwitkow/kedge/lib/http/ctxtags"
	"github.com/mwitkow/kedge/lib/http/tripperware"
	"github.com/mwitkow/kedge/lib/sharedflags"
	"github.com/oxtoacart/bpool"
	"github.com/sirupsen/logrus"
)

var (
	AdhocTransport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          100,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}

	flagBufferSizeBytes  = sharedflags.Set.Int("http_reverseproxy_buffer_size_bytes", 32*1024, "Size (bytes) of reusable buffer used for copying HTTP reverse proxy responses.")
	flagBufferCount      = sharedflags.Set.Int("http_reverseproxy_buffer_count", 2*1024, "Maximum number of of reusable buffer used for copying HTTP reverse proxy responses.")
	flagFlushingInterval = sharedflags.Set.Duration("http_reverseproxy_flushing_interval", 10*time.Millisecond, "Interval for flushing the responses in HTTP reverse proxy code.")
)

// New creates a forward/reverse proxy that is either Route+Backend and Adhoc Rules forwarding.
//
// The Router decides which "well-known" routes a given request matches, and which backend from the Pool it should be
// sent to. The backends in the Pool have pre-dialed connections and are load balanced.
//
// If  Adhoc routing supports dialing to whitelisted DNS names either through DNS A or SRV records for undefined backends.
func New(pool backendpool.Pool, router router.Router, addresser adhoc.Addresser) *Proxy {
	AdhocTransport.DialContext = conntrack.NewDialContextFunc(conntrack.DialWithName("adhoc"), conntrack.DialWithTracing())
	bufferpool := bpool.NewBytePool(*flagBufferCount, *flagBufferSizeBytes)
	p := &Proxy{
		backendReverseProxy: &httputil.ReverseProxy{
			Director:      func(r *http.Request) {},
			Transport:     &backendPoolTripper{pool: pool},
			FlushInterval: *flagFlushingInterval,
			BufferPool:    bufferpool,
		},
		adhocReverseProxy: &httputil.ReverseProxy{
			Director:      func(r *http.Request) {},
			Transport:     AdhocTransport,
			FlushInterval: *flagFlushingInterval,
			BufferPool:    bufferpool,
		},
		router:    router,
		addresser: addresser,
	}
	return p
}

// Proxy is a forward/reverse proxy that implements Route+Backend and Adhoc Rules forwarding.
type Proxy struct {
	router    router.Router
	addresser adhoc.Addresser

	backendReverseProxy *httputil.ReverseProxy
	adhocReverseProxy   *httputil.ReverseProxy
}

func (p *Proxy) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	if _, ok := resp.(http.Flusher); !ok {
		panic("the http.ResponseWriter passed must be an http.Flusher")
	}
	// note resp needs to implement Flusher, otherwise flush intervals won't work.
	normReq := proxyreq.NormalizeInboundRequest(req)
	backend, err := p.router.Route(req)
	tags := http_ctxtags.ExtractInbound(req)
	tags.Set(http_ctxtags.TagForCallService, "proxy")
	if err == nil {
		resp.Header().Set("x-kedge-backend-name", backend)
		tags.Set(ctxtags.TagForProxyBackend, backend)
		tags.Set(http_ctxtags.TagForHandlerName, backend)
		normReq.URL.Host = backend
		p.backendReverseProxy.ServeHTTP(resp, normReq)
		return
	} else if err != router.ErrRouteNotFound {
		respondWithError(err, req, resp)
		return
	}
	addr, err := p.addresser.Address(req)
	if err == nil {
		normReq.URL.Host = addr
		tags.Set(ctxtags.TagForProxyAdhoc, addr)
		tags.Set(http_ctxtags.TagForHandlerName, "_adhoc")
		p.adhocReverseProxy.ServeHTTP(resp, normReq)
		return
	}
	respondWithError(err, req, resp)
}

// backendPoolTripper assumes the response has been rewritten by the proxy to have the backend as req.URL.Host
type backendPoolTripper struct {
	pool backendpool.Pool
}

func (t *backendPoolTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	tripper, err := t.pool.Tripper(req.URL.Host)
	if err == nil {
		return tripper.RoundTrip(req)
	}
	return nil, err
}

func respondWithError(err error, req *http.Request, resp http.ResponseWriter) {
	status := http.StatusBadGateway
	if rErr, ok := (err).(*router.Error); ok {
		status = rErr.StatusCode()
	}
	http_ctxtags.ExtractInbound(req).Set(logrus.ErrorKey, err)
	resp.Header().Set("x-kedge-error", err.Error())
	resp.Header().Set("content-type", "text/plain")
	resp.WriteHeader(status)
}

func AuthMiddleware(authorizer authorize.Authorizer) httpwares.Middleware {
	return func(nextHandler http.Handler) http.Handler {
		return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
			err := authorize.IsRequestAuthorized(req, authorizer, tripperware.ProxyAuthHeader)
			if err != nil {
				respondWithUnauthorized(err, req, resp)
				return
			}
			// Request authorized - continue.
			nextHandler.ServeHTTP(resp, req)
		})
	}
}

func respondWithUnauthorized(err error, req *http.Request, resp http.ResponseWriter) {
	status := http.StatusUnauthorized
	http_ctxtags.ExtractInbound(req).Set(logrus.ErrorKey, err)
	resp.Header().Set("x-kedge-error", err.Error())
	resp.Header().Set("content-type", "text/plain")
	resp.WriteHeader(status)
}
<commit_msg>Actually added log line which is crucial<commit_after>package director

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httputil"
	"time"

	"github.com/Bplotka/oidc/authorize"
	"github.com/mwitkow/go-conntrack"
	"github.com/mwitkow/go-httpwares"
	"github.com/mwitkow/go-httpwares/tags"
	"github.com/mwitkow/kedge/http/backendpool"
	"github.com/mwitkow/kedge/http/director/adhoc"
	"github.com/mwitkow/kedge/http/director/proxyreq"
	"github.com/mwitkow/kedge/http/director/router"
	"github.com/mwitkow/kedge/lib/http/ctxtags"
	"github.com/mwitkow/kedge/lib/http/tripperware"
	"github.com/mwitkow/kedge/lib/sharedflags"
	"github.com/oxtoacart/bpool"
	"github.com/sirupsen/logrus"
)

var (
	AdhocTransport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          100,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}

	flagBufferSizeBytes  = sharedflags.Set.Int("http_reverseproxy_buffer_size_bytes", 32*1024, "Size (bytes) of reusable buffer used for copying HTTP reverse proxy responses.")
	flagBufferCount      = sharedflags.Set.Int("http_reverseproxy_buffer_count", 2*1024, "Maximum number of of reusable buffer used for copying HTTP reverse proxy responses.")
	flagFlushingInterval = sharedflags.Set.Duration("http_reverseproxy_flushing_interval", 10*time.Millisecond, "Interval for flushing the responses in HTTP reverse proxy code.")
)

// New creates a forward/reverse proxy that is either Route+Backend and Adhoc Rules forwarding.
//
// The Router decides which "well-known" routes a given request matches, and which backend from the Pool it should be
// sent to. The backends in the Pool have pre-dialed connections and are load balanced.
//
// If  Adhoc routing supports dialing to whitelisted DNS names either through DNS A or SRV records for undefined backends.
func New(pool backendpool.Pool, router router.Router, addresser adhoc.Addresser) *Proxy {
	AdhocTransport.DialContext = conntrack.NewDialContextFunc(conntrack.DialWithName("adhoc"), conntrack.DialWithTracing())
	bufferpool := bpool.NewBytePool(*flagBufferCount, *flagBufferSizeBytes)
	p := &Proxy{
		backendReverseProxy: &httputil.ReverseProxy{
			Director:      func(r *http.Request) {},
			Transport:     &backendPoolTripper{pool: pool},
			FlushInterval: *flagFlushingInterval,
			BufferPool:    bufferpool,
		},
		adhocReverseProxy: &httputil.ReverseProxy{
			Director:      func(r *http.Request) {},
			Transport:     AdhocTransport,
			FlushInterval: *flagFlushingInterval,
			BufferPool:    bufferpool,
		},
		router:    router,
		addresser: addresser,
	}
	return p
}

// Proxy is a forward/reverse proxy that implements Route+Backend and Adhoc Rules forwarding.
type Proxy struct {
	router    router.Router
	addresser adhoc.Addresser

	backendReverseProxy *httputil.ReverseProxy
	adhocReverseProxy   *httputil.ReverseProxy
}

func (p *Proxy) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	if _, ok := resp.(http.Flusher); !ok {
		panic("the http.ResponseWriter passed must be an http.Flusher")
	}
	// note resp needs to implement Flusher, otherwise flush intervals won't work.
	normReq := proxyreq.NormalizeInboundRequest(req)
	backend, err := p.router.Route(req)
	tags := http_ctxtags.ExtractInbound(req)
	tags.Set(http_ctxtags.TagForCallService, "proxy")
	if err == nil {
		resp.Header().Set("x-kedge-backend-name", backend)
		tags.Set(ctxtags.TagForProxyBackend, backend)
		tags.Set(http_ctxtags.TagForHandlerName, backend)
		normReq.URL.Host = backend
		p.backendReverseProxy.ServeHTTP(resp, normReq)
		return
	} else if err != router.ErrRouteNotFound {
		respondWithError(err, req, resp)
		return
	}
	addr, err := p.addresser.Address(req)
	if err == nil {
		normReq.URL.Host = addr
		tags.Set(ctxtags.TagForProxyAdhoc, addr)
		tags.Set(http_ctxtags.TagForHandlerName, "_adhoc")
		p.adhocReverseProxy.ServeHTTP(resp, normReq)
		return
	}
	respondWithError(err, req, resp)
}

// backendPoolTripper assumes the response has been rewritten by the proxy to have the backend as req.URL.Host
type backendPoolTripper struct {
	pool backendpool.Pool
}

func (t *backendPoolTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	tripper, err := t.pool.Tripper(req.URL.Host)
	if err == nil {
		return tripper.RoundTrip(req)
	}
	return nil, err
}

func respondWithError(err error, req *http.Request, resp http.ResponseWriter) {
	status := http.StatusBadGateway
	if rErr, ok := (err).(*router.Error); ok {
		status = rErr.StatusCode()
	}
	http_ctxtags.ExtractInbound(req).Set(logrus.ErrorKey, err)
	resp.Header().Set("x-kedge-error", err.Error())
	resp.Header().Set("content-type", "text/plain")
	resp.WriteHeader(status)
	fmt.Fprintf(resp, "%v", err.Error())
}

func AuthMiddleware(authorizer authorize.Authorizer) httpwares.Middleware {
	return func(nextHandler http.Handler) http.Handler {
		return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
			err := authorize.IsRequestAuthorized(req, authorizer, tripperware.ProxyAuthHeader)
			if err != nil {
				respondWithUnauthorized(err, req, resp)
				return
			}
			// Request authorized - continue.
			nextHandler.ServeHTTP(resp, req)
		})
	}
}

func respondWithUnauthorized(err error, req *http.Request, resp http.ResponseWriter) {
	status := http.StatusUnauthorized
	http_ctxtags.ExtractInbound(req).Set(logrus.ErrorKey, err)
	resp.Header().Set("x-kedge-error", err.Error())
	resp.Header().Set("content-type", "text/plain")
	resp.WriteHeader(status)
}
<|endoftext|>


<commit_before>package common

import (
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/pluginaction"
	"code.cloudfoundry.org/cli/api/plugin"
	"code.cloudfoundry.org/cli/api/plugin/pluginerror"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/plugin/shared"
	"code.cloudfoundry.org/cli/command/translatableerror"
	"code.cloudfoundry.org/cli/util"
	"code.cloudfoundry.org/cli/util/configv3"
	log "github.com/sirupsen/logrus"
)

//go:generate counterfeiter . InstallPluginActor

type InstallPluginActor interface {
	CreateExecutableCopy(path string, tempPluginDir string) (string, error)
	DownloadExecutableBinaryFromURL(url string, tempPluginDir string, proxyReader plugin.ProxyReader) (string, error)
	FileExists(path string) bool
	GetAndValidatePlugin(metadata pluginaction.PluginMetadata, commands pluginaction.CommandList, path string) (configv3.Plugin, error)
	GetPlatformString(runtimeGOOS string, runtimeGOARCH string) string
	GetPluginInfoFromRepositoriesForPlatform(pluginName string, pluginRepos []configv3.PluginRepository, platform string) (pluginaction.PluginInfo, []string, error)
	GetPluginRepository(repositoryName string) (configv3.PluginRepository, error)
	InstallPluginFromPath(path string, plugin configv3.Plugin) error
	UninstallPlugin(uninstaller pluginaction.PluginUninstaller, name string) error
	ValidateFileChecksum(path string, checksum string) bool
}

const installConfirmationPrompt = "Do you want to install the plugin {{.Path}}?"

type cancelInstall struct {
}

func (cancelInstall) Error() string {
	return "Nobody should see this error. If you do, report it!"
}

type PluginSource int

const (
	PluginFromRepository PluginSource = iota
	PluginFromLocalFile
	PluginFromURL
)

type InstallPluginCommand struct {
	OptionalArgs         flag.InstallPluginArgs `positional-args:"yes"`
	SkipSSLValidation    bool                   `short:"k" hidden:"true" description:"Skip SSL certificate validation"`
	Force                bool                   `short:"f" description:"Force install of plugin without confirmation"`
	RegisteredRepository string                 `short:"r" description:"Restrict search for plugin to this registered repository"`
	usage                interface{}            `usage:"CF_NAME install-plugin PLUGIN_NAME [-r REPO_NAME] [-f]\nCF_NAME install-plugin LOCAL-PATH/TO/PLUGIN | URL [-f]\n\nWARNING:\n   Plugins are binaries written by potentially untrusted authors.\n   Install and use plugins at your own risk.\n\nEXAMPLES:\n   CF_NAME install-plugin ~/Downloads/plugin-foobar\n   CF_NAME install-plugin https://example.com/plugin-foobar_linux_amd64\n   CF_NAME install-plugin -r My-Repo plugin-echo"`
	relatedCommands      interface{}            `related_commands:"add-plugin-repo, list-plugin-repos, plugins"`
	UI                   command.UI
	Config               command.Config
	Actor                InstallPluginActor
	ProgressBar          plugin.ProxyReader
}

func (cmd *InstallPluginCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	cmd.Actor = pluginaction.NewActor(config, shared.NewClient(config, ui, cmd.SkipSSLValidation))

	cmd.ProgressBar = shared.NewProgressBarProxyReader(cmd.UI.Writer())

	return nil
}

func (cmd InstallPluginCommand) Execute([]string) error {
	log.WithField("PluginHome", cmd.Config.PluginHome()).Info("making plugin dir")
	err := os.MkdirAll(cmd.Config.PluginHome(), 0700)
	if err != nil {
		return err
	}

	tempPluginDir, err := ioutil.TempDir(cmd.Config.PluginHome(), "temp")
	log.WithField("tempPluginDir", tempPluginDir).Debug("making tempPluginDir dir")
	defer os.RemoveAll(tempPluginDir)

	if err != nil {
		return err
	}

	tempPluginPath, pluginSource, err := cmd.getPluginBinaryAndSource(tempPluginDir)
	if _, ok := err.(cancelInstall); ok {
		cmd.UI.DisplayText("Plugin installation cancelled.")
		return nil
	} else if err != nil {
		return err
	}
	log.WithFields(log.Fields{"tempPluginPath": tempPluginPath, "pluginSource": pluginSource}).Debug("getPluginBinaryAndSource")

	// copy twice when downloading from a URL to keep Windows specific code
	// isolated to CreateExecutableCopy
	executablePath, err := cmd.Actor.CreateExecutableCopy(tempPluginPath, tempPluginDir)
	if err != nil {
		return err
	}
	log.WithField("executablePath", executablePath).Debug("created executable copy")

	rpcService, err := shared.NewRPCService(cmd.Config, cmd.UI)
	if err != nil {
		return err
	}
	log.Info("started RPC server")

	plugin, err := cmd.Actor.GetAndValidatePlugin(rpcService, Commands, executablePath)
	if err != nil {
		return err
	}
	log.Info("validated plugin")

	if installedPlugin, installed := cmd.Config.GetPluginCaseInsensitive(plugin.Name); installed {
		log.WithField("version", installedPlugin.Version).Debug("uninstall plugin")

		if !cmd.Force && pluginSource != PluginFromRepository {
			return translatableerror.PluginAlreadyInstalledError{
				BinaryName: cmd.Config.BinaryName(),
				Name:       plugin.Name,
				Version:    plugin.Version.String(),
			}
		}

		err = cmd.uninstallPlugin(installedPlugin, rpcService)
		if err != nil {
			return err
		}
	}

	log.Info("install plugin")
	return cmd.installPlugin(plugin, executablePath)
}

func (cmd InstallPluginCommand) installPlugin(plugin configv3.Plugin, pluginPath string) error {
	cmd.UI.DisplayTextWithFlavor("Installing plugin {{.Name}}...", map[string]interface{}{
		"Name": plugin.Name,
	})

	installErr := cmd.Actor.InstallPluginFromPath(pluginPath, plugin)
	if installErr != nil {
		return installErr
	}

	cmd.UI.DisplayOK()
	cmd.UI.DisplayText("Plugin {{.Name}} {{.Version}} successfully installed.", map[string]interface{}{
		"Name":    plugin.Name,
		"Version": plugin.Version.String(),
	})
	return nil
}

func (cmd InstallPluginCommand) uninstallPlugin(plugin configv3.Plugin, rpcService *shared.RPCService) error {
	cmd.UI.DisplayText("Plugin {{.Name}} {{.Version}} is already installed. Uninstalling existing plugin...", map[string]interface{}{
		"Name":    plugin.Name,
		"Version": plugin.Version.String(),
	})

	uninstallErr := cmd.Actor.UninstallPlugin(rpcService, plugin.Name)
	if uninstallErr != nil {
		return uninstallErr
	}

	cmd.UI.DisplayOK()
	cmd.UI.DisplayText("Plugin {{.Name}} successfully uninstalled.", map[string]interface{}{
		"Name": plugin.Name,
	})

	return nil
}

func (cmd InstallPluginCommand) getPluginBinaryAndSource(tempPluginDir string) (string, PluginSource, error) {
	pluginNameOrLocation := cmd.OptionalArgs.PluginNameOrLocation.String()

	switch {
	case cmd.RegisteredRepository != "":
		log.WithField("RegisteredRepository", cmd.RegisteredRepository).Info("installing from specified repository")
		pluginRepository, err := cmd.Actor.GetPluginRepository(cmd.RegisteredRepository)
		if err != nil {
			return "", 0, err
		}
		path, pluginSource, err := cmd.getPluginFromRepositories(pluginNameOrLocation, []configv3.PluginRepository{pluginRepository}, tempPluginDir)

		if err != nil {
			switch pluginErr := err.(type) {
			case actionerror.PluginNotFoundInAnyRepositoryError:
				return "", 0, translatableerror.PluginNotFoundInRepositoryError{
					BinaryName:     cmd.Config.BinaryName(),
					PluginName:     pluginNameOrLocation,
					RepositoryName: cmd.RegisteredRepository,
				}

			case actionerror.FetchingPluginInfoFromRepositoryError:
				// The error wrapped inside pluginErr is handled differently in the case of
				// a specified repo from that of searching through all repos.  pluginErr.Err
				// is then processed by shared.HandleError by this function's caller.
				return "", 0, pluginErr.Err

			default:
				return "", 0, err
			}
		}
		return path, pluginSource, nil

	case cmd.Actor.FileExists(pluginNameOrLocation):
		log.WithField("pluginNameOrLocation", pluginNameOrLocation).Info("installing from specified file")
		return cmd.getPluginFromLocalFile(pluginNameOrLocation)

	case util.IsHTTPScheme(pluginNameOrLocation):
		log.WithField("pluginNameOrLocation", pluginNameOrLocation).Info("installing from specified URL")
		return cmd.getPluginFromURL(pluginNameOrLocation, tempPluginDir)

	case util.IsUnsupportedURLScheme(pluginNameOrLocation):
		log.WithField("pluginNameOrLocation", pluginNameOrLocation).Error("Unsupported URL")
		return "", 0, translatableerror.UnsupportedURLSchemeError{UnsupportedURL: pluginNameOrLocation}

	default:
		log.Info("installing from first repository with plugin")
		repos := cmd.Config.PluginRepositories()
		if len(repos) == 0 {
			return "", 0, translatableerror.PluginNotFoundOnDiskOrInAnyRepositoryError{PluginName: pluginNameOrLocation, BinaryName: cmd.Config.BinaryName()}
		}

		path, pluginSource, err := cmd.getPluginFromRepositories(pluginNameOrLocation, repos, tempPluginDir)
		if err != nil {
			switch pluginErr := err.(type) {
			case actionerror.PluginNotFoundInAnyRepositoryError:
				return "", 0, translatableerror.PluginNotFoundOnDiskOrInAnyRepositoryError{PluginName: pluginNameOrLocation, BinaryName: cmd.Config.BinaryName()}

			case actionerror.FetchingPluginInfoFromRepositoryError:
				return "", 0, cmd.handleFetchingPluginInfoFromRepositoriesError(pluginErr)

			default:
				return "", 0, err
			}
		}
		return path, pluginSource, nil
	}
}

// These are specific errors that we output to the user in the context of
// installing from any repository.
func (InstallPluginCommand) handleFetchingPluginInfoFromRepositoriesError(fetchErr actionerror.FetchingPluginInfoFromRepositoryError) error {
	switch clientErr := fetchErr.Err.(type) {
	case pluginerror.RawHTTPStatusError:
		return translatableerror.FetchingPluginInfoFromRepositoriesError{
			Message:        clientErr.Status,
			RepositoryName: fetchErr.RepositoryName,
		}

	case pluginerror.SSLValidationHostnameError:
		return translatableerror.FetchingPluginInfoFromRepositoriesError{
			Message:        clientErr.Error(),
			RepositoryName: fetchErr.RepositoryName,
		}

	case pluginerror.UnverifiedServerError:
		return translatableerror.FetchingPluginInfoFromRepositoriesError{
			Message:        clientErr.Error(),
			RepositoryName: fetchErr.RepositoryName,
		}

	default:
		return clientErr
	}
}

func (cmd InstallPluginCommand) getPluginFromLocalFile(pluginLocation string) (string, PluginSource, error) {
	err := cmd.installPluginPrompt(installConfirmationPrompt, map[string]interface{}{
		"Path": pluginLocation,
	})
	if err != nil {
		return "", 0, err
	}

	return pluginLocation, PluginFromLocalFile, err
}

func (cmd InstallPluginCommand) getPluginFromURL(pluginLocation string, tempPluginDir string) (string, PluginSource, error) {
	err := cmd.installPluginPrompt(installConfirmationPrompt, map[string]interface{}{
		"Path": pluginLocation,
	})
	if err != nil {
		return "", 0, err
	}

	cmd.UI.DisplayText("Starting download of plugin binary from URL...")

	tempPath, err := cmd.Actor.DownloadExecutableBinaryFromURL(pluginLocation, tempPluginDir, cmd.ProgressBar)
	if err != nil {
		return "", 0, err
	}

	return tempPath, PluginFromURL, err
}

func (cmd InstallPluginCommand) getPluginFromRepositories(pluginName string, repos []configv3.PluginRepository, tempPluginDir string) (string, PluginSource, error) {
	var repoNames []string
	for _, repo := range repos {
		repoNames = append(repoNames, repo.Name)
	}

	cmd.UI.DisplayTextWithFlavor("Searching {{.RepositoryName}} for plugin {{.PluginName}}...", map[string]interface{}{
		"RepositoryName": strings.Join(repoNames, ", "),
		"PluginName":     pluginName,
	})

	currentPlatform := cmd.Actor.GetPlatformString(runtime.GOOS, runtime.GOARCH)
	pluginInfo, repoList, err := cmd.Actor.GetPluginInfoFromRepositoriesForPlatform(pluginName, repos, currentPlatform)
	if err != nil {
		return "", 0, err
	}

	cmd.UI.DisplayText("Plugin {{.PluginName}} {{.PluginVersion}} found in: {{.RepositoryName}}", map[string]interface{}{
		"PluginName":     pluginName,
		"PluginVersion":  pluginInfo.Version,
		"RepositoryName": strings.Join(repoList, ", "),
	})

	installedPlugin, exist := cmd.Config.GetPlugin(pluginName)
	if exist {
		cmd.UI.DisplayText("Plugin {{.PluginName}} {{.PluginVersion}} is already installed.", map[string]interface{}{
			"PluginName":    installedPlugin.Name,
			"PluginVersion": installedPlugin.Version.String(),
		})

		err = cmd.installPluginPrompt("Do you want to uninstall the existing plugin and install {{.Path}} {{.PluginVersion}}?", map[string]interface{}{
			"Path":          pluginName,
			"PluginVersion": pluginInfo.Version,
		})
	} else {
		err = cmd.installPluginPrompt(installConfirmationPrompt, map[string]interface{}{
			"Path": pluginName,
		})
	}

	if err != nil {
		return "", 0, err
	}

	cmd.UI.DisplayText("Starting download of plugin binary from repository {{.RepositoryName}}...", map[string]interface{}{
		"RepositoryName": repoList[0],
	})

	tempPath, err := cmd.Actor.DownloadExecutableBinaryFromURL(pluginInfo.URL, tempPluginDir, cmd.ProgressBar)
	if err != nil {
		return "", 0, err
	}

	if !cmd.Actor.ValidateFileChecksum(tempPath, pluginInfo.Checksum) {
		return "", 0, translatableerror.InvalidChecksumError{}
	}

	return tempPath, PluginFromRepository, err
}

func (cmd InstallPluginCommand) installPluginPrompt(template string, templateValues ...map[string]interface{}) error {
	cmd.UI.DisplayHeader("Attention: Plugins are binaries written by potentially untrusted authors.")
	cmd.UI.DisplayHeader("Install and use plugins at your own risk.")

	if cmd.Force {
		return nil
	}

	var (
		really    bool
		promptErr error
	)

	really, promptErr = cmd.UI.DisplayBoolPrompt(false, template, templateValues...)

	if promptErr != nil {
		return promptErr
	}

	if !really {
		log.Debug("plugin confirmation - 'no' inputed")
		return cancelInstall{}
	}

	return nil
}
<commit_msg>fix help text spacing<commit_after>package common

import (
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/pluginaction"
	"code.cloudfoundry.org/cli/api/plugin"
	"code.cloudfoundry.org/cli/api/plugin/pluginerror"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/plugin/shared"
	"code.cloudfoundry.org/cli/command/translatableerror"
	"code.cloudfoundry.org/cli/util"
	"code.cloudfoundry.org/cli/util/configv3"
	log "github.com/sirupsen/logrus"
)

//go:generate counterfeiter . InstallPluginActor

type InstallPluginActor interface {
	CreateExecutableCopy(path string, tempPluginDir string) (string, error)
	DownloadExecutableBinaryFromURL(url string, tempPluginDir string, proxyReader plugin.ProxyReader) (string, error)
	FileExists(path string) bool
	GetAndValidatePlugin(metadata pluginaction.PluginMetadata, commands pluginaction.CommandList, path string) (configv3.Plugin, error)
	GetPlatformString(runtimeGOOS string, runtimeGOARCH string) string
	GetPluginInfoFromRepositoriesForPlatform(pluginName string, pluginRepos []configv3.PluginRepository, platform string) (pluginaction.PluginInfo, []string, error)
	GetPluginRepository(repositoryName string) (configv3.PluginRepository, error)
	InstallPluginFromPath(path string, plugin configv3.Plugin) error
	UninstallPlugin(uninstaller pluginaction.PluginUninstaller, name string) error
	ValidateFileChecksum(path string, checksum string) bool
}

const installConfirmationPrompt = "Do you want to install the plugin {{.Path}}?"

type cancelInstall struct {
}

func (cancelInstall) Error() string {
	return "Nobody should see this error. If you do, report it!"
}

type PluginSource int

const (
	PluginFromRepository PluginSource = iota
	PluginFromLocalFile
	PluginFromURL
)

type InstallPluginCommand struct {
	OptionalArgs         flag.InstallPluginArgs `positional-args:"yes"`
	SkipSSLValidation    bool                   `short:"k" hidden:"true" description:"Skip SSL certificate validation"`
	Force                bool                   `short:"f" description:"Force install of plugin without confirmation"`
	RegisteredRepository string                 `short:"r" description:"Restrict search for plugin to this registered repository"`
	usage                interface{}            `usage:"CF_NAME install-plugin PLUGIN_NAME [-r REPO_NAME] [-f]\n   CF_NAME install-plugin LOCAL-PATH/TO/PLUGIN | URL [-f]\n\nWARNING:\n   Plugins are binaries written by potentially untrusted authors.\n   Install and use plugins at your own risk.\n\nEXAMPLES:\n   CF_NAME install-plugin ~/Downloads/plugin-foobar\n   CF_NAME install-plugin https://example.com/plugin-foobar_linux_amd64\n   CF_NAME install-plugin -r My-Repo plugin-echo"`
	relatedCommands      interface{}            `related_commands:"add-plugin-repo, list-plugin-repos, plugins"`
	UI                   command.UI
	Config               command.Config
	Actor                InstallPluginActor
	ProgressBar          plugin.ProxyReader
}

func (cmd *InstallPluginCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	cmd.Actor = pluginaction.NewActor(config, shared.NewClient(config, ui, cmd.SkipSSLValidation))

	cmd.ProgressBar = shared.NewProgressBarProxyReader(cmd.UI.Writer())

	return nil
}

func (cmd InstallPluginCommand) Execute([]string) error {
	log.WithField("PluginHome", cmd.Config.PluginHome()).Info("making plugin dir")
	err := os.MkdirAll(cmd.Config.PluginHome(), 0700)
	if err != nil {
		return err
	}

	tempPluginDir, err := ioutil.TempDir(cmd.Config.PluginHome(), "temp")
	log.WithField("tempPluginDir", tempPluginDir).Debug("making tempPluginDir dir")
	defer os.RemoveAll(tempPluginDir)

	if err != nil {
		return err
	}

	tempPluginPath, pluginSource, err := cmd.getPluginBinaryAndSource(tempPluginDir)
	if _, ok := err.(cancelInstall); ok {
		cmd.UI.DisplayText("Plugin installation cancelled.")
		return nil
	} else if err != nil {
		return err
	}
	log.WithFields(log.Fields{"tempPluginPath": tempPluginPath, "pluginSource": pluginSource}).Debug("getPluginBinaryAndSource")

	// copy twice when downloading from a URL to keep Windows specific code
	// isolated to CreateExecutableCopy
	executablePath, err := cmd.Actor.CreateExecutableCopy(tempPluginPath, tempPluginDir)
	if err != nil {
		return err
	}
	log.WithField("executablePath", executablePath).Debug("created executable copy")

	rpcService, err := shared.NewRPCService(cmd.Config, cmd.UI)
	if err != nil {
		return err
	}
	log.Info("started RPC server")

	plugin, err := cmd.Actor.GetAndValidatePlugin(rpcService, Commands, executablePath)
	if err != nil {
		return err
	}
	log.Info("validated plugin")

	if installedPlugin, installed := cmd.Config.GetPluginCaseInsensitive(plugin.Name); installed {
		log.WithField("version", installedPlugin.Version).Debug("uninstall plugin")

		if !cmd.Force && pluginSource != PluginFromRepository {
			return translatableerror.PluginAlreadyInstalledError{
				BinaryName: cmd.Config.BinaryName(),
				Name:       plugin.Name,
				Version:    plugin.Version.String(),
			}
		}

		err = cmd.uninstallPlugin(installedPlugin, rpcService)
		if err != nil {
			return err
		}
	}

	log.Info("install plugin")
	return cmd.installPlugin(plugin, executablePath)
}

func (cmd InstallPluginCommand) installPlugin(plugin configv3.Plugin, pluginPath string) error {
	cmd.UI.DisplayTextWithFlavor("Installing plugin {{.Name}}...", map[string]interface{}{
		"Name": plugin.Name,
	})

	installErr := cmd.Actor.InstallPluginFromPath(pluginPath, plugin)
	if installErr != nil {
		return installErr
	}

	cmd.UI.DisplayOK()
	cmd.UI.DisplayText("Plugin {{.Name}} {{.Version}} successfully installed.", map[string]interface{}{
		"Name":    plugin.Name,
		"Version": plugin.Version.String(),
	})
	return nil
}

func (cmd InstallPluginCommand) uninstallPlugin(plugin configv3.Plugin, rpcService *shared.RPCService) error {
	cmd.UI.DisplayText("Plugin {{.Name}} {{.Version}} is already installed. Uninstalling existing plugin...", map[string]interface{}{
		"Name":    plugin.Name,
		"Version": plugin.Version.String(),
	})

	uninstallErr := cmd.Actor.UninstallPlugin(rpcService, plugin.Name)
	if uninstallErr != nil {
		return uninstallErr
	}

	cmd.UI.DisplayOK()
	cmd.UI.DisplayText("Plugin {{.Name}} successfully uninstalled.", map[string]interface{}{
		"Name": plugin.Name,
	})

	return nil
}

func (cmd InstallPluginCommand) getPluginBinaryAndSource(tempPluginDir string) (string, PluginSource, error) {
	pluginNameOrLocation := cmd.OptionalArgs.PluginNameOrLocation.String()

	switch {
	case cmd.RegisteredRepository != "":
		log.WithField("RegisteredRepository", cmd.RegisteredRepository).Info("installing from specified repository")
		pluginRepository, err := cmd.Actor.GetPluginRepository(cmd.RegisteredRepository)
		if err != nil {
			return "", 0, err
		}
		path, pluginSource, err := cmd.getPluginFromRepositories(pluginNameOrLocation, []configv3.PluginRepository{pluginRepository}, tempPluginDir)

		if err != nil {
			switch pluginErr := err.(type) {
			case actionerror.PluginNotFoundInAnyRepositoryError:
				return "", 0, translatableerror.PluginNotFoundInRepositoryError{
					BinaryName:     cmd.Config.BinaryName(),
					PluginName:     pluginNameOrLocation,
					RepositoryName: cmd.RegisteredRepository,
				}

			case actionerror.FetchingPluginInfoFromRepositoryError:
				// The error wrapped inside pluginErr is handled differently in the case of
				// a specified repo from that of searching through all repos.  pluginErr.Err
				// is then processed by shared.HandleError by this function's caller.
				return "", 0, pluginErr.Err

			default:
				return "", 0, err
			}
		}
		return path, pluginSource, nil

	case cmd.Actor.FileExists(pluginNameOrLocation):
		log.WithField("pluginNameOrLocation", pluginNameOrLocation).Info("installing from specified file")
		return cmd.getPluginFromLocalFile(pluginNameOrLocation)

	case util.IsHTTPScheme(pluginNameOrLocation):
		log.WithField("pluginNameOrLocation", pluginNameOrLocation).Info("installing from specified URL")
		return cmd.getPluginFromURL(pluginNameOrLocation, tempPluginDir)

	case util.IsUnsupportedURLScheme(pluginNameOrLocation):
		log.WithField("pluginNameOrLocation", pluginNameOrLocation).Error("Unsupported URL")
		return "", 0, translatableerror.UnsupportedURLSchemeError{UnsupportedURL: pluginNameOrLocation}

	default:
		log.Info("installing from first repository with plugin")
		repos := cmd.Config.PluginRepositories()
		if len(repos) == 0 {
			return "", 0, translatableerror.PluginNotFoundOnDiskOrInAnyRepositoryError{PluginName: pluginNameOrLocation, BinaryName: cmd.Config.BinaryName()}
		}

		path, pluginSource, err := cmd.getPluginFromRepositories(pluginNameOrLocation, repos, tempPluginDir)
		if err != nil {
			switch pluginErr := err.(type) {
			case actionerror.PluginNotFoundInAnyRepositoryError:
				return "", 0, translatableerror.PluginNotFoundOnDiskOrInAnyRepositoryError{PluginName: pluginNameOrLocation, BinaryName: cmd.Config.BinaryName()}

			case actionerror.FetchingPluginInfoFromRepositoryError:
				return "", 0, cmd.handleFetchingPluginInfoFromRepositoriesError(pluginErr)

			default:
				return "", 0, err
			}
		}
		return path, pluginSource, nil
	}
}

// These are specific errors that we output to the user in the context of
// installing from any repository.
func (InstallPluginCommand) handleFetchingPluginInfoFromRepositoriesError(fetchErr actionerror.FetchingPluginInfoFromRepositoryError) error {
	switch clientErr := fetchErr.Err.(type) {
	case pluginerror.RawHTTPStatusError:
		return translatableerror.FetchingPluginInfoFromRepositoriesError{
			Message:        clientErr.Status,
			RepositoryName: fetchErr.RepositoryName,
		}

	case pluginerror.SSLValidationHostnameError:
		return translatableerror.FetchingPluginInfoFromRepositoriesError{
			Message:        clientErr.Error(),
			RepositoryName: fetchErr.RepositoryName,
		}

	case pluginerror.UnverifiedServerError:
		return translatableerror.FetchingPluginInfoFromRepositoriesError{
			Message:        clientErr.Error(),
			RepositoryName: fetchErr.RepositoryName,
		}

	default:
		return clientErr
	}
}

func (cmd InstallPluginCommand) getPluginFromLocalFile(pluginLocation string) (string, PluginSource, error) {
	err := cmd.installPluginPrompt(installConfirmationPrompt, map[string]interface{}{
		"Path": pluginLocation,
	})
	if err != nil {
		return "", 0, err
	}

	return pluginLocation, PluginFromLocalFile, err
}

func (cmd InstallPluginCommand) getPluginFromURL(pluginLocation string, tempPluginDir string) (string, PluginSource, error) {
	err := cmd.installPluginPrompt(installConfirmationPrompt, map[string]interface{}{
		"Path": pluginLocation,
	})
	if err != nil {
		return "", 0, err
	}

	cmd.UI.DisplayText("Starting download of plugin binary from URL...")

	tempPath, err := cmd.Actor.DownloadExecutableBinaryFromURL(pluginLocation, tempPluginDir, cmd.ProgressBar)
	if err != nil {
		return "", 0, err
	}

	return tempPath, PluginFromURL, err
}

func (cmd InstallPluginCommand) getPluginFromRepositories(pluginName string, repos []configv3.PluginRepository, tempPluginDir string) (string, PluginSource, error) {
	var repoNames []string
	for _, repo := range repos {
		repoNames = append(repoNames, repo.Name)
	}

	cmd.UI.DisplayTextWithFlavor("Searching {{.RepositoryName}} for plugin {{.PluginName}}...", map[string]interface{}{
		"RepositoryName": strings.Join(repoNames, ", "),
		"PluginName":     pluginName,
	})

	currentPlatform := cmd.Actor.GetPlatformString(runtime.GOOS, runtime.GOARCH)
	pluginInfo, repoList, err := cmd.Actor.GetPluginInfoFromRepositoriesForPlatform(pluginName, repos, currentPlatform)
	if err != nil {
		return "", 0, err
	}

	cmd.UI.DisplayText("Plugin {{.PluginName}} {{.PluginVersion}} found in: {{.RepositoryName}}", map[string]interface{}{
		"PluginName":     pluginName,
		"PluginVersion":  pluginInfo.Version,
		"RepositoryName": strings.Join(repoList, ", "),
	})

	installedPlugin, exist := cmd.Config.GetPlugin(pluginName)
	if exist {
		cmd.UI.DisplayText("Plugin {{.PluginName}} {{.PluginVersion}} is already installed.", map[string]interface{}{
			"PluginName":    installedPlugin.Name,
			"PluginVersion": installedPlugin.Version.String(),
		})

		err = cmd.installPluginPrompt("Do you want to uninstall the existing plugin and install {{.Path}} {{.PluginVersion}}?", map[string]interface{}{
			"Path":          pluginName,
			"PluginVersion": pluginInfo.Version,
		})
	} else {
		err = cmd.installPluginPrompt(installConfirmationPrompt, map[string]interface{}{
			"Path": pluginName,
		})
	}

	if err != nil {
		return "", 0, err
	}

	cmd.UI.DisplayText("Starting download of plugin binary from repository {{.RepositoryName}}...", map[string]interface{}{
		"RepositoryName": repoList[0],
	})

	tempPath, err := cmd.Actor.DownloadExecutableBinaryFromURL(pluginInfo.URL, tempPluginDir, cmd.ProgressBar)
	if err != nil {
		return "", 0, err
	}

	if !cmd.Actor.ValidateFileChecksum(tempPath, pluginInfo.Checksum) {
		return "", 0, translatableerror.InvalidChecksumError{}
	}

	return tempPath, PluginFromRepository, err
}

func (cmd InstallPluginCommand) installPluginPrompt(template string, templateValues ...map[string]interface{}) error {
	cmd.UI.DisplayHeader("Attention: Plugins are binaries written by potentially untrusted authors.")
	cmd.UI.DisplayHeader("Install and use plugins at your own risk.")

	if cmd.Force {
		return nil
	}

	var (
		really    bool
		promptErr error
	)

	really, promptErr = cmd.UI.DisplayBoolPrompt(false, template, templateValues...)

	if promptErr != nil {
		return promptErr
	}

	if !really {
		log.Debug("plugin confirmation - 'no' inputed")
		return cancelInstall{}
	}

	return nil
}
<|endoftext|>


<commit_before>package brain

import (
	"io"

	"github.com/BytemarkHosting/bytemark-client/lib/output"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
)

// Migration represents the migration of a single disc.
// The json returned from the brain can also represent virtual machine
// migrations, but we're ignoring that for now.
type Migration struct {
	ID             int    `json:"id,omitempty"`
	TailID         int    `json:"tail_id,omitempty"`
	DiscID         int    `json:"disc_id,omitempty"`
	Port           int    `json:"port,omitempty"`
	CreatedAt      string `json:"created_at,omitempty"`
	UpdatedAt      string `json:"updated_at,omitempty"`
	MigrationJobID int    `json:"migration_job_id,omitempty"`
}

// DefaultFields returns the list of default fields to feed to github.com/BytemarkHosting/row.From for this type.
func (m Migration) DefaultFields(f output.Format) string {
	return "ID, TailID, DiscID, Port, CreatedAt, UpdatedAt, MigrationJobID"
}

// PrettyPrint formats a Migration for display
func (m Migration) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{ define "migration_full" }} ▸ {{ .ID }}
     migration_job_id: {{ .MigrationJobID }}
     tail_id: {{ .TailID }}
     disc_id: {{ .DiscID }}
     port: {{ .Port }}
     created_at: {{ .CreatedAt }}
     updated_at: {{ .UpdatedAt }}
{{ end -}}{{- define "migration_sgl" -}}{{ .DiscID }}{{- end -}}`
	return prettyprint.Run(wr, template, "migration"+string(detail), m)
}
<commit_msg>fix simple line output<commit_after>package brain

import (
	"io"

	"github.com/BytemarkHosting/bytemark-client/lib/output"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
)

// Migration represents the migration of a single disc.
// The json returned from the brain can also represent virtual machine
// migrations, but we're ignoring that for now.
type Migration struct {
	ID             int    `json:"id,omitempty"`
	TailID         int    `json:"tail_id,omitempty"`
	DiscID         int    `json:"disc_id,omitempty"`
	Port           int    `json:"port,omitempty"`
	CreatedAt      string `json:"created_at,omitempty"`
	UpdatedAt      string `json:"updated_at,omitempty"`
	MigrationJobID int    `json:"migration_job_id,omitempty"`
}

// DefaultFields returns the list of default fields to feed to github.com/BytemarkHosting/row.From for this type.
func (m Migration) DefaultFields(f output.Format) string {
	return "ID, TailID, DiscID, Port, CreatedAt, UpdatedAt, MigrationJobID"
}

// PrettyPrint formats a Migration for display
func (m Migration) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) error {
	const template = `{{ define "migration_full" }} ▸ {{ .ID }}
     migration_job_id: {{ .MigrationJobID }}
     tail_id: {{ .TailID }}
     disc_id: {{ .DiscID }}
     port: {{ .Port }}
     created_at: {{ .CreatedAt }}
     updated_at: {{ .UpdatedAt }}
{{ end -}}{{- define "migration_sgl" }} ▸ {{ .ID }} disc: {{ .DiscID }}{{- end -}}`
	return prettyprint.Run(wr, template, "migration"+string(detail), m)
}
<|endoftext|>


<commit_before>package falcon_portal

import (
	"errors"
	"fmt"

	con "github.com/open-falcon/falcon-plus/modules/api/config"
)

// +----------------+------------------+------+-----+-------------------+-----------------------------+
// | Field          | Type             | Null | Key | Default           | Extra                       |
// +----------------+------------------+------+-----+-------------------+-----------------------------+
// | id             | int(11)          | NO   | PRI | NULL              | auto_increment              |
// | hostname       | varchar(255)     | NO   | UNI |                   |                             |
// | ip             | varchar(16)      | NO   |     |                   |                             |
// | agent_version  | varchar(16)      | NO   |     |                   |                             |
// | plugin_version | varchar(128)     | NO   |     |                   |                             |
// | maintain_begin | int(10) unsigned | NO   |     | 0                 |                             |
// | maintain_end   | int(10) unsigned | NO   |     | 0                 |                             |
// | update_at      | timestamp        | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
// +----------------+------------------+------+-----+-------------------+-----------------------------+

type Host struct {
	ID            int64  `json:"id" gorm:"column:id"`
	Hostname      string `json:"hostname" gorm:"column:hostname"`
	Ip            string `json:"ip" gorm:"column:ip"`
	AgentVersion  string `json:"agent_version"  gorm:"column:agent_version"`
	PluginVersion string `json:"plugin_version"  gorm:"column:plugin_version"`
	MaintainBegin uint16 `json:"maintain_begin"  gorm:"column:maintain_begin"`
	MaintainEnd   uint16 `json:"maintain_end"  gorm:"column:maintain_end"`
}

func (this Host) TableName() string {
	return "host"
}

func (this Host) Existing() (int64, bool) {
	db := con.Con()
	db.Falcon.Table(this.TableName()).Where("hostname = ?", this.Hostname).Scan(&this)
	if this.ID != 0 {
		return this.ID, true
	} else {
		return 0, false
	}
}

func (this Host) RelatedGrp() (Grps []HostGroup) {
	db := con.Con()
	grpHost := []GrpHost{}
	db.Falcon.Select("grp_id").Where("host_id = ?", this.ID).Find(&grpHost)
	tids := []int64{}
	for _, t := range grpHost {
		tids = append(tids, t.GrpID)
	}
	tidStr, _ := arrInt64ToString(tids)
	Grps = []HostGroup{}
	db.Falcon.Where(fmt.Sprintf("id in (%s)", tidStr)).Find(&Grps)
	return
}

func (this Host) RelatedTpl() (tpls []Template) {
	db := con.Con()
	grps := this.RelatedGrp()
	gids := []int64{}
	for _, g := range grps {
		gids = append(gids, g.ID)
	}
	gidStr, _ := arrInt64ToString(gids)
	grpTpls := []GrpTpl{}
	db.Falcon.Select("tpl_id").Where(fmt.Sprintf("grp_id in (%s)", gidStr)).Find(&grpTpls)
	tids := []int64{}
	for _, t := range grpTpls {
		tids = append(tids, t.TplID)
	}
	tidStr, _ := arrInt64ToString(tids)
	tpls = []Template{}
	db.Falcon.Where(fmt.Sprintf("id in (%s)", tidStr)).Find(&tpls)
	return
}

func arrInt64ToString(arr []int64) (result string, err error) {
	result = ""
	for indx, a := range arr {
		if indx == 0 {
			result = fmt.Sprintf("%v", a)
		} else {
			result = fmt.Sprintf("%v,%v", result, a)
		}
	}
	if result == "" {
		err = errors.New(fmt.Sprintf("array is empty, err: %v", arr))
	}
	return
}
<commit_msg>fix api host model maintain type<commit_after>package falcon_portal

import (
	"errors"
	"fmt"

	con "github.com/open-falcon/falcon-plus/modules/api/config"
)

// +----------------+------------------+------+-----+-------------------+-----------------------------+
// | Field          | Type             | Null | Key | Default           | Extra                       |
// +----------------+------------------+------+-----+-------------------+-----------------------------+
// | id             | int(11)          | NO   | PRI | NULL              | auto_increment              |
// | hostname       | varchar(255)     | NO   | UNI |                   |                             |
// | ip             | varchar(16)      | NO   |     |                   |                             |
// | agent_version  | varchar(16)      | NO   |     |                   |                             |
// | plugin_version | varchar(128)     | NO   |     |                   |                             |
// | maintain_begin | int(10) unsigned | NO   |     | 0                 |                             |
// | maintain_end   | int(10) unsigned | NO   |     | 0                 |                             |
// | update_at      | timestamp        | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
// +----------------+------------------+------+-----+-------------------+-----------------------------+

type Host struct {
	ID            int64  `json:"id" gorm:"column:id"`
	Hostname      string `json:"hostname" gorm:"column:hostname"`
	Ip            string `json:"ip" gorm:"column:ip"`
	AgentVersion  string `json:"agent_version"  gorm:"column:agent_version"`
	PluginVersion string `json:"plugin_version"  gorm:"column:plugin_version"`
	MaintainBegin int64  `json:"maintain_begin"  gorm:"column:maintain_begin"`
	MaintainEnd   int64  `json:"maintain_end"  gorm:"column:maintain_end"`
}

func (this Host) TableName() string {
	return "host"
}

func (this Host) Existing() (int64, bool) {
	db := con.Con()
	db.Falcon.Table(this.TableName()).Where("hostname = ?", this.Hostname).Scan(&this)
	if this.ID != 0 {
		return this.ID, true
	} else {
		return 0, false
	}
}

func (this Host) RelatedGrp() (Grps []HostGroup) {
	db := con.Con()
	grpHost := []GrpHost{}
	db.Falcon.Select("grp_id").Where("host_id = ?", this.ID).Find(&grpHost)
	tids := []int64{}
	for _, t := range grpHost {
		tids = append(tids, t.GrpID)
	}
	tidStr, _ := arrInt64ToString(tids)
	Grps = []HostGroup{}
	db.Falcon.Where(fmt.Sprintf("id in (%s)", tidStr)).Find(&Grps)
	return
}

func (this Host) RelatedTpl() (tpls []Template) {
	db := con.Con()
	grps := this.RelatedGrp()
	gids := []int64{}
	for _, g := range grps {
		gids = append(gids, g.ID)
	}
	gidStr, _ := arrInt64ToString(gids)
	grpTpls := []GrpTpl{}
	db.Falcon.Select("tpl_id").Where(fmt.Sprintf("grp_id in (%s)", gidStr)).Find(&grpTpls)
	tids := []int64{}
	for _, t := range grpTpls {
		tids = append(tids, t.TplID)
	}
	tidStr, _ := arrInt64ToString(tids)
	tpls = []Template{}
	db.Falcon.Where(fmt.Sprintf("id in (%s)", tidStr)).Find(&tpls)
	return
}

func arrInt64ToString(arr []int64) (result string, err error) {
	result = ""
	for indx, a := range arr {
		if indx == 0 {
			result = fmt.Sprintf("%v", a)
		} else {
			result = fmt.Sprintf("%v,%v", result, a)
		}
	}
	if result == "" {
		err = errors.New(fmt.Sprintf("array is empty, err: %v", arr))
	}
	return
}
<|endoftext|>


<commit_before>package column

import (
	"time"

	"github.com/ClickHouse/clickhouse-go/lib/binary"
)

type DateTime struct {
	base
	Timezone *time.Location
}

func (dt *DateTime) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
	sec, err := decoder.Int32()
	if err != nil {
		return nil, err
	}
	return time.Unix(int64(sec), 0).In(dt.Timezone), nil
}

func (dt *DateTime) Write(encoder *binary.Encoder, v interface{}) error {
	var timestamp int64
	switch value := v.(type) {
	case time.Time:
		if !value.IsZero() {
			timestamp = value.Unix()
		}
	case int16:
		timestamp = int64(value)
	case int32:
		timestamp = int64(value)
	case uint32:
		timestamp = int64(value)
	case uint64:
		timestamp = int64(value)
	case int64:
		timestamp = value
	case string:
		var err error
		timestamp, err = dt.parse(value)
		if err != nil {
			return err
		}

	case *time.Time:
		if value != nil && !(*value).IsZero() {
			timestamp = (*value).Unix()
		}
	case *int16:
		timestamp = int64(*value)
	case *int32:
		timestamp = int64(*value)
	case *int64:
		timestamp = *value
	case *string:
		var err error
		timestamp, err = dt.parse(*value)
		if err != nil {
			return err
		}

	default:
		return &ErrUnexpectedType{
			T:      v,
			Column: dt,
		}
	}

	return encoder.Int32(int32(timestamp))
}

func (dt *DateTime) parse(value string) (int64, error) {
	tv, err := time.Parse("2006-01-02 15:04:05", value)
	if err != nil {
		return 0, err
	}
	return time.Date(
		time.Time(tv).Year(),
		time.Time(tv).Month(),
		time.Time(tv).Day(),
		time.Time(tv).Hour(),
		time.Time(tv).Minute(),
		time.Time(tv).Second(),
		0, time.UTC,
	).Unix(), nil
}
<commit_msg>use local timezone when insert into clickhouse<commit_after>package column

import (
	"time"

	"github.com/ClickHouse/clickhouse-go/lib/binary"
)

type DateTime struct {
	base
	Timezone *time.Location
}

func (dt *DateTime) Read(decoder *binary.Decoder, isNull bool) (interface{}, error) {
	sec, err := decoder.Int32()
	if err != nil {
		return nil, err
	}
	return time.Unix(int64(sec), 0).In(dt.Timezone), nil
}

func (dt *DateTime) Write(encoder *binary.Encoder, v interface{}) error {
	var timestamp int64
	switch value := v.(type) {
	case time.Time:
		if !value.IsZero() {
			timestamp = value.Unix()
		}
	case int16:
		timestamp = int64(value)
	case int32:
		timestamp = int64(value)
	case uint32:
		timestamp = int64(value)
	case uint64:
		timestamp = int64(value)
	case int64:
		timestamp = value
	case string:
		var err error
		timestamp, err = dt.parse(value)
		if err != nil {
			return err
		}

	case *time.Time:
		if value != nil && !(*value).IsZero() {
			timestamp = (*value).Unix()
		}
	case *int16:
		timestamp = int64(*value)
	case *int32:
		timestamp = int64(*value)
	case *int64:
		timestamp = *value
	case *string:
		var err error
		timestamp, err = dt.parse(*value)
		if err != nil {
			return err
		}

	default:
		return &ErrUnexpectedType{
			T:      v,
			Column: dt,
		}
	}

	return encoder.Int32(int32(timestamp))
}

func (dt *DateTime) parse(value string) (int64, error) {
	tv, err := time.Parse("2006-01-02 15:04:05", value)
	if err != nil {
		return 0, err
	}
	return time.Date(
		time.Time(tv).Year(),
		time.Time(tv).Month(),
		time.Time(tv).Day(),
		time.Time(tv).Hour(),
		time.Time(tv).Minute(),
		time.Time(tv).Second(),
		0, time.Local,    //use local timzone when insert into clickhouse
	).Unix(), nil
}
<|endoftext|>


<commit_before>package doorman

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"

	log "github.com/sirupsen/logrus"
)

type headers map[string]string

type githubLoader struct {
	headers headers
}

func (ghl *githubLoader) CanLoad(url string) bool {
	regexpRepo, _ := regexp.Compile("^https://.*github.*/.*$")
	return regexpRepo.MatchString(url)
}

func (ghl *githubLoader) Load(url string) ([]*ServiceConfig, error) {
	log.Infof("Load %q from Github", url)

	regexpFile, _ := regexp.Compile("^.*\\.ya?ml$")

	urls := []string{}
	// Single file URL.
	if regexpFile.MatchString(url) {
		urls = []string{url}
	} else {
		// Folder on remote repo.
		return nil, fmt.Errorf("loading from Github folder is not supported yet")
	}
	// Load configurations.
	configs := []*ServiceConfig{}
	for _, url := range urls {
		tmpFile, err := download(url, ghl.headers)
		if err != nil {
			return nil, err
		}
		config, err := loadFile(tmpFile.Name())
		if err != nil {
			return nil, err
		}

		// Only delete temp file if successful
		os.Remove(tmpFile.Name())
		configs = append(configs, config)
	}
	return configs, nil
}

func download(url string, headers headers) (*os.File, error) {
	f, err := ioutil.TempFile("", "doorman-policy-")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	log.Debugf("Download %q", url)
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	size, err := io.Copy(f, response.Body)
	if err != nil {
		return nil, err
	}
	log.Debugf("Downloaded %dkB", size/1000)
	return f, nil
}

func init() {
	loaders = append(loaders, &githubLoader{
		headers: headers{
			"Authorization": fmt.Sprintf("token %s", ""), // Config.GithubToken),
		},
	})
}
<commit_msg>Read Github token from env while waiting for #68<commit_after>package doorman

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"

	log "github.com/sirupsen/logrus"
)

type headers map[string]string

type githubLoader struct {
	headers headers
}

func (ghl *githubLoader) CanLoad(url string) bool {
	regexpRepo, _ := regexp.Compile("^https://.*github.*/.*$")
	return regexpRepo.MatchString(url)
}

func (ghl *githubLoader) Load(url string) ([]*ServiceConfig, error) {
	log.Infof("Load %q from Github", url)

	regexpFile, _ := regexp.Compile("^.*\\.ya?ml$")

	urls := []string{}
	// Single file URL.
	if regexpFile.MatchString(url) {
		urls = []string{url}
	} else {
		// Folder on remote repo.
		return nil, fmt.Errorf("loading from Github folder is not supported yet")
	}
	// Load configurations.
	configs := []*ServiceConfig{}
	for _, url := range urls {
		tmpFile, err := download(url, ghl.headers)
		if err != nil {
			return nil, err
		}
		config, err := loadFile(tmpFile.Name())
		if err != nil {
			return nil, err
		}

		// Only delete temp file if successful
		os.Remove(tmpFile.Name())
		configs = append(configs, config)
	}
	return configs, nil
}

func download(url string, headers headers) (*os.File, error) {
	f, err := ioutil.TempFile("", "doorman-policy-")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	log.Debugf("Download %q", url)
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	size, err := io.Copy(f, response.Body)
	if err != nil {
		return nil, err
	}
	log.Debugf("Downloaded %dkB", size/1000)
	return f, nil
}

func init() {
	// XXX: Because we don't have access to doorman Config here,
	// we still use the env variable (even with the refactor of #67)
	// Will be sorted out in #68
	githubToken := os.Getenv("GITHUB_TOKEN")

	loaders = append(loaders, &githubLoader{
		headers: headers{
			"Authorization": fmt.Sprintf("token %s", githubToken),
		},
	})
}
<|endoftext|>