<commit_before>package gotest

import (
	"fmt"
	"strings"
	"time"

	"github.com/jstemmer/go-junit-report/v2/gtr"
	"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/collector"
)

const (
	globalID = 0
)

// reportBuilder helps build a test Report from a collection of events.
//
// The reportBuilder keeps track of the active context whenever a test or build
// error is created. This is necessary because the test parser do not contain
// any state themselves and simply just emit an event for every line that is
// read. By tracking the active context, any output that is appended to the
// reportBuilder gets attributed to the correct test or build error.
type reportBuilder struct {
	packages    []gtr.Package
	tests       map[int]gtr.Test
	buildErrors map[int]gtr.Error

	// state
	nextID    int               // next free unused id
	lastID    int               // most recently created id
	output    *collector.Output // output collected for each id
	coverage  float64           // coverage percentage
	parentIDs map[int]struct{}  // set of test id's that contain subtests

	// options
	packageName   string
	subtestMode   SubtestMode
	timestampFunc func() time.Time
}

// newReportBuilder creates a new reportBuilder.
func newReportBuilder() *reportBuilder {
	return &reportBuilder{
		tests:         make(map[int]gtr.Test),
		buildErrors:   make(map[int]gtr.Error),
		nextID:        1,
		output:        collector.New(),
		parentIDs:     make(map[int]struct{}),
		timestampFunc: time.Now,
	}
}

// ProcessEvent gives an event to this reportBuilder to be processed for this
// report.
func (b *reportBuilder) ProcessEvent(ev Event) {
	switch ev.Type {
	case "run_test":
		b.CreateTest(ev.Name)
	case "pause_test":
		b.PauseTest(ev.Name)
	case "cont_test":
		b.ContinueTest(ev.Name)
	case "end_test":
		b.EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent)
	case "run_benchmark":
		b.CreateTest(ev.Name)
	case "benchmark":
		b.BenchmarkResult(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp)
	case "end_benchmark":
		b.EndTest(ev.Name, ev.Result, 0, 0)
	case "status":
		b.End()
	case "summary":
		b.CreatePackage(ev.Name, ev.Result, ev.Duration, ev.Data)
	case "coverage":
		b.Coverage(ev.CovPct, ev.CovPackages)
	case "build_output":
		b.CreateBuildError(ev.Name)
	case "output":
		b.AppendOutput(ev.Data)
	default:
		fmt.Printf("reportBuilder: unhandled event type: %v\n", ev.Type)
	}
}

// newID returns a new unique id and sets the active context this id.
func (b *reportBuilder) newID() int {
	id := b.nextID
	b.lastID = id
	b.nextID++
	return id
}

// flush creates a new package in this report containing any tests we've
// collected so far. This is necessary when a test did not end with a summary.
func (b *reportBuilder) flush() {
	if len(b.tests) > 0 {
		b.CreatePackage(b.packageName, "", 0, "")
	}
}

// Build returns the new Report containing all the tests and output created so
// far.
func (b *reportBuilder) Build() gtr.Report {
	b.flush()
	return gtr.Report{Packages: b.packages}
}

// CreateTest adds a test with the given name to the report, and marks it as
// active.
func (b *reportBuilder) CreateTest(name string) {
	if parentID, ok := b.findTestParentID(name); ok {
		b.parentIDs[parentID] = struct{}{}
	}
	id := b.newID()
	b.tests[id] = gtr.NewTest(id, name)
}

// PauseTest marks the active context as no longer active. Any results or
// output added to the report after calling PauseTest will no longer be assumed
// to belong to this test.
func (b *reportBuilder) PauseTest(name string) {
	b.lastID = 0
}

// ContinueTest finds the test with the given name and marks it as active. If
// more than one test exist with this name, the most recently created test will
// be used.
func (b *reportBuilder) ContinueTest(name string) {
	b.lastID, _ = b.findTest(name)
}

// EndTest finds the test with the given name, sets the result, duration and
// level. If more than one test exists with this name, the most recently
// created test will be used. If no test exists with this name, a new test is
// created.
func (b *reportBuilder) EndTest(name, result string, duration time.Duration, level int) {
	id, ok := b.findTest(name)
	if !ok {
		// test did not exist, create one
		// TODO: Likely reason is that the user ran go test without the -v
		// flag, should we report this somewhere?
		b.CreateTest(name)
		id = b.lastID
	}

	t := b.tests[id]
	t.Result = parseResult(result)
	t.Duration = duration
	t.Level = level
	b.tests[id] = t
	b.lastID = 0
}

// End marks the active context as no longer active.
func (b *reportBuilder) End() {
	b.lastID = 0
}

// BenchmarkResult updates an existing or adds a new test with the given
// results and marks it as active. If an existing test with this name exists
// but without result, then that one is updated. Otherwise a new one is added
// to the report.
func (b *reportBuilder) BenchmarkResult(name string, iterations int64, nsPerOp, mbPerSec float64, bytesPerOp, allocsPerOp int64) {
	id, ok := b.findTest(name)
	if !ok || b.tests[id].Result != gtr.Unknown {
		b.CreateTest(name)
		id = b.lastID
	}

	benchmark := Benchmark{iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp}
	test := gtr.NewTest(id, name)
	test.Result = gtr.Pass
	test.Duration = benchmark.ApproximateDuration()
	SetBenchmarkData(&test, benchmark)
	b.tests[id] = test
}

// CreateBuildError creates a new build error and marks it as active.
func (b *reportBuilder) CreateBuildError(packageName string) {
	id := b.newID()
	b.buildErrors[id] = gtr.Error{ID: id, Name: packageName}
}

// CreatePackage adds a new package with the given name to the Report. This
// package contains all the build errors, output, tests and benchmarks created
// so far. Afterwards all state is reset.
func (b *reportBuilder) CreatePackage(name, result string, duration time.Duration, data string) {
	pkg := gtr.Package{
		Name:     name,
		Duration: duration,
	}

	if b.timestampFunc != nil {
		pkg.Timestamp = b.timestampFunc()
	}

	// Build errors are treated somewhat differently. Rather than having a
	// single package with all build errors collected so far, we only care
	// about the build errors for this particular package.
	for id, buildErr := range b.buildErrors {
		if buildErr.Name == name {
			if len(b.tests) > 0 {
				panic("unexpected tests found in build error package")
			}
			buildErr.ID = id
			buildErr.Duration = duration
			buildErr.Cause = data
			buildErr.Output = b.output.Get(id)

			pkg.BuildError = buildErr
			b.packages = append(b.packages, pkg)

			delete(b.buildErrors, id)
			// TODO: reset state
			// TODO: buildErrors shouldn't reset/use nextID/lastID, they're more like a global cache
			return
		}
	}

	// If we've collected output, but there were no tests then either there
	// actually were no tests, or there was some other non-build error.
	if b.output.Contains(globalID) && len(b.tests) == 0 {
		if parseResult(result) == gtr.Fail {
			pkg.RunError = gtr.Error{
				Name:   name,
				Output: b.output.Get(globalID),
			}
		} else if b.output.Contains(globalID) {
			pkg.Output = b.output.Get(globalID)
		}
		b.packages = append(b.packages, pkg)
		b.output.Clear(globalID)
		return
	}

	// If the summary result says we failed, but there were no failing tests
	// then something else must have failed.
	if parseResult(result) == gtr.Fail && len(b.tests) > 0 && !b.containsFailures() {
		pkg.RunError = gtr.Error{
			Name:   name,
			Output: b.output.Get(globalID),
		}
		b.output.Clear(globalID)
	}

	// Collect tests for this package, maintaining insertion order.
	var tests []gtr.Test
	for id := 1; id < b.nextID; id++ {
		if t, ok := b.tests[id]; ok {
			if b.isParent(id) {
				if b.subtestMode == IgnoreParentResults {
					t.Result = gtr.Pass
				} else if b.subtestMode == ExcludeParents {
					b.output.Merge(id, globalID)
					continue
				}
			}
			t.Output = b.output.Get(id)
			tests = append(tests, t)
			continue
		}
	}
	tests = b.groupBenchmarksByName(tests)

	pkg.Coverage = b.coverage
	pkg.Output = b.output.Get(globalID)
	pkg.Tests = tests
	b.packages = append(b.packages, pkg)

	// reset state, except for nextID to ensure all id's are unique.
	b.lastID = 0
	b.output.Clear(globalID)
	b.coverage = 0
	b.tests = make(map[int]gtr.Test)
	b.parentIDs = make(map[int]struct{})
}

// Coverage sets the code coverage percentage.
func (b *reportBuilder) Coverage(pct float64, packages []string) {
	b.coverage = pct
}

// AppendOutput appends the given text to the currently active context. If no
// active context exists, the output is assumed to belong to the package.
func (b *reportBuilder) AppendOutput(text string) {
	b.output.Append(b.lastID, text)
}

// findTest returns the id of the most recently created test with the given
// name if it exists.
func (b *reportBuilder) findTest(name string) (int, bool) {
	// check if this test was lastID
	if t, ok := b.tests[b.lastID]; ok && t.Name == name {
		return b.lastID, true
	}
	for i := b.nextID; i > 0; i-- {
		if test, ok := b.tests[i]; ok && test.Name == name {
			return i, true
		}
	}
	return 0, false
}

func (b *reportBuilder) findTestParentID(name string) (int, bool) {
	parent := dropLastSegment(name)
	for parent != "" {
		if id, ok := b.findTest(parent); ok {
			return id, true
		}
		parent = dropLastSegment(parent)
	}
	return 0, false
}

func (b *reportBuilder) isParent(id int) bool {
	_, ok := b.parentIDs[id]
	return ok
}

func dropLastSegment(name string) string {
	if idx := strings.LastIndexByte(name, '/'); idx >= 0 {
		return name[:idx]
	}
	return ""
}

// containsFailures return true if the current list of tests contains at least
// one failing test or an unknown result.
func (b *reportBuilder) containsFailures() bool {
	for _, test := range b.tests {
		if test.Result == gtr.Fail || test.Result == gtr.Unknown {
			return true
		}
	}
	return false
}

// parseResult returns a Result for the given string r.
func parseResult(r string) gtr.Result {
	switch r {
	case "PASS":
		return gtr.Pass
	case "FAIL":
		return gtr.Fail
	case "SKIP":
		return gtr.Skip
	case "BENCH":
		return gtr.Pass
	default:
		return gtr.Unknown
	}
}

func (b *reportBuilder) groupBenchmarksByName(tests []gtr.Test) []gtr.Test {
	if len(tests) == 0 {
		return nil
	}

	var grouped []gtr.Test
	byName := make(map[string][]gtr.Test)
	for _, test := range tests {
		if !strings.HasPrefix(test.Name, "Benchmark") {
			// If this test is not a benchmark, we won't group it by name but
			// just add it to the final result.
			grouped = append(grouped, test)
			continue
		}
		if _, ok := byName[test.Name]; !ok {
			grouped = append(grouped, gtr.NewTest(test.ID, test.Name))
		}
		byName[test.Name] = append(byName[test.Name], test)
	}

	for i, group := range grouped {
		if !strings.HasPrefix(group.Name, "Benchmark") {
			continue
		}
		var (
			ids   []int
			total Benchmark
			count int
		)
		for _, test := range byName[group.Name] {
			ids = append(ids, test.ID)
			if test.Result != gtr.Pass {
				continue
			}

			if bench, ok := GetBenchmarkData(test); ok {
				total.Iterations += bench.Iterations
				total.NsPerOp += bench.NsPerOp
				total.MBPerSec += bench.MBPerSec
				total.BytesPerOp += bench.BytesPerOp
				total.AllocsPerOp += bench.AllocsPerOp
				count++
			}
		}

		group.Duration = combinedDuration(byName[group.Name])
		group.Result = groupResults(byName[group.Name])
		group.Output = b.output.GetAll(ids...)
		if count > 0 {
			total.Iterations /= int64(count)
			total.NsPerOp /= float64(count)
			total.MBPerSec /= float64(count)
			total.BytesPerOp /= int64(count)
			total.AllocsPerOp /= int64(count)
			SetBenchmarkData(&group, total)
		}
		grouped[i] = group
	}
	return grouped
}

