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

package assert

import (
	"bytes"
	"fmt"
	"os"
	"testing"
	"unicode/utf8"

	"github.com/golangplus/testing"
)

func TestFilePosition(t *testing.T) {
	var b bytes.Buffer
	bt := &testingp.WriterTB{
		Writer: &b,
	}

	Equal(bt, "v", 1, 2)
	line := 23 // the line number of the last line
	Equal(t, "log", b.String(), fmt.Sprintf("assert_test.go:%d: v is expected to be \"2\", but got \"1\"\n", line))

	b.Reset()
	Panic(bt, "nonpanic", func() {})
	line = 28 // the line number of the last line
	Equal(t, "log", b.String(), fmt.Sprintf("assert_test.go:%d: nonpanic does not panic as expected.\n", line))

	func(outLine int) {
		b.Reset()
		Equal(bt, "v", 1, 2)
		line := 34 // the line number of the last line
		Equal(t, "log", b.String(), fmt.Sprintf("assert_test.go:%d: assert_test.go:%d: v is expected to be \"2\", but got \"1\"\n", outLine, line))
	}(37) // 37 is the line number of current line
}

func TestSuccess(t *testing.T) {
	True(t, "return value", Equal(t, "v", 1, 1))
	True(t, "return true", Equal(t, "slice", []int{1}, []int{1}))
	True(t, "return true", Equal(t, "map", map[int]int{2: 1}, map[int]int{2: 1}))
	True(t, "return value", ValueShould(t, "s", "abc", func(s string) bool {
		return s == "abc"
	}, "is not abc"))
	True(t, "return value", ValueShould(t, "s", "abc", true, "is not abc"))
	True(t, "return value", NotEqual(t, "v", 1, 4))
	True(t, "return value", True(t, "bool", true))
	True(t, "return value", Should(t, true, "failed"))
	True(t, "return value", False(t, "bool", false))
	True(t, "return value", StringEqual(t, "string", 1, "1"))
}

func ExampleEqual() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	Equal(t, "v", 1, 2)
	Equal(t, "v", 1, "1")
	Equal(t, "m", map[string]int{"Extra": 2, "Modified": 4},
		map[string]int{"Missing": 1, "Modified": 5})

	// OUTPUT:
	// v is expected to be "2", but got "1"
	// v is expected to be "1"(type string), but got "1"(type int)
	// Unexpected m: both 2 entries
	//   Difference(expected ---  actual +++)
	//     --- "Missing": "1"
	//     --- "Modified": "5"
	//     +++ "Modified": "4"
	//     +++ "Extra": "2"
}

func ExampleValueShould() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	ValueShould(t, "s", "\xff\xfe\xfd", utf8.ValidString, "is not valid UTF8")
	ValueShould(t, "s", "abcd", len("abcd") <= 3, "has more than 3 bytes")

	// OUTPUT:
	// s is not valid UTF8: "\xff\xfe\xfd"(type string)
	// s has more than 3 bytes: "abcd"(type string)
}

func ExampleStringEqual() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	StringEqual(t, "s", []int{2, 3}, []string{"1", "2"})

	// OUTPUT:
	// Unexpected s: both 2 lines
	//   Difference(expected ---  actual +++)
	//     ---   1: "1"
	//     +++   2: "3"
}

func ExampleFailureTesting() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	Equal(t, "v", 1, "2")
	NotEqual(t, "v", 1, 1)
	True(t, "v", false)
	Should(t, false, "failed")
	StringEqual(t, "s", 1, "2")
	False(t, "v", true)
	Panic(t, "nonpanic", func() {})

	// OUTPUT:
	// v is expected to be "2"(type string), but got "1"(type int)
	// v is not expected to be "1"
	// v unexpectedly got false
	// failed
	// s is expected to be "2", but got "1"
	// v unexpectedly got true
	// nonpanic does not panic as expected.
}

func TestPanic(t *testing.T) {
	True(t, "return value", Panic(t, "panic", func() {
		panic("error")
	}))
}
<commit_msg>Change example to testcases<commit_after>// Copyright 2015 The Golang Plus Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package assert

import (
	"fmt"
	"os"
	"testing"
	"unicode/utf8"

	"github.com/golangplus/bytes"
	"github.com/golangplus/testing"
)

func TestFilePosition(t *testing.T) {
	var b bytesp.ByteSlice
	bt := &testingp.WriterTB{Writer: &b}

	Equal(bt, "v", 1, 2)
	line := 21 // the line number of the last line
	Equal(t, "log", string(b), fmt.Sprintf("assert_test.go:%d: v is expected to be \"2\", but got \"1\"\n", line))

	b.Reset()
	Panic(bt, "nonpanic", func() {})
	line = 26 // the line number of the last line
	Equal(t, "log", string(b), fmt.Sprintf("assert_test.go:%d: nonpanic does not panic as expected.\n", line))

	func(outLine int) {
		b.Reset()
		Equal(bt, "v", 1, 2)
		line := 32 // the line number of the last line
		Equal(t, "log", string(b), fmt.Sprintf("assert_test.go:%d: assert_test.go:%d: v is expected to be \"2\", but got \"1\"\n", outLine, line))
	}(35) // 37 is the line number of current line

	b.Reset()
	StringEqual(bt, "s", "1", 2)
	line = 38 // the line number of the last line
	Equal(t, "log", string(b), fmt.Sprintf("assert_test.go:%d: s is expected to be \"2\", but got \"1\"\n", line))
}

func TestSuccess(t *testing.T) {
	True(t, "return value", Equal(t, "v", 1, 1))
	True(t, "return true", Equal(t, "slice", []int{1}, []int{1}))
	True(t, "return true", Equal(t, "map", map[int]int{2: 1}, map[int]int{2: 1}))
	True(t, "return value", ValueShould(t, "s", "abc", func(s string) bool {
		return s == "abc"
	}, "is not abc"))
	True(t, "return value", ValueShould(t, "s", "abc", true, "is not abc"))
	True(t, "return value", NotEqual(t, "v", 1, 4))
	True(t, "return value", True(t, "bool", true))
	True(t, "return value", Should(t, true, "failed"))
	True(t, "return value", False(t, "bool", false))
	True(t, "return value", StringEqual(t, "string", 1, "1"))
}

func ExampleEqual() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	Equal(t, "v", 1, 2)
	Equal(t, "v", 1, "1")
	Equal(t, "m", map[string]int{"Extra": 2, "Modified": 4},
		map[string]int{"Missing": 1, "Modified": 5})

	// OUTPUT:
	// v is expected to be "2", but got "1"
	// v is expected to be "1"(type string), but got "1"(type int)
	// Unexpected m: both 2 entries
	//   Difference(expected ---  actual +++)
	//     --- "Missing": "1"
	//     --- "Modified": "5"
	//     +++ "Modified": "4"
	//     +++ "Extra": "2"
}

func ExampleValueShould() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	ValueShould(t, "s", "\xff\xfe\xfd", utf8.ValidString, "is not valid UTF8")
	ValueShould(t, "s", "abcd", len("abcd") <= 3, "has more than 3 bytes")

	// OUTPUT:
	// s is not valid UTF8: "\xff\xfe\xfd"(type string)
	// s has more than 3 bytes: "abcd"(type string)
}

func ExampleStringEqual() {
	// The following two lines are for test/example of assert package itself. Use
	// *testing.T as t in normal testing instead.
	IncludeFilePosition = false
	t := &testingp.WriterTB{Writer: os.Stdout}

	StringEqual(t, "s", []int{2, 3}, []string{"1", "2"})

	// OUTPUT:
	// Unexpected s: both 2 lines
	//   Difference(expected ---  actual +++)
	//     ---   1: "1"
	//     +++   2: "3"
}

func TestFailures(t *testing.T) {
	IncludeFilePosition = false
	var b bytesp.ByteSlice
	bt := &testingp.WriterTB{Writer: &b}

	Equal(bt, "v", 1, "2")
	NotEqual(bt, "v", 1, 1)
	True(bt, "v", false)
	Should(bt, false, "failed")
	StringEqual(bt, "s", 1, "2")
	False(bt, "v", true)
	Panic(bt, "nonpanic", func() {})

	StringEqual(t, "output", "\n"+string(b), `
v is expected to be "2"(type string), but got "1"(type int)
v is not expected to be "1"
v unexpectedly got false
failed
s is expected to be "2", but got "1"
v unexpectedly got true
nonpanic does not panic as expected.
`)
}

func TestPanic(t *testing.T) {
	True(t, "return value", Panic(t, "panic", func() {
		panic("error")
	}))
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"encoding/json"
	"io"
)

const (
	ACTION_TYPING       = "typing"
	ACTION_POSTED       = "posted"
	ACTION_POST_EDITED  = "post_edited"
	ACTION_POST_DELETED = "post_deleted"
	ACTION_VIEWED       = "viewed"
	ACTION_NEW_USER     = "new_user"
	ACTION_USER_ADDED	= "user_added"
)

type Message struct {
	TeamId    string            `json:"team_id"`
	ChannelId string            `json:"channel_id"`
	UserId    string            `json:"user_id"`
	Action    string            `json:"action"`
	Props     map[string]string `json:"props"`
}

func (m *Message) Add(key string, value string) {
	m.Props[key] = value
}

func NewMessage(teamId string, channekId string, userId string, action string) *Message {
	return &Message{TeamId: teamId, ChannelId: channekId, UserId: userId, Action: action, Props: make(map[string]string)}
}

func (o *Message) ToJson() string {
	b, err := json.Marshal(o)
	if err != nil {
		return ""
	} else {
		return string(b)
	}
}

func MessageFromJson(data io.Reader) *Message {
	decoder := json.NewDecoder(data)
	var o Message
	err := decoder.Decode(&o)
	if err == nil {
		return &o
	} else {
		return nil
	}
}
<commit_msg>Minor formatting change<commit_after>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"encoding/json"
	"io"
)

const (
	ACTION_TYPING       = "typing"
	ACTION_POSTED       = "posted"
	ACTION_POST_EDITED  = "post_edited"
	ACTION_POST_DELETED = "post_deleted"
	ACTION_VIEWED       = "viewed"
	ACTION_NEW_USER     = "new_user"
	ACTION_USER_ADDED   = "user_added"
)

type Message struct {
	TeamId    string            `json:"team_id"`
	ChannelId string            `json:"channel_id"`
	UserId    string            `json:"user_id"`
	Action    string            `json:"action"`
	Props     map[string]string `json:"props"`
}

func (m *Message) Add(key string, value string) {
	m.Props[key] = value
}

func NewMessage(teamId string, channekId string, userId string, action string) *Message {
	return &Message{TeamId: teamId, ChannelId: channekId, UserId: userId, Action: action, Props: make(map[string]string)}
}

func (o *Message) ToJson() string {
	b, err := json.Marshal(o)
	if err != nil {
		return ""
	} else {
		return string(b)
	}
}

func MessageFromJson(data io.Reader) *Message {
	decoder := json.NewDecoder(data)
	var o Message
	err := decoder.Decode(&o)
	if err == nil {
		return &o
	} else {
		return nil
	}
}
<|endoftext|>


<commit_before>package test

import (
	"bytes"
	"fmt"
	"go/build"
	"io"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/constabulary/gb"
	"github.com/constabulary/gb/log"
)

// Test returns a Target representing the result of compiling the
// package pkg, and its dependencies, and linking it with the
// test runner.
func Test(flags []string, pkgs ...*gb.Package) error {
	test, err := TestPackages(flags, pkgs...)
	if err != nil {
		return err
	}
	return gb.Execute(test)
}

// TestPackages produces a graph of Actions that when executed build
// and test the supplied packages.
func TestPackages(flags []string, pkgs ...*gb.Package) (*gb.Action, error) {
	if len(pkgs) < 1 {
		return nil, fmt.Errorf("no test packages provided")
	}
	targets := make(map[string]*gb.Action) // maps package import paths to their test run action

	names := func(pkgs []*gb.Package) []string {
		var names []string
		for _, pkg := range pkgs {
			names = append(names, pkg.ImportPath)
		}
		return names
	}

	// create top level test action to root all test actions
	t0 := time.Now()
	test := gb.Action{
		Name: fmt.Sprintf("test: %s", strings.Join(names(pkgs), ",")),
		Run: func() error {
			log.Debugf("test duration: %v %v", time.Since(t0), pkgs[0].Statistics.String())
			return nil
		},
	}

	for _, pkg := range pkgs {
		a, err := TestPackage(targets, pkg, flags)
		if err != nil {
			return nil, err
		}
		if a == nil {
			// nothing to do ?? not even a test action ?
			continue
		}
		test.Deps = append(test.Deps, a)
	}
	return &test, nil
}