func combinedDuration(tests []gtr.Test) time.Duration {
	var total time.Duration
	for _, test := range tests {
		total += test.Duration
	}
	return total
}

func groupResults(tests []gtr.Test) gtr.Result {
	var result gtr.Result
	for _, test := range tests {
		if test.Result == gtr.Fail {
			return gtr.Fail
		}
		if result != gtr.Pass {
			result = test.Result
		}
	}
	return result
}
<commit_msg>parser/gotest: Return created id from CreateTest method<commit_after>package gotest

import (
	"fmt"
	"strings"
	"time"

	"github.com/jstemmer/go-junit-report/v2/gtr"
	"github.com/jstemmer/go-junit-report/v2/parser/gotest/internal/collector"
)

const (
	globalID = 0
)

// reportBuilder helps build a test Report from a collection of events.
//
// The reportBuilder keeps track of the active context whenever a test or build
// error is created. This is necessary because the test parser do not contain
// any state themselves and simply just emit an event for every line that is
// read. By tracking the active context, any output that is appended to the
// reportBuilder gets attributed to the correct test or build error.
type reportBuilder struct {
	packages    []gtr.Package
	tests       map[int]gtr.Test
	buildErrors map[int]gtr.Error

	// state
	nextID    int               // next free unused id
	lastID    int               // most recently created id
	output    *collector.Output // output collected for each id
	coverage  float64           // coverage percentage
	parentIDs map[int]struct{}  // set of test id's that contain subtests

	// options
	packageName   string
	subtestMode   SubtestMode
	timestampFunc func() time.Time
}

// newReportBuilder creates a new reportBuilder.
func newReportBuilder() *reportBuilder {
	return &reportBuilder{
		tests:         make(map[int]gtr.Test),
		buildErrors:   make(map[int]gtr.Error),
		nextID:        1,
		output:        collector.New(),
		parentIDs:     make(map[int]struct{}),
		timestampFunc: time.Now,
	}
}

// ProcessEvent gives an event to this reportBuilder to be processed for this
// report.
func (b *reportBuilder) ProcessEvent(ev Event) {
	switch ev.Type {
	case "run_test":
		b.CreateTest(ev.Name)
	case "pause_test":
		b.PauseTest(ev.Name)
	case "cont_test":
		b.ContinueTest(ev.Name)
	case "end_test":
		b.EndTest(ev.Name, ev.Result, ev.Duration, ev.Indent)
	case "run_benchmark":
		b.CreateTest(ev.Name)
	case "benchmark":
		b.BenchmarkResult(ev.Name, ev.Iterations, ev.NsPerOp, ev.MBPerSec, ev.BytesPerOp, ev.AllocsPerOp)
	case "end_benchmark":
		b.EndTest(ev.Name, ev.Result, 0, 0)
	case "status":
		b.End()
	case "summary":
		b.CreatePackage(ev.Name, ev.Result, ev.Duration, ev.Data)
	case "coverage":
		b.Coverage(ev.CovPct, ev.CovPackages)
	case "build_output":
		b.CreateBuildError(ev.Name)
	case "output":
		b.AppendOutput(ev.Data)
	default:
		fmt.Printf("reportBuilder: unhandled event type: %v\n", ev.Type)
	}
}

// newID returns a new unique id and sets the active context this id.
func (b *reportBuilder) newID() int {
	id := b.nextID
	b.lastID = id
	b.nextID++
	return id
}

// flush creates a new package in this report containing any tests we've
// collected so far. This is necessary when a test did not end with a summary.
func (b *reportBuilder) flush() {
	if len(b.tests) > 0 {
		b.CreatePackage(b.packageName, "", 0, "")
	}
}

// Build returns the new Report containing all the tests and output created so
// far.
func (b *reportBuilder) Build() gtr.Report {
	b.flush()
	return gtr.Report{Packages: b.packages}
}

// CreateTest adds a test with the given name to the report, and marks it as
// active.
func (b *reportBuilder) CreateTest(name string) int {
	if parentID, ok := b.findTestParentID(name); ok {
		b.parentIDs[parentID] = struct{}{}
	}
	id := b.newID()
	b.tests[id] = gtr.NewTest(id, name)
	return id
}

// PauseTest marks the active context as no longer active. Any results or
// output added to the report after calling PauseTest will no longer be assumed
// to belong to this test.
func (b *reportBuilder) PauseTest(name string) {
	b.lastID = 0
}

// ContinueTest finds the test with the given name and marks it as active. If
// more than one test exist with this name, the most recently created test will
// be used.
func (b *reportBuilder) ContinueTest(name string) {
	b.lastID, _ = b.findTest(name)
}

// EndTest finds the test with the given name, sets the result, duration and
// level. If more than one test exists with this name, the most recently
// created test will be used. If no test exists with this name, a new test is
// created.
func (b *reportBuilder) EndTest(name, result string, duration time.Duration, level int) {
	id, ok := b.findTest(name)
	if !ok {
		// test did not exist, create one
		// TODO: Likely reason is that the user ran go test without the -v
		// flag, should we report this somewhere?
		id = b.CreateTest(name)
	}

	t := b.tests[id]
	t.Result = parseResult(result)
	t.Duration = duration
	t.Level = level
	b.tests[id] = t
	b.lastID = 0
}

// End marks the active context as no longer active.
func (b *reportBuilder) End() {
	b.lastID = 0
}

// BenchmarkResult updates an existing or adds a new test with the given
// results and marks it as active. If an existing test with this name exists
// but without result, then that one is updated. Otherwise a new one is added
// to the report.
func (b *reportBuilder) BenchmarkResult(name string, iterations int64, nsPerOp, mbPerSec float64, bytesPerOp, allocsPerOp int64) {
	id, ok := b.findTest(name)
	if !ok || b.tests[id].Result != gtr.Unknown {
		id = b.CreateTest(name)
	}

	benchmark := Benchmark{iterations, nsPerOp, mbPerSec, bytesPerOp, allocsPerOp}
	test := gtr.NewTest(id, name)
	test.Result = gtr.Pass
	test.Duration = benchmark.ApproximateDuration()
	SetBenchmarkData(&test, benchmark)
	b.tests[id] = test
}

// CreateBuildError creates a new build error and marks it as active.
func (b *reportBuilder) CreateBuildError(packageName string) {
	id := b.newID()
	b.buildErrors[id] = gtr.Error{ID: id, Name: packageName}
}

// CreatePackage adds a new package with the given name to the Report. This
// package contains all the build errors, output, tests and benchmarks created
// so far. Afterwards all state is reset.
func (b *reportBuilder) CreatePackage(name, result string, duration time.Duration, data string) {
	pkg := gtr.Package{
		Name:     name,
		Duration: duration,
	}

	if b.timestampFunc != nil {
		pkg.Timestamp = b.timestampFunc()
	}

	// Build errors are treated somewhat differently. Rather than having a
	// single package with all build errors collected so far, we only care
	// about the build errors for this particular package.
	for id, buildErr := range b.buildErrors {
		if buildErr.Name == name {
			if len(b.tests) > 0 {
				panic("unexpected tests found in build error package")
			}
			buildErr.ID = id
			buildErr.Duration = duration
			buildErr.Cause = data
			buildErr.Output = b.output.Get(id)

			pkg.BuildError = buildErr
			b.packages = append(b.packages, pkg)

			delete(b.buildErrors, id)
			// TODO: reset state
			// TODO: buildErrors shouldn't reset/use nextID/lastID, they're more like a global cache
			return
		}
	}

	// If we've collected output, but there were no tests then either there
	// actually were no tests, or there was some other non-build error.
	if b.output.Contains(globalID) && len(b.tests) == 0 {
		if parseResult(result) == gtr.Fail {
			pkg.RunError = gtr.Error{
				Name:   name,
				Output: b.output.Get(globalID),
			}
		} else if b.output.Contains(globalID) {
			pkg.Output = b.output.Get(globalID)
		}
		b.packages = append(b.packages, pkg)
		b.output.Clear(globalID)
		return
	}

	// If the summary result says we failed, but there were no failing tests
	// then something else must have failed.
	if parseResult(result) == gtr.Fail && len(b.tests) > 0 && !b.containsFailures() {
		pkg.RunError = gtr.Error{
			Name:   name,
			Output: b.output.Get(globalID),
		}
		b.output.Clear(globalID)
	}

	// Collect tests for this package, maintaining insertion order.
	var tests []gtr.Test
	for id := 1; id < b.nextID; id++ {
		if t, ok := b.tests[id]; ok {
			if b.isParent(id) {
				if b.subtestMode == IgnoreParentResults {
					t.Result = gtr.Pass
				} else if b.subtestMode == ExcludeParents {
					b.output.Merge(id, globalID)
					continue
				}
			}
			t.Output = b.output.Get(id)
			tests = append(tests, t)
			continue
		}
	}
	tests = b.groupBenchmarksByName(tests)

	pkg.Coverage = b.coverage
	pkg.Output = b.output.Get(globalID)
	pkg.Tests = tests
	b.packages = append(b.packages, pkg)

	// reset state, except for nextID to ensure all id's are unique.
	b.lastID = 0
	b.output.Clear(globalID)
	b.coverage = 0
	b.tests = make(map[int]gtr.Test)
	b.parentIDs = make(map[int]struct{})
}

// Coverage sets the code coverage percentage.
func (b *reportBuilder) Coverage(pct float64, packages []string) {
	b.coverage = pct
}

// AppendOutput appends the given text to the currently active context. If no
// active context exists, the output is assumed to belong to the package.
func (b *reportBuilder) AppendOutput(text string) {
	b.output.Append(b.lastID, text)
}

// findTest returns the id of the most recently created test with the given
// name if it exists.
func (b *reportBuilder) findTest(name string) (int, bool) {
	// check if this test was lastID
	if t, ok := b.tests[b.lastID]; ok && t.Name == name {
		return b.lastID, true
	}
	for i := b.nextID; i > 0; i-- {
		if test, ok := b.tests[i]; ok && test.Name == name {
			return i, true
		}
	}
	return 0, false
}

func (b *reportBuilder) findTestParentID(name string) (int, bool) {
	parent := dropLastSegment(name)
	for parent != "" {
		if id, ok := b.findTest(parent); ok {
			return id, true
		}
		parent = dropLastSegment(parent)
	}
	return 0, false
}

func (b *reportBuilder) isParent(id int) bool {
	_, ok := b.parentIDs[id]
	return ok
}

func dropLastSegment(name string) string {
	if idx := strings.LastIndexByte(name, '/'); idx >= 0 {
		return name[:idx]
	}
	return ""
}

// containsFailures return true if the current list of tests contains at least
// one failing test or an unknown result.
func (b *reportBuilder) containsFailures() bool {
	for _, test := range b.tests {
		if test.Result == gtr.Fail || test.Result == gtr.Unknown {
			return true
		}
	}
	return false
}

// parseResult returns a Result for the given string r.
func parseResult(r string) gtr.Result {
	switch r {
	case "PASS":
		return gtr.Pass
	case "FAIL":
		return gtr.Fail
	case "SKIP":
		return gtr.Skip
	case "BENCH":
		return gtr.Pass
	default:
		return gtr.Unknown
	}
}

func (b *reportBuilder) groupBenchmarksByName(tests []gtr.Test) []gtr.Test {
	if len(tests) == 0 {
		return nil
	}

	var grouped []gtr.Test
	byName := make(map[string][]gtr.Test)
	for _, test := range tests {
		if !strings.HasPrefix(test.Name, "Benchmark") {
			// If this test is not a benchmark, we won't group it by name but
			// just add it to the final result.
			grouped = append(grouped, test)
			continue
		}
		if _, ok := byName[test.Name]; !ok {
			grouped = append(grouped, gtr.NewTest(test.ID, test.Name))
		}
		byName[test.Name] = append(byName[test.Name], test)
	}

	for i, group := range grouped {
		if !strings.HasPrefix(group.Name, "Benchmark") {
			continue
		}
		var (
			ids   []int
			total Benchmark
			count int
		)
		for _, test := range byName[group.Name] {
			ids = append(ids, test.ID)
			if test.Result != gtr.Pass {
				continue
			}

			if bench, ok := GetBenchmarkData(test); ok {
				total.Iterations += bench.Iterations
				total.NsPerOp += bench.NsPerOp
				total.MBPerSec += bench.MBPerSec
				total.BytesPerOp += bench.BytesPerOp
				total.AllocsPerOp += bench.AllocsPerOp
				count++
			}
		}

		group.Duration = combinedDuration(byName[group.Name])
		group.Result = groupResults(byName[group.Name])
		group.Output = b.output.GetAll(ids...)
		if count > 0 {
			total.Iterations /= int64(count)
			total.NsPerOp /= float64(count)
			total.MBPerSec /= float64(count)
			total.BytesPerOp /= int64(count)
			total.AllocsPerOp /= int64(count)
			SetBenchmarkData(&group, total)
		}
		grouped[i] = group
	}
	return grouped
}

func combinedDuration(tests []gtr.Test) time.Duration {
	var total time.Duration
	for _, test := range tests {
		total += test.Duration
	}
	return total
}

func groupResults(tests []gtr.Test) gtr.Result {
	var result gtr.Result
	for _, test := range tests {
		if test.Result == gtr.Fail {
			return gtr.Fail
		}
		if result != gtr.Pass {
			result = test.Result
		}
	}
	return result
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccAWSRouteDataSource_basic(t *testing.T) {
	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsRouteGroupConfig(),
				Check: resource.ComposeTestCheckFunc(
					testAccDataSourceAwsRouteCheck("data.aws_route.by_destination_cidr_block"),
					testAccDataSourceAwsRouteCheck("data.aws_route.by_instance_id"),
					testAccDataSourceAwsRouteCheck("data.aws_route.by_peering_connection_id"),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func TestAccAWSRouteDataSource_TransitGatewayID(t *testing.T) {
	var route ec2.Route
	dataSourceName := "data.aws_route.test"
	resourceName := "aws_route.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSRouteDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSRouteDataSourceConfigTransitGatewayID(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSRouteExists(resourceName, &route),
					resource.TestCheckResourceAttrPair(resourceName, "destination_cidr_block", dataSourceName, "destination_cidr_block"),
					resource.TestCheckResourceAttrPair(resourceName, "route_table_id", dataSourceName, "route_table_id"),
					resource.TestCheckResourceAttrPair(resourceName, "transit_gateway_id", dataSourceName, "transit_gateway_id"),
				),
			},
		},
	})
}

func TestAccAWSRouteDataSource_LocalGatewayID(t *testing.T) {
	var route ec2.Route
	dataSourceName := "data.aws_route.by_local_gateway_id"
	resourceName := "aws_route.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccPreCheckAWSOutpostsOutposts(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSRouteDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSRouteDataSourceConfigLocalGatewayID(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSRouteExists(resourceName, &route),
					resource.TestCheckResourceAttrPair(resourceName, "destination_cidr_block", dataSourceName, "destination_cidr_block"),
					resource.TestCheckResourceAttrPair(resourceName, "route_table_id", dataSourceName, "route_table_id"),
					resource.TestCheckResourceAttrPair(resourceName, "local_gateway_id", dataSourceName, "local_gateway_id"),
				),
			},
		},
	})
}

func testAccDataSourceAwsRouteCheck(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]

		if !ok {
			return fmt.Errorf("root module has no resource called %s", name)
		}

		r, ok := s.RootModule().Resources["aws_route.test"]
		if !ok {
			return fmt.Errorf("can't find aws_route.test in state")
		}
		rts, ok := s.RootModule().Resources["aws_route_table.test"]
		if !ok {
			return fmt.Errorf("can't find aws_route_table.test in state")
		}

		attr := rs.Primary.Attributes

		if attr["route_table_id"] != r.Primary.Attributes["route_table_id"] {
			return fmt.Errorf(
				"route_table_id is %s; want %s",
				attr["route_table_id"],
				r.Primary.Attributes["route_table_id"],
			)
		}

		if attr["route_table_id"] != rts.Primary.Attributes["id"] {
			return fmt.Errorf(
				"route_table_id is %s; want %s",
				attr["route_table_id"],
				rts.Primary.Attributes["id"],
			)
		}

		return nil
	}
}

func testAccDataSourceAwsRouteGroupConfig() string {
	return testAccLatestAmazonLinuxHvmEbsAmiConfig() + `
resource "aws_vpc" "test" {
  cidr_block = "172.16.0.0/16"

  tags = {
    Name = "terraform-testacc-route-table-data-source"
  }
}

resource "aws_vpc" "dest" {
  cidr_block = "172.17.0.0/16"

  tags = {
    Name = "terraform-testacc-route-table-data-source"
  }
}

resource "aws_vpc_peering_connection" "test" {
  peer_vpc_id = aws_vpc.dest.id
  vpc_id      = aws_vpc.test.id
  auto_accept = true
}

resource "aws_subnet" "test" {
  cidr_block = "172.16.0.0/24"
  vpc_id     = aws_vpc.test.id

  tags = {
    Name = "tf-acc-route-table-data-source"
  }
}

resource "aws_route_table" "test" {
  vpc_id = aws_vpc.test.id

  tags = {
    Name = "terraform-testacc-routetable-data-source"
  }
}

resource "aws_route" "pcx" {
  route_table_id            = aws_route_table.test.id
  vpc_peering_connection_id = aws_vpc_peering_connection.test.id
  destination_cidr_block    = "10.0.2.0/24"
}

resource "aws_route_table_association" "a" {
  subnet_id      = aws_subnet.test.id
  route_table_id = aws_route_table.test.id
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amzn-ami-minimal-hvm-ebs.id
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.test.id

  tags = {
    Name = "HelloWorld"
  }
}

resource "aws_route" "test" {
  route_table_id         = aws_route_table.test.id
  destination_cidr_block = "10.0.1.0/24"
  instance_id            = aws_instance.web.id

  timeouts {
    create = "5m"
  }
}

data "aws_route" "by_peering_connection_id" {
  route_table_id            = aws_route_table.test.id
  vpc_peering_connection_id = aws_route.pcx.vpc_peering_connection_id
}

data "aws_route" "by_destination_cidr_block" {
  route_table_id         = aws_route_table.test.id
  destination_cidr_block = "10.0.1.0/24"
  depends_on             = [aws_route.test]
}

data "aws_route" "by_instance_id" {
  route_table_id = aws_route_table.test.id
  instance_id    = aws_instance.web.id
  depends_on     = [aws_route.test]
}
`
}

func testAccAWSRouteDataSourceConfigTransitGatewayID() string {
	return testAccAvailableAZsNoOptInDefaultExcludeConfig() + `
# IncorrectState: Transit Gateway is not available in some availability zones

resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "tf-acc-test-ec2-route-datasource-transit-gateway-id"
  }
}

resource "aws_subnet" "test" {
  availability_zone = data.aws_availability_zones.available.names[0]
  cidr_block        = "10.0.0.0/24"
  vpc_id            = aws_vpc.test.id

  tags = {
    Name = "tf-acc-test-ec2-route-datasource-transit-gateway-id"
  }
}

resource "aws_ec2_transit_gateway" "test" {}

resource "aws_ec2_transit_gateway_vpc_attachment" "test" {
  subnet_ids         = [aws_subnet.test.id]
  transit_gateway_id = aws_ec2_transit_gateway.test.id
  vpc_id             = aws_vpc.test.id
}

resource "aws_route" "test" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_vpc.test.default_route_table_id
  transit_gateway_id     = aws_ec2_transit_gateway_vpc_attachment.test.transit_gateway_id
}

data "aws_route" "test" {
  route_table_id     = aws_route.test.route_table_id
  transit_gateway_id = aws_route.test.transit_gateway_id
}
`
}

func testAccAWSRouteDataSourceConfigLocalGatewayID() string {
	return fmt.Sprintf(`
data "aws_ec2_local_gateways" "all" {}
data "aws_ec2_local_gateway" "first" {
  id = tolist(data.aws_ec2_local_gateways.all.ids)[0]
}

data "aws_ec2_local_gateway_route_tables" "all" {}
data "aws_ec2_local_gateway_route_table" "first" {
  local_gateway_route_table_id = tolist(data.aws_ec2_local_gateway_route_tables.all.ids)[0]
}

resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_ec2_local_gateway_route_table_vpc_association" "example" {
  local_gateway_route_table_id = data.aws_ec2_local_gateway_route_table.first.id
  vpc_id                       = aws_vpc.test.id
}

resource "aws_route_table" "test" {
  vpc_id = aws_vpc.test.id
}

resource "aws_route" "test" {
  route_table_id         = aws_route_table.test.id
  destination_cidr_block = "172.16.1.0/24"
  local_gateway_id       = data.aws_ec2_local_gateway.first.id
  depends_on             = [aws_ec2_local_gateway_route_table_vpc_association.example]
}

data "aws_route" "by_local_gateway_id" {
  route_table_id   = aws_route_table.test.id
  local_gateway_id = data.aws_ec2_local_gateway.first.id
  depends_on       = [aws_route.test]
}
`)
}
<commit_msg>Restricts TestAccAWSRouteDataSource_basic to supported subnets<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccAWSRouteDataSource_basic(t *testing.T) {
	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsRouteGroupConfig(),
				Check: resource.ComposeTestCheckFunc(
					testAccDataSourceAwsRouteCheck("data.aws_route.by_destination_cidr_block"),
					testAccDataSourceAwsRouteCheck("data.aws_route.by_instance_id"),
					testAccDataSourceAwsRouteCheck("data.aws_route.by_peering_connection_id"),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func TestAccAWSRouteDataSource_TransitGatewayID(t *testing.T) {
	var route ec2.Route
	dataSourceName := "data.aws_route.test"
	resourceName := "aws_route.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSRouteDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSRouteDataSourceConfigTransitGatewayID(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSRouteExists(resourceName, &route),
					resource.TestCheckResourceAttrPair(resourceName, "destination_cidr_block", dataSourceName, "destination_cidr_block"),
					resource.TestCheckResourceAttrPair(resourceName, "route_table_id", dataSourceName, "route_table_id"),
					resource.TestCheckResourceAttrPair(resourceName, "transit_gateway_id", dataSourceName, "transit_gateway_id"),
				),
			},
		},
	})
}

func TestAccAWSRouteDataSource_LocalGatewayID(t *testing.T) {
	var route ec2.Route
	dataSourceName := "data.aws_route.by_local_gateway_id"
	resourceName := "aws_route.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t); testAccPreCheckAWSOutpostsOutposts(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSRouteDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSRouteDataSourceConfigLocalGatewayID(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSRouteExists(resourceName, &route),
					resource.TestCheckResourceAttrPair(resourceName, "destination_cidr_block", dataSourceName, "destination_cidr_block"),
					resource.TestCheckResourceAttrPair(resourceName, "route_table_id", dataSourceName, "route_table_id"),
					resource.TestCheckResourceAttrPair(resourceName, "local_gateway_id", dataSourceName, "local_gateway_id"),
				),
			},
		},
	})
}

func testAccDataSourceAwsRouteCheck(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]

		if !ok {
			return fmt.Errorf("root module has no resource called %s", name)
		}

		r, ok := s.RootModule().Resources["aws_route.test"]
		if !ok {
			return fmt.Errorf("can't find aws_route.test in state")
		}
		rts, ok := s.RootModule().Resources["aws_route_table.test"]
		if !ok {
			return fmt.Errorf("can't find aws_route_table.test in state")
		}

		attr := rs.Primary.Attributes

		if attr["route_table_id"] != r.Primary.Attributes["route_table_id"] {
			return fmt.Errorf(
				"route_table_id is %s; want %s",
				attr["route_table_id"],
				r.Primary.Attributes["route_table_id"],
			)
		}

		if attr["route_table_id"] != rts.Primary.Attributes["id"] {
			return fmt.Errorf(
				"route_table_id is %s; want %s",
				attr["route_table_id"],
				rts.Primary.Attributes["id"],
			)
		}

		return nil
	}
}