// TestPackage returns an Action representing the steps required to build
// and test this Package.
func TestPackage(targets map[string]*gb.Action, pkg *gb.Package, flags []string) (*gb.Action, error) {
	var gofiles []string
	gofiles = append(gofiles, pkg.GoFiles...)
	gofiles = append(gofiles, pkg.TestGoFiles...)

	var cgofiles []string
	cgofiles = append(cgofiles, pkg.CgoFiles...)

	var imports []string
	imports = append(imports, pkg.Package.Imports...)
	imports = append(imports, pkg.Package.TestImports...)

	name := pkg.Name
	if name == "main" {
		// rename the main package to its package name for testing.
		name = filepath.Base(filepath.FromSlash(pkg.ImportPath))
	}

	// internal tests
	testpkg := gb.NewPackage(pkg.Context, &build.Package{
		Name:       name,
		ImportPath: pkg.ImportPath,
		Dir:        pkg.Dir,
		SrcRoot:    pkg.SrcRoot,

		GoFiles:      gofiles,
		CFiles:       pkg.CFiles,
		CgoFiles:     cgofiles,
		TestGoFiles:  pkg.TestGoFiles,  // passed directly to buildTestMain
		XTestGoFiles: pkg.XTestGoFiles, // passed directly to buildTestMain

		CgoCFLAGS:    pkg.CgoCFLAGS,
		CgoCPPFLAGS:  pkg.CgoCPPFLAGS,
		CgoCXXFLAGS:  pkg.CgoCXXFLAGS,
		CgoLDFLAGS:   pkg.CgoLDFLAGS,
		CgoPkgConfig: pkg.CgoPkgConfig,

		Imports: imports,
	})
	testpkg.Scope = "test"
	testpkg.Stale = true

	// build dependencies
	deps, err := gb.BuildDependencies(targets, testpkg)
	if err != nil {
		return nil, err
	}

	// only build the internal test if there is Go source or
	// internal test files.
	var testobj *gb.Action
	if len(testpkg.GoFiles)+len(testpkg.CgoFiles)+len(testpkg.TestGoFiles) > 0 {
		var err error
		testobj, err = gb.Compile(testpkg, deps...)
		if err != nil {
			return nil, err
		}
	}

	// external tests
	if len(pkg.XTestGoFiles) > 0 {
		xtestpkg := gb.NewPackage(pkg.Context, &build.Package{
			Name:       name,
			ImportPath: pkg.ImportPath + "_test",
			Dir:        pkg.Dir,
			GoFiles:    pkg.XTestGoFiles,
			Imports:    pkg.XTestImports,
		})
		// build external test dependencies
		deps, err := gb.BuildDependencies(targets, xtestpkg)
		if err != nil {
			return nil, err
		}
		xtestpkg.Scope = "test"
		xtestpkg.Stale = true
		xtestpkg.ExtraIncludes = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test")

		// if there is an internal test object, add it as a dependency.
		if testobj != nil {
			deps = append(deps, testobj)
		}
		testobj, err = gb.Compile(xtestpkg, deps...)
		if err != nil {
			return nil, err
		}
	}

	testmainpkg, err := buildTestMain(testpkg)
	if err != nil {
		return nil, err
	}
	testmain, err := gb.Compile(testmainpkg, testobj)
	if err != nil {
		return nil, err
	}

	cmd := exec.Command(testmainpkg.Binfile(), flags...)
	cmd.Dir = pkg.Dir // tests run in the original source directory
	var output bytes.Buffer
	cmd.Stdout = &output
	cmd.Stderr = &output

	logInfoFn := func(fn func() error, format string, args ...interface{}) func() error {
		return func() error {
			err := fn()
			log.Infof(format, args...)
			if err != nil {
				io.Copy(os.Stdout, &output)
			}
			return err
		}
	}

	return &gb.Action{
		Name: fmt.Sprintf("run: %s", cmd.Args),
		Deps: []*gb.Action{testmain},
		Run:  logInfoFn(cmd.Run, pkg.ImportPath),
	}, nil
}

func buildTestMain(pkg *gb.Package) (*gb.Package, error) {
	if pkg.Scope != "test" {
		return nil, fmt.Errorf("package %q is not test scoped", pkg.Name)
	}
	dir := gb.Workdir(pkg)
	if err := mkdir(dir); err != nil {
		return nil, fmt.Errorf("buildTestmain: %v", err)
	}
	tests, err := loadTestFuncs(pkg.Package)
	if err != nil {
		return nil, err
	}
	if len(pkg.Package.XTestGoFiles) > 0 {
		// if there are external tests ensure that we import the
		// test package into the final binary for side effects.
		tests.ImportXtest = true
	}
	if err := writeTestmain(filepath.Join(dir, "_testmain.go"), tests); err != nil {
		return nil, err
	}
	testmain := gb.NewPackage(pkg.Context, &build.Package{
		Name:       pkg.Name,
		ImportPath: path.Join(pkg.ImportPath, "testmain"),
		Dir:        dir,
		SrcRoot:    pkg.SrcRoot,

		GoFiles: []string{"_testmain.go"},

		Imports: pkg.Package.Imports,
	})
	testmain.Scope = "test"
	testmain.ExtraIncludes = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test")
	return testmain, nil
}

func mkdir(path string) error {
	return os.MkdirAll(path, 0755)
}
<commit_msg>gb/test: scale test improvements<commit_after>package test

import (
	"bytes"
	"fmt"
	"go/build"
	"io"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/constabulary/gb"
	"github.com/constabulary/gb/log"
)

// Test returns a Target representing the result of compiling the
// package pkg, and its dependencies, and linking it with the
// test runner.
func Test(flags []string, pkgs ...*gb.Package) error {
	test, err := TestPackages(flags, pkgs...)
	if err != nil {
		return err
	}
	return gb.Execute(test)
}

// TestPackages produces a graph of Actions that when executed build
// and test the supplied packages.
func TestPackages(flags []string, pkgs ...*gb.Package) (*gb.Action, error) {
	if len(pkgs) < 1 {
		return nil, fmt.Errorf("no test packages provided")
	}
	targets := make(map[string]*gb.Action) // maps package import paths to their test run action

	names := func(pkgs []*gb.Package) []string {
		var names []string
		for _, pkg := range pkgs {
			names = append(names, pkg.ImportPath)
		}
		return names
	}

	// create top level test action to root all test actions
	t0 := time.Now()
	test := gb.Action{
		Name: fmt.Sprintf("test: %s", strings.Join(names(pkgs), ",")),
		Run: func() error {
			log.Debugf("test duration: %v %v", time.Since(t0), pkgs[0].Statistics.String())
			return nil
		},
	}

	for _, pkg := range pkgs {
		a, err := TestPackage(targets, pkg, flags)
		if err != nil {
			return nil, err
		}
		if a == nil {
			// nothing to do ?? not even a test action ?
			continue
		}
		test.Deps = append(test.Deps, a)
	}
	return &test, nil
}

// TestPackage returns an Action representing the steps required to build
// and test this Package.
func TestPackage(targets map[string]*gb.Action, pkg *gb.Package, flags []string) (*gb.Action, error) {
	var gofiles []string
	gofiles = append(gofiles, pkg.GoFiles...)
	gofiles = append(gofiles, pkg.TestGoFiles...)

	var cgofiles []string
	cgofiles = append(cgofiles, pkg.CgoFiles...)

	var imports []string
	imports = append(imports, pkg.Package.Imports...)
	imports = append(imports, pkg.Package.TestImports...)

	name := pkg.Name
	if name == "main" {
		// rename the main package to its package name for testing.
		name = filepath.Base(filepath.FromSlash(pkg.ImportPath))
	}

	// internal tests
	testpkg := gb.NewPackage(pkg.Context, &build.Package{
		Name:       name,
		ImportPath: pkg.ImportPath,
		Dir:        pkg.Dir,
		SrcRoot:    pkg.SrcRoot,

		GoFiles:      gofiles,
		CFiles:       pkg.CFiles,
		CgoFiles:     cgofiles,
		TestGoFiles:  pkg.TestGoFiles,  // passed directly to buildTestMain
		XTestGoFiles: pkg.XTestGoFiles, // passed directly to buildTestMain

		CgoCFLAGS:    pkg.CgoCFLAGS,
		CgoCPPFLAGS:  pkg.CgoCPPFLAGS,
		CgoCXXFLAGS:  pkg.CgoCXXFLAGS,
		CgoLDFLAGS:   pkg.CgoLDFLAGS,
		CgoPkgConfig: pkg.CgoPkgConfig,

		Imports: imports,
	})
	testpkg.Scope = "test"
	testpkg.Stale = true

	// only build the internal test if there is Go source or
	// internal test files.
	var testobj *gb.Action
	if len(testpkg.GoFiles)+len(testpkg.CgoFiles)+len(testpkg.TestGoFiles) > 0 {

		// build internal testpkg dependencies
		deps, err := gb.BuildDependencies(targets, testpkg)
		if err != nil {
			return nil, err
		}

		testobj, err = gb.Compile(testpkg, deps...)
		if err != nil {
			return nil, err
		}
	}

	// external tests
	if len(pkg.XTestGoFiles) > 0 {
		xtestpkg := gb.NewPackage(pkg.Context, &build.Package{
			Name:       name,
			ImportPath: pkg.ImportPath + "_test",
			Dir:        pkg.Dir,
			GoFiles:    pkg.XTestGoFiles,
			Imports:    pkg.XTestImports,
		})
		// build external test dependencies
		deps, err := gb.BuildDependencies(targets, xtestpkg)
		if err != nil {
			return nil, err
		}
		xtestpkg.Scope = "test"
		xtestpkg.Stale = true
		xtestpkg.ExtraIncludes = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test")

		// if there is an internal test object, add it as a dependency.
		if testobj != nil {
			deps = append(deps, testobj)
		}
		testobj, err = gb.Compile(xtestpkg, deps...)
		if err != nil {
			return nil, err
		}
	}

	testmainpkg, err := buildTestMain(testpkg)
	if err != nil {
		return nil, err
	}
	testmain, err := gb.Compile(testmainpkg, testobj)
	if err != nil {
		return nil, err
	}

	cmd := exec.Command(testmainpkg.Binfile(), flags...)
	cmd.Dir = pkg.Dir // tests run in the original source directory
	var output bytes.Buffer
	cmd.Stdout = &output
	cmd.Stderr = &output

	logInfoFn := func(fn func() error, format string, args ...interface{}) func() error {
		return func() error {
			err := fn()
			log.Infof(format, args...)
			if err != nil {
				io.Copy(os.Stdout, &output)
			}
			return err
		}
	}

	// test binaries can be very large, so always unlink the
	// binary after the test has run to free up temporary space
	// technically this is done by ctx.Destroy(), but freeing
	// the space earlier is important for projects with many
	// packages
	withcleanup := func(fn func() error) func() error {
		return func() error {
			file := testmainpkg.Binfile()
			err := fn()
			os.Remove(file)
			return err
		}
	}
	fn := withcleanup(cmd.Run)
	fn = logInfoFn(fn, pkg.ImportPath)
	// When used with the concurrent executor, building deps and
	// linking the test binary can cause a lot of disk space to be
	// pinned as linking will tend to occur more frequenty than retiring
	// tests.
	//
	// To solve this, we merge the testmain compile step (which includes
	// linking) and the execute and cleanup steps so they are executed
	// as one atomic operation.

	return &gb.Action{
		Name: fmt.Sprintf("run: %s", cmd.Args),
		Deps: testmain.Deps,
		Run: func() error {
			err := testmain.Run()
			if err != nil {
				return err
			}
			return fn()
		},
	}, nil
}

func buildTestMain(pkg *gb.Package) (*gb.Package, error) {
	if pkg.Scope != "test" {
		return nil, fmt.Errorf("package %q is not test scoped", pkg.Name)
	}
	dir := gb.Workdir(pkg)
	if err := mkdir(dir); err != nil {
		return nil, fmt.Errorf("buildTestmain: %v", err)
	}
	tests, err := loadTestFuncs(pkg.Package)
	if err != nil {
		return nil, err
	}
	if len(pkg.Package.XTestGoFiles) > 0 {
		// if there are external tests ensure that we import the
		// test package into the final binary for side effects.
		tests.ImportXtest = true
	}
	if err := writeTestmain(filepath.Join(dir, "_testmain.go"), tests); err != nil {
		return nil, err
	}
	testmain := gb.NewPackage(pkg.Context, &build.Package{
		Name:       pkg.Name,
		ImportPath: path.Join(pkg.ImportPath, "testmain"),
		Dir:        dir,
		SrcRoot:    pkg.SrcRoot,

		GoFiles: []string{"_testmain.go"},

		Imports: pkg.Package.Imports,
	})
	testmain.Scope = "test"
	testmain.ExtraIncludes = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test")
	return testmain, nil
}

func mkdir(path string) error {
	return os.MkdirAll(path, 0755)
}
<|endoftext|>


<commit_before>package snowdrift

import (
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"net/http"
	"net/url"

	"bitbucket.org/ww/goautoneg"
	"github.com/codegangsta/martini"
	"github.com/codegangsta/martini-contrib/binding"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/speps/go-hashids"
)

type Config struct {
	Backend      Backend
	HashSalt     string
	URLPrefix    string
	RootRedirect string
	ReportErr    func(err error, req *http.Request)
}

func New(c *Config) *martini.Martini {
	r := martini.NewRouter()
	m := martini.New()
	m.Action(r.Handle)

	ctx := &context{
		Backend:   c.Backend,
		ShortHash: hashids.New(),
		LongHash:  hashids.New(),
		URLPrefix: c.URLPrefix,
		ReportErr: c.ReportErr,
	}
	if c.HashSalt == "" {
		c.HashSalt = "salt"
	}
	ctx.ShortHash.Salt = c.HashSalt
	ctx.LongHash.Salt = c.HashSalt
	ctx.LongHash.MinLength = 12
	m.Map(ctx)
	m.Use(render.Renderer())

	r.Get("/", func(r *http.Request, w http.ResponseWriter) {
		http.Redirect(w, r, c.RootRedirect, http.StatusFound)
	})
	r.Post("/", binding.Bind(link{}), createLink)
	r.Get("/:code", getLink)

	return m
}

var ErrNotFound = errors.New("snowdrift: not found")
var ErrURLExists = errors.New("snowdrift: url already exists")
var ErrCodeExists = errors.New("snowdrift: code already exists")

type Backend interface {
	Add(url, digest, code string) error
	GetCode(digest string) (string, error)
	GetURL(code string) (string, error)
	NextID() (int, error)
}

type link struct {
	LongURL  string `json:"long_url" riak:"long_url"`
	ShortURL string `json:"short_url" riak:"-"`
	Obscure  *bool  `json:"obscure,omitempty" riak:"-"`
}

type context struct {
	Backend
	ShortHash *hashids.HashID
	LongHash  *hashids.HashID
	URLPrefix string
	ReportErr func(err error, req *http.Request)
}

func urlDigest(url string) string {
	digest := sha512.Sum512([]byte(url))
	return hex.EncodeToString(digest[:32])
}

func createLink(c *context, link link, r render.Render, req *http.Request) {
	if len(link.LongURL) > 2000 {
		r.Error(400)
		return
	}
	u, err := url.Parse(link.LongURL)
	if err != nil || u.Scheme != "http" && u.Scheme != "https" {
		r.Error(400)
		return
	}

	digest := urlDigest(link.LongURL)

	code, err := c.GetCode(digest)
	if err == nil {
		link.ShortURL = c.URLPrefix + code
		link.Obscure = nil
		r.JSON(200, link)
		return
	}

	id, err := c.NextID()
	if err != nil {
		r.Error(500)
		if c.ReportErr != nil {
			c.ReportErr(err, req)
		}
		return
	}
	if link.Obscure != nil && *link.Obscure {
		code = c.LongHash.Encrypt([]int{id})
	} else {
		code = c.ShortHash.Encrypt([]int{id})
	}

	if err := c.Add(link.LongURL, digest, code); err != nil {
		r.Error(500)
		if c.ReportErr != nil {
			c.ReportErr(err, req)
		}
		return
	}
	link.Obscure = nil
	link.ShortURL = c.URLPrefix + code
	r.JSON(200, link)
}

func getLink(c *context, params martini.Params, r render.Render, req *http.Request, w http.ResponseWriter) {
	url, err := c.GetURL(params["code"])
	if err == ErrNotFound {
		http.NotFound(w, req)
		return
	}
	if err != nil {
		r.Error(500)
		if c.ReportErr != nil {
			c.ReportErr(err, req)
		}
		return
	}
	contentType := goautoneg.Negotiate(req.Header.Get("Accept"), []string{"text/html", "application/json"})
	if contentType == "application/json" {
		r.JSON(200, link{LongURL: url, ShortURL: c.URLPrefix + params["code"]})
		return
	}

	http.Redirect(w, req, url, http.StatusMovedPermanently)
}
<commit_msg>Add CORS support<commit_after>package snowdrift

import (
	"crypto/sha512"
	"encoding/hex"
	"errors"
	"net/http"
	"net/url"
	"regexp"

	"bitbucket.org/ww/goautoneg"
	"github.com/codegangsta/martini"
	"github.com/codegangsta/martini-contrib/binding"
	"github.com/codegangsta/martini-contrib/render"
	"github.com/speps/go-hashids"
)

type Config struct {
	Backend        Backend
	HashSalt       string
	URLPrefix      string
	RootRedirect   string
	AllowedOrigins *regexp.Regexp
	ReportErr      func(err error, req *http.Request)
}

func New(c *Config) *martini.Martini {
	r := martini.NewRouter()
	m := martini.New()
	m.Action(r.Handle)

	ctx := &context{
		Backend:        c.Backend,
		ShortHash:      hashids.New(),
		LongHash:       hashids.New(),
		URLPrefix:      c.URLPrefix,
		AllowedOrigins: c.AllowedOrigins,
		ReportErr:      c.ReportErr,
	}
	if c.HashSalt == "" {
		c.HashSalt = "salt"
	}
	ctx.ShortHash.Salt = c.HashSalt
	ctx.LongHash.Salt = c.HashSalt
	ctx.LongHash.MinLength = 12
	m.Map(ctx)
	m.Use(render.Renderer())

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, c.RootRedirect, http.StatusFound)
	})
	r.Options("/", func(w http.ResponseWriter, r *http.Request) {
		origin := r.Header.Get("Origin")
		if origin == "" {
			w.WriteHeader(200)
			return
		}
		if c.AllowedOrigins != nil && !c.AllowedOrigins.MatchString(origin) {
			w.WriteHeader(400)
			return
		}
		w.Header().Set("Access-Control-Allow-Origin", origin)
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST")
		w.Header().Set("Access-Control-Max-Age", "3600")
		w.WriteHeader(200)
	})
	r.Post("/", binding.Bind(link{}), createLink)
	r.Get("/:code", getLink)

	return m
}

var ErrNotFound = errors.New("snowdrift: not found")
var ErrURLExists = errors.New("snowdrift: url already exists")
var ErrCodeExists = errors.New("snowdrift: code already exists")

type Backend interface {
	Add(url, digest, code string) error
	GetCode(digest string) (string, error)
	GetURL(code string) (string, error)
	NextID() (int, error)
}

type link struct {
	LongURL  string `json:"long_url" riak:"long_url"`
	ShortURL string `json:"short_url" riak:"-"`
	Obscure  *bool  `json:"obscure,omitempty" riak:"-"`
}

type context struct {
	Backend
	ShortHash      *hashids.HashID
	LongHash       *hashids.HashID
	URLPrefix      string
	AllowedOrigins *regexp.Regexp
	ReportErr      func(err error, req *http.Request)
}

func (c *context) validCORS(w http.ResponseWriter, req *http.Request) bool {
	if origin := req.Header.Get("Origin"); origin != "" && (c.AllowedOrigins == nil || c.AllowedOrigins.MatchString(origin)) {
		w.Header().Set("Access-Control-Allow-Origin", origin)
		return true
	}
	w.WriteHeader(400)
	return false
}

func urlDigest(url string) string {
	digest := sha512.Sum512([]byte(url))
	return hex.EncodeToString(digest[:32])
}

func createLink(c *context, link link, r render.Render, w http.ResponseWriter, req *http.Request) {
	if !c.validCORS(w, req) {
		return
	}
	if len(link.LongURL) > 2000 {
		r.Error(400)
		return
	}
	u, err := url.Parse(link.LongURL)
	if err != nil || u.Scheme != "http" && u.Scheme != "https" {
		r.Error(400)
		return
	}

	digest := urlDigest(link.LongURL)

	code, err := c.GetCode(digest)
	if err == nil {
		link.ShortURL = c.URLPrefix + code
		link.Obscure = nil
		r.JSON(200, link)
		return
	}

	id, err := c.NextID()
	if err != nil {
		r.Error(500)
		if c.ReportErr != nil {
			c.ReportErr(err, req)
		}
		return
	}
	if link.Obscure != nil && *link.Obscure {
		code = c.LongHash.Encrypt([]int{id})
	} else {
		code = c.ShortHash.Encrypt([]int{id})
	}

	if err := c.Add(link.LongURL, digest, code); err != nil {
		r.Error(500)
		if c.ReportErr != nil {
			c.ReportErr(err, req)
		}
		return
	}
	link.Obscure = nil
	link.ShortURL = c.URLPrefix + code
	r.JSON(200, link)
}

func getLink(c *context, params martini.Params, r render.Render, req *http.Request, w http.ResponseWriter) {
	if !c.validCORS(w, req) {
		return
	}

	url, err := c.GetURL(params["code"])
	if err == ErrNotFound {
		http.NotFound(w, req)
		return
	}
	if err != nil {
		r.Error(500)
		if c.ReportErr != nil {
			c.ReportErr(err, req)
		}
		return
	}
	contentType := goautoneg.Negotiate(req.Header.Get("Accept"), []string{"text/html", "application/json"})
	if contentType == "application/json" {
		r.JSON(200, link{LongURL: url, ShortURL: c.URLPrefix + params["code"]})
		return
	}

	http.Redirect(w, req, url, http.StatusMovedPermanently)
}
<|endoftext|>


<commit_before>package openstack

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/jrperritt/terraform/helper/hashcode"
	"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
)

func resourceNetworkingSubnet() *schema.Resource {
	return &schema.Resource{
		Create: resourceNetworkingSubnetCreate,
		Read:   resourceNetworkingSubnetRead,
		Update: resourceNetworkingSubnetUpdate,
		Delete: resourceNetworkingSubnetDelete,

		Schema: map[string]*schema.Schema{
			"network_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"cidr": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"allocation_pools": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"start": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"end": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},

			"gateway_ip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

			"ip_version": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"enable_dhcp": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

			"dns_nameservers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: false,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"host_routes": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: false,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"destination_cidr": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"next_hop": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
		},
	}
}

func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	createOpts := subnets.CreateOpts{
		NetworkID:       d.Get("network_id").(string),
		CIDR:            d.Get("cidr").(string),
		Name:            d.Get("name").(string),
		TenantID:        d.Get("tenant_id").(string),
		AllocationPools: resourceSubnetAllocationPools(d),
		GatewayIP:       d.Get("gateway_ip").(string),
		IPVersion:       d.Get("ip_version").(int),
		DNSNameservers:  resourceSubnetDNSNameservers(d),
		HostRoutes:      resourceSubnetHostRoutes(d),
	}

	edRaw := d.Get("enable_dhcp").(string)
	if edRaw != "" {
		ed, err := strconv.ParseBool(edRaw)
		if err != nil {
			return fmt.Errorf("enable_dhcp, if provided, must be either 'true' or 'false'")
		}
		createOpts.EnableDHCP = &ed
	}

	log.Printf("[INFO] Requesting subnet creation")
	s, err := subnets.Create(osClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err)
	}
	log.Printf("[INFO] Subnet ID: %s", s.ID)

	d.SetId(s.ID)

	return resourceNetworkingSubnetRead(d, meta)
}