func testAccDataSourceAwsRouteGroupConfig() string {
	return composeConfig(
		testAccLatestAmazonLinuxHvmEbsAmiConfig(),
		testAccAvailableAZsNoOptInDefaultExcludeConfig(), `
resource "aws_vpc" "test" {
  cidr_block = "172.16.0.0/16"

  tags = {
    Name = "terraform-testacc-route-table-data-source"
  }
}

resource "aws_vpc" "dest" {
  cidr_block = "172.17.0.0/16"

  tags = {
    Name = "terraform-testacc-route-table-data-source"
  }
}

resource "aws_vpc_peering_connection" "test" {
  peer_vpc_id = aws_vpc.dest.id
  vpc_id      = aws_vpc.test.id
  auto_accept = true
}

resource "aws_subnet" "test" {
  cidr_block        = "172.16.0.0/24"
  vpc_id            = aws_vpc.test.id
  availability_zone = data.aws_availability_zones.available.names[0]

  tags = {
    Name = "tf-acc-route-table-data-source"
  }
}

resource "aws_route_table" "test" {
  vpc_id = aws_vpc.test.id

  tags = {
    Name = "terraform-testacc-routetable-data-source"
  }
}

resource "aws_route" "pcx" {
  route_table_id            = aws_route_table.test.id
  vpc_peering_connection_id = aws_vpc_peering_connection.test.id
  destination_cidr_block    = "10.0.2.0/24"
}

resource "aws_route_table_association" "a" {
  subnet_id      = aws_subnet.test.id
  route_table_id = aws_route_table.test.id
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amzn-ami-minimal-hvm-ebs.id
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.test.id

  tags = {
    Name = "HelloWorld"
  }
}

resource "aws_route" "test" {
  route_table_id         = aws_route_table.test.id
  destination_cidr_block = "10.0.1.0/24"
  instance_id            = aws_instance.web.id

  timeouts {
    create = "5m"
  }
}

data "aws_route" "by_peering_connection_id" {
  route_table_id            = aws_route_table.test.id
  vpc_peering_connection_id = aws_route.pcx.vpc_peering_connection_id
}

data "aws_route" "by_destination_cidr_block" {
  route_table_id         = aws_route_table.test.id
  destination_cidr_block = "10.0.1.0/24"
  depends_on             = [aws_route.test]
}

data "aws_route" "by_instance_id" {
  route_table_id = aws_route_table.test.id
  instance_id    = aws_instance.web.id
  depends_on     = [aws_route.test]
}
`)
}

func testAccAWSRouteDataSourceConfigTransitGatewayID() string {
	return testAccAvailableAZsNoOptInDefaultExcludeConfig() + `
# IncorrectState: Transit Gateway is not available in some availability zones

resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "tf-acc-test-ec2-route-datasource-transit-gateway-id"
  }
}

resource "aws_subnet" "test" {
  availability_zone = data.aws_availability_zones.available.names[0]
  cidr_block        = "10.0.0.0/24"
  vpc_id            = aws_vpc.test.id

  tags = {
    Name = "tf-acc-test-ec2-route-datasource-transit-gateway-id"
  }
}

resource "aws_ec2_transit_gateway" "test" {}

resource "aws_ec2_transit_gateway_vpc_attachment" "test" {
  subnet_ids         = [aws_subnet.test.id]
  transit_gateway_id = aws_ec2_transit_gateway.test.id
  vpc_id             = aws_vpc.test.id
}

resource "aws_route" "test" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = aws_vpc.test.default_route_table_id
  transit_gateway_id     = aws_ec2_transit_gateway_vpc_attachment.test.transit_gateway_id
}

data "aws_route" "test" {
  route_table_id     = aws_route.test.route_table_id
  transit_gateway_id = aws_route.test.transit_gateway_id
}
`
}