func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	s, err := subnets.Get(osClient, d.Id()).Extract()
	if err != nil {
		return fmt.Errorf("Error retrieving OpenStack Neutron Subnet: %s", err)
	}

	log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s)

	d.Set("newtork_id", s.NetworkID)
	d.Set("cidr", s.CIDR)
	d.Set("ip_version", s.IPVersion)

	if _, exists := d.GetOk("name"); exists {
		if d.HasChange("name") {
			d.Set("name", s.Name)
		}
	} else {
		d.Set("name", "")
	}

	if _, exists := d.GetOk("tenant_id"); exists {
		if d.HasChange("tenant_id") {
			d.Set("tenant_id", s.Name)
		}
	} else {
		d.Set("tenant_id", "")
	}

	if _, exists := d.GetOk("allocation_pools"); exists {
		d.Set("allocation_pools", s.AllocationPools)
	}

	if _, exists := d.GetOk("gateway_ip"); exists {
		if d.HasChange("gateway_ip") {
			d.Set("gateway_ip", s.Name)
		}
	} else {
		d.Set("gateway_ip", "")
	}

	if _, exists := d.GetOk("enable_dhcp"); exists {
		if d.HasChange("enable_dhcp") {
			d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP))
		}
	} else {
		d.Set("enable_dhcp", "")
	}

	if _, exists := d.GetOk("dns_nameservers"); exists {
		d.Set("dns_nameservers", s.DNSNameservers)
	}

	if _, exists := d.GetOk("host_routes"); exists {
		d.Set("host_routes", s.HostRoutes)
	}

	return nil
}

func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	var updateOpts subnets.UpdateOpts

	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}

	if d.HasChange("gateway_ip") {
		updateOpts.GatewayIP = d.Get("gateway_ip").(string)
	}

	if d.HasChange("dns_nameservers") {
		updateOpts.DNSNameservers = resourceSubnetDNSNameservers(d)
	}

	if d.HasChange("host_routes") {
		updateOpts.HostRoutes = resourceSubnetHostRoutes(d)
	}

	if d.HasChange("enable_dhcp") {
		edRaw := d.Get("enable_dhcp").(string)
		if edRaw != "" {
			ed, err := strconv.ParseBool(edRaw)
			if err != nil {
				return fmt.Errorf("enable_dhcp, if provided, must be either 'true' or 'false'")
			}
			updateOpts.EnableDHCP = &ed
		}
	}

	log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts)

	_, err := subnets.Update(osClient, d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err)
	}

	return resourceNetworkingSubnetRead(d, meta)
}

func resourceNetworkingSubnetDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	err := subnets.Delete(osClient, d.Id()).ExtractErr()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceSubnetAllocationPools(d *schema.ResourceData) []subnets.AllocationPool {
	rawAPs := d.Get("allocation_pools").([]interface{})
	aps := make([]subnets.AllocationPool, len(rawAPs))
	for i, raw := range rawAPs {
		aps[i] = raw.(subnets.AllocationPool)
	}
	return aps
}

func resourceSubnetDNSNameservers(d *schema.ResourceData) []string {
	rawDNSN := d.Get("dns_nameservers").(*schema.Set)
	dnsn := make([]string, rawDNSN.Len())
	for i, raw := range rawDNSN.List() {
		dnsn[i] = raw.(string)
	}
	return dnsn
}

func resourceSubnetHostRoutes(d *schema.ResourceData) []subnets.HostRoute {
	rawHR := d.Get("host_routes").([]interface{})
	hr := make([]subnets.HostRoute, len(rawHR))
	for i, raw := range rawHR {
		hr[i] = raw.(subnets.HostRoute)
	}
	return hr
}
<commit_msg>neutron subnet operations<commit_after>package openstack

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/jrperritt/terraform/helper/hashcode"
	"github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
)

func resourceNetworkingSubnet() *schema.Resource {
	return &schema.Resource{
		Create: resourceNetworkingSubnetCreate,
		Read:   resourceNetworkingSubnetRead,
		Update: resourceNetworkingSubnetUpdate,
		Delete: resourceNetworkingSubnetDelete,

		Schema: map[string]*schema.Schema{
			"network_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"cidr": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"allocation_pools": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"start": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"end": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},

			"gateway_ip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

			"ip_version": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"enable_dhcp": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

			"dns_nameservers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: false,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"host_routes": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: false,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"destination_cidr": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"next_hop": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
		},
	}
}

func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	createOpts := subnets.CreateOpts{
		NetworkID:       d.Get("network_id").(string),
		CIDR:            d.Get("cidr").(string),
		Name:            d.Get("name").(string),
		TenantID:        d.Get("tenant_id").(string),
		AllocationPools: resourceSubnetAllocationPools(d),
		GatewayIP:       d.Get("gateway_ip").(string),
		IPVersion:       d.Get("ip_version").(int),
		DNSNameservers:  resourceSubnetDNSNameservers(d),
		HostRoutes:      resourceSubnetHostRoutes(d),
	}

	edRaw := d.Get("enable_dhcp").(string)
	if edRaw != "" {
		ed, err := strconv.ParseBool(edRaw)
		if err != nil {
			return fmt.Errorf("enable_dhcp, if provided, must be either 'true' or 'false'")
		}
		createOpts.EnableDHCP = &ed
	}

	log.Printf("[INFO] Requesting subnet creation")
	s, err := subnets.Create(osClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err)
	}
	log.Printf("[INFO] Subnet ID: %s", s.ID)

	d.SetId(s.ID)

	return resourceNetworkingSubnetRead(d, meta)
}

func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	s, err := subnets.Get(osClient, d.Id()).Extract()
	if err != nil {
		return fmt.Errorf("Error retrieving OpenStack Neutron Subnet: %s", err)
	}

	log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s)

	d.Set("newtork_id", s.NetworkID)
	d.Set("cidr", s.CIDR)
	d.Set("ip_version", s.IPVersion)

	if _, exists := d.GetOk("name"); exists {
		if d.HasChange("name") {
			d.Set("name", s.Name)
		}
	} else {
		d.Set("name", "")
	}

	if _, exists := d.GetOk("tenant_id"); exists {
		if d.HasChange("tenant_id") {
			d.Set("tenant_id", s.Name)
		}
	} else {
		d.Set("tenant_id", "")
	}

	if _, exists := d.GetOk("allocation_pools"); exists {
		d.Set("allocation_pools", s.AllocationPools)
	}

	if _, exists := d.GetOk("gateway_ip"); exists {
		if d.HasChange("gateway_ip") {
			d.Set("gateway_ip", s.Name)
		}
	} else {
		d.Set("gateway_ip", "")
	}

	if _, exists := d.GetOk("enable_dhcp"); exists {
		if d.HasChange("enable_dhcp") {
			d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP))
		}
	} else {
		d.Set("enable_dhcp", "")
	}

	if _, exists := d.GetOk("dns_nameservers"); exists {
		d.Set("dns_nameservers", s.DNSNameservers)
	}

	if _, exists := d.GetOk("host_routes"); exists {
		d.Set("host_routes", s.HostRoutes)
	}

	return nil
}

func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	var updateOpts subnets.UpdateOpts

	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}

	if d.HasChange("gateway_ip") {
		updateOpts.GatewayIP = d.Get("gateway_ip").(string)
	}

	if d.HasChange("dns_nameservers") {
		updateOpts.DNSNameservers = resourceSubnetDNSNameservers(d)
	}

	if d.HasChange("host_routes") {
		updateOpts.HostRoutes = resourceSubnetHostRoutes(d)
	}

	if d.HasChange("enable_dhcp") {
		edRaw := d.Get("enable_dhcp").(string)
		if edRaw != "" {
			ed, err := strconv.ParseBool(edRaw)
			if err != nil {
				return fmt.Errorf("enable_dhcp, if provided, must be either 'true' or 'false'")
			}
			updateOpts.EnableDHCP = &ed
		}
	}

	log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts)

	_, err := subnets.Update(osClient, d.Id(), updateOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err)
	}

	return resourceNetworkingSubnetRead(d, meta)
}

func resourceNetworkingSubnetDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.networkingV2Client

	err := subnets.Delete(osClient, d.Id()).ExtractErr()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err)
	}

	d.SetId("")
	return nil
}

func resourceSubnetAllocationPools(d *schema.ResourceData) []subnets.AllocationPool {
	rawAPs := d.Get("allocation_pools").([]interface{})
	aps := make([]subnets.AllocationPool, len(rawAPs))
	for i, raw := range rawAPs {
		rawMap := raw.(map[string]interface{})
		aps[i] = subnets.AllocationPool{
			Start: rawMap["start"].(string),
			End:   rawMap["end"].(string),
		}
	}
	return aps
}

func resourceSubnetDNSNameservers(d *schema.ResourceData) []string {
	rawDNSN := d.Get("dns_nameservers").(*schema.Set)
	dnsn := make([]string, rawDNSN.Len())
	for i, raw := range rawDNSN.List() {
		dnsn[i] = raw.(string)
	}
	return dnsn
}

func resourceSubnetHostRoutes(d *schema.ResourceData) []subnets.HostRoute {
	rawHR := d.Get("host_routes").([]interface{})
	hr := make([]subnets.HostRoute, len(rawHR))
	for i, raw := range rawHR {
		rawMap := raw.(map[string]interface{})
		hr[i] = subnets.HostRoute{
			DestinationCIDR: rawMap["destination_cidr"].(string),
			NextHop:         rawMap["next_hop"].(string),
		}
	}
	return hr
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"fmt"
	"strconv"
	"strings"
)

// This is a list of all the current viersions including any patches.
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
	"1.4.0",
	"1.3.0",
	"1.2.1",
	"1.2.0",
	"1.1.0",
	"1.0.0",
	"0.7.1",
	"0.7.0",
	"0.6.0",
	"0.5.0",
}

var CurrentVersion string = versions[0]

var BuildNumber = "_BUILD_NUMBER_"
var BuildDate = "_BUILD_DATE_"
var BuildHash = "_BUILD_HASH_"
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_"
var versionsWithoutHotFixes []string

func init() {
	versionsWithoutHotFixes = make([]string, 0, len(versions))
	seen := make(map[string]string)

	for _, version := range versions {
		maj, min, _ := SplitVersion(version)
		verStr := fmt.Sprintf("%v.%v.0", maj, min)

		if seen[verStr] == "" {
			versionsWithoutHotFixes = append(versionsWithoutHotFixes, verStr)
			seen[verStr] = verStr
		}
	}
}

func SplitVersion(version string) (int64, int64, int64) {
	parts := strings.Split(version, ".")

	major := int64(0)
	minor := int64(0)
	patch := int64(0)

	if len(parts) > 0 {
		major, _ = strconv.ParseInt(parts[0], 10, 64)
	}

	if len(parts) > 1 {
		minor, _ = strconv.ParseInt(parts[1], 10, 64)
	}

	if len(parts) > 2 {
		patch, _ = strconv.ParseInt(parts[2], 10, 64)
	}

	return major, minor, patch
}

func GetPreviousVersion(version string) string {
	verMajor, verMinor, _ := SplitVersion(version)
	verStr := fmt.Sprintf("%v.%v.0", verMajor, verMinor)

	for index, v := range versionsWithoutHotFixes {
		if v == verStr && len(versionsWithoutHotFixes) > index+1 {
			return versionsWithoutHotFixes[index+1]
		}
	}

	return ""
}

func IsOfficalBuild() bool {
	return BuildNumber != "dev"
}

func IsCurrentVersion(versionToCheck string) bool {
	currentMajor, currentMinor, _ := SplitVersion(CurrentVersion)
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)

	if toCheckMajor == currentMajor && toCheckMinor == currentMinor {
		return true
	} else {
		return false
	}
}

func IsPreviousVersionsSupported(versionToCheck string) bool {
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
	versionToCheckStr := fmt.Sprintf("%v.%v.0", toCheckMajor, toCheckMinor)

	// Current Supported
	if versionsWithoutHotFixes[0] == versionToCheckStr {
		return true
	}

	// Current - 1 Supported
	if versionsWithoutHotFixes[1] == versionToCheckStr {
		return true
	}

	// Current - 2 Supported
	if versionsWithoutHotFixes[2] == versionToCheckStr {
		return true
	}

	return false
}
<commit_msg>Fixing version<commit_after>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"fmt"
	"strconv"
	"strings"
)

// This is a list of all the current viersions including any patches.
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
	"1.4.0",
	"1.3.0",
	"1.2.1",
	"1.2.0",
	"1.1.0",
	"1.0.0",
	"0.7.1",
	"0.7.0",
	"0.6.0",
	"0.5.0",
}

var CurrentVersion string = versions[0]

var BuildNumber = "_BUILD_NUMBER_"
var BuildDate = "_BUILD_DATE_"
var BuildHash = "_BUILD_HASH_"
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_"
var versionsWithoutHotFixes []string

func init() {
	versionsWithoutHotFixes = make([]string, 0, len(versions))
	seen := make(map[string]string)

	for _, version := range versions {
		maj, min, _ := SplitVersion(version)
		verStr := fmt.Sprintf("%v.%v.0", maj, min)

		if seen[verStr] == "" {
			versionsWithoutHotFixes = append(versionsWithoutHotFixes, verStr)
			seen[verStr] = verStr
		}
	}
}

func SplitVersion(version string) (int64, int64, int64) {
	parts := strings.Split(version, ".")

	major := int64(0)
	minor := int64(0)
	patch := int64(0)

	if len(parts) > 0 {
		major, _ = strconv.ParseInt(parts[0], 10, 64)
	}

	if len(parts) > 1 {
		minor, _ = strconv.ParseInt(parts[1], 10, 64)
	}

	if len(parts) > 2 {
		patch, _ = strconv.ParseInt(parts[2], 10, 64)
	}

	return major, minor, patch
}

func GetPreviousVersion(version string) string {
	verMajor, verMinor, _ := SplitVersion(version)
	verStr := fmt.Sprintf("%v.%v.0", verMajor, verMinor)

	for index, v := range versionsWithoutHotFixes {
		if v == verStr && len(versionsWithoutHotFixes) > index+1 {
			return versionsWithoutHotFixes[index+1]
		}
	}

	return ""
}

func IsOfficalBuild() bool {
	return BuildNumber != "_BUILD_NUMBER_"
}

func IsCurrentVersion(versionToCheck string) bool {
	currentMajor, currentMinor, _ := SplitVersion(CurrentVersion)
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)

	if toCheckMajor == currentMajor && toCheckMinor == currentMinor {
		return true
	} else {
		return false
	}
}

func IsPreviousVersionsSupported(versionToCheck string) bool {
	toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
	versionToCheckStr := fmt.Sprintf("%v.%v.0", toCheckMajor, toCheckMinor)

	// Current Supported
	if versionsWithoutHotFixes[0] == versionToCheckStr {
		return true
	}

	// Current - 1 Supported
	if versionsWithoutHotFixes[1] == versionToCheckStr {
		return true
	}

	// Current - 2 Supported
	if versionsWithoutHotFixes[2] == versionToCheckStr {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package moviestore

import (
	"context"

	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/pkg/errors"

	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/gilcrest/go-api-basic/domain/movie"
	"github.com/google/uuid"
)

// Transactor performs DML actions against the DB
type Transactor interface {
	Create(ctx context.Context, m *movie.Movie) error
	Update(ctx context.Context, m *movie.Movie) error
	Delete(ctx context.Context, m *movie.Movie) error
}

// NewDefaultTransactor is an initializer for DefaultMovieStore
func NewDefaultTransactor(ds datastore.Datastorer) DefaultTransactor {
	return DefaultTransactor{ds}
}

// DefaultTransactor is the default database implementation
// for DML operations for a movie
type DefaultTransactor struct {
	datastorer datastore.Datastorer
}

// Create inserts a record in the user table using a stored function
func (dt DefaultTransactor) Create(ctx context.Context, m *movie.Movie) error {
	tx, err := dt.datastorer.BeginTx(ctx)
	if err != nil {
		return err
	}

	// Prepare the sql statement using bind variables
	stmt, err := tx.PrepareContext(ctx, `
	select o_create_timestamp,
		   o_update_timestamp
	  from demo.create_movie (
		p_id => $1,
		p_extl_id => $2,
		p_title => $3,
		p_rated => $4,
		p_released => $5,
		p_run_time => $6,
		p_director => $7,
		p_writer => $8,
		p_create_client_id => $9,
		p_create_username => $10)`)

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer stmt.Close()

	// At some point, I will add a whole client flow, but for now
	// faking a client uuid....
	fakeClientID := uuid.New()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.ID,               //$1
		m.ExternalID,       //$2
		m.Title,            //$3
		m.Rated,            //$4
		m.Released,         //$5
		m.RunTime,          //$6
		m.Director,         //$7
		m.Writer,           //$8
		fakeClientID,       //$9
		m.CreateUser.Email) //$10

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.CreateTime, &m.UpdateTime); err != nil {
			return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	// Commit the Transaction
	if err := dt.datastorer.CommitTx(tx); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	return nil
}

// Update updates a record in the database using the external ID of
// the Movie
func (dt DefaultTransactor) Update(ctx context.Context, m *movie.Movie) error {
	tx, err := dt.datastorer.BeginTx(ctx)
	if err != nil {
		return err
	}

	// Prepare the sql statement using bind variables
	stmt, err := tx.PrepareContext(ctx, `
	update demo.movie
	   set title = $1,
		   rated = $2,
		   released = $3,
		   run_time = $4,
		   director = $5,
		   writer = $6,
		   update_username = $7,
		   update_timestamp = $8
	 where extl_id = $9
returning movie_id, create_username, create_timestamp`)

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer stmt.Close()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.Title,            //$1
		m.Rated,            //$2
		m.Released,         //$3
		m.RunTime,          //$4
		m.Director,         //$5
		m.Writer,           //$6
		m.UpdateUser.Email, //$7
		m.UpdateTime,       //$8
		m.ExternalID)       //$9

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.ID, &m.CreateUser.Email, &m.CreateTime); err != nil {
			return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	// If the table's primary key is not returned as part of the
	// RETURNING clause, this means the row was not actually updated.
	// The update request does not contain this key (I don't believe
	// in exposing primary keys), so this is a way of returning data
	// from an update statement and checking whether or not the
	// update was actually successful. Typically you would use
	// db.Exec and check RowsAffected (like I do in delete below),
	// but I wanted to show an alternative which can be useful here
	if m.ID == uuid.Nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, errors.New("Invalid ID - no records updated")))
	}

	// Commit the Transaction
	if err := dt.datastorer.CommitTx(tx); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	return nil
}

// Delete removes the Movie record from the table
func (dt DefaultTransactor) Delete(ctx context.Context, m *movie.Movie) error {
	tx, err := dt.datastorer.BeginTx(ctx)
	if err != nil {
		return err
	}

	result, execErr := tx.ExecContext(ctx,
		`DELETE from demo.movie
		        WHERE movie_id = $1`, m.ID)

	if execErr != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, execErr))
	}

	// Only 1 row should be deleted, check the result count to
	// ensure this is correct
	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	if rowsAffected == 0 {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, errors.New("No Rows Deleted")))
	} else if rowsAffected > 1 {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, errors.New("Too Many Rows Deleted")))
	}

	// Commit the Transaction
	if err := dt.datastorer.CommitTx(tx); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	return nil
}
<commit_msg>organize imports<commit_after>package moviestore

import (
	"context"

	"github.com/google/uuid"
	"github.com/pkg/errors"

	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/gilcrest/go-api-basic/domain/movie"
)

// Transactor performs DML actions against the DB
type Transactor interface {
	Create(ctx context.Context, m *movie.Movie) error
	Update(ctx context.Context, m *movie.Movie) error
	Delete(ctx context.Context, m *movie.Movie) error
}

// NewDefaultTransactor is an initializer for DefaultMovieStore
func NewDefaultTransactor(ds datastore.Datastorer) DefaultTransactor {
	return DefaultTransactor{ds}
}

// DefaultTransactor is the default database implementation
// for DML operations for a movie
type DefaultTransactor struct {
	datastorer datastore.Datastorer
}

// Create inserts a record in the user table using a stored function
func (dt DefaultTransactor) Create(ctx context.Context, m *movie.Movie) error {
	tx, err := dt.datastorer.BeginTx(ctx)
	if err != nil {
		return err
	}

	// Prepare the sql statement using bind variables
	stmt, err := tx.PrepareContext(ctx, `
	select o_create_timestamp,
		   o_update_timestamp
	  from demo.create_movie (
		p_id => $1,
		p_extl_id => $2,
		p_title => $3,
		p_rated => $4,
		p_released => $5,
		p_run_time => $6,
		p_director => $7,
		p_writer => $8,
		p_create_client_id => $9,
		p_create_username => $10)`)

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer stmt.Close()

	// At some point, I will add a whole client flow, but for now
	// faking a client uuid....
	fakeClientID := uuid.New()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.ID,               //$1
		m.ExternalID,       //$2
		m.Title,            //$3
		m.Rated,            //$4
		m.Released,         //$5
		m.RunTime,          //$6
		m.Director,         //$7
		m.Writer,           //$8
		fakeClientID,       //$9
		m.CreateUser.Email) //$10

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.CreateTime, &m.UpdateTime); err != nil {
			return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	// Commit the Transaction
	if err := dt.datastorer.CommitTx(tx); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	return nil
}

// Update updates a record in the database using the external ID of
// the Movie
func (dt DefaultTransactor) Update(ctx context.Context, m *movie.Movie) error {
	tx, err := dt.datastorer.BeginTx(ctx)
	if err != nil {
		return err
	}

	// Prepare the sql statement using bind variables
	stmt, err := tx.PrepareContext(ctx, `
	update demo.movie
	   set title = $1,
		   rated = $2,
		   released = $3,
		   run_time = $4,
		   director = $5,
		   writer = $6,
		   update_username = $7,
		   update_timestamp = $8
	 where extl_id = $9
returning movie_id, create_username, create_timestamp`)

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer stmt.Close()

	// Execute stored function that returns the create_date timestamp,
	// hence the use of QueryContext instead of Exec
	rows, err := stmt.QueryContext(ctx,
		m.Title,            //$1
		m.Rated,            //$2
		m.Released,         //$3
		m.RunTime,          //$4
		m.Director,         //$5
		m.Writer,           //$6
		m.UpdateUser.Email, //$7
		m.UpdateTime,       //$8
		m.ExternalID)       //$9

	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	defer rows.Close()

	// Iterate through the returned record(s)
	for rows.Next() {
		if err := rows.Scan(&m.ID, &m.CreateUser.Email, &m.CreateTime); err != nil {
			return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
		}
	}

	// If any error was encountered while iterating through rows.Next above
	// it will be returned here
	if err := rows.Err(); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	// If the table's primary key is not returned as part of the
	// RETURNING clause, this means the row was not actually updated.
	// The update request does not contain this key (I don't believe
	// in exposing primary keys), so this is a way of returning data
	// from an update statement and checking whether or not the
	// update was actually successful. Typically you would use
	// db.Exec and check RowsAffected (like I do in delete below),
	// but I wanted to show an alternative which can be useful here
	if m.ID == uuid.Nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, errors.New("Invalid ID - no records updated")))
	}

	// Commit the Transaction
	if err := dt.datastorer.CommitTx(tx); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	return nil
}

// Delete removes the Movie record from the table
func (dt DefaultTransactor) Delete(ctx context.Context, m *movie.Movie) error {
	tx, err := dt.datastorer.BeginTx(ctx)
	if err != nil {
		return err
	}

	result, execErr := tx.ExecContext(ctx,
		`DELETE from demo.movie
		        WHERE movie_id = $1`, m.ID)

	if execErr != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, execErr))
	}

	// Only 1 row should be deleted, check the result count to
	// ensure this is correct
	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}
	if rowsAffected == 0 {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, errors.New("No Rows Deleted")))
	} else if rowsAffected > 1 {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, errors.New("Too Many Rows Deleted")))
	}

	// Commit the Transaction
	if err := dt.datastorer.CommitTx(tx); err != nil {
		return errs.E(errs.Database, dt.datastorer.RollbackTx(tx, err))
	}

	return nil
}
<|endoftext|>