func testAccAWSRouteDataSourceConfigLocalGatewayID() string {
	return fmt.Sprintf(`
data "aws_ec2_local_gateways" "all" {}
data "aws_ec2_local_gateway" "first" {
  id = tolist(data.aws_ec2_local_gateways.all.ids)[0]
}

data "aws_ec2_local_gateway_route_tables" "all" {}
data "aws_ec2_local_gateway_route_table" "first" {
  local_gateway_route_table_id = tolist(data.aws_ec2_local_gateway_route_tables.all.ids)[0]
}

resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_ec2_local_gateway_route_table_vpc_association" "example" {
  local_gateway_route_table_id = data.aws_ec2_local_gateway_route_table.first.id
  vpc_id                       = aws_vpc.test.id
}

resource "aws_route_table" "test" {
  vpc_id = aws_vpc.test.id
}

resource "aws_route" "test" {
  route_table_id         = aws_route_table.test.id
  destination_cidr_block = "172.16.1.0/24"
  local_gateway_id       = data.aws_ec2_local_gateway.first.id
  depends_on             = [aws_ec2_local_gateway_route_table_vpc_association.example]
}

data "aws_route" "by_local_gateway_id" {
  route_table_id   = aws_route_table.test.id
  local_gateway_id = data.aws_ec2_local_gateway.first.id
  depends_on       = [aws_route.test]
}
`)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/arn"
	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsSsmParameter() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSsmParameterPut,
		Read:   resourceAwsSsmParameterRead,
		Update: resourceAwsSsmParameterPut,
		Delete: resourceAwsSsmParameterDelete,
		Exists: resourceAwsSmmParameterExists,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"type": {
				Type:     schema.TypeString,
				Required: true,
				ValidateFunc: validation.StringInSlice([]string{
					ssm.ParameterTypeString,
					ssm.ParameterTypeStringList,
					ssm.ParameterTypeSecureString,
				}, false),
			},
			"value": {
				Type:      schema.TypeString,
				Required:  true,
				Sensitive: true,
			},
			"arn": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"key_id": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"overwrite": {
				Type:     schema.TypeBool,
				Optional: true,
			},
			"allowed_pattern": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsSmmParameterExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	ssmconn := meta.(*AWSClient).ssmconn
	_, err := ssmconn.GetParameter(&ssm.GetParameterInput{
		Name:           aws.String(d.Id()),
		WithDecryption: aws.Bool(false),
	})
	if err != nil {
		if isAWSErr(err, ssm.ErrCodeParameterNotFound, "") {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func resourceAwsSsmParameterRead(d *schema.ResourceData, meta interface{}) error {
	ssmconn := meta.(*AWSClient).ssmconn

	log.Printf("[DEBUG] Reading SSM Parameter: %s", d.Id())

	resp, err := ssmconn.GetParameter(&ssm.GetParameterInput{
		Name:           aws.String(d.Id()),
		WithDecryption: aws.Bool(true),
	})
	if err != nil {
		return fmt.Errorf("error getting SSM parameter: %s", err)
	}

	param := resp.Parameter
	d.Set("name", param.Name)
	d.Set("type", param.Type)
	d.Set("value", param.Value)

	describeParamsInput := &ssm.DescribeParametersInput{
		ParameterFilters: []*ssm.ParameterStringFilter{
			&ssm.ParameterStringFilter{
				Key:    aws.String("Name"),
				Option: aws.String("Equals"),
				Values: []*string{aws.String(d.Get("name").(string))},
			},
		},
	}
	describeResp, err := ssmconn.DescribeParameters(describeParamsInput)
	if err != nil {
		return fmt.Errorf("error describing SSM parameter: %s", err)
	}

	detail := describeResp.Parameters[0]
	d.Set("key_id", detail.KeyId)
	d.Set("description", detail.Description)
	d.Set("allowed_pattern", detail.AllowedPattern)

	if tagList, err := ssmconn.ListTagsForResource(&ssm.ListTagsForResourceInput{
		ResourceId:   aws.String(d.Get("name").(string)),
		ResourceType: aws.String("Parameter"),
	}); err != nil {
		return fmt.Errorf("Failed to get SSM parameter tags for %s: %s", d.Get("name"), err)
	} else {
		d.Set("tags", tagsToMapSSM(tagList.TagList))
	}

	arn := arn.ARN{
		Partition: meta.(*AWSClient).partition,
		Region:    meta.(*AWSClient).region,
		Service:   "ssm",
		AccountID: meta.(*AWSClient).accountid,
		Resource:  fmt.Sprintf("parameter/%s", strings.TrimPrefix(d.Id(), "/")),
	}
	d.Set("arn", arn.String())

	return nil
}

func resourceAwsSsmParameterDelete(d *schema.ResourceData, meta interface{}) error {
	ssmconn := meta.(*AWSClient).ssmconn

	log.Printf("[INFO] Deleting SSM Parameter: %s", d.Id())

	_, err := ssmconn.DeleteParameter(&ssm.DeleteParameterInput{
		Name: aws.String(d.Get("name").(string)),
	})
	if err != nil {
		return err
	}

	return nil
}

func resourceAwsSsmParameterPut(d *schema.ResourceData, meta interface{}) error {
	ssmconn := meta.(*AWSClient).ssmconn

	log.Printf("[INFO] Creating SSM Parameter: %s", d.Get("name").(string))

	paramInput := &ssm.PutParameterInput{
		Name:           aws.String(d.Get("name").(string)),
		Type:           aws.String(d.Get("type").(string)),
		Value:          aws.String(d.Get("value").(string)),
		Overwrite:      aws.Bool(shouldUpdateSsmParameter(d)),
		AllowedPattern: aws.String(d.Get("allowed_pattern").(string)),
	}

	if d.HasChange("description") {
		_, n := d.GetChange("description")
		paramInput.Description = aws.String(n.(string))
	}

	if keyID, ok := d.GetOk("key_id"); ok {
		log.Printf("[DEBUG] Setting key_id for SSM Parameter %v: %s", d.Get("name"), keyID)
		paramInput.SetKeyId(keyID.(string))
	}

	log.Printf("[DEBUG] Waiting for SSM Parameter %v to be updated", d.Get("name"))
	if _, err := ssmconn.PutParameter(paramInput); err != nil {
		return fmt.Errorf("error creating SSM parameter: %s", err)
	}

	if err := setTagsSSM(ssmconn, d, d.Get("name").(string), "Parameter"); err != nil {
		return fmt.Errorf("error creating SSM parameter tags: %s", err)
	}

	d.SetId(d.Get("name").(string))

	return resourceAwsSsmParameterRead(d, meta)
}

func shouldUpdateSsmParameter(d *schema.ResourceData) bool {
	// If the user has specified a preference, return their preference
	if value, ok := d.GetOkExists("overwrite"); ok {
		return value.(bool)
	}

	// Since the user has not specified a preference, obey lifecycle rules
	// if it is not a new resource, otherwise overwrite should be set to false.
	return !d.IsNewResource()
}
<commit_msg>Check that the SSM DescribeParameters call returned a correct response<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/arn"
	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsSsmParameter() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSsmParameterPut,
		Read:   resourceAwsSsmParameterRead,
		Update: resourceAwsSsmParameterPut,
		Delete: resourceAwsSsmParameterDelete,
		Exists: resourceAwsSmmParameterExists,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"type": {
				Type:     schema.TypeString,
				Required: true,
				ValidateFunc: validation.StringInSlice([]string{
					ssm.ParameterTypeString,
					ssm.ParameterTypeStringList,
					ssm.ParameterTypeSecureString,
				}, false),
			},
			"value": {
				Type:      schema.TypeString,
				Required:  true,
				Sensitive: true,
			},
			"arn": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"key_id": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"overwrite": {
				Type:     schema.TypeBool,
				Optional: true,
			},
			"allowed_pattern": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsSmmParameterExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	ssmconn := meta.(*AWSClient).ssmconn
	_, err := ssmconn.GetParameter(&ssm.GetParameterInput{
		Name:           aws.String(d.Id()),
		WithDecryption: aws.Bool(false),
	})
	if err != nil {
		if isAWSErr(err, ssm.ErrCodeParameterNotFound, "") {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func resourceAwsSsmParameterRead(d *schema.ResourceData, meta interface{}) error {
	ssmconn := meta.(*AWSClient).ssmconn

	log.Printf("[DEBUG] Reading SSM Parameter: %s", d.Id())

	resp, err := ssmconn.GetParameter(&ssm.GetParameterInput{
		Name:           aws.String(d.Id()),
		WithDecryption: aws.Bool(true),
	})
	if err != nil {
		return fmt.Errorf("error getting SSM parameter: %s", err)
	}

	param := resp.Parameter
	d.Set("name", param.Name)
	d.Set("type", param.Type)
	d.Set("value", param.Value)

	describeParamsInput := &ssm.DescribeParametersInput{
		ParameterFilters: []*ssm.ParameterStringFilter{
			&ssm.ParameterStringFilter{
				Key:    aws.String("Name"),
				Option: aws.String("Equals"),
				Values: []*string{aws.String(d.Get("name").(string))},
			},
		},
	}
	describeResp, err := ssmconn.DescribeParameters(describeParamsInput)
	if err != nil {
		return fmt.Errorf("error describing SSM parameter: %s", err)
	}

	if describeResp == nil || len(describeResp.Parameters) == 0 || describeResp.Parameters[0] == nil {
		log.Printf("[WARN] SSM Parameter %q not found, removing from state", d.Id())
		d.SetId("")
		return nil
	}

	detail := describeResp.Parameters[0]
	d.Set("key_id", detail.KeyId)
	d.Set("description", detail.Description)
	d.Set("allowed_pattern", detail.AllowedPattern)

	if tagList, err := ssmconn.ListTagsForResource(&ssm.ListTagsForResourceInput{
		ResourceId:   aws.String(d.Get("name").(string)),
		ResourceType: aws.String("Parameter"),
	}); err != nil {
		return fmt.Errorf("Failed to get SSM parameter tags for %s: %s", d.Get("name"), err)
	} else {
		d.Set("tags", tagsToMapSSM(tagList.TagList))
	}

	arn := arn.ARN{
		Partition: meta.(*AWSClient).partition,
		Region:    meta.(*AWSClient).region,
		Service:   "ssm",
		AccountID: meta.(*AWSClient).accountid,
		Resource:  fmt.Sprintf("parameter/%s", strings.TrimPrefix(d.Id(), "/")),
	}
	d.Set("arn", arn.String())

	return nil
}

func resourceAwsSsmParameterDelete(d *schema.ResourceData, meta interface{}) error {
	ssmconn := meta.(*AWSClient).ssmconn

	log.Printf("[INFO] Deleting SSM Parameter: %s", d.Id())

	_, err := ssmconn.DeleteParameter(&ssm.DeleteParameterInput{
		Name: aws.String(d.Get("name").(string)),
	})
	if err != nil {
		return err
	}

	return nil
}

func resourceAwsSsmParameterPut(d *schema.ResourceData, meta interface{}) error {
	ssmconn := meta.(*AWSClient).ssmconn

	log.Printf("[INFO] Creating SSM Parameter: %s", d.Get("name").(string))

	paramInput := &ssm.PutParameterInput{
		Name:           aws.String(d.Get("name").(string)),
		Type:           aws.String(d.Get("type").(string)),
		Value:          aws.String(d.Get("value").(string)),
		Overwrite:      aws.Bool(shouldUpdateSsmParameter(d)),
		AllowedPattern: aws.String(d.Get("allowed_pattern").(string)),
	}

	if d.HasChange("description") {
		_, n := d.GetChange("description")
		paramInput.Description = aws.String(n.(string))
	}

	if keyID, ok := d.GetOk("key_id"); ok {
		log.Printf("[DEBUG] Setting key_id for SSM Parameter %v: %s", d.Get("name"), keyID)
		paramInput.SetKeyId(keyID.(string))
	}

	log.Printf("[DEBUG] Waiting for SSM Parameter %v to be updated", d.Get("name"))
	if _, err := ssmconn.PutParameter(paramInput); err != nil {
		return fmt.Errorf("error creating SSM parameter: %s", err)
	}

	if err := setTagsSSM(ssmconn, d, d.Get("name").(string), "Parameter"); err != nil {
		return fmt.Errorf("error creating SSM parameter tags: %s", err)
	}

	d.SetId(d.Get("name").(string))

	return resourceAwsSsmParameterRead(d, meta)
}

func shouldUpdateSsmParameter(d *schema.ResourceData) bool {
	// If the user has specified a preference, return their preference
	if value, ok := d.GetOkExists("overwrite"); ok {
		return value.(bool)
	}

	// Since the user has not specified a preference, obey lifecycle rules
	// if it is not a new resource, otherwise overwrite should be set to false.
	return !d.IsNewResource()
}
<|endoftext|>


<commit_before><commit_msg>Bring Windows behaviour more into line with ANSI<commit_after><|endoftext|>


<commit_before>package actor

import (
	"log"
)

type paniced struct {
	actor  Actor
	reason interface{}
}

type superviseMe struct {
	actor Actor
}

type Supervisor interface {
	Supervise(Actor)
	Children() []Actor
}

type supervisor struct {
	Actor
	onPanic  func(Supervisor, Actor)
	children []Actor
}

func (sv *supervisor) Supervise(target Actor) {
	sv.Send() <- superviseMe{target}
}

func (sv *supervisor) Children() []Actor {
	return sv.children
}

func (sv *supervisor) Init() {
}

func (sv *supervisor) Receive(_ Actor, msg interface{}) {
	switch msg := msg.(type) {
	case paniced:
		log.Println(msg.actor.Path(), "paniced")
		sv.onPanic(sv, msg.actor)
	case superviseMe:
		sv.children = append(sv.children, msg.actor)
		sv.Monitor(msg.actor)
	default:
		panic("Supervisor error: received unexpected message")
	}
}

func NewSupervisor(name string, strategy SupervisorStrategy, sys ActorSystem) Supervisor {
	sv := &supervisor{
		onPanic: strategy.onPanic,
	}
	sv.Actor = sys.ActorOf(name, sv)
	sv.start()
	return sv
}
<commit_msg>Fix bug on NewSupervisor<commit_after>package actor

import (
	"log"
)

type paniced struct {
	actor  Actor
	reason interface{}
}

type superviseMe struct {
	actor Actor
}

type Supervisor interface {
	Supervise(Actor)
	Children() []Actor
}

type supervisor struct {
	Actor
	onPanic  func(Supervisor, Actor)
	children []Actor
}

func (sv *supervisor) Supervise(target Actor) {
	sv.Send() <- superviseMe{target}
}

func (sv *supervisor) Children() []Actor {
	return sv.children
}

func (sv *supervisor) Init() {
}

func (sv *supervisor) Receive(_ Actor, msg interface{}) {
	switch msg := msg.(type) {
	case paniced:
		log.Println(msg.actor.Path(), "paniced")
		sv.onPanic(sv, msg.actor)
	case superviseMe:
		sv.children = append(sv.children, msg.actor)
		sv.Monitor(msg.actor)
	default:
		panic("Supervisor error: received unexpected message")
	}
}

func NewSupervisor(name string, strategy SupervisorStrategy, sys ActorSystem) Supervisor {
	sv := &supervisor{
		onPanic: strategy.onPanic,
	}
	sv.Actor = sys.ActorOf(name, sv)
	return sv
}
<|endoftext|>


<commit_before>/*
(c) Copyright [2015] Hewlett Packard Enterprise Development LP

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 ov -
package ov

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"

	"github.com/HewlettPackard/oneview-golang/rest"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// HardwareState
type HardwareState int

const (
	H_UNKNOWN HardwareState = 1 + iota
	H_ADDING
	H_NOPROFILE_APPLIED
	H_MONITORED
	H_UNMANAGED
	H_REMOVING
	H_REMOVE_FAILED
	H_REMOVED
	H_APPLYING_PROFILE
	H_PROFILE_APPLIED
	H_REMOVING_PROFILE
	H_PROFILE_ERROR
	H_UNSUPPORTED
	H_UPATING_FIRMWARE
)

var hardwarestates = [...]string{
	"Unknown",          // not initialized
	"Adding",           // server being added
	"NoProfileApplied", // server successfully added
	"Monitored",        // server being monitored
	"Unmanaged",        // discovered a supported server
	"Removing",         // server being removed
	"RemoveFailed",     // unsuccessful server removal
	"Removed",          // server successfully removed
	"ApplyingProfile",  // profile being applied to server
	"ProfileApplied",   // profile successfully applied
	"RemovingProfile",  // profile being removed
	"ProfileError",     // unsuccessful profile apply or removal
	"Unsupported",      // server model or version not currently supported by the appliance
	"UpdatingFirmware", // server firmware update in progress
}

func (h HardwareState) String() string { return hardwarestates[h-1] }
func (h HardwareState) Equal(s string) bool {
	return (strings.ToUpper(s) == strings.ToUpper(h.String()))
}

// ServerHardware get server hardware from ov
type ServerHardware struct {
	ServerHardwarev200
	AssetTag              string        `json:"assetTag,omitempty"`              // "assetTag": "[Unknown]",
	Category              string        `json:"category,omitempty"`              // "category": "server-hardware",
	Created               string        `json:"created,omitempty"`               // "created": "2015-08-14T21:02:01.537Z",
	Description           utils.Nstring `json:"description,omitempty"`           // "description": null,
	ETAG                  string        `json:"eTag,omitempty"`                  // "eTag": "1441147370086",
	FormFactor            string        `json:"formFactor,omitempty"`            // "formFactor": "HalfHeight",
	LicensingIntent       string        `json:"licensingIntent,omitempty"`       // "licensingIntent": "OneView",
	LocationURI           utils.Nstring `json:"locationUri,omitempty"`           // "locationUri": "/rest/enclosures/092SN51207RR",
	MemoryMb              int           `json:"memoryMb,omitempty"`              // "memoryMb": 262144,
	Model                 string        `json:"model,omitempty"`                 // "model": "ProLiant BL460c Gen9",
	Modified              string        `json:"modified,omitempty"`              // "modified": "2015-09-01T22:42:50.086Z",
	MpFirwareVersion      string        `json:"mpFirmwareVersion,omitempty"`     // "mpFirmwareVersion": "2.03 Nov 07 2014",
	MpModel               string        `json:"mpModel,omitempty"`               // "mpModel": "iLO4",
	Name                  string        `json:"name,omitempty"`                  // "name": "se05, bay 16",
	PartNumber            string        `json:"partNumber,omitempty"`            // "partNumber": "727021-B21",
	Position              int           `json:"position,omitempty"`              // "position": 16,
	PowerLock             bool          `json:"powerLock,omitempty"`             // "powerLock": false,
	PowerState            string        `json:"powerState,omitempty"`            // "powerState": "Off",
	ProcessorCoreCount    int           `json:"processorCoreCount,omitempty"`    // "processorCoreCount": 14,
	ProcessorCount        int           `json:"processorCount,omitempty"`        // "processorCount": 2,
	ProcessorSpeedMhz     int           `json:"processorSpeedMhz,omitempty"`     // "processorSpeedMhz": 2300,
	ProcessorType         string        `json:"processorType,omitempty"`         // "processorType": "Intel(R) Xeon(R) CPU E5-2695 v3 @ 2.30GHz",
	RefreshState          string        `json:"refreshState,omitempty"`          // "refreshState": "NotRefreshing",
	RomVersion            string        `json:"romVersion,omitempty"`            // "romVersion": "I36 11/03/2014",
	SerialNumber          utils.Nstring `json:"serialNumber,omitempty"`          // "serialNumber": "2M25090RMW",
	ServerGroupURI        utils.Nstring `json:"serverGroupUri,omitempty"`        // "serverGroupUri": "/rest/enclosure-groups/56ad0069-8362-42fd-b4e3-f5c5a69af039",
	ServerHardwareTypeURI utils.Nstring `json:"serverHardwareTypeUri,omitempty"` // "serverHardwareTypeUri": "/rest/server-hardware-types/DB7726F7-F601-4EA8-B4A6-D1EE1B32C07C",
	ServerProfileURI      utils.Nstring `json:"serverProfileUri,omitempty"`      // "serverProfileUri": "/rest/server-profiles/9979b3a4-646a-4c3e-bca6-80ca0b403a93",
	ShortModel            string        `json:"shortModel,omitempty"`            // "shortModel": "BL460c Gen9",
	State                 string        `json:"state,omitempty"`                 // "state": "ProfileApplied",
	StateReason           string        `json:"stateReason,omitempty"`           // "stateReason": "NotApplicable",
	Status                string        `json:"status,omitempty"`                // "status": "Warning",
	Type                  string        `json:"type,omitempty"`                  // "type": "server-hardware-3",
	URI                   utils.Nstring `json:"uri,omitempty"`                   // "uri": "/rest/server-hardware/30373237-3132-4D32-3235-303930524D57",
	UUID                  utils.Nstring `json:"uuid,omitempty"`                  // "uuid": "30373237-3132-4D32-3235-303930524D57",
	VirtualSerialNumber   utils.Nstring `json:"VirtualSerialNumber,omitempty"`   // "virtualSerialNumber": "",
	VirtualUUID           string        `json:"virtualUuid,omitempty"`           // "virtualUuid": "00000000-0000-0000-0000-000000000000"
	// v1 properties
	MpDnsName   string `json:"mpDnsName,omitempty"`   // "mpDnsName": "ILO2M25090RMW",
	MpIpAddress string `json:"mpIpAddress,omitempty"` // make this private to force calls to GetIloIPAddress() "mpIpAddress": "172.28.3.136",
	// extra client struct
	Client *OVClient
}

// GetIloIPAddress - Use MpIpAddress for v1 and
// For v2 check MpHostInfo is not nil , loop through MpHostInfo.MpIPAddress[],
// and return the first nonzero address
func (h ServerHardware) GetIloIPAddress() string {
	if h.Client.IsHardwareSchemaV2() {
		if h.MpHostInfo != nil {
			log.Debug("working on getting IloIPAddress from MpHostInfo")
			for _, MpIpObj := range h.MpHostInfo.MpIPAddress {
				if len(MpIpObj.Address) > 0 &&
					(MpDHCP.Equal(MpIpObj.Type) || MpStatic.Equal(MpIpObj.Type)) {
					return MpIpObj.Address
				}
			}
		}
	} else {
		return h.MpIpAddress
	}
	return ""
}

// server hardware list, simillar to ServerProfileList with a TODO
type ServerHardwareList struct {
	Type        string           `json:"type,omitempty"`        // "type": "server-hardware-list-3",
	Category    string           `json:"category,omitempty"`    // "category": "server-hardware",
	Count       int              `json:"count,omitempty"`       // "count": 15,
	Created     string           `json:"created,omitempty"`     // "created": "2015-09-08T04:58:21.489Z",
	ETAG        string           `json:"eTag,omitempty"`        // "eTag": "1441688301489",
	Modified    string           `json:"modified,omitempty"`    // "modified": "2015-09-08T04:58:21.489Z",
	NextPageURI utils.Nstring    `json:"nextPageUri,omitempty"` // "nextPageUri": null,
	PrevPageURI utils.Nstring    `json:"prevPageUri,omitempty"` // "prevPageUri": null,
	Start       int              `json:"start,omitempty"`       // "start": 0,
	Total       int              `json:"total,omitempty"`       // "total": 15,
	URI         string           `json:"uri,omitempty"`         // "uri": "/rest/server-hardware?sort=name:asc&filter=serverHardwareTypeUri=%27/rest/server-hardware-types/DB7726F7-F601-4EA8-B4A6-D1EE1B32C07C%27&filter=serverGroupUri=%27/rest/enclosure-groups/56ad0069-8362-42fd-b4e3-f5c5a69af039%27&start=0&count=100"
	Members     []ServerHardware `json:"members,omitempty"`     //"members":[]
}

// server hardware power off
func (s ServerHardware) PowerOff() error {
	var pt *PowerTask
	pt = pt.NewPowerTask(s)
	return pt.PowerExecutor(P_OFF)
}

// server hardware power on
func (s ServerHardware) PowerOn() error {
	var pt *PowerTask
	pt = pt.NewPowerTask(s)
	return pt.PowerExecutor(P_ON)
}

// get the power state
func (s ServerHardware) GetPowerState() (PowerState, error) {
	var pt *PowerTask
	pt = pt.NewPowerTask(s)
	if err := pt.GetCurrentPowerState(); err != nil {
		return P_UKNOWN, err
	}
	return pt.State, nil
}

// get a server hardware with uri
func (c *OVClient) GetServerHardware(uri utils.Nstring) (ServerHardware, error) {

	var hardware ServerHardware
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	// rest call
	data, err := c.RestAPICall(rest.GET, uri.String(), nil)
	if err != nil {
		return hardware, err
	}

	log.Debugf("GetServerHardware %s", data)
	if err := json.Unmarshal([]byte(data), &hardware); err != nil {
		return hardware, err
	}
	hardware.Client = c
	return hardware, nil
}

// get a server hardware with filters
func (c *OVClient) GetServerHardwareList(filters []string, sort string) (ServerHardwareList, error) {
	var (
		uri        = "/rest/server-hardware"
		q          map[string]interface{}
		serverlist ServerHardwareList
	)
	q = make(map[string]interface{})
	if len(filters) > 0 {
		q["filter"] = filters
	}

	if sort != "" {
		q["sort"] = sort
	}

	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())
	// Setup query
	if len(q) > 0 {
		c.SetQueryString(q)
	}
	data, err := c.RestAPICall(rest.GET, uri, nil)

	// parse the url and setup any query strings
	var Url *url.URL
	Url, err = url.Parse(utils.Sanatize(c.Endpoint))
	if err != nil {
		return serverlist, err
	}
	Url.Path += uri
	c.GetQueryString(Url)

	log.Debugf("GetServerHardwareList %s", data)
	if err := json.Unmarshal([]byte(data), &serverlist); err != nil {
		return serverlist, err
	}
	return serverlist, nil
}

// get available server
// blades = rest_api(:oneview, :get, "/rest/server-hardware?sort=name:asc&filter=serverHardwareTypeUri='#{server_hardware_type_uri}'&filter=serverGroupUri='#{enclosure_group_uri}'")
func (c *OVClient) GetAvailableHardware(hardwaretype_uri utils.Nstring, servergroup_uri utils.Nstring) (hw ServerHardware, err error) {
	var (
		hwlist ServerHardwareList
		f      = []string{"serverHardwareTypeUri='" + hardwaretype_uri.String() + "'",
			"serverGroupUri='" + servergroup_uri.String() + "'"}
	)
	if hwlist, err = c.GetServerHardwareList(f, "name:desc"); err != nil {
		return hw, err
	}
	if !(len(hwlist.Members) > 0) {
		return hw, errors.New("Error! No available blades that are compatible with the server profile!")
	}

	// pick an available blade
	for _, blade := range hwlist.Members {
		if H_NOPROFILE_APPLIED.Equal(blade.State) {
			hw = blade
			break
		}
	}
	if hw.Name == "" {
		return hw, errors.New("No more blades are available for provisioning!")
	}
	return hw, nil
}
<commit_msg>fixup iloip address for c7000 200<commit_after>/*
(c) Copyright [2015] Hewlett Packard Enterprise Development LP

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 ov -
package ov

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"

	"github.com/HewlettPackard/oneview-golang/rest"
	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// HardwareState
type HardwareState int

const (
	H_UNKNOWN HardwareState = 1 + iota
	H_ADDING
	H_NOPROFILE_APPLIED
	H_MONITORED
	H_UNMANAGED
	H_REMOVING
	H_REMOVE_FAILED
	H_REMOVED
	H_APPLYING_PROFILE
	H_PROFILE_APPLIED
	H_REMOVING_PROFILE
	H_PROFILE_ERROR
	H_UNSUPPORTED
	H_UPATING_FIRMWARE
)

var hardwarestates = [...]string{
	"Unknown",          // not initialized
	"Adding",           // server being added
	"NoProfileApplied", // server successfully added
	"Monitored",        // server being monitored
	"Unmanaged",        // discovered a supported server
	"Removing",         // server being removed
	"RemoveFailed",     // unsuccessful server removal
	"Removed",          // server successfully removed
	"ApplyingProfile",  // profile being applied to server
	"ProfileApplied",   // profile successfully applied
	"RemovingProfile",  // profile being removed
	"ProfileError",     // unsuccessful profile apply or removal
	"Unsupported",      // server model or version not currently supported by the appliance
	"UpdatingFirmware", // server firmware update in progress
}

func (h HardwareState) String() string { return hardwarestates[h-1] }
func (h HardwareState) Equal(s string) bool {
	return (strings.ToUpper(s) == strings.ToUpper(h.String()))
}

// ServerHardware get server hardware from ov
type ServerHardware struct {
	ServerHardwarev200
	AssetTag              string        `json:"assetTag,omitempty"`              // "assetTag": "[Unknown]",
	Category              string        `json:"category,omitempty"`              // "category": "server-hardware",
	Created               string        `json:"created,omitempty"`               // "created": "2015-08-14T21:02:01.537Z",
	Description           utils.Nstring `json:"description,omitempty"`           // "description": null,
	ETAG                  string        `json:"eTag,omitempty"`                  // "eTag": "1441147370086",
	FormFactor            string        `json:"formFactor,omitempty"`            // "formFactor": "HalfHeight",
	LicensingIntent       string        `json:"licensingIntent,omitempty"`       // "licensingIntent": "OneView",
	LocationURI           utils.Nstring `json:"locationUri,omitempty"`           // "locationUri": "/rest/enclosures/092SN51207RR",
	MemoryMb              int           `json:"memoryMb,omitempty"`              // "memoryMb": 262144,
	Model                 string        `json:"model,omitempty"`                 // "model": "ProLiant BL460c Gen9",
	Modified              string        `json:"modified,omitempty"`              // "modified": "2015-09-01T22:42:50.086Z",
	MpFirwareVersion      string        `json:"mpFirmwareVersion,omitempty"`     // "mpFirmwareVersion": "2.03 Nov 07 2014",
	MpModel               string        `json:"mpModel,omitempty"`               // "mpModel": "iLO4",
	Name                  string        `json:"name,omitempty"`                  // "name": "se05, bay 16",
	PartNumber            string        `json:"partNumber,omitempty"`            // "partNumber": "727021-B21",
	Position              int           `json:"position,omitempty"`              // "position": 16,
	PowerLock             bool          `json:"powerLock,omitempty"`             // "powerLock": false,
	PowerState            string        `json:"powerState,omitempty"`            // "powerState": "Off",
	ProcessorCoreCount    int           `json:"processorCoreCount,omitempty"`    // "processorCoreCount": 14,
	ProcessorCount        int           `json:"processorCount,omitempty"`        // "processorCount": 2,
	ProcessorSpeedMhz     int           `json:"processorSpeedMhz,omitempty"`     // "processorSpeedMhz": 2300,
	ProcessorType         string        `json:"processorType,omitempty"`         // "processorType": "Intel(R) Xeon(R) CPU E5-2695 v3 @ 2.30GHz",
	RefreshState          string        `json:"refreshState,omitempty"`          // "refreshState": "NotRefreshing",
	RomVersion            string        `json:"romVersion,omitempty"`            // "romVersion": "I36 11/03/2014",
	SerialNumber          utils.Nstring `json:"serialNumber,omitempty"`          // "serialNumber": "2M25090RMW",
	ServerGroupURI        utils.Nstring `json:"serverGroupUri,omitempty"`        // "serverGroupUri": "/rest/enclosure-groups/56ad0069-8362-42fd-b4e3-f5c5a69af039",
	ServerHardwareTypeURI utils.Nstring `json:"serverHardwareTypeUri,omitempty"` // "serverHardwareTypeUri": "/rest/server-hardware-types/DB7726F7-F601-4EA8-B4A6-D1EE1B32C07C",
	ServerProfileURI      utils.Nstring `json:"serverProfileUri,omitempty"`      // "serverProfileUri": "/rest/server-profiles/9979b3a4-646a-4c3e-bca6-80ca0b403a93",
	ShortModel            string        `json:"shortModel,omitempty"`            // "shortModel": "BL460c Gen9",
	State                 string        `json:"state,omitempty"`                 // "state": "ProfileApplied",
	StateReason           string        `json:"stateReason,omitempty"`           // "stateReason": "NotApplicable",
	Status                string        `json:"status,omitempty"`                // "status": "Warning",
	Type                  string        `json:"type,omitempty"`                  // "type": "server-hardware-3",
	URI                   utils.Nstring `json:"uri,omitempty"`                   // "uri": "/rest/server-hardware/30373237-3132-4D32-3235-303930524D57",
	UUID                  utils.Nstring `json:"uuid,omitempty"`                  // "uuid": "30373237-3132-4D32-3235-303930524D57",
	VirtualSerialNumber   utils.Nstring `json:"VirtualSerialNumber,omitempty"`   // "virtualSerialNumber": "",
	VirtualUUID           string        `json:"virtualUuid,omitempty"`           // "virtualUuid": "00000000-0000-0000-0000-000000000000"
	// v1 properties
	MpDnsName   string `json:"mpDnsName,omitempty"`   // "mpDnsName": "ILO2M25090RMW",
	MpIpAddress string `json:"mpIpAddress,omitempty"` // make this private to force calls to GetIloIPAddress() "mpIpAddress": "172.28.3.136",
	// extra client struct
	Client *OVClient
}

// GetIloIPAddress - Use MpIpAddress for v1 and
// For v2 check MpHostInfo is not nil , loop through MpHostInfo.MpIPAddress[],
// and return the first nonzero address
func (h ServerHardware) GetIloIPAddress() string {
	if h.Client.IsHardwareSchemaV2() {
		if h.MpHostInfo != nil {
			log.Debug("working on getting IloIPAddress from MpHostInfo")
			for _, MpIpObj := range h.MpHostInfo.MpIPAddress {
				if len(MpIpObj.Address) > 0 &&
					(MpDHCP.Equal(MpIpObj.Type) ||
						MpStatic.Equal(MpIpObj.Type) ||
						MpUndefined.Equal(MpIpObj.Type)) {
					return MpIpObj.Address
				}
			}
		}
	} else {
		return h.MpIpAddress
	}
	return ""
}

// server hardware list, simillar to ServerProfileList with a TODO
type ServerHardwareList struct {
	Type        string           `json:"type,omitempty"`        // "type": "server-hardware-list-3",
	Category    string           `json:"category,omitempty"`    // "category": "server-hardware",
	Count       int              `json:"count,omitempty"`       // "count": 15,
	Created     string           `json:"created,omitempty"`     // "created": "2015-09-08T04:58:21.489Z",
	ETAG        string           `json:"eTag,omitempty"`        // "eTag": "1441688301489",
	Modified    string           `json:"modified,omitempty"`    // "modified": "2015-09-08T04:58:21.489Z",
	NextPageURI utils.Nstring    `json:"nextPageUri,omitempty"` // "nextPageUri": null,
	PrevPageURI utils.Nstring    `json:"prevPageUri,omitempty"` // "prevPageUri": null,
	Start       int              `json:"start,omitempty"`       // "start": 0,
	Total       int              `json:"total,omitempty"`       // "total": 15,
	URI         string           `json:"uri,omitempty"`         // "uri": "/rest/server-hardware?sort=name:asc&filter=serverHardwareTypeUri=%27/rest/server-hardware-types/DB7726F7-F601-4EA8-B4A6-D1EE1B32C07C%27&filter=serverGroupUri=%27/rest/enclosure-groups/56ad0069-8362-42fd-b4e3-f5c5a69af039%27&start=0&count=100"
	Members     []ServerHardware `json:"members,omitempty"`     //"members":[]
}

// server hardware power off
func (s ServerHardware) PowerOff() error {
	var pt *PowerTask
	pt = pt.NewPowerTask(s)
	return pt.PowerExecutor(P_OFF)
}

// server hardware power on
func (s ServerHardware) PowerOn() error {
	var pt *PowerTask
	pt = pt.NewPowerTask(s)
	return pt.PowerExecutor(P_ON)
}

// get the power state
func (s ServerHardware) GetPowerState() (PowerState, error) {
	var pt *PowerTask
	pt = pt.NewPowerTask(s)
	if err := pt.GetCurrentPowerState(); err != nil {
		return P_UKNOWN, err
	}
	return pt.State, nil
}

// get a server hardware with uri
func (c *OVClient) GetServerHardware(uri utils.Nstring) (ServerHardware, error) {

	var hardware ServerHardware
	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())

	// rest call
	data, err := c.RestAPICall(rest.GET, uri.String(), nil)
	if err != nil {
		return hardware, err
	}

	log.Debugf("GetServerHardware %s", data)
	if err := json.Unmarshal([]byte(data), &hardware); err != nil {
		return hardware, err
	}
	hardware.Client = c
	return hardware, nil
}

// get a server hardware with filters
func (c *OVClient) GetServerHardwareList(filters []string, sort string) (ServerHardwareList, error) {
	var (
		uri        = "/rest/server-hardware"
		q          map[string]interface{}
		serverlist ServerHardwareList
	)
	q = make(map[string]interface{})
	if len(filters) > 0 {
		q["filter"] = filters
	}

	if sort != "" {
		q["sort"] = sort
	}

	// refresh login
	c.RefreshLogin()
	c.SetAuthHeaderOptions(c.GetAuthHeaderMap())
	// Setup query
	if len(q) > 0 {
		c.SetQueryString(q)
	}
	data, err := c.RestAPICall(rest.GET, uri, nil)

	// parse the url and setup any query strings
	var Url *url.URL
	Url, err = url.Parse(utils.Sanatize(c.Endpoint))
	if err != nil {
		return serverlist, err
	}
	Url.Path += uri
	c.GetQueryString(Url)

	log.Debugf("GetServerHardwareList %s", data)
	if err := json.Unmarshal([]byte(data), &serverlist); err != nil {
		return serverlist, err
	}
	return serverlist, nil
}

// get available server
// blades = rest_api(:oneview, :get, "/rest/server-hardware?sort=name:asc&filter=serverHardwareTypeUri='#{server_hardware_type_uri}'&filter=serverGroupUri='#{enclosure_group_uri}'")
func (c *OVClient) GetAvailableHardware(hardwaretype_uri utils.Nstring, servergroup_uri utils.Nstring) (hw ServerHardware, err error) {
	var (
		hwlist ServerHardwareList
		f      = []string{"serverHardwareTypeUri='" + hardwaretype_uri.String() + "'",
			"serverGroupUri='" + servergroup_uri.String() + "'"}
	)
	if hwlist, err = c.GetServerHardwareList(f, "name:desc"); err != nil {
		return hw, err
	}
	if !(len(hwlist.Members) > 0) {
		return hw, errors.New("Error! No available blades that are compatible with the server profile!")
	}

	// pick an available blade
	for _, blade := range hwlist.Members {
		if H_NOPROFILE_APPLIED.Equal(blade.State) {
			hw = blade
			break
		}
	}
	if hw.Name == "" {
		return hw, errors.New("No more blades are available for provisioning!")
	}
	return hw, nil
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"crypto/sha256"
	//_ "expvar"
	"flag"
	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/imageserver"
	imageserver_cache_async "github.com/pierrre/imageserver/cache/async"
	imageserver_cache_list "github.com/pierrre/imageserver/cache/list"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_parser_graphicsmagick "github.com/pierrre/imageserver/http/parser/graphicsmagick"
	imageserver_http_parser_list "github.com/pierrre/imageserver/http/parser/list"
	imageserver_http_parser_source "github.com/pierrre/imageserver/http/parser/source"
	imageserver_processor_graphicsmagick "github.com/pierrre/imageserver/processor/graphicsmagick"
	imageserver_processor_limit "github.com/pierrre/imageserver/processor/limit"
	imageserver_provider_cache "github.com/pierrre/imageserver/provider/cache"
	imageserver_provider_http "github.com/pierrre/imageserver/provider/http"
	"log"
	"net/http"
	//_ "net/http/pprof"
	"os"
	"strconv"
	"time"
)

func main() {
	var verbose bool
	flag.BoolVar(&verbose, "verbose", false, "Verbose")
	flag.Parse()

	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	var cache imageserver.Cache
	cache = &imageserver_cache_redis.RedisCache{
		Pool: &redigo.Pool{
			Dial: func() (redigo.Conn, error) {
				return redigo.Dial("tcp", "localhost:6379")
			},
			MaxIdle: 50,
		},
		Expire: time.Duration(7 * 24 * time.Hour),
	}
	cache = &imageserver_cache_async.AsyncCache{
		Cache: cache,
		ErrFunc: func(err error, key string, image *imageserver.Image, parameters imageserver.Parameters) {
			if verbose {
				log.Println(err)
			}
		},
	}
	cache = imageserver_cache_list.ListCache{
		imageserver_cache_memory.New(10 * 1024 * 1024),
		cache,
	}

	provider := &imageserver_provider_cache.CacheProvider{
		Provider:     &imageserver_provider_http.HTTPProvider{},
		Cache:        cache,
		CacheKeyFunc: imageserver_provider_cache.NewSourceHashCacheKeyFunc(sha256.New),
	}

	var processor imageserver.Processor
	processor = &imageserver_processor_graphicsmagick.GraphicsMagickProcessor{
		Executable: "gm",
		Timeout:    time.Duration(10 * time.Second),
		AllowedFormats: []string{
			"jpeg",
			"png",
			"bmp",
			"gif",
		},
		DefaultQualities: map[string]string{
			"jpeg": "85",
		},
	}
	processor = imageserver_processor_limit.New(processor, 16)

	imageServer := &imageserver.Server{
		Cache:        cache,
		CacheKeyFunc: imageserver.NewParametersHashCacheKeyFunc(sha256.New),
		Provider:     provider,
		Processor:    processor,
	}

	httpImageServer := &imageserver_http.Server{
		Parser: &imageserver_http_parser_list.ListParser{
			&imageserver_http_parser_source.SourceParser{},
			&imageserver_http_parser_graphicsmagick.GraphicsMagickParser{},
		},
		ImageServer: imageServer,
		ETagFunc:    imageserver_http.NewParametersHashETagFunc(sha256.New),
		Expire:      time.Duration(7 * 24 * time.Hour),
		RequestFunc: func(request *http.Request) error {
			url := request.URL
			query := url.Query()
			errorCodeString := query.Get("error")
			if len(errorCodeString) == 0 {
				return nil
			}
			errorCode, err := strconv.Atoi(errorCodeString)
			if err != nil {
				return imageserver.NewError(err.Error())
			}
			return imageserver_http.NewError(errorCode)
		},
		HeaderFunc: func(header http.Header, request *http.Request, err error) {
			header.Set("X-Hostname", hostname)
		},
		ErrorFunc: func(err error, request *http.Request) {
			if verbose {
				log.Println(err)
			}
		},
		ResponseFunc: func(request *http.Request, statusCode int, contentSize int64, err error) {
			if verbose {
				var errString string
				if err != nil {
					errString = err.Error()
				}
				log.Println(request.RemoteAddr, request.Method, strconv.Quote(request.URL.String()), statusCode, contentSize, strconv.Quote(errString))
			}
		},
	}

	http.Handle("/", httpImageServer)
	err = http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Add http flag in advanced example<commit_after>// +build ignore

package main

import (
	"crypto/sha256"
	//_ "expvar"
	"flag"
	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/imageserver"
	imageserver_cache_async "github.com/pierrre/imageserver/cache/async"
	imageserver_cache_list "github.com/pierrre/imageserver/cache/list"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_parser_graphicsmagick "github.com/pierrre/imageserver/http/parser/graphicsmagick"
	imageserver_http_parser_list "github.com/pierrre/imageserver/http/parser/list"
	imageserver_http_parser_source "github.com/pierrre/imageserver/http/parser/source"
	imageserver_processor_graphicsmagick "github.com/pierrre/imageserver/processor/graphicsmagick"
	imageserver_processor_limit "github.com/pierrre/imageserver/processor/limit"
	imageserver_provider_cache "github.com/pierrre/imageserver/provider/cache"
	imageserver_provider_http "github.com/pierrre/imageserver/provider/http"
	"log"
	"net/http"
	//_ "net/http/pprof"
	"os"
	"strconv"
	"time"
)

func main() {
	var verbose bool
	var httpAddr string
	flag.BoolVar(&verbose, "verbose", false, "Verbose")
	flag.StringVar(&httpAddr, "http", ":8080", "Http")
	flag.Parse()

	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	var cache imageserver.Cache
	cache = &imageserver_cache_redis.RedisCache{
		Pool: &redigo.Pool{
			Dial: func() (redigo.Conn, error) {
				return redigo.Dial("tcp", "localhost:6379")
			},
			MaxIdle: 50,
		},
		Expire: time.Duration(7 * 24 * time.Hour),
	}
	cache = &imageserver_cache_async.AsyncCache{
		Cache: cache,
		ErrFunc: func(err error, key string, image *imageserver.Image, parameters imageserver.Parameters) {
			if verbose {
				log.Println(err)
			}
		},
	}
	cache = imageserver_cache_list.ListCache{
		imageserver_cache_memory.New(10 * 1024 * 1024),
		cache,
	}

	provider := &imageserver_provider_cache.CacheProvider{
		Provider:     &imageserver_provider_http.HTTPProvider{},
		Cache:        cache,
		CacheKeyFunc: imageserver_provider_cache.NewSourceHashCacheKeyFunc(sha256.New),
	}

	var processor imageserver.Processor
	processor = &imageserver_processor_graphicsmagick.GraphicsMagickProcessor{
		Executable: "gm",
		Timeout:    time.Duration(10 * time.Second),
		AllowedFormats: []string{
			"jpeg",
			"png",
			"bmp",
			"gif",
		},
		DefaultQualities: map[string]string{
			"jpeg": "85",
		},
	}
	processor = imageserver_processor_limit.New(processor, 16)

	imageServer := &imageserver.Server{
		Cache:        cache,
		CacheKeyFunc: imageserver.NewParametersHashCacheKeyFunc(sha256.New),
		Provider:     provider,
		Processor:    processor,
	}

	httpImageServer := &imageserver_http.Server{
		Parser: &imageserver_http_parser_list.ListParser{
			&imageserver_http_parser_source.SourceParser{},
			&imageserver_http_parser_graphicsmagick.GraphicsMagickParser{},
		},
		ImageServer: imageServer,
		ETagFunc:    imageserver_http.NewParametersHashETagFunc(sha256.New),
		Expire:      time.Duration(7 * 24 * time.Hour),
		RequestFunc: func(request *http.Request) error {
			url := request.URL
			query := url.Query()
			errorCodeString := query.Get("error")
			if len(errorCodeString) == 0 {
				return nil
			}
			errorCode, err := strconv.Atoi(errorCodeString)
			if err != nil {
				return imageserver.NewError(err.Error())
			}
			return imageserver_http.NewError(errorCode)
		},
		HeaderFunc: func(header http.Header, request *http.Request, err error) {
			header.Set("X-Hostname", hostname)
		},
		ErrorFunc: func(err error, request *http.Request) {
			if verbose {
				log.Println(err)
			}
		},
		ResponseFunc: func(request *http.Request, statusCode int, contentSize int64, err error) {
			if verbose {
				var errString string
				if err != nil {
					errString = err.Error()
				}
				log.Println(request.RemoteAddr, request.Method, strconv.Quote(request.URL.String()), statusCode, contentSize, strconv.Quote(errString))
			}
		},
	}

	http.Handle("/", httpImageServer)
	err = http.ListenAndServe(httpAddr, nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package brew

import (
	"bytes"
	"context"
	"crypto/sha256"
	"fmt"
	"log"
	"strings"
	"text/template"

	"github.com/google/go-github/github"
	"github.com/goreleaser/releaser/config"
	"github.com/goreleaser/releaser/split"
	"golang.org/x/oauth2"
)

const formulae = `class {{ .Name }} < Formula
  desc "{{ .Desc }}"
  homepage "{{ .Homepage }}"
  url "https://github.com/{{ .Repo }}/releases/download/{{ .Tag }}/{{ .BinaryName }}_#{%x(uname -s).gsub(/\n/, '')}_#{%x(uname -m).gsub(/\n/, '')}.tar.gz"
  head "https://github.com/{{ .Repo }}.git"
  version "{{ .Tag }}"

  def install
    bin.install "{{ .BinaryName }}"
  end

  {{- if .Caveats }}

  def caveats
    "{{ .Caveats }}"
  end
  {{- end }}
end
`

type templateData struct {
	Name, Desc, Homepage, Repo, Tag, BinaryName, Caveats string
}

// Pipe for brew deployment
type Pipe struct{}

// Name of the pipe
func (Pipe) Name() string {
	return "Homebrew"
}

// Run the pipe
func (Pipe) Run(config config.ProjectConfig) error {
	if config.Brew.Repo == "" {
		return nil
	}
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: config.Token},
	)
	tc := oauth2.NewClient(context.Background(), ts)
	client := github.NewClient(tc)

	owner, repo := split.OnSlash(config.Brew.Repo)
	name := config.BinaryName + ".rb"

	log.Println("Updating", name, "on", config.Brew.Repo, "...")
	out, err := buildFormulae(config, client)
	if err != nil {
		return err
	}
	sha, err := sha(client, owner, repo, name, out)
	if err != nil {
		return err
	}
	_, _, err = client.Repositories.UpdateFile(
		owner, repo, name, &github.RepositoryContentFileOptions{
			Committer: &github.CommitAuthor{
				Name:  github.String("goreleaserbot"),
				Email: github.String("bot@goreleaser"),
			},
			Content: out.Bytes(),
			Message: github.String(config.BinaryName + " version " + config.Git.CurrentTag),
			SHA:     sha,
		},
	)
	return err
}
func sha(client *github.Client, owner, repo, name string, out bytes.Buffer) (*string, error) {
	var sha *string
	file, _, _, err := client.Repositories.GetContents(
		owner, repo, name, &github.RepositoryContentGetOptions{},
	)
	if err == nil {
		sha = file.SHA
	} else {
		sha = github.String(fmt.Sprintf("%s", sha256.Sum256(out.Bytes())))
	}
	return sha, err
}

func buildFormulae(config config.ProjectConfig, client *github.Client) (bytes.Buffer, error) {
	data, err := dataFor(config, client)
	if err != nil {
		return bytes.Buffer{}, err
	}
	return doBuildFormulae(data)
}

func doBuildFormulae(data templateData) (bytes.Buffer, error) {
	var out bytes.Buffer
	tmpl, err := template.New(data.BinaryName).Parse(formulae)
	if err != nil {
		return out, err
	}
	err = tmpl.Execute(&out, data)
	return out, err
}

func dataFor(config config.ProjectConfig, client *github.Client) (result templateData, err error) {
	var homepage string
	var description string
	owner, repo := split.OnSlash(config.Repo)
	rep, _, err := client.Repositories.Get(owner, repo)
	if err != nil {
		return result, err
	}
	if rep.Homepage != nil && *rep.Homepage != "" {
		homepage = *rep.Homepage
	} else {
		homepage = *rep.HTMLURL
	}
	if rep.Description == nil {
		description = "TODO"
	} else {
		description = *rep.Description
	}
	return templateData{
		Name:       formulaNameFor(config.BinaryName),
		Desc:       description,
		Homepage:   homepage,
		Repo:       config.Repo,
		Tag:        config.Git.CurrentTag,
		BinaryName: config.BinaryName,
		Caveats:    config.Brew.Caveats,
	}, err
}

func formulaNameFor(name string) string {
	name = strings.Replace(name, "-", " ", -1)
	name = strings.Replace(name, "_", " ", -1)
	return strings.Replace(strings.Title(name), " ", "", -1)
}
<commit_msg>improved code a little<commit_after>package brew

import (
	"bytes"
	"context"
	"crypto/sha256"
	"fmt"
	"log"
	"strings"
	"text/template"

	"github.com/google/go-github/github"
	"github.com/goreleaser/releaser/config"
	"github.com/goreleaser/releaser/split"
	"golang.org/x/oauth2"
)

const formulae = `class {{ .Name }} < Formula
  desc "{{ .Desc }}"
  homepage "{{ .Homepage }}"
  url "https://github.com/{{ .Repo }}/releases/download/{{ .Tag }}/{{ .BinaryName }}_#{%x(uname -s).gsub(/\n/, '')}_#{%x(uname -m).gsub(/\n/, '')}.tar.gz"
  head "https://github.com/{{ .Repo }}.git"
  version "{{ .Tag }}"

  def install
    bin.install "{{ .BinaryName }}"
  end

  {{- if .Caveats }}

  def caveats
    "{{ .Caveats }}"
  end
  {{- end }}
end
`

type templateData struct {
	Name, Desc, Homepage, Repo, Tag, BinaryName, Caveats string
}

// Pipe for brew deployment
type Pipe struct{}

// Name of the pipe
func (Pipe) Name() string {
	return "Homebrew"
}

// Run the pipe
func (Pipe) Run(config config.ProjectConfig) error {
	if config.Brew.Repo == "" {
		return nil
	}
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: config.Token},
	)
	tc := oauth2.NewClient(context.Background(), ts)
	client := github.NewClient(tc)

	owner, repo := split.OnSlash(config.Brew.Repo)
	name := config.BinaryName + ".rb"

	log.Println("Updating", name, "on", config.Brew.Repo, "...")
	out, err := buildFormulae(config, client)
	if err != nil {
		return err
	}
	sha, err := sha(client, owner, repo, name, out)
	if err != nil {
		return err
	}
	_, _, err = client.Repositories.UpdateFile(
		owner, repo, name, &github.RepositoryContentFileOptions{
			Committer: &github.CommitAuthor{
				Name:  github.String("goreleaserbot"),
				Email: github.String("bot@goreleaser"),
			},
			Content: out.Bytes(),
			Message: github.String(config.BinaryName + " version " + config.Git.CurrentTag),
			SHA:     sha,
		},
	)
	return err
}
func sha(client *github.Client, owner, repo, name string, out bytes.Buffer) (*string, error) {
	file, _, _, err := client.Repositories.GetContents(
		owner, repo, name, &github.RepositoryContentGetOptions{},
	)
	if err == nil {
		return file.SHA, err
	}
	return github.String(fmt.Sprintf("%s", sha256.Sum256(out.Bytes()))), err
}

func buildFormulae(config config.ProjectConfig, client *github.Client) (bytes.Buffer, error) {
	data, err := dataFor(config, client)
	if err != nil {
		return bytes.Buffer{}, err
	}
	return doBuildFormulae(data)
}

func doBuildFormulae(data templateData) (bytes.Buffer, error) {
	var out bytes.Buffer
	tmpl, err := template.New(data.BinaryName).Parse(formulae)
	if err != nil {
		return out, err
	}
	err = tmpl.Execute(&out, data)
	return out, err
}

func dataFor(config config.ProjectConfig, client *github.Client) (result templateData, err error) {
	var homepage string
	var description string
	owner, repo := split.OnSlash(config.Repo)
	rep, _, err := client.Repositories.Get(owner, repo)
	if err != nil {
		return result, err
	}
	if rep.Homepage != nil && *rep.Homepage != "" {
		homepage = *rep.Homepage
	} else {
		homepage = *rep.HTMLURL
	}
	if rep.Description == nil {
		description = "TODO"
	} else {
		description = *rep.Description
	}
	return templateData{
		Name:       formulaNameFor(config.BinaryName),
		Desc:       description,
		Homepage:   homepage,
		Repo:       config.Repo,
		Tag:        config.Git.CurrentTag,
		BinaryName: config.BinaryName,
		Caveats:    config.Brew.Caveats,
	}, err
}

func formulaNameFor(name string) string {
	name = strings.Replace(name, "-", " ", -1)
	name = strings.Replace(name, "_", " ", -1)
	return strings.Replace(strings.Title(name), " ", "", -1)
}
<|endoftext|>