<commit_before>// +build !race

package utils

import (
	"fmt"
	"sync"
	"testing"
)

type safeMap struct {
	mu sync.RWMutex
	m  map[int]bool
}

func (s *safeMap) Add(index int, ok bool) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.m[index] = ok
}

func (s *safeMap) Read() map[int]bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.m
}

func TestInParallel(t *testing.T) {
	size := 5
	booleanMap := safeMap{
		m: make(map[int]bool, size+1),
	}
	tasks := InParallel{}
	for i := 0; i < size; i++ {
		task := func(index int) func() error {
			return func() error {
				booleanMap.Add(index, true)
				return nil
			}
		}(i)
		tasks.Add(task)
	}
	err := tasks.Wait()
	if err != nil {
		t.Fatal(err)
	}
	// Make sure every value is true
	for _, value := range booleanMap.Read() {
		if !value {
			t.Fatalf("booleanMap expected to contain only true values, got at least one false")
		}
	}
}

func TestInParallelError(t *testing.T) {
	size := 5
	booleanMap := safeMap{
		m: make(map[int]bool, size+1),
	}
	tasks := InParallel{}
	for i := 0; i < size; i++ {
		task := func(index int) func() error {
			return func() error {
				booleanMap.Add(index, true)
				t.Log("index", index)
				if index%2 == 0 {
					t.Log("return an error for", index)
					return fmt.Errorf("Error with %v", index)
				}
				return nil
			}
		}(i)
		tasks.Add(task)
	}
	err := tasks.Wait()
	if err == nil {
		t.Fatalf("Expected an error on Wait, got nothing.")
	}
	for key, value := range booleanMap.Read() {
		if key%2 != 0 && !value {
			t.Fatalf("booleanMap expected to contain true values on odd number, got %v", booleanMap)
		}
	}
}
<commit_msg>fix the testcase TestInParallelError<commit_after>// +build !race

package utils

import (
	"fmt"
	"sync"
	"testing"
)

type safeMap struct {
	mu sync.RWMutex
	m  map[int]bool
}

func (s *safeMap) Add(index int, ok bool) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.m[index] = ok
}

func (s *safeMap) Read() map[int]bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.m
}

func TestInParallel(t *testing.T) {
	size := 5
	booleanMap := safeMap{
		m: make(map[int]bool, size+1),
	}
	tasks := InParallel{}
	for i := 0; i < size; i++ {
		task := func(index int) func() error {
			return func() error {
				booleanMap.Add(index, true)
				return nil
			}
		}(i)
		tasks.Add(task)
	}
	err := tasks.Wait()
	if err != nil {
		t.Fatal(err)
	}
	// Make sure every value is true
	for _, value := range booleanMap.Read() {
		if !value {
			t.Fatalf("booleanMap expected to contain only true values, got at least one false")
		}
	}
}

func TestInParallelError(t *testing.T) {
	size := 5
	booleanMap := safeMap{
		m: make(map[int]bool, size+1),
	}
	tasks := InParallel{}
	for i := 0; i < size; i++ {
		task := func(index int) func() error {
			return func() error {
				booleanMap.Add(index, false)
				t.Log("index", index)
				if index%2 == 0 {
					t.Log("return an error for", index)
					return fmt.Errorf("Error with %v", index)
				}
				booleanMap.Add(index, true)
				return nil
			}
		}(i)
		tasks.Add(task)
	}
	err := tasks.Wait()
	if err == nil {
		t.Fatalf("Expected an error on Wait, got nothing.")
	}
	for key, value := range booleanMap.Read() {
		if key%2 != 0 && !value {
			t.Fatalf("booleanMap expected to contain true values on odd number, got %v", booleanMap)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.

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

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

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

package finder

import (
	"context"
	"fmt"
	"path"
	"strings"

	"github.com/vmware/govmomi/vapi/library"
)

// Finder is a helper object for finding content library objects by their
// inventory paths: /LIBRARY/ITEM/FILE.
//
// Wildcard characters `*` and `?` are both supported. However, the use
// of a wildcard character in the search string results in a full listing of
// that part of the path's server-side items.
//
// Path parts that do not use wildcard characters rely on server-side Find
// functions to find the path token by its name. Ironically finding one
// item with a direct path takes longer than if a wildcard is used because
// of the multiple round-trips. Direct paths will be more performant on
// systems that have numerous items.
type Finder struct {
	M *library.Manager
}

// NewFinder returns a new Finder.
func NewFinder(m *library.Manager) *Finder {
	return &Finder{m}
}

// Find finds one or more items that match the provided inventory path(s).
func (f *Finder) Find(
	ctx context.Context, ipath ...string) ([]FindResult, error) {

	if len(ipath) == 0 {
		ipath = []string{""}
	}
	var result []FindResult
	for _, p := range ipath {
		results, err := f.find(ctx, p)
		if err != nil {
			return nil, err
		}
		result = append(result, results...)
	}
	return result, nil
}

func (f *Finder) find(ctx context.Context, ipath string) ([]FindResult, error) {

	if ipath == "" {
		ipath = "*"
	}

	// Get the argument and remove any leading separator characters.
	if strings.HasPrefix(ipath, "/") {
		ipath = ipath[1:]
	}

	// Tokenize the path into its distinct parts.
	parts := strings.Split(ipath, "/")

	libs, err := f.findLibraries(ctx, parts[0])
	if err != nil {
		return nil, err
	}

	// If the path is a single token then the libraries are requested.
	if len(parts) < 2 {
		return libs, nil
	}

	items, err := f.findLibraryItems(ctx, libs, parts[1])
	if err != nil {
		return nil, err
	}

	// If the path is two tokens then the library items are requested.
	if len(parts) < 3 {
		return items, nil
	}

	// Get the library item files.
	return f.findLibraryItemFiles(ctx, items, parts[2])
}

// FindResult is the type of object returned from a Find operation.
type FindResult interface {

	// GetParent returns the parent of the find result. If the find result
	// is a Library then this function will return nil.
	GetParent() FindResult

	// GetPath returns the inventory path of the find result.
	GetPath() string

	// GetID returns the ID of the find result.
	GetID() string

	// GetName returns the name of the find result.
	GetName() string

	// GetResult gets the underlying library object.
	GetResult() interface{}
}

type findResult struct {
	result interface{}
	parent FindResult
}

func (f findResult) GetResult() interface{} {
	return f.result
}
func (f findResult) GetParent() FindResult {
	return f.parent
}
func (f findResult) GetPath() string {
	switch f.result.(type) {
	case library.Library:
		return fmt.Sprintf("/%s", f.GetName())
	case library.Item, library.File:
		return fmt.Sprintf("%s/%s", f.parent.GetPath(), f.GetName())
	default:
		return ""
	}
}

func (f findResult) GetID() string {
	switch t := f.result.(type) {
	case library.Library:
		return t.ID
	case library.Item:
		return t.ID
	default:
		return ""
	}
}

func (f findResult) GetName() string {
	switch t := f.result.(type) {
	case library.Library:
		return t.Name
	case library.Item:
		return t.Name
	case library.File:
		return t.Name
	default:
		return ""
	}
}

func (f *Finder) findLibraries(
	ctx context.Context,
	token string) ([]FindResult, error) {

	if token == "" {
		token = "*"
	}

	var result []FindResult

	// If the token does not contain any wildcard characters then perform
	// a lookup by name using a server side call.
	if !strings.ContainsAny(token, "*?") {
		libIDs, err := f.M.FindLibrary(
			ctx, library.FindLibraryRequest{Name: token, Type: "LOCAL"})
		if err != nil {
			return nil, err
		}
		for _, id := range libIDs {
			lib, err := f.M.GetLibraryByID(ctx, id)
			if err != nil {
				return nil, err
			}
			result = append(result, findResult{result: *lib})
		}
		return result, nil
	}

	libs, err := f.M.GetLibraries(ctx)
	if err != nil {
		return nil, err
	}
	for _, lib := range libs {
		match, err := path.Match(token, lib.Name)
		if err != nil {
			return nil, err
		}
		if match {
			result = append(result, findResult{result: lib})
		}
	}
	return result, nil
}

func (f *Finder) findLibraryItems(
	ctx context.Context,
	parents []FindResult, token string) ([]FindResult, error) {

	if token == "" {
		token = "*"
	}

	var result []FindResult

	for _, parent := range parents {
		// If the token does not contain any wildcard characters then perform
		// a lookup by name using a server side call.
		if !strings.ContainsAny(token, "*?") {
			childIDs, err := f.M.FindLibraryItems(
				ctx, library.FindLibraryItemsRequest{
					Name:      token,
					LibraryID: parent.GetID(),
				})
			if err != nil {
				return nil, err
			}
			for _, id := range childIDs {
				child, err := f.M.GetLibraryItem(ctx, id)
				if err != nil {
					return nil, err
				}
				result = append(result, findResult{
					result: *child,
					parent: parent,
				})
			}
			continue
		}

		children, err := f.M.GetLibraryItems(ctx, parent.GetID())
		if err != nil {
			return nil, err
		}
		for _, child := range children {
			match, err := path.Match(token, child.Name)
			if err != nil {
				return nil, err
			}
			if match {
				result = append(
					result, findResult{parent: parent, result: child})
			}
		}
	}
	return result, nil
}

func (f *Finder) findLibraryItemFiles(
	ctx context.Context,
	parents []FindResult, token string) ([]FindResult, error) {

	if token == "" {
		token = "*"
	}

	var result []FindResult

	for _, parent := range parents {
		// If the token does not contain any wildcard characters then perform
		// a lookup by name using a server side call.
		if !strings.ContainsAny(token, "*?") {
			child, err := f.M.GetLibraryItemFile(ctx, parent.GetID(), token)
			if err != nil {
				return nil, err
			}
			result = append(result, findResult{
				result: *child,
				parent: parent,
			})
			continue
		}

		children, err := f.M.ListLibraryItemFiles(ctx, parent.GetID())
		if err != nil {
			return nil, err
		}
		for _, child := range children {
			match, err := path.Match(token, child.Name)
			if err != nil {
				return nil, err
			}
			if match {
				result = append(
					result, findResult{parent: parent, result: child})
			}
		}
	}
	return result, nil
}
<commit_msg>lib/finder: Support filenames with "/"<commit_after>/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.

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

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

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

package finder

import (
	"context"
	"fmt"
	"path"
	"strings"

	"github.com/vmware/govmomi/vapi/library"
)

// Finder is a helper object for finding content library objects by their
// inventory paths: /LIBRARY/ITEM/FILE.
//
// Wildcard characters `*` and `?` are both supported. However, the use
// of a wildcard character in the search string results in a full listing of
// that part of the path's server-side items.
//
// Path parts that do not use wildcard characters rely on server-side Find
// functions to find the path token by its name. Ironically finding one
// item with a direct path takes longer than if a wildcard is used because
// of the multiple round-trips. Direct paths will be more performant on
// systems that have numerous items.
type Finder struct {
	M *library.Manager
}

// NewFinder returns a new Finder.
func NewFinder(m *library.Manager) *Finder {
	return &Finder{m}
}

// Find finds one or more items that match the provided inventory path(s).
func (f *Finder) Find(
	ctx context.Context, ipath ...string) ([]FindResult, error) {

	if len(ipath) == 0 {
		ipath = []string{""}
	}
	var result []FindResult
	for _, p := range ipath {
		results, err := f.find(ctx, p)
		if err != nil {
			return nil, err
		}
		result = append(result, results...)
	}
	return result, nil
}

func (f *Finder) find(ctx context.Context, ipath string) ([]FindResult, error) {

	if ipath == "" {
		ipath = "*"
	}

	// Get the argument and remove any leading separator characters.
	if strings.HasPrefix(ipath, "/") {
		ipath = ipath[1:]
	}

	// Tokenize the path into its distinct parts.
	parts := strings.Split(ipath, "/")

	// If there are more than three parts then the file name contains
	// the "/" character. In that case collapse any additional parts
	// back into the filename.
	if len(parts) > 3 {
		parts = []string{
			parts[0],
			parts[1],
			strings.Join(parts[2:], "/"),
		}
	}

	libs, err := f.findLibraries(ctx, parts[0])
	if err != nil {
		return nil, err
	}

	// If the path is a single token then the libraries are requested.
	if len(parts) < 2 {
		return libs, nil
	}

	items, err := f.findLibraryItems(ctx, libs, parts[1])
	if err != nil {
		return nil, err
	}

	// If the path is two tokens then the library items are requested.
	if len(parts) < 3 {
		return items, nil
	}

	// Get the library item files.
	return f.findLibraryItemFiles(ctx, items, parts[2])
}

// FindResult is the type of object returned from a Find operation.
type FindResult interface {

	// GetParent returns the parent of the find result. If the find result
	// is a Library then this function will return nil.
	GetParent() FindResult

	// GetPath returns the inventory path of the find result.
	GetPath() string

	// GetID returns the ID of the find result.
	GetID() string

	// GetName returns the name of the find result.
	GetName() string

	// GetResult gets the underlying library object.
	GetResult() interface{}
}

type findResult struct {
	result interface{}
	parent FindResult
}

func (f findResult) GetResult() interface{} {
	return f.result
}
func (f findResult) GetParent() FindResult {
	return f.parent
}
func (f findResult) GetPath() string {
	switch f.result.(type) {
	case library.Library:
		return fmt.Sprintf("/%s", f.GetName())
	case library.Item, library.File:
		return fmt.Sprintf("%s/%s", f.parent.GetPath(), f.GetName())
	default:
		return ""
	}
}

func (f findResult) GetID() string {
	switch t := f.result.(type) {
	case library.Library:
		return t.ID
	case library.Item:
		return t.ID
	default:
		return ""
	}
}

func (f findResult) GetName() string {
	switch t := f.result.(type) {
	case library.Library:
		return t.Name
	case library.Item:
		return t.Name
	case library.File:
		return t.Name
	default:
		return ""
	}
}

func (f *Finder) findLibraries(
	ctx context.Context,
	token string) ([]FindResult, error) {

	if token == "" {
		token = "*"
	}

	var result []FindResult

	// If the token does not contain any wildcard characters then perform
	// a lookup by name using a server side call.
	if !strings.ContainsAny(token, "*?") {
		libIDs, err := f.M.FindLibrary(
			ctx, library.FindLibraryRequest{Name: token, Type: "LOCAL"})
		if err != nil {
			return nil, err
		}
		for _, id := range libIDs {
			lib, err := f.M.GetLibraryByID(ctx, id)
			if err != nil {
				return nil, err
			}
			result = append(result, findResult{result: *lib})
		}
		return result, nil
	}

	libs, err := f.M.GetLibraries(ctx)
	if err != nil {
		return nil, err
	}
	for _, lib := range libs {
		match, err := path.Match(token, lib.Name)
		if err != nil {
			return nil, err
		}
		if match {
			result = append(result, findResult{result: lib})
		}
	}
	return result, nil
}

func (f *Finder) findLibraryItems(
	ctx context.Context,
	parents []FindResult, token string) ([]FindResult, error) {

	if token == "" {
		token = "*"
	}

	var result []FindResult

	for _, parent := range parents {
		// If the token does not contain any wildcard characters then perform
		// a lookup by name using a server side call.
		if !strings.ContainsAny(token, "*?") {
			childIDs, err := f.M.FindLibraryItems(
				ctx, library.FindLibraryItemsRequest{
					Name:      token,
					LibraryID: parent.GetID(),
				})
			if err != nil {
				return nil, err
			}
			for _, id := range childIDs {
				child, err := f.M.GetLibraryItem(ctx, id)
				if err != nil {
					return nil, err
				}
				result = append(result, findResult{
					result: *child,
					parent: parent,
				})
			}
			continue
		}

		children, err := f.M.GetLibraryItems(ctx, parent.GetID())
		if err != nil {
			return nil, err
		}
		for _, child := range children {
			match, err := path.Match(token, child.Name)
			if err != nil {
				return nil, err
			}
			if match {
				result = append(
					result, findResult{parent: parent, result: child})
			}
		}
	}
	return result, nil
}

func (f *Finder) findLibraryItemFiles(
	ctx context.Context,
	parents []FindResult, token string) ([]FindResult, error) {

	if token == "" {
		token = "*"
	}

	var result []FindResult

	for _, parent := range parents {
		// If the token does not contain any wildcard characters then perform
		// a lookup by name using a server side call.
		if !strings.ContainsAny(token, "*?") {
			child, err := f.M.GetLibraryItemFile(ctx, parent.GetID(), token)
			if err != nil {
				return nil, err
			}
			result = append(result, findResult{
				result: *child,
				parent: parent,
			})
			continue
		}

		children, err := f.M.ListLibraryItemFiles(ctx, parent.GetID())
		if err != nil {
			return nil, err
		}
		for _, child := range children {
			match, err := path.Match(token, child.Name)
			if err != nil {
				return nil, err
			}
			if match {
				result = append(
					result, findResult{parent: parent, result: child})
			}
		}
	}
	return result, nil
}
<|endoftext|>


<commit_before>package gang

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/ysugimoto/go-cliargs"
	"github.com/ysugimoto/pecolify"
	"io/ioutil"
	"os"
	"sort"
	"strings"
)

var conf *Config = &Config{}

func init() {
	var buffer []byte

	// check configuration file
	confFile := os.Getenv("HOME") + "/.gang"
	if _, err := os.Stat(confFile); err != nil {
		// create file
		buffer = []byte("{\"commands\":[]}")
		ioutil.WriteFile(confFile, buffer, 0644)
	} else {
		buffer, _ = ioutil.ReadFile(confFile)
	}
	json.Unmarshal(buffer, conf)
}

type Runner struct {
	args *cliarg.Arguments
}

func NewRunner(args *cliarg.Arguments) *Runner {
	return &Runner{
		args: args,
	}
}

func (r *Runner) Run() {

	ret := r._run()
	if ret == 0 {
		conf.Save()
	}
}

func (r *Runner) _run() int {
	if r.args.GetCommandSize() == 0 {
		list := r.getCommandList(false)

		if len(list) == 0 {
			fmt.Println("No Commands Available")
			return 0
		}

		p := pecolify.New()
		selected, _ := p.Transform(list)
		if selected != "" {
			r.runCommand(selected)
		}
		return 0
	}

	switch cmd, _ := r.args.GetCommandAt(1); cmd {
	case "reload":
		command := r.getLatestCommand()
		name := strings.Split(command, " ")
		conf.AddCommand(name[0], command)
		return 0

	case "ammo":
		list := r.getCommandList(false)

		if len(list) == 0 {
			fmt.Println("No Commands Available")
			return 0
		}

		p := pecolify.New()
		selected, _ := p.Transform(list)
		if selected != "" {
			r.runCommand(selected)
		}
		return 0

	case "kill":
		name, ok := r.args.GetCommandAt(2)
		if !ok {
			fmt.Println("[Error] \"kill\" must be supplied command name.")
			return 1
		}
		commands := []Command{}

		for _, cmd := range conf.Commands {
			if cmd.Name != name {
				commands = append(commands, cmd)
			}
		}

		if len(commands) == len(conf.Commands) {
			fmt.Printf("[Error] \"%s\" command is not exists. Nothig to do.\n", name)
			return 1
		}

		conf.Commands = commands
		fmt.Printf("Command %s killed.\n", name)
		return 0

	case "bullet":
		var (
			name, cmd string
			ok        bool
		)

		if name, ok = r.args.GetCommandAt(2); !ok {
			fmt.Println("[Error] \"bullet\" command needs 2 parametes: [name/command].")
			return 1
		}
		if cmd, ok = r.args.GetCommandAt(3); !ok {
			fmt.Println("[Error] \"bullet\" command needs 2 parametes: [name/command].")
			return 1
		}

		for _, cmd := range conf.Commands {
			if cmd.Name == name {
				fmt.Printf("[Error] command \"%s\" already exists.\n", name)
			}
		}

		conf.Commands = append(conf.Commands, Command{
			Name:  name,
			Cmd:   cmd,
			Times: 0,
		})

		fmt.Printf("Command \"%s\" Bulleted.\n", name)
		return 0

	default:

	}

	return 0
}

func (r *Runner) getCommandList(sorted bool) (list []string) {
	if sorted {
		sort.Sort(conf.Commands)
	}

	for _, cmd := range conf.Commands {
		list = append(list, cmd.String())
	}

	return
}

func (r *Runner) runCommand(cmd string) {
	name, command := r.ParseCommand(cmd)

	conf.IncrementCount(name)
	fmt.Printf("Execute Command: %s\n", command)

	shell := NewShell(command)
	out, _ := shell.Run()
	fmt.Println(string(bytes.Trim(out, "\r\n\"")))
}

func (r *Runner) ParseCommand(cmd string) (name, command string) {
	spl := strings.Split(cmd, ":")
	name = spl[0]
	command = strings.Join(spl[1:], ":")

	return name, strings.TrimSpace(command)
}

func (r *Runner) getLatestCommand() string {
	return ""
}
<commit_msg>Formatted output linefeed<commit_after>package gang

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/ysugimoto/go-cliargs"
	"github.com/ysugimoto/pecolify"
	"io/ioutil"
	"os"
	"sort"
	"strings"
)

var conf *Config = &Config{}

func init() {
	var buffer []byte

	// check configuration file
	confFile := os.Getenv("HOME") + "/.gang"
	if _, err := os.Stat(confFile); err != nil {
		// create file
		buffer = []byte("{\"commands\":[]}")
		ioutil.WriteFile(confFile, buffer, 0644)
	} else {
		buffer, _ = ioutil.ReadFile(confFile)
	}
	json.Unmarshal(buffer, conf)
}

type Runner struct {
	args *cliarg.Arguments
}

func NewRunner(args *cliarg.Arguments) *Runner {
	return &Runner{
		args: args,
	}
}

func (r *Runner) Run() {

	ret := r._run()
	if ret == 0 {
		conf.Save()
	}
}

func (r *Runner) _run() int {
	if r.args.GetCommandSize() == 0 {
		list := r.getCommandList(false)

		if len(list) == 0 {
			fmt.Println("No Commands Available")
			return 0
		}

		p := pecolify.New()
		selected, _ := p.Transform(list)
		if selected != "" {
			r.runCommand(selected)
		}
		return 0
	}

	switch cmd, _ := r.args.GetCommandAt(1); cmd {
	case "reload":
		command := r.getLatestCommand()
		name := strings.Split(command, " ")
		conf.AddCommand(name[0], command)
		return 0

	case "ammo":
		list := r.getCommandList(false)

		if len(list) == 0 {
			fmt.Println("No Commands Available")
			return 0
		}

		p := pecolify.New()
		selected, _ := p.Transform(list)
		if selected != "" {
			r.runCommand(selected)
		}
		return 0

	case "kill":
		name, ok := r.args.GetCommandAt(2)
		if !ok {
			fmt.Println("[Error] \"kill\" must be supplied command name.")
			return 1
		}
		commands := []Command{}

		for _, cmd := range conf.Commands {
			if cmd.Name != name {
				commands = append(commands, cmd)
			}
		}

		if len(commands) == len(conf.Commands) {
			fmt.Printf("[Error] \"%s\" command is not exists. Nothig to do.\n", name)
			return 1
		}

		conf.Commands = commands
		fmt.Printf("Command %s killed.\n", name)
		return 0

	case "bullet":
		var (
			name, cmd string
			ok        bool
		)

		if name, ok = r.args.GetCommandAt(2); !ok {
			fmt.Println("[Error] \"bullet\" command needs 2 parametes: [name/command].")
			return 1
		}
		if cmd, ok = r.args.GetCommandAt(3); !ok {
			fmt.Println("[Error] \"bullet\" command needs 2 parametes: [name/command].")
			return 1
		}

		for _, cmd := range conf.Commands {
			if cmd.Name == name {
				fmt.Printf("[Error] command \"%s\" already exists.\n", name)
			}
		}

		conf.Commands = append(conf.Commands, Command{
			Name:  name,
			Cmd:   cmd,
			Times: 0,
		})

		fmt.Printf("Command \"%s\" Bulleted.\n", name)
		return 0

	default:

	}

	return 0
}

func (r *Runner) getCommandList(sorted bool) (list []string) {
	if sorted {
		sort.Sort(conf.Commands)
	}

	for _, cmd := range conf.Commands {
		list = append(list, cmd.String())
	}

	return
}

func (r *Runner) runCommand(cmd string) {
	name, command := r.ParseCommand(cmd)

	conf.IncrementCount(name)
	fmt.Printf("Execute Command: %s\n", command)

	shell := NewShell(command)
	out, _ := shell.Run()

	output := bytes.Trim(out, "\r\n\"")
	if len(output) > 0 {
		fmt.Println(string(bytes.Trim(out, "\r\n\"")))
	}
}

func (r *Runner) ParseCommand(cmd string) (name, command string) {
	spl := strings.Split(cmd, ":")
	name = spl[0]
	command = strings.Join(spl[1:], ":")

	return name, strings.TrimSpace(command)
}

func (r *Runner) getLatestCommand() string {
	return ""
}
<|endoftext|>


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

// A tool to add missing fields to an existing GCS bucket, for #18.
//
// Input is on stdin, and is of the form "<SHA-1> <CRC32C> <MD5>", e.g.:
//
//     e04b25d650dee1dff6ab1743724fa7c184282e94 0x12e9bf88 2bad5bb78f17232ef8c727f59eb82325
//
package main

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/oauthutil"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

var fKeyFile = flag.String("key_file", "", "")
var fBucket = flag.String("bucket", "", "")
var fToken = flag.String("token", "", "Initial continuation token. Be careful.")
var fUpdateParallelism = flag.Int("parallelism", 128, "")

type crc32cChecksum uint32
type md5Hash [md5.Size]byte
type sha1Hash [sha1.Size]byte

type checksums struct {
	crc32c crc32cChecksum
	md5    md5Hash
}

// A mapping from SHA-1 to CRC32C and MD5.
type checksumMap map[sha1Hash]checksums

const (
	// Cf. blob_store.go
	blobObjectNamePrefix = "blobs/"

	// Cf. gcs_store.go
	metadataKey_SHA1   = "comeback_sha1"
	metadataKey_CRC32C = "comeback_crc32c"
	metadataKey_MD5    = "comeback_md5"
)

var gInputLineRe = regexp.MustCompile(
	"^([0-9a-f]{40}) (0x[0-9a-f]{8}) ([0-9a-f]{32})$")

func parseInputLine(line []byte) (sha1 sha1Hash, c checksums, err error) {
	// Match against the regexp.
	matches := gInputLineRe.FindSubmatch(line)
	if matches == nil {
		err = errors.New("No match.")
		return
	}

	// Parse each component.
	_, err = hex.Decode(sha1[:], matches[1])
	if err != nil {
		panic(fmt.Sprintf("Unexpected decode error for %q: %v", matches[1], err))
	}

	crc32c64, err := strconv.ParseUint(string(matches[2]), 0, 32)
	if err != nil {
		panic(fmt.Sprintf("Unexpected decode error for %q: %v", matches[2], err))
	}

	c.crc32c = crc32cChecksum(crc32c64)

	_, err = hex.Decode(c.md5[:], matches[3])
	if err != nil {
		panic(fmt.Sprintf("Unexpected decode error for %q: %v", matches[3], err))
	}

	return
}

// Read the supplied input file, producing a checksum map.
func parseInput(in io.Reader) (m checksumMap, err error) {
	m = make(checksumMap)

	// Scan each line.
	scanner := bufio.NewScanner(in)
	for scanner.Scan() {
		var sha1 sha1Hash
		var c checksums
		sha1, c, err = parseInputLine(scanner.Bytes())
		if err != nil {
			err = fmt.Errorf("Parsing input line %q: %v", scanner.Text(), err)
			return
		}

		m[sha1] = c
	}

	// Was there an error scanning?
	if scanner.Err() != nil {
		err = fmt.Errorf("Scanning: %v", scanner.Err())
		return
	}

	return
}

// Filter to names of objects that lack the appropriate metadata keys.
func filterToProblematicNames(
	ctx context.Context,
	objects <-chan *gcs.Object,
	names chan<- string) (err error) {
	for o := range objects {
		// Skip objects that already have all of the keys.
		_, ok0 := o.Metadata[metadataKey_SHA1]
		_, ok1 := o.Metadata[metadataKey_CRC32C]
		_, ok2 := o.Metadata[metadataKey_MD5]

		if ok0 && ok1 && ok2 {
			continue
		}

		// Pass on the names of others.
		select {
		case names <- o.Name:

			// Cancelled?
		case <-ctx.Done():
			err = ctx.Err()
			return
		}
	}

	return
}

// Parse the object name into its expected SHA-1 hash.
func parseObjectName(name string) (sha1 sha1Hash, err error) {
	if !strings.HasPrefix(name, blobObjectNamePrefix) {
		err = fmt.Errorf("Expected prefix")
		return
	}

	hexSha1 := strings.TrimPrefix(name, blobObjectNamePrefix)
	score, err := blob.ParseHexScore(hexSha1)
	if err != nil {
		err = fmt.Errorf("ParseHexScore: %v", err)
		return
	}

	sha1 = sha1Hash(score)
	return
}

// For each object name, issue a request to set the appropriate metadata keys
// based on the contents of the supplied map. Write out the names of the
// objects processed, and those for whom info wasn't available.
func fixProblematicObjects(
	ctx context.Context,
	bucket gcs.Bucket,
	info checksumMap,
	names <-chan string,
	processed chan<- string,
	unknown chan<- string) (err error) {
	for name := range names {
		// Parse the name.
		var sha1 sha1Hash
		sha1, err = parseObjectName(name)
		if err != nil {
			err = fmt.Errorf("Parsing object name %q: %v", name, err)
			return
		}

		// Do we have info for this object?
		c, ok := info[sha1]
		if !ok {
			select {
			case unknown <- name:

				// Cancelled?
			case <-ctx.Done():
				err = ctx.Err()
				return
			}

			continue
		}

		// Fix it up.
		//
		// Formats cf. gcs_store.go.
		sha1Str := hex.EncodeToString(sha1[:])
		crc32cStr := fmt.Sprintf("%#08x", c.crc32c)
		md5Str := hex.EncodeToString(c.md5[:])

		req := &gcs.UpdateObjectRequest{
			Name: name,
			Metadata: map[string]*string{
				metadataKey_SHA1:   &sha1Str,
				metadataKey_CRC32C: &crc32cStr,
				metadataKey_MD5:    &md5Str,
			},
		}

		_, err = bucket.UpdateObject(ctx, req)
		if err != nil {
			err = fmt.Errorf("UpdateObject: %v", err)
			return
		}

		// Pass on the name as processed.
		select {
		case processed <- name:

			// Cancelled?
		case <-ctx.Done():
			err = ctx.Err()
			return
		}
	}

	return
}

// Log status updates, and at the end log the objects that were not
// processed, returning an error if non-zero.
func monitorProgress(
	ctx context.Context,
	processedChan <-chan string,
	unknownChan <-chan string) (err error) {
	var processed int
	var unknown int

	// Set up a ticker for logging status updates.
	const period = time.Second
	ticker := time.NewTicker(period)
	defer ticker.Stop()

	// Keep going until both channels are closed.
	for processedChan != nil || unknownChan != nil {
		select {
		case <-ticker.C:
			log.Printf("%v processed successfully, %v unknown", processed, unknown)

		case _, ok := <-processedChan:
			if ok {
				processed++
			} else {
				processedChan = nil
			}

		case name, ok := <-unknownChan:
			if ok {
				log.Printf("Unknown object: %q", name)
				unknown++
			} else {
				unknownChan = nil
			}
		}
	}

	// Return an error if any object was unknown.
	if unknown != 0 {
		err = fmt.Errorf("%v unknown objects", unknown)
		return
	}

	return
}

func run(
	bucket gcs.Bucket,
	info checksumMap) (err error) {
	b := syncutil.NewBundle(context.Background())
	defer func() { err = b.Join() }()

	// List all of the blob objects.
	objectRecords := make(chan *gcs.Object, 10000)
	b.Add(func(ctx context.Context) (err error) {
		defer close(objectRecords)
		err = blob.ListBlobObjects(ctx, bucket, blobObjectNamePrefix, objectRecords)
		if err != nil {
			err = fmt.Errorf("ListBlobObjects: %v", err)
			return
		}

		return
	})

	// Filter to the ones we need to fix up.
	problematicNames := make(chan string, 100)
	b.Add(func(ctx context.Context) (err error) {
		defer close(problematicNames)
		err = filterToProblematicNames(ctx, objectRecords, problematicNames)
		if err != nil {
			err = fmt.Errorf("filterToProblematicNames: %v", err)
			return
		}

		return
	})

	// Fix those objects with some parallelism.
	const parallelism = 128
	var wg sync.WaitGroup

	processed := make(chan string, 100)
	unknown := make(chan string, 100)

	for i := 0; i < *fUpdateParallelism; i++ {
		wg.Add(1)
		b.Add(func(ctx context.Context) (err error) {
			defer wg.Done()
			err = fixProblematicObjects(
				ctx,
				bucket,
				info,
				problematicNames,
				processed,
				unknown)

			if err != nil {
				err = fmt.Errorf("fixProblematicObjects: %v", err)
				return
			}

			return
		})
	}

	go func() {
		wg.Wait()
		close(processed)
		close(unknown)
	}()

	// Log status updates, and at the end log the objects that were not
	// processed, returning an error if non-zero.
	b.Add(func(ctx context.Context) (err error) {
		err = monitorProgress(ctx, processed, unknown)
		if err != nil {
			err = fmt.Errorf("monitorProgress: %v", err)
			return
		}

		return
	})

	return
}

func panicIf(err *error) {
	if *err != nil {
		panic(*err)
	}
}

func getHTTPClient() (client *http.Client, err error) {
	if *fKeyFile == "" {
		err = errors.New("You must set --key_file.")
		return
	}

	const scope = gcs.Scope_FullControl
	client, err = oauthutil.NewJWTHttpClient(*fKeyFile, []string{scope})
	if err != nil {
		err = fmt.Errorf("oauthutil.NewJWTHttpClient: %v", err)
		return
	}

	return
}

func bucketName() (name string, err error) {
	name = *fBucket
	if name == "" {
		err = errors.New("You must set --bucket.")
		return
	}

	return
}

func getBucket() (b gcs.Bucket) {
	var err error
	defer panicIf(&err)

	// Get the HTTP client,
	client, err := getHTTPClient()
	if err != nil {
		err = fmt.Errorf("IntegrationTestHTTPClient: %v", err)
		return
	}

	// Find the bucket name.
	name, err := bucketName()
	if err != nil {
		err = fmt.Errorf("bucketName: %v", err)
		return
	}

	// Create a connection.
	cfg := &gcs.ConnConfig{
		HTTPClient:      client,
		MaxBackoffSleep: 30 * time.Second,
	}

	conn, err := gcs.NewConn(cfg)
	if err != nil {
		err = fmt.Errorf("gcs.NewConn: %v", err)
		return
	}

	// Extract the bucket.
	b = conn.GetBucket(name)

	return
}

func main() {
	flag.Parse()
	bucket := getBucket()
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	// Panic if anything below fails.
	var err error
	defer func() {
		if err != nil {
			log.Fatal(err)
		}
	}()

	// Parse the input.
	log.Println("Parsing input...")
	info, err := parseInput(os.Stdin)
	if err != nil {
		err = fmt.Errorf("parseInput: %v", err)
		return
	}

	log.Println("Done parsing input.")

	// Run.
	err = run(bucket, info)
	if err != nil {
		err = fmt.Errorf("run: %v", err)
		return
	}
}
<commit_msg>Deleted fix_metadata, which was broken anyway.<commit_after><|endoftext|>