<commit_before>package main

import (
	"errors"
	"fmt"
	"go/parser"
	"go/types"
	"os"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/loader"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "%s ./pkg/foo > tests/clone/generated/foo_test.go\n", os.Args[0])
		os.Exit(1)
	}
	infos := extractInfos(os.Args[1:])
	generateTests(infos)
}

func extractInfos(pkgs []string) []info {
	infos := make([]info, 0)
	docIface := getDocIface()

	for _, pkgPath := range pkgs {
		pkg, err := pkgInfoFromPath(pkgPath)
		if err != nil {
			panic(err)
		}

		in := info{
			PkgName: pkg.Name(),
			PkgPath: pkg.Path(),
			Structs: make(map[string][]mutableField),
		}
		scope := pkg.Scope()
		for _, name := range scope.Names() {
			obj := scope.Lookup(name)
			s, ok := obj.Type().Underlying().(*types.Struct)
			if !ok {
				continue
			}
			ptr := types.NewPointer(obj.Type())
			// FIXME implements returns false for intents.Intent but it should
			// return true, find why!
			// implements := types.Implements(ptr.Underlying(), docIface)
			f, g := types.MissingMethod(ptr.Underlying(), docIface, true)
			if f != nil && !g {
				continue
			}
			fields := make([]mutableField, 0)
			for i := 0; i < s.NumFields(); i++ {
				field := s.Field(i)
				// fmt.Printf(" - %d. %s - %s\n", i, field.Name(), field.Type())
				switch t := field.Type().(type) {
				case (*types.Slice):
					fields = append(fields, &sliceField{
						Name:  field.Name(),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Map):
					fields = append(fields, &mapField{
						Name:  field.Name(),
						Key:   generatorForType(t.Key()),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Named):
					named := fmt.Sprintf("%s.%s", t.Obj().Pkg().Name(), t.Obj().Name())
					switch named {
					case "time.Time", "time.Duration":
						// These structs are known to be safe
					default:
						panic(fmt.Errorf("Unknown named type: %s", named))
					}
				case (*types.Interface):
					fmt.Fprintf(os.Stderr, "Warning: cannot check interfaces: %s.%s -> %s\n",
						pkg.Name(), name, field)
				case (*types.Pointer):
					fields = append(fields, &ptrField{
						Name:  field.Name(),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Basic):
					// Basic types are immutables
				default:
					panic(fmt.Errorf("Unknown type: %#v", field.Type()))
				}
			}
			if len(fields) > 0 {
				in.Structs[name] = fields
			}
		}
		if len(in.Structs) > 0 {
			infos = append(infos, in)
		}
	}
	return infos
}

func generateTests(infos []info) {
	fmt.Printf(`// Generated tests for Clone(). Do not manually edit!
package clone

import (
	"testing"
`)
	for _, info := range infos {
		fmt.Printf("\t\"%s\"\n", info.PkgPath)
	}
	fmt.Printf(")\n\n")

	for _, info := range infos {
		fmt.Printf("func Test%s(t *testing.T) {\n", strings.Title(info.PkgName))
		for name, fields := range info.Structs {
			v := strings.ToLower(name)
			fmt.Printf("\t%sA := &%s.%s{}\n", v, info.PkgName, name)
			for _, field := range fields {
				field.Initialize(v)
			}
			ptr := "*"
			if name == "JSONDoc" {
				ptr = ""
			}
			fmt.Printf("\t%sB := %sA.Clone().(%s%s.%s)\n", v, v, ptr, info.PkgName, name)
			for _, field := range fields {
				field.Reassign(v)
				field.Compare(v)
				fmt.Printf("\t\tt.Fatalf(\"Error for clone %s.%s -> %s\")\n\t}\n", info.PkgName, name, field)
			}
		}
		fmt.Printf("}\n\n")
	}
}

type info struct {
	PkgName string
	PkgPath string
	Structs map[string][]mutableField
}

type mutableField interface {
	String() string
	Initialize(v string)
	Reassign(v string)
	Compare(v string)
}

type sliceField struct {
	Name  string
	Value generator
}

func (f *sliceField) String() string { return f.Name }

func (f *sliceField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = []%s{%s}\n", v, f.Name, f.Value.Type, f.Value.Initial)
}
func (f *sliceField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[0]%s = %s\n", v, f.Name, f.Value.SubKey, f.Value.Altered)
}
func (f *sliceField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[0]%s != %s {\n", v, f.Name, f.Value.SubKey, f.Value.SubValue)
}

type mapField struct {
	Name  string
	Key   generator
	Value generator
}

func (f *mapField) String() string { return f.Name }

func (f *mapField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s\n", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = map[%s]%s{%s: %s}\n", v, f.Name, f.Key.Type, f.Value.Type, f.Key.Key, f.Value.Initial)
}
func (f *mapField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[%s]%s = %s\n", v, f.Name, f.Key.Key, f.Value.SubKey, f.Value.Altered)
}
func (f *mapField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[%s]%s != %s {\n", v, f.Name, f.Key.Key, f.Value.SubKey, f.Value.SubValue)
}

type ptrField struct {
	Name  string
	Value generator
}

func (f *ptrField) String() string { return f.Name }

func (f *ptrField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = &%s\n", v, f.Name, f.Value.Initial)
}
func (f *ptrField) Reassign(v string) {
	fmt.Printf("\t%sA.%s%s = %s\n", v, f.Name, f.Value.SubKey, f.Value.Altered)
}
func (f *ptrField) Compare(v string) {
	fmt.Printf("\tif %sB.%s%s != %s {\n", v, f.Name, f.Value.SubKey, f.Value.SubValue)
}

func generatorForType(typ types.Type) generator {
	switch t := typ.(type) {
	case (*types.Basic):
		switch t.Name() {
		case "string":
			return stringGenerator
		default:
			panic(fmt.Errorf("Unknown basic type: %s", t.Name()))
		}
	case (*types.Interface):
		if t.Empty() {
			return emptyInterfaceGenerator
		}
	case (*types.Named):
		if s, ok := t.Obj().Type().Underlying().(*types.Struct); ok {
			named := fmt.Sprintf("%s.%s", t.Obj().Pkg().Name(), t.Obj().Name())
			return structGenerator(named, s)
		}
	}
	panic(fmt.Errorf("Unknown generator type: %#v", typ))
}

type generator struct {
	Type     string
	Key      string
	Initial  string
	Altered  string
	Warning  string
	SubKey   string
	SubValue string
}

var stringGenerator = generator{
	Type:     "string",
	Key:      `"foo"`,
	Initial:  `"bar"`,
	Altered:  `"baz"`,
	SubValue: `"bar"`,
}

var emptyInterfaceGenerator = generator{
	Type:     "interface{}",
	Key:      "0",
	Initial:  "1",
	Altered:  "2",
	SubValue: "1",
	Warning:  "interface{} can contain nested data!",
}

func structGenerator(name string, s *types.Struct) generator {
	f := s.Field(0)
	g := generatorForType(f.Type())
	return generator{
		Type:     "&ptr",
		Initial:  fmt.Sprintf("%s{%s: %s}", name, f.Name(), g.Initial),
		Altered:  g.Altered,
		SubKey:   "." + f.Name(),
		SubValue: g.SubValue,
	}
}

// getDocIface returns the couchdb.Doc interface
func getDocIface() *types.Interface {
	couchPkg := "github.com/cozy/cozy-stack/pkg/couchdb"
	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(couchPkg)
	lprog, err := conf.Load()
	if err != nil {
		panic(err)
	}
	scope := lprog.Package(couchPkg).Pkg.Scope()
	return scope.Lookup("Doc").Type().Underlying().(*types.Interface)
}

// pkgInfoFromPath returns information about the package
// Taken from https://github.com/matryer/moq
func pkgInfoFromPath(src string) (*types.Package, error) {
	abs, err := filepath.Abs(src)
	if err != nil {
		return nil, err
	}
	pkgFull := stripGopath(abs)

	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(pkgFull)
	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}

	pkgInfo := lprog.Package(pkgFull)
	if pkgInfo == nil {
		return nil, errors.New("package was nil")
	}

	return pkgInfo.Pkg, nil
}

// stripGopath takes the directory to a package and remove the gopath to get the
// canonical package name.
// Taken from https://github.com/ernesto-jimenez/gogen
func stripGopath(p string) string {
	for _, gopath := range gopaths() {
		p = strings.TrimPrefix(p, path.Join(gopath, "src")+"/")
	}
	return p
}

func gopaths() []string {
	return strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
}
<commit_msg>Ignore json.RawMessage for clone tests<commit_after>package main

import (
	"errors"
	"fmt"
	"go/parser"
	"go/types"
	"os"
	"path"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/loader"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "%s ./pkg/foo > tests/clone/generated/foo_test.go\n", os.Args[0])
		os.Exit(1)
	}
	infos := extractInfos(os.Args[1:])
	generateTests(infos)
}

func extractInfos(pkgs []string) []info {
	infos := make([]info, 0)
	docIface := getDocIface()

	for _, pkgPath := range pkgs {
		pkg, err := pkgInfoFromPath(pkgPath)
		if err != nil {
			panic(err)
		}

		in := info{
			PkgName: pkg.Name(),
			PkgPath: pkg.Path(),
			Structs: make(map[string][]mutableField),
		}
		scope := pkg.Scope()
		for _, name := range scope.Names() {
			obj := scope.Lookup(name)
			s, ok := obj.Type().Underlying().(*types.Struct)
			if !ok {
				continue
			}
			ptr := types.NewPointer(obj.Type())
			// FIXME implements returns false for intents.Intent but it should
			// return true, find why!
			// implements := types.Implements(ptr.Underlying(), docIface)
			f, g := types.MissingMethod(ptr.Underlying(), docIface, true)
			if f != nil && !g {
				continue
			}
			fields := make([]mutableField, 0)
			for i := 0; i < s.NumFields(); i++ {
				field := s.Field(i)
				// fmt.Printf(" - %d. %s - %s\n", i, field.Name(), field.Type())
				switch t := field.Type().(type) {
				case (*types.Slice):
					fields = append(fields, &sliceField{
						Name:  field.Name(),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Map):
					fields = append(fields, &mapField{
						Name:  field.Name(),
						Key:   generatorForType(t.Key()),
						Value: generatorForType(t.Elem()),
					})
				case (*types.Named):
					var named string
					if pkg := t.Obj().Pkg(); pkg != nil {
						named = fmt.Sprintf("%s.%s", pkg.Name(), t.Obj().Name())
					}
					switch named {
					case "time.Time", "time.Duration":
						// These structs are known to be safe
					default:
						panic(fmt.Errorf("Unknown named type: %s", named))
					}
				case (*types.Interface):
					fmt.Fprintf(os.Stderr, "Warning: cannot check interfaces: %s.%s -> %s\n",
						pkg.Name(), name, field)
				case (*types.Pointer):
					if gen := generatorForType(t.Elem()); gen != nil {
						fields = append(fields, &ptrField{
							Name:  field.Name(),
							Value: gen,
						})
					}
				case (*types.Basic):
					// Basic types are immutables
				default:
					panic(fmt.Errorf("Unknown type: %#v", field.Type()))
				}
			}
			if len(fields) > 0 {
				in.Structs[name] = fields
			}
		}
		if len(in.Structs) > 0 {
			infos = append(infos, in)
		}
	}
	return infos
}

func generateTests(infos []info) {
	fmt.Printf(`// Generated tests for Clone(). Do not manually edit!
package clone

import (
	"testing"
`)
	for _, info := range infos {
		fmt.Printf("\t\"%s\"\n", info.PkgPath)
	}
	fmt.Printf(")\n\n")

	for _, info := range infos {
		fmt.Printf("func Test%s(t *testing.T) {\n", strings.Title(info.PkgName))
		for name, fields := range info.Structs {
			v := strings.ToLower(name)
			fmt.Printf("\t%sA := &%s.%s{}\n", v, info.PkgName, name)
			for _, field := range fields {
				field.Initialize(v)
			}
			ptr := "*"
			if name == "JSONDoc" {
				ptr = ""
			}
			fmt.Printf("\t%sB := %sA.Clone().(%s%s.%s)\n", v, v, ptr, info.PkgName, name)
			for _, field := range fields {
				field.Reassign(v)
				field.Compare(v)
				fmt.Printf("\t\tt.Fatalf(\"Error for clone %s.%s -> %s\")\n\t}\n", info.PkgName, name, field)
			}
		}
		fmt.Printf("}\n\n")
	}
}

type info struct {
	PkgName string
	PkgPath string
	Structs map[string][]mutableField
}

type mutableField interface {
	String() string
	Initialize(v string)
	Reassign(v string)
	Compare(v string)
}

type sliceField struct {
	Name  string
	Value *generator
}

func (f *sliceField) String() string { return f.Name }

func (f *sliceField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = []%s{%s}\n", v, f.Name, f.Value.Type, f.Value.Initial)
}
func (f *sliceField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[0]%s = %s\n", v, f.Name, f.Value.SubKey, f.Value.Altered)
}
func (f *sliceField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[0]%s != %s {\n", v, f.Name, f.Value.SubKey, f.Value.SubValue)
}

type mapField struct {
	Name  string
	Key   *generator
	Value *generator
}

func (f *mapField) String() string { return f.Name }

func (f *mapField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s\n", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = map[%s]%s{%s: %s}\n", v, f.Name, f.Key.Type, f.Value.Type, f.Key.Key, f.Value.Initial)
}
func (f *mapField) Reassign(v string) {
	fmt.Printf("\t%sA.%s[%s]%s = %s\n", v, f.Name, f.Key.Key, f.Value.SubKey, f.Value.Altered)
}
func (f *mapField) Compare(v string) {
	fmt.Printf("\tif %sB.%s[%s]%s != %s {\n", v, f.Name, f.Key.Key, f.Value.SubKey, f.Value.SubValue)
}

type ptrField struct {
	Name  string
	Value *generator
}

func (f *ptrField) String() string { return f.Name }

func (f *ptrField) Initialize(v string) {
	if f.Value.Warning != "" {
		fmt.Printf("\t// Warning: %s", f.Value.Warning)
	}
	fmt.Printf("\t%sA.%s = func() *%s { tmp := %s; return &tmp }()\n", v, f.Name, f.Value.Type, f.Value.Initial)
}
func (f *ptrField) Reassign(v string) {
	fmt.Printf("\t%sA.%s%s = %s\n", v, f.Name, f.Value.SubKey, f.Value.Altered)
}
func (f *ptrField) Compare(v string) {
	fmt.Printf("\tif %sB.%s%s != %s {\n", v, f.Name, f.Value.SubKey, f.Value.SubValue)
}

func generatorForType(typ types.Type) *generator {
	switch t := typ.(type) {
	case (*types.Basic):
		switch t.Name() {
		case "string":
			return &stringGenerator
		default:
			panic(fmt.Errorf("Unknown basic type: %s", t.Name()))
		}
	case (*types.Interface):
		if t.Empty() {
			return &emptyInterfaceGenerator
		}
	case (*types.Named):
		named := fmt.Sprintf("%s.%s", t.Obj().Pkg().Name(), t.Obj().Name())
		if named == "json.RawMessage" {
			// We consider that json.RawMessage is not modifiable in our code
			return nil
		}
		if s, ok := t.Obj().Type().Underlying().(*types.Struct); ok {
			return structGenerator(named, s)
		}
	}
	panic(fmt.Errorf("Unknown generator type: %#v", typ))
}

type generator struct {
	Type     string
	Key      string
	Initial  string
	Altered  string
	Warning  string
	SubKey   string
	SubValue string
}

var stringGenerator = generator{
	Type:     "string",
	Key:      `"foo"`,
	Initial:  `"bar"`,
	Altered:  `"baz"`,
	SubValue: `"bar"`,
}

var emptyInterfaceGenerator = generator{
	Type:     "interface{}",
	Key:      "0",
	Initial:  "1",
	Altered:  "2",
	SubValue: "1",
	Warning:  "interface{} can contain nested data!",
}

func structGenerator(name string, s *types.Struct) *generator {
	f := s.Field(0)
	g := generatorForType(f.Type())
	return &generator{
		Type:     name,
		Initial:  fmt.Sprintf("%s{%s: %s}", name, f.Name(), g.Initial),
		Altered:  g.Altered,
		SubKey:   "." + f.Name(),
		SubValue: g.SubValue,
	}
}

// getDocIface returns the couchdb.Doc interface
func getDocIface() *types.Interface {
	couchPkg := "github.com/cozy/cozy-stack/pkg/couchdb"
	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(couchPkg)
	lprog, err := conf.Load()
	if err != nil {
		panic(err)
	}
	scope := lprog.Package(couchPkg).Pkg.Scope()
	return scope.Lookup("Doc").Type().Underlying().(*types.Interface)
}

// pkgInfoFromPath returns information about the package
// Taken from https://github.com/matryer/moq
func pkgInfoFromPath(src string) (*types.Package, error) {
	abs, err := filepath.Abs(src)
	if err != nil {
		return nil, err
	}
	pkgFull := stripGopath(abs)

	conf := loader.Config{
		ParserMode: parser.SpuriousErrors,
	}
	conf.Import(pkgFull)
	lprog, err := conf.Load()
	if err != nil {
		return nil, err
	}

	pkgInfo := lprog.Package(pkgFull)
	if pkgInfo == nil {
		return nil, errors.New("package was nil")
	}

	return pkgInfo.Pkg, nil
}

// stripGopath takes the directory to a package and remove the gopath to get the
// canonical package name.
// Taken from https://github.com/ernesto-jimenez/gogen
func stripGopath(p string) string {
	for _, gopath := range gopaths() {
		p = strings.TrimPrefix(p, path.Join(gopath, "src")+"/")
	}
	return p
}

func gopaths() []string {
	return strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
}
<|endoftext|>


<commit_before>package lib

import (
    "os"
    "time"
    "fmt"

    . "gopkg.in/check.v1"
)

func (s *OssutilCommandSuite) rawUpdate(force bool, language string) (bool, error) {
    command := "update"
    var args []string
    options := OptionMapType{
        OptionForce: &force,
        OptionLanguage: &language,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    return showElapse, err
}

func (s *OssutilCommandSuite) TestUpdate(c *C) {
    showElapse, err := s.rawUpdate(false, "中文")
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawUpdate(false, "English")
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawUpdate(true, "中文")

    showElapse, err = s.rawUpdate(true, "English")

    err = updateCommand.updateVersion(Version, "中文")

    fileName := "ossutil_test_not_exist"
    err = updateCommand.rewriteLoadConfig(fileName)
    c.Assert(err, IsNil)
}

func (s *OssutilCommandSuite) TestRevertRename(c *C) {
    filePath := ".ossutil_tempf"
    renameFilePath := ".ossutil_tempr"

    s.createFile(filePath, filePath + "i", c)
    s.createFile(renameFilePath, renameFilePath + "i", c)

    updateCommand.revertRename(filePath, renameFilePath)
    _, err := os.Stat(renameFilePath)
    c.Assert(err, NotNil)

    str := s.readFile(filePath, c)
    c.Assert(str, Equals, renameFilePath + "i")

    _ = os.Remove(filePath)
    _ = os.Remove(renameFilePath)
}

func (s *OssutilCommandSuite) TestDownloadLastestBinary(c *C) {
    tempBinaryFile := ".ossutil_test_update.temp"
    err := updateCommand.getBinary(tempBinaryFile, "1.0.0.Beta")
    c.Assert(err, IsNil)

    _ = os.Remove(tempBinaryFile)
}

func (s *OssutilCommandSuite) TestAnonymousGetToFileError(c *C) {
    bucket := bucketNamePrefix + "update"
    object := "object"
    os.Stdout = out
    os.Stderr = errout
    err := updateCommand.anonymousGetToFileRetry(bucket, object, object)
    c.Assert(err, NotNil)

    s.putBucket(bucket, c)
    time.Sleep(sleepTime)
    s.putObject(bucket, object, uploadFileName, c)
    fileName := "*"
    err = updateCommand.anonymousGetToFileRetry(bucket, object, fileName)
    c.Assert(err, NotNil)
    os.Stdout = testLogFile
    os.Stderr = testLogFile
}
<commit_msg>modify case<commit_after>package lib

import (
    "os"
    "time"

    . "gopkg.in/check.v1"
)

func (s *OssutilCommandSuite) rawUpdate(force bool, language string) (bool, error) {
    command := "update"
    var args []string
    options := OptionMapType{
        OptionForce: &force,
        OptionLanguage: &language,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    return showElapse, err
}

func (s *OssutilCommandSuite) TestUpdate(c *C) {
    showElapse, err := s.rawUpdate(false, "中文")
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawUpdate(false, "English")
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawUpdate(true, "中文")

    showElapse, err = s.rawUpdate(true, "English")

    err = updateCommand.updateVersion(Version, "中文")

    fileName := "ossutil_test_not_exist"
    err = updateCommand.rewriteLoadConfig(fileName)
    c.Assert(err, IsNil)
}

func (s *OssutilCommandSuite) TestRevertRename(c *C) {
    filePath := ".ossutil_tempf"
    renameFilePath := ".ossutil_tempr"

    s.createFile(filePath, filePath + "i", c)
    s.createFile(renameFilePath, renameFilePath + "i", c)

    updateCommand.revertRename(filePath, renameFilePath)
    _, err := os.Stat(renameFilePath)
    c.Assert(err, NotNil)

    str := s.readFile(filePath, c)
    c.Assert(str, Equals, renameFilePath + "i")

    _ = os.Remove(filePath)
    _ = os.Remove(renameFilePath)
}

func (s *OssutilCommandSuite) TestDownloadLastestBinary(c *C) {
    tempBinaryFile := ".ossutil_test_update.temp"
    err := updateCommand.getBinary(tempBinaryFile, "1.0.0.Beta")
    c.Assert(err, IsNil)

    _ = os.Remove(tempBinaryFile)
}

func (s *OssutilCommandSuite) TestAnonymousGetToFileError(c *C) {
    bucket := bucketNamePrefix + "update"
    object := "object"
    os.Stdout = out
    os.Stderr = errout
    err := updateCommand.anonymousGetToFileRetry(bucket, object, object)
    c.Assert(err, NotNil)

    s.putBucket(bucket, c)
    time.Sleep(sleepTime)
    s.putObject(bucket, object, uploadFileName, c)
    fileName := "*"
    err = updateCommand.anonymousGetToFileRetry(bucket, object, fileName)
    c.Assert(err, NotNil)
    os.Stdout = testLogFile
    os.Stderr = testLogFile
}
<|endoftext|>


<commit_before>package dlv

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/derekparker/delve/service/rpc1"
	"github.com/solo-io/squash/pkg/debuggers"
)

type DLV struct {
}

type DLVLiveDebugSession struct {
	client *rpc1.RPCClient
	port   int
}

func (d *DLVLiveDebugSession) Detach() error {
	d.client.Detach(false)
	return nil
}

func (d *DLVLiveDebugSession) Port() int {
	return d.port
}

func (d *DLVLiveDebugSession) HostType() debuggers.DebugHostType {
	return debuggers.DebugHostTypeClient
}

func (d *DLV) attachTo(pid int) (*DLVLiveDebugSession, error) {
	cmd, port, err := startDebugServer(pid)

	if cmd != nil {
		go cmd.Wait()
	}
	if err != nil {
		return nil, err
	}
	// use rpc1 client for vscode extension support
	client := rpc1.NewClient(fmt.Sprintf("localhost:%d", port))
	dls := &DLVLiveDebugSession{
		client: client,
		port:   port,
	}
	return dls, nil
}

func (d *DLV) Attach(pid int) (debuggers.DebugServer, error) {
	return d.attachTo(pid)
}

func startDebugServer(pid int) (*exec.Cmd, int, error) {

	log.WithField("pid", pid).Debug("StartDebugServer called")
	cmd := exec.Command("dlv", "attach", fmt.Sprintf("%d", pid), "--listen=127.0.0.1:0", "--accept-multiclient=true", "--headless", "--log")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.WithFields(log.Fields{"cmd": cmd, "args": cmd.Args}).Debug("dlv command")

	err := cmd.Start()
	if err != nil {
		log.WithField("err", err).Error("Failed to start dlv")
		return nil, 0, err
	}

	log.Debug("starting headless dlv for user started, trying to get port")
	time.Sleep(2 * time.Second)
	port, err := debuggers.GetPort(cmd.Process.Pid)
	if err != nil {
		log.WithField("err", err).Error("can't get headless dlv port")
		cmd.Process.Kill()
		cmd.Process.Release()
		return cmd, 0, err
	}

	return cmd, port, nil
}
<commit_msg>exit dlv server after detaching.<commit_after>package dlv

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/derekparker/delve/service/rpc1"
	"github.com/solo-io/squash/pkg/debuggers"
)

type DLV struct {
}

type DLVLiveDebugSession struct {
	client  *rpc1.RPCClient
	port    int
	process *os.Process
}

func (d *DLVLiveDebugSession) Detach() error {
	d.client.Detach(false)
	d.process.Kill()
	return nil
}

func (d *DLVLiveDebugSession) Port() int {
	return d.port
}

func (d *DLVLiveDebugSession) HostType() debuggers.DebugHostType {
	return debuggers.DebugHostTypeClient
}

func (d *DLV) attachTo(pid int) (*DLVLiveDebugSession, error) {
	cmd, port, err := startDebugServer(pid)

	if cmd != nil {
		go cmd.Wait()
	}
	if err != nil {
		return nil, err
	}
	// use rpc1 client for vscode extension support
	client := rpc1.NewClient(fmt.Sprintf("localhost:%d", port))
	dls := &DLVLiveDebugSession{
		client:  client,
		port:    port,
		process: cmd.Process,
	}
	return dls, nil
}

func (d *DLV) Attach(pid int) (debuggers.DebugServer, error) {
	return d.attachTo(pid)
}

func startDebugServer(pid int) (*exec.Cmd, int, error) {

	log.WithField("pid", pid).Debug("StartDebugServer called")
	cmd := exec.Command("dlv", "attach", fmt.Sprintf("%d", pid), "--listen=127.0.0.1:0", "--accept-multiclient=true", "--headless", "--log")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.WithFields(log.Fields{"cmd": cmd, "args": cmd.Args}).Debug("dlv command")

	err := cmd.Start()
	if err != nil {
		log.WithField("err", err).Error("Failed to start dlv")
		return nil, 0, err
	}

	log.Debug("starting headless dlv for user started, trying to get port")
	time.Sleep(2 * time.Second)
	port, err := debuggers.GetPort(cmd.Process.Pid)
	if err != nil {
		log.WithField("err", err).Error("can't get headless dlv port")
		cmd.Process.Kill()
		cmd.Process.Release()
		return cmd, 0, err
	}

	return cmd, port, nil
}
<|endoftext|>


<commit_before>package demoinfocs

import (
	"fmt"
	"io"
	"math"
	"sync"
	"time"

	"github.com/gogo/protobuf/proto"
	"github.com/markus-wa/go-unassert"
	dispatch "github.com/markus-wa/godispatch"
	"github.com/pkg/errors"

	common "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/common"
	events "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/events"
	msg "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/msg"
)

const maxOsPath = 260

const (
	playerWeaponPrefix    = "m_hMyWeapons."
	playerWeaponPrePrefix = "bcc_nonlocaldata."
	gameRulesPrefix       = "cs_gamerules_data"
)

// Parsing errors
var (
	// ErrCancelled signals that parsing was cancelled via Parser.Cancel()
	ErrCancelled = errors.New("parsing was cancelled before it finished (ErrCancelled)")

	// ErrUnexpectedEndOfDemo signals that the demo is incomplete / corrupt -
	// these demos may still be useful, check how far the parser got.
	ErrUnexpectedEndOfDemo = errors.New("demo stream ended unexpectedly (ErrUnexpectedEndOfDemo)")

	// ErrInvalidFileType signals that the input isn't a valid CS:GO demo.
	ErrInvalidFileType = errors.New("invalid File-Type; expecting HL2DEMO in the first 8 bytes (ErrInvalidFileType)")
)

// ParseHeader attempts to parse the header of the demo and returns it.
// If not done manually this will be called by Parser.ParseNextFrame() or Parser.ParseToEnd().
//
// Returns ErrInvalidFileType if the filestamp (first 8 bytes) doesn't match HL2DEMO.
func (p *parser) ParseHeader() (common.DemoHeader, error) {
	var h common.DemoHeader
	h.Filestamp = p.bitReader.ReadCString(8)
	h.Protocol = p.bitReader.ReadSignedInt(32)
	h.NetworkProtocol = p.bitReader.ReadSignedInt(32)
	h.ServerName = p.bitReader.ReadCString(maxOsPath)
	h.ClientName = p.bitReader.ReadCString(maxOsPath)
	h.MapName = p.bitReader.ReadCString(maxOsPath)
	h.GameDirectory = p.bitReader.ReadCString(maxOsPath)
	h.PlaybackTime = time.Duration(p.bitReader.ReadFloat() * float32(time.Second))
	h.PlaybackTicks = p.bitReader.ReadSignedInt(32)
	h.PlaybackFrames = p.bitReader.ReadSignedInt(32)
	h.SignonLength = p.bitReader.ReadSignedInt(32)

	if h.Filestamp != "HL2DEMO" {
		return h, ErrInvalidFileType
	}

	// Initialize queue if the buffer size wasn't specified, the amount of ticks
	// seems to be a good indicator of how many events we'll get
	if p.msgQueue == nil {
		p.initMsgQueue(msgQueueSize(h.PlaybackTicks))
	}

	p.header = &h

	return h, nil
}

func msgQueueSize(ticks int) int {
	const (
		msgQueueMinSize = 50000
		msgQueueMaxSize = 500000
	)

	size := math.Max(msgQueueMinSize, float64(ticks))
	size = math.Min(msgQueueMaxSize, size)

	return int(size)
}

// ParseToEnd attempts to parse the demo until the end.
// Aborts and returns ErrCancelled if Cancel() is called before the end.
//
// See also: ParseNextFrame() for other possible errors.
func (p *parser) ParseToEnd() (err error) {
	defer func() {
		// Make sure all the messages of the demo are handled
		p.msgDispatcher.SyncAllQueues()
		p.msgDispatcher.RemoveAllQueues()

		// Close msgQueue
		if p.msgQueue != nil {
			close(p.msgQueue)
		}

		if err == nil {
			err = recoverFromUnexpectedEOF(recover())
		}
	}()

	if p.header == nil {
		_, err = p.ParseHeader()
		if err != nil {
			return
		}
	}

	for {
		if !p.parseFrame() {
			return p.error()
		}

		if err = p.error(); err != nil {
			return
		}
	}
}

func recoverFromUnexpectedEOF(r interface{}) error {
	if r == nil {
		return nil
	}

	if r == io.ErrUnexpectedEOF || r == io.EOF {
		return ErrUnexpectedEndOfDemo
	}

	switch err := r.(type) {
	case dispatch.ConsumerCodePanic:
		panic(err.Value())

	default:
		panic(err)
	}
}

// Cancel aborts ParseToEnd() and drains the internal event queues.
// No further events will be sent to event or message handlers after this.
func (p *parser) Cancel() {
	p.setError(ErrCancelled)
	p.eventDispatcher.UnregisterAllHandlers()
	p.msgDispatcher.UnregisterAllHandlers()
}

/*
ParseNextFrame attempts to parse the next frame / demo-tick (not ingame tick).

Returns true unless the demo command 'stop' or an error was encountered.

May return ErrUnexpectedEndOfDemo for incomplete / corrupt demos.
May panic if the demo is corrupt in some way.

See also: ParseToEnd() for parsing the complete demo in one go (faster).
*/
func (p *parser) ParseNextFrame() (moreFrames bool, err error) {
	defer func() {
		// Make sure all the messages of the frame are handled
		p.msgDispatcher.SyncAllQueues()

		// Close msgQueue (only if we are done)
		if p.msgQueue != nil && !moreFrames {
			p.msgDispatcher.RemoveAllQueues()
			close(p.msgQueue)
		}

		if err == nil {
			err = recoverFromUnexpectedEOF(recover())
		}
	}()

	if p.header == nil {
		_, err = p.ParseHeader()
		if err != nil {
			return
		}
	}

	moreFrames = p.parseFrame()

	return moreFrames, p.error()
}

// Demo commands as documented at https://developer.valvesoftware.com/wiki/DEM_Format
type demoCommand byte

const (
	dcSignon         demoCommand = 1
	dcPacket         demoCommand = 2
	dcSynctick       demoCommand = 3
	dcConsoleCommand demoCommand = 4
	dcUserCommand    demoCommand = 5
	dcDataTables     demoCommand = 6
	dcStop           demoCommand = 7
	dcCustomData     demoCommand = 8
	dcStringTables   demoCommand = 9
)

//nolint:funlen,cyclop
func (p *parser) parseFrame() bool {
	cmd := demoCommand(p.bitReader.ReadSingleByte())

	// Send ingame tick number update
	p.msgQueue <- ingameTickNumber(p.bitReader.ReadSignedInt(32))

	// Skip 'player slot'
	const nSlotBits = 8
	p.bitReader.Skip(nSlotBits) //nolint:wsl

	debugDemoCommand(cmd)

	switch cmd {
	case dcSynctick:
		// Ignore

	case dcStop:
		return false

	case dcConsoleCommand:
		// Skip
		p.bitReader.Skip(p.bitReader.ReadSignedInt(32) << 3)

	case dcDataTables:
		p.msgDispatcher.SyncAllQueues()

		p.bitReader.BeginChunk(p.bitReader.ReadSignedInt(32) << 3)
		p.stParser.ParsePacket(p.bitReader)
		p.bitReader.EndChunk()

		debugAllServerClasses(p.ServerClasses())

		p.mapEquipment()
		p.bindEntities()

		p.eventDispatcher.Dispatch(events.DataTablesParsed{})

	case dcStringTables:
		p.msgDispatcher.SyncAllQueues()

		p.parseStringTables()

	case dcUserCommand:
		// Skip
		p.bitReader.Skip(32)
		p.bitReader.Skip(p.bitReader.ReadSignedInt(32) << 3)

	case dcSignon:
		fallthrough
	case dcPacket:
		p.parsePacket()

	case dcCustomData:
		// Might as well panic since we'll be way off if we dont skip the whole thing
		panic("Found CustomData but not handled")

	default:
		panic(fmt.Sprintf("I haven't programmed that pathway yet (command %v unknown)", cmd))
	}

	// Queue up some post processing
	p.msgQueue <- frameParsedToken

	return true
}

var byteSlicePool = sync.Pool{
	New: func() interface{} {
		s := make([]byte, 0, 256)

		return &s
	},
}

var defaultNetMessageCreators = map[int]NetMessageCreator{
	// We could pool CSVCMsg_PacketEntities as they take up A LOT of the allocations
	// but unless we're on a system that's doing a lot of concurrent parsing there isn't really a point
	// as handling packets is a lot slower than creating them and we can't pool until they are handled.
	int(msg.SVC_Messages_svc_PacketEntities):    func() proto.Message { return new(msg.CSVCMsg_PacketEntities) },
	int(msg.SVC_Messages_svc_GameEventList):     func() proto.Message { return new(msg.CSVCMsg_GameEventList) },
	int(msg.SVC_Messages_svc_GameEvent):         func() proto.Message { return new(msg.CSVCMsg_GameEvent) },
	int(msg.SVC_Messages_svc_CreateStringTable): func() proto.Message { return new(msg.CSVCMsg_CreateStringTable) },
	int(msg.SVC_Messages_svc_UpdateStringTable): func() proto.Message { return new(msg.CSVCMsg_UpdateStringTable) },
	int(msg.SVC_Messages_svc_UserMessage):       func() proto.Message { return new(msg.CSVCMsg_UserMessage) },
	int(msg.SVC_Messages_svc_ServerInfo):        func() proto.Message { return new(msg.CSVCMsg_ServerInfo) },
	int(msg.NET_Messages_net_SetConVar):         func() proto.Message { return new(msg.CNETMsg_SetConVar) },
}

//nolint:funlen
func (p *parser) parsePacket() {
	// Booooring
	// 152 bytes CommandInfo, 4 bytes SeqNrIn, 4 bytes SeqNrOut
	// See at the bottom of the file what the CommandInfo would contain if you are interested.
	const nCommandInfoBits = (152 + 4 + 4) << 3
	p.bitReader.Skip(nCommandInfoBits) //nolint:wsl

	// Here we go
	p.bitReader.BeginChunk(p.bitReader.ReadSignedInt(32) << 3)

	for !p.bitReader.ChunkFinished() {
		cmd := int(p.bitReader.ReadVarInt32())
		size := int(p.bitReader.ReadVarInt32())

		p.bitReader.BeginChunk(size << 3)

		msgCreator := defaultNetMessageCreators[cmd]

		if msgCreator == nil {
			var msgName string
			if cmd < 8 || cmd >= 100 {
				msgName = msg.NET_Messages_name[int32(cmd)]
			} else {
				msgName = msg.SVC_Messages_name[int32(cmd)]
			}

			if msgName == "" {
				// Send a warning if the command is unknown
				// This might mean our proto files are out of date
				p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("unknown message command %q", cmd)})
				unassert.Error("unknown message command %q", cmd)
			}

			// Handle additional net-messages as defined by the user
			msgCreator = p.additionalNetMessageCreators[cmd]
			if msgCreator == nil {
				debugUnhandledMessage(cmd, msgName)

				// On to the next one
				p.bitReader.EndChunk()

				continue
			}
		}

		b := byteSlicePool.Get().(*[]byte)

		p.bitReader.ReadBytesInto(b, size)

		m := msgCreator()

		err := proto.Unmarshal(*b, m)
		if err != nil {
			// TODO: Don't crash here, happens with demos that work in gotv
			p.setError(errors.Wrapf(err, "failed to unmarshal cmd %d", cmd))

			return
		}

		p.msgQueue <- m

		// Reset length to 0 and pool
		*b = (*b)[:0]
		byteSlicePool.Put(b)

		p.bitReader.EndChunk()
	}

	p.bitReader.EndChunk()
}

type frameParsedTokenType struct{}

var frameParsedToken = new(frameParsedTokenType)

func (p *parser) handleFrameParsed(*frameParsedTokenType) {
	// PlayerFlashed events need to be dispatched at the end of the tick
	// because Player.FlashDuration is updated after the game-events are parsed.
	for _, eventHandler := range p.delayedEventHandlers {
		eventHandler()
	}

	p.delayedEventHandlers = p.delayedEventHandlers[:0]

	p.currentFrame++
	p.eventDispatcher.Dispatch(events.FrameDone{})
}

/*
Format of 'CommandInfos' - I honestly have no clue what they are good for.
This data is skipped in Parser.parsePacket().
If you find a use for this please let me know!

Here is all i know:

CommandInfo [152 bytes]
- [2]Split

Split [76 bytes]
- flags [4 bytes]
- viewOrigin [12 bytes]
- viewAngles [12 bytes]
- localViewAngles [12 bytes]
- viewOrigin2 [12 bytes]
- viewAngles2 [12 bytes]
- localViewAngles2 [12 bytes]

Origin [12 bytes]
- X [4 bytes]
- Y [4 bytes]
- Z [4 bytes]

Angle [12 bytes]
- X [4 bytes]
- Y [4 bytes]
- Z [4 bytes]

They are parsed in the following order:
split1.flags
split1.viewOrigin.x
split1.viewOrigin.y
split1.viewOrigin.z
split1.viewAngles.x
split1.viewAngles.y
split1.viewAngles.z
split1.localViewAngles.x
split1.localViewAngles.y
split1.localViewAngles.z
split1.viewOrigin2...
split1.viewAngles2...
split1.localViewAngles2...
split2.flags
...

Or just check this file's history for an example on how to parse them
*/
<commit_msg>core: return errors in ParseToEnd() that happen during SyncAllQueues() (#321)<commit_after>package demoinfocs

import (
	"fmt"
	"io"
	"math"
	"sync"
	"time"

	"github.com/gogo/protobuf/proto"
	"github.com/markus-wa/go-unassert"
	dispatch "github.com/markus-wa/godispatch"
	"github.com/pkg/errors"

	common "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/common"
	events "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/events"
	msg "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/msg"
)

const maxOsPath = 260

const (
	playerWeaponPrefix    = "m_hMyWeapons."
	playerWeaponPrePrefix = "bcc_nonlocaldata."
	gameRulesPrefix       = "cs_gamerules_data"
)

// Parsing errors
var (
	// ErrCancelled signals that parsing was cancelled via Parser.Cancel()
	ErrCancelled = errors.New("parsing was cancelled before it finished (ErrCancelled)")

	// ErrUnexpectedEndOfDemo signals that the demo is incomplete / corrupt -
	// these demos may still be useful, check how far the parser got.
	ErrUnexpectedEndOfDemo = errors.New("demo stream ended unexpectedly (ErrUnexpectedEndOfDemo)")

	// ErrInvalidFileType signals that the input isn't a valid CS:GO demo.
	ErrInvalidFileType = errors.New("invalid File-Type; expecting HL2DEMO in the first 8 bytes (ErrInvalidFileType)")
)

// ParseHeader attempts to parse the header of the demo and returns it.
// If not done manually this will be called by Parser.ParseNextFrame() or Parser.ParseToEnd().
//
// Returns ErrInvalidFileType if the filestamp (first 8 bytes) doesn't match HL2DEMO.
func (p *parser) ParseHeader() (common.DemoHeader, error) {
	var h common.DemoHeader
	h.Filestamp = p.bitReader.ReadCString(8)
	h.Protocol = p.bitReader.ReadSignedInt(32)
	h.NetworkProtocol = p.bitReader.ReadSignedInt(32)
	h.ServerName = p.bitReader.ReadCString(maxOsPath)
	h.ClientName = p.bitReader.ReadCString(maxOsPath)
	h.MapName = p.bitReader.ReadCString(maxOsPath)
	h.GameDirectory = p.bitReader.ReadCString(maxOsPath)
	h.PlaybackTime = time.Duration(p.bitReader.ReadFloat() * float32(time.Second))
	h.PlaybackTicks = p.bitReader.ReadSignedInt(32)
	h.PlaybackFrames = p.bitReader.ReadSignedInt(32)
	h.SignonLength = p.bitReader.ReadSignedInt(32)

	if h.Filestamp != "HL2DEMO" {
		return h, ErrInvalidFileType
	}

	// Initialize queue if the buffer size wasn't specified, the amount of ticks
	// seems to be a good indicator of how many events we'll get
	if p.msgQueue == nil {
		p.initMsgQueue(msgQueueSize(h.PlaybackTicks))
	}

	p.header = &h

	return h, nil
}

func msgQueueSize(ticks int) int {
	const (
		msgQueueMinSize = 50000
		msgQueueMaxSize = 500000
	)

	size := math.Max(msgQueueMinSize, float64(ticks))
	size = math.Min(msgQueueMaxSize, size)

	return int(size)
}

// ParseToEnd attempts to parse the demo until the end.
// Aborts and returns ErrCancelled if Cancel() is called before the end.
//
// See also: ParseNextFrame() for other possible errors.
func (p *parser) ParseToEnd() (err error) {
	defer func() {
		// Make sure all the messages of the demo are handled
		p.msgDispatcher.SyncAllQueues()
		p.msgDispatcher.RemoveAllQueues()

		// Close msgQueue
		if p.msgQueue != nil {
			close(p.msgQueue)
		}

		if err == nil {
			err = recoverFromUnexpectedEOF(recover())
		}

		// any errors that happened during SyncAllQueues()
		if err == nil {
			err = p.error()
		}
	}()

	if p.header == nil {
		_, err = p.ParseHeader()
		if err != nil {
			return
		}
	}

	for {
		if !p.parseFrame() {
			return p.error()
		}

		if err = p.error(); err != nil {
			return
		}
	}
}

func recoverFromUnexpectedEOF(r interface{}) error {
	if r == nil {
		return nil
	}

	if r == io.ErrUnexpectedEOF || r == io.EOF {
		return ErrUnexpectedEndOfDemo
	}

	switch err := r.(type) {
	case dispatch.ConsumerCodePanic:
		panic(err.Value())

	default:
		panic(err)
	}
}

// Cancel aborts ParseToEnd() and drains the internal event queues.
// No further events will be sent to event or message handlers after this.
func (p *parser) Cancel() {
	p.setError(ErrCancelled)
	p.eventDispatcher.UnregisterAllHandlers()
	p.msgDispatcher.UnregisterAllHandlers()
}

/*
ParseNextFrame attempts to parse the next frame / demo-tick (not ingame tick).

Returns true unless the demo command 'stop' or an error was encountered.

May return ErrUnexpectedEndOfDemo for incomplete / corrupt demos.
May panic if the demo is corrupt in some way.

See also: ParseToEnd() for parsing the complete demo in one go (faster).
*/
func (p *parser) ParseNextFrame() (moreFrames bool, err error) {
	defer func() {
		// Make sure all the messages of the frame are handled
		p.msgDispatcher.SyncAllQueues()

		// Close msgQueue (only if we are done)
		if p.msgQueue != nil && !moreFrames {
			p.msgDispatcher.RemoveAllQueues()
			close(p.msgQueue)
		}

		if err == nil {
			err = recoverFromUnexpectedEOF(recover())
		}
	}()

	if p.header == nil {
		_, err = p.ParseHeader()
		if err != nil {
			return
		}
	}

	moreFrames = p.parseFrame()

	return moreFrames, p.error()
}

// Demo commands as documented at https://developer.valvesoftware.com/wiki/DEM_Format
type demoCommand byte

const (
	dcSignon         demoCommand = 1
	dcPacket         demoCommand = 2
	dcSynctick       demoCommand = 3
	dcConsoleCommand demoCommand = 4
	dcUserCommand    demoCommand = 5
	dcDataTables     demoCommand = 6
	dcStop           demoCommand = 7
	dcCustomData     demoCommand = 8
	dcStringTables   demoCommand = 9
)

//nolint:funlen,cyclop
func (p *parser) parseFrame() bool {
	cmd := demoCommand(p.bitReader.ReadSingleByte())

	// Send ingame tick number update
	p.msgQueue <- ingameTickNumber(p.bitReader.ReadSignedInt(32))

	// Skip 'player slot'
	const nSlotBits = 8
	p.bitReader.Skip(nSlotBits) //nolint:wsl

	debugDemoCommand(cmd)

	switch cmd {
	case dcSynctick:
		// Ignore

	case dcStop:
		return false

	case dcConsoleCommand:
		// Skip
		p.bitReader.Skip(p.bitReader.ReadSignedInt(32) << 3)

	case dcDataTables:
		p.msgDispatcher.SyncAllQueues()

		p.bitReader.BeginChunk(p.bitReader.ReadSignedInt(32) << 3)
		p.stParser.ParsePacket(p.bitReader)
		p.bitReader.EndChunk()

		debugAllServerClasses(p.ServerClasses())

		p.mapEquipment()
		p.bindEntities()

		p.eventDispatcher.Dispatch(events.DataTablesParsed{})

	case dcStringTables:
		p.msgDispatcher.SyncAllQueues()

		p.parseStringTables()

	case dcUserCommand:
		// Skip
		p.bitReader.Skip(32)
		p.bitReader.Skip(p.bitReader.ReadSignedInt(32) << 3)

	case dcSignon:
		fallthrough
	case dcPacket:
		p.parsePacket()

	case dcCustomData:
		// Might as well panic since we'll be way off if we dont skip the whole thing
		panic("Found CustomData but not handled")

	default:
		panic(fmt.Sprintf("I haven't programmed that pathway yet (command %v unknown)", cmd))
	}

	// Queue up some post processing
	p.msgQueue <- frameParsedToken

	return true
}

var byteSlicePool = sync.Pool{
	New: func() interface{} {
		s := make([]byte, 0, 256)

		return &s
	},
}

var defaultNetMessageCreators = map[int]NetMessageCreator{
	// We could pool CSVCMsg_PacketEntities as they take up A LOT of the allocations
	// but unless we're on a system that's doing a lot of concurrent parsing there isn't really a point
	// as handling packets is a lot slower than creating them and we can't pool until they are handled.
	int(msg.SVC_Messages_svc_PacketEntities):    func() proto.Message { return new(msg.CSVCMsg_PacketEntities) },
	int(msg.SVC_Messages_svc_GameEventList):     func() proto.Message { return new(msg.CSVCMsg_GameEventList) },
	int(msg.SVC_Messages_svc_GameEvent):         func() proto.Message { return new(msg.CSVCMsg_GameEvent) },
	int(msg.SVC_Messages_svc_CreateStringTable): func() proto.Message { return new(msg.CSVCMsg_CreateStringTable) },
	int(msg.SVC_Messages_svc_UpdateStringTable): func() proto.Message { return new(msg.CSVCMsg_UpdateStringTable) },
	int(msg.SVC_Messages_svc_UserMessage):       func() proto.Message { return new(msg.CSVCMsg_UserMessage) },
	int(msg.SVC_Messages_svc_ServerInfo):        func() proto.Message { return new(msg.CSVCMsg_ServerInfo) },
	int(msg.NET_Messages_net_SetConVar):         func() proto.Message { return new(msg.CNETMsg_SetConVar) },
}

//nolint:funlen
func (p *parser) parsePacket() {
	// Booooring
	// 152 bytes CommandInfo, 4 bytes SeqNrIn, 4 bytes SeqNrOut
	// See at the bottom of the file what the CommandInfo would contain if you are interested.
	const nCommandInfoBits = (152 + 4 + 4) << 3
	p.bitReader.Skip(nCommandInfoBits) //nolint:wsl

	// Here we go
	p.bitReader.BeginChunk(p.bitReader.ReadSignedInt(32) << 3)

	for !p.bitReader.ChunkFinished() {
		cmd := int(p.bitReader.ReadVarInt32())
		size := int(p.bitReader.ReadVarInt32())

		p.bitReader.BeginChunk(size << 3)

		msgCreator := defaultNetMessageCreators[cmd]

		if msgCreator == nil {
			var msgName string
			if cmd < 8 || cmd >= 100 {
				msgName = msg.NET_Messages_name[int32(cmd)]
			} else {
				msgName = msg.SVC_Messages_name[int32(cmd)]
			}

			if msgName == "" {
				// Send a warning if the command is unknown
				// This might mean our proto files are out of date
				p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("unknown message command %q", cmd)})
				unassert.Error("unknown message command %q", cmd)
			}

			// Handle additional net-messages as defined by the user
			msgCreator = p.additionalNetMessageCreators[cmd]
			if msgCreator == nil {
				debugUnhandledMessage(cmd, msgName)

				// On to the next one
				p.bitReader.EndChunk()

				continue
			}
		}

		b := byteSlicePool.Get().(*[]byte)

		p.bitReader.ReadBytesInto(b, size)

		m := msgCreator()

		err := proto.Unmarshal(*b, m)
		if err != nil {
			// TODO: Don't crash here, happens with demos that work in gotv
			p.setError(errors.Wrapf(err, "failed to unmarshal cmd %d", cmd))

			return
		}

		p.msgQueue <- m

		// Reset length to 0 and pool
		*b = (*b)[:0]
		byteSlicePool.Put(b)

		p.bitReader.EndChunk()
	}

	p.bitReader.EndChunk()
}

type frameParsedTokenType struct{}

var frameParsedToken = new(frameParsedTokenType)

func (p *parser) handleFrameParsed(*frameParsedTokenType) {
	// PlayerFlashed events need to be dispatched at the end of the tick
	// because Player.FlashDuration is updated after the game-events are parsed.
	for _, eventHandler := range p.delayedEventHandlers {
		eventHandler()
	}

	p.delayedEventHandlers = p.delayedEventHandlers[:0]

	p.currentFrame++
	p.eventDispatcher.Dispatch(events.FrameDone{})
}

/*
Format of 'CommandInfos' - I honestly have no clue what they are good for.
This data is skipped in Parser.parsePacket().
If you find a use for this please let me know!

Here is all i know:

CommandInfo [152 bytes]
- [2]Split

Split [76 bytes]
- flags [4 bytes]
- viewOrigin [12 bytes]
- viewAngles [12 bytes]
- localViewAngles [12 bytes]
- viewOrigin2 [12 bytes]
- viewAngles2 [12 bytes]
- localViewAngles2 [12 bytes]

Origin [12 bytes]
- X [4 bytes]
- Y [4 bytes]
- Z [4 bytes]

Angle [12 bytes]
- X [4 bytes]
- Y [4 bytes]
- Z [4 bytes]

They are parsed in the following order:
split1.flags
split1.viewOrigin.x
split1.viewOrigin.y
split1.viewOrigin.z
split1.viewAngles.x
split1.viewAngles.y
split1.viewAngles.z
split1.localViewAngles.x
split1.localViewAngles.y
split1.localViewAngles.z
split1.viewOrigin2...
split1.viewAngles2...
split1.localViewAngles2...
split2.flags
...

Or just check this file's history for an example on how to parse them
*/
<|endoftext|>


<commit_before>/*
Package response provides helpers and utils for working with HTTP response
*/
package response

import (
	"context"
	"encoding/json"
	"net/http"
)

// JSON returns data as json response
func JSON(ctx context.Context, w http.ResponseWriter, statusCode int, payload interface{}) error {
	w.Header().Set("Content-Type", "application/json")

	// If there is nothing to marshal then set status code and return.
	if payload == nil {
		_, err := w.Write([]byte("{}"))
		return err
	}

	w.WriteHeader(statusCode)

	encoder := json.NewEncoder(w)
	encoder.SetEscapeHTML(true)
	encoder.SetIndent("", "")

	if err := encoder.Encode(payload); err != nil {
		return err
	}

	Flush(w)

	return nil
}

// MustJSON returns data as json response
// will panic if unable to marshal payload into JSON object
// uses JSON internally
func MustJSON(ctx context.Context, w http.ResponseWriter, statusCode int, payload interface{}) {
	if err := JSON(ctx, w, statusCode, payload); err != nil {
		panic(err)
	}
}
<commit_msg>Set header only if not OK<commit_after>/*
Package response provides helpers and utils for working with HTTP response
*/
package response

import (
	"context"
	"encoding/json"
	"net/http"
)

// JSON returns data as json response
func JSON(ctx context.Context, w http.ResponseWriter, statusCode int, payload interface{}) error {
	w.Header().Set("Content-Type", "application/json")

	// If there is nothing to marshal then set status code and return.
	if payload == nil {
		_, err := w.Write([]byte("{}"))
		return err
	}

	if statusCode != http.StatusOK {
		w.WriteHeader(statusCode)
	}

	encoder := json.NewEncoder(w)
	encoder.SetEscapeHTML(true)
	encoder.SetIndent("", "")

	if err := encoder.Encode(payload); err != nil {
		return err
	}

	Flush(w)

	return nil
}

// MustJSON returns data as json response
// will panic if unable to marshal payload into JSON object
// uses JSON internally
func MustJSON(ctx context.Context, w http.ResponseWriter, statusCode int, payload interface{}) {
	if err := JSON(ctx, w, statusCode, payload); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package plugin

import (
	"fmt"
	"net"
	"strconv"

	log "github.com/golang/glog"

	kapi "k8s.io/kubernetes/pkg/api"
	kapiunversioned "k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/client/cache"
	kclient "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/types"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	utilwait "k8s.io/kubernetes/pkg/util/wait"

	osapi "github.com/openshift/origin/pkg/sdn/api"
	"github.com/openshift/origin/pkg/util/netutils"
)

func (master *OsdnMaster) SubnetStartMaster(clusterNetwork *net.IPNet, hostSubnetLength uint32) error {
	subrange := make([]string, 0)
	subnets, err := master.osClient.HostSubnets().List(kapi.ListOptions{})
	if err != nil {
		log.Errorf("Error in initializing/fetching subnets: %v", err)
		return err
	}
	for _, sub := range subnets.Items {
		subrange = append(subrange, sub.Subnet)
		if err = master.networkInfo.validateNodeIP(sub.HostIP); err != nil {
			// Don't error out; just warn so the error can be corrected with 'oc'
			log.Errorf("Failed to validate HostSubnet %s: %v", hostSubnetToString(&sub), err)
		} else {
			log.Infof("Found existing HostSubnet %s", hostSubnetToString(&sub))
		}
	}

	master.subnetAllocator, err = netutils.NewSubnetAllocator(clusterNetwork.String(), hostSubnetLength, subrange)
	if err != nil {
		return err
	}

	go utilwait.Forever(master.watchNodes, 0)
	go utilwait.Forever(master.watchSubnets, 0)
	return nil
}

func (master *OsdnMaster) addNode(nodeName string, nodeIP string, hsAnnotations map[string]string) error {
	// Validate node IP before proceeding
	if err := master.networkInfo.validateNodeIP(nodeIP); err != nil {
		return err
	}

	// Check if subnet needs to be created or updated
	sub, err := master.osClient.HostSubnets().Get(nodeName)
	if err == nil {
		if sub.HostIP == nodeIP {
			return nil
		} else {
			// Node IP changed, update old subnet
			sub.HostIP = nodeIP
			sub, err = master.osClient.HostSubnets().Update(sub)
			if err != nil {
				return fmt.Errorf("Error updating subnet %s for node %s: %v", sub.Subnet, nodeName, err)
			}
			log.Infof("Updated HostSubnet %s", hostSubnetToString(sub))
			return nil
		}
	}

	// Create new subnet
	sn, err := master.subnetAllocator.GetNetwork()
	if err != nil {
		return fmt.Errorf("Error allocating network for node %s: %v", nodeName, err)
	}

	sub = &osapi.HostSubnet{
		TypeMeta:   kapiunversioned.TypeMeta{Kind: "HostSubnet"},
		ObjectMeta: kapi.ObjectMeta{Name: nodeName, Annotations: hsAnnotations},
		Host:       nodeName,
		HostIP:     nodeIP,
		Subnet:     sn.String(),
	}
	sub, err = master.osClient.HostSubnets().Create(sub)
	if err != nil {
		master.subnetAllocator.ReleaseNetwork(sn)
		return fmt.Errorf("Error creating subnet %s for node %s: %v", sn.String(), nodeName, err)
	}
	log.Infof("Created HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func (master *OsdnMaster) deleteNode(nodeName string) error {
	sub, err := master.osClient.HostSubnets().Get(nodeName)
	if err != nil {
		return fmt.Errorf("Error fetching subnet for node %q for deletion: %v", nodeName, err)
	}
	err = master.osClient.HostSubnets().Delete(nodeName)
	if err != nil {
		return fmt.Errorf("Error deleting subnet %v for node %q: %v", sub, nodeName, err)
	}

	log.Infof("Deleted HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func getNodeIP(node *kapi.Node) (string, error) {
	if len(node.Status.Addresses) > 0 && node.Status.Addresses[0].Address != "" {
		return node.Status.Addresses[0].Address, nil
	} else {
		return netutils.GetNodeIP(node.Name)
	}
}

// Because openshift-sdn uses an overlay and doesn't need GCE Routes, we need to
// clear the NetworkUnavailable condition that kubelet adds to initial node
// status when using GCE.
// TODO: make upstream kubelet more flexible with overlays and GCE so this
// condition doesn't get added for network plugins that don't want it, and then
// we can remove this function.
func (master *OsdnMaster) clearInitialNodeNetworkUnavailableCondition(node *kapi.Node) {
	knode := node
	cleared := false
	resultErr := kclient.RetryOnConflict(kclient.DefaultBackoff, func() error {
		var err error

		if knode != node {
			knode, err = master.kClient.Nodes().Get(node.ObjectMeta.Name)
			if err != nil {
				return err
			}
		}

		// Let caller modify knode's status, then push to api server.
		_, condition := kapi.GetNodeCondition(&node.Status, kapi.NodeNetworkUnavailable)
		if condition != nil && condition.Status != kapi.ConditionFalse && condition.Reason == "NoRouteCreated" {
			condition.Status = kapi.ConditionFalse
			condition.Reason = "RouteCreated"
			condition.Message = "openshift-sdn cleared kubelet-set NoRouteCreated"
			condition.LastTransitionTime = kapiunversioned.Now()
			knode, err = master.kClient.Nodes().UpdateStatus(knode)
			if err == nil {
				cleared = true
			}
		}
		return err
	})
	if resultErr != nil {
		utilruntime.HandleError(fmt.Errorf("Status update failed for local node: %v", resultErr))
	} else if cleared {
		log.Infof("Cleared node NetworkUnavailable/NoRouteCreated condition for %s", node.ObjectMeta.Name)
	}
}

func (master *OsdnMaster) watchNodes() {
	nodeAddressMap := map[types.UID]string{}
	RunEventQueue(master.kClient.CoreClient, Nodes, func(delta cache.Delta) error {
		node := delta.Object.(*kapi.Node)
		name := node.ObjectMeta.Name
		uid := node.ObjectMeta.UID

		nodeIP, err := getNodeIP(node)
		if err != nil {
			return fmt.Errorf("failed to get node IP for %s, skipping event: %v, node: %v", name, delta.Type, node)
		}

		switch delta.Type {
		case cache.Sync, cache.Added, cache.Updated:
			master.clearInitialNodeNetworkUnavailableCondition(node)

			if oldNodeIP, ok := nodeAddressMap[uid]; ok && (oldNodeIP == nodeIP) {
				break
			}
			// Node status is frequently updated by kubelet, so log only if the above condition is not met
			log.V(5).Infof("Watch %s event for Node %q", delta.Type, name)

			err = master.addNode(name, nodeIP, nil)
			if err != nil {
				return fmt.Errorf("error creating subnet for node %s, ip %s: %v", name, nodeIP, err)
			}
			nodeAddressMap[uid] = nodeIP
		case cache.Deleted:
			log.V(5).Infof("Watch %s event for Node %q", delta.Type, name)
			delete(nodeAddressMap, uid)

			err = master.deleteNode(name)
			if err != nil {
				return fmt.Errorf("Error deleting node %s: %v", name, err)
			}
		}
		return nil
	})
}

func (node *OsdnNode) SubnetStartNode() error {
	go utilwait.Forever(node.watchSubnets, 0)
	return nil
}

// Only run on the master
// Watch for all hostsubnet events and if one is found with the right annotation, use the SubnetAllocator to dole a real subnet
func (master *OsdnMaster) watchSubnets() {
	RunEventQueue(master.osClient, HostSubnets, func(delta cache.Delta) error {
		hs := delta.Object.(*osapi.HostSubnet)
		name := hs.ObjectMeta.Name
		hostIP := hs.HostIP
		subnet := hs.Subnet

		log.V(5).Infof("Watch %s event for HostSubnet %q", delta.Type, hs.ObjectMeta.Name)
		switch delta.Type {
		case cache.Sync, cache.Added, cache.Updated:
			if _, ok := hs.Annotations[osapi.AssignHostSubnetAnnotation]; ok {
				// Delete the annotated hostsubnet and create a new one with an assigned subnet
				// We do not update (instead of delete+create) because the watchSubnets on the nodes
				// will skip the event if it finds that the hostsubnet has the same host
				// And we cannot fix the watchSubnets code for node because it will break migration if
				// nodes are upgraded after the master
				err := master.osClient.HostSubnets().Delete(name)
				if err != nil {
					log.Errorf("Error in deleting annotated subnet from master, name: %s, ip %s: %v", name, hostIP, err)
					return nil
				}
				var hsAnnotations map[string]string
				if vnid, ok := hs.Annotations[osapi.FixedVnidHost]; ok {
					vnidInt, err := strconv.Atoi(vnid)
					if err == nil && vnidInt >= 0 && uint32(vnidInt) <= osapi.MaxVNID {
						hsAnnotations = make(map[string]string)
						hsAnnotations[osapi.FixedVnidHost] = strconv.Itoa(vnidInt)
					} else {
						log.Errorf("Vnid %s is an invalid value for annotation %s. Annotation will be ignored.", vnid, osapi.FixedVnidHost)
					}
				}
				err = master.addNode(name, hostIP, hsAnnotations)
				if err != nil {
					log.Errorf("Error creating subnet for node %s, ip %s: %v", name, hostIP, err)
					return nil
				}
			}
		case cache.Deleted:
			if _, ok := hs.Annotations[osapi.AssignHostSubnetAnnotation]; !ok {
				// release the subnet
				_, ipnet, err := net.ParseCIDR(subnet)
				if err != nil {
					return fmt.Errorf("Error parsing subnet %q for node %q for deletion: %v", subnet, name, err)
				}
				master.subnetAllocator.ReleaseNetwork(ipnet)
			}
		}
		return nil
	})
}

// Only run on the nodes
func (node *OsdnNode) watchSubnets() {
	subnets := make(map[string]*osapi.HostSubnet)
	RunEventQueue(node.osClient, HostSubnets, func(delta cache.Delta) error {
		hs := delta.Object.(*osapi.HostSubnet)
		if hs.HostIP == node.localIP {
			return nil
		}

		log.V(5).Infof("Watch %s event for HostSubnet %q", delta.Type, hs.ObjectMeta.Name)
		switch delta.Type {
		case cache.Sync, cache.Added, cache.Updated:
			oldSubnet, exists := subnets[string(hs.UID)]
			if exists {
				if oldSubnet.HostIP == hs.HostIP {
					break
				} else {
					// Delete old subnet rules
					if err := node.DeleteHostSubnetRules(oldSubnet); err != nil {
						return err
					}
				}
			}
			if err := node.networkInfo.validateNodeIP(hs.HostIP); err != nil {
				log.Warningf("Ignoring invalid subnet for node %s: %v", hs.HostIP, err)
				break
			}

			if err := node.AddHostSubnetRules(hs); err != nil {
				return err
			}
			subnets[string(hs.UID)] = hs
		case cache.Deleted:
			delete(subnets, string(hs.UID))
			if err := node.DeleteHostSubnetRules(hs); err != nil {
				return err
			}
		}
		return nil
	})
}
<commit_msg>fix for bz1400609; if the node status flips on the order of ip addresses (when there are multiple NICs to report), do not let the SDN chase it<commit_after>package plugin

import (
	"fmt"
	"net"
	"strconv"

	log "github.com/golang/glog"

	kapi "k8s.io/kubernetes/pkg/api"
	kapiunversioned "k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/client/cache"
	kclient "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/types"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	utilwait "k8s.io/kubernetes/pkg/util/wait"

	osapi "github.com/openshift/origin/pkg/sdn/api"
	"github.com/openshift/origin/pkg/util/netutils"
)

func (master *OsdnMaster) SubnetStartMaster(clusterNetwork *net.IPNet, hostSubnetLength uint32) error {
	subrange := make([]string, 0)
	subnets, err := master.osClient.HostSubnets().List(kapi.ListOptions{})
	if err != nil {
		log.Errorf("Error in initializing/fetching subnets: %v", err)
		return err
	}
	for _, sub := range subnets.Items {
		subrange = append(subrange, sub.Subnet)
		if err = master.networkInfo.validateNodeIP(sub.HostIP); err != nil {
			// Don't error out; just warn so the error can be corrected with 'oc'
			log.Errorf("Failed to validate HostSubnet %s: %v", hostSubnetToString(&sub), err)
		} else {
			log.Infof("Found existing HostSubnet %s", hostSubnetToString(&sub))
		}
	}

	master.subnetAllocator, err = netutils.NewSubnetAllocator(clusterNetwork.String(), hostSubnetLength, subrange)
	if err != nil {
		return err
	}

	go utilwait.Forever(master.watchNodes, 0)
	go utilwait.Forever(master.watchSubnets, 0)
	return nil
}

func (master *OsdnMaster) addNode(nodeName string, nodeIP string, hsAnnotations map[string]string) error {
	// Validate node IP before proceeding
	if err := master.networkInfo.validateNodeIP(nodeIP); err != nil {
		return err
	}

	// Check if subnet needs to be created or updated
	sub, err := master.osClient.HostSubnets().Get(nodeName)
	if err == nil {
		if sub.HostIP == nodeIP {
			return nil
		} else {
			// Node IP changed, update old subnet
			sub.HostIP = nodeIP
			sub, err = master.osClient.HostSubnets().Update(sub)
			if err != nil {
				return fmt.Errorf("Error updating subnet %s for node %s: %v", sub.Subnet, nodeName, err)
			}
			log.Infof("Updated HostSubnet %s", hostSubnetToString(sub))
			return nil
		}
	}

	// Create new subnet
	sn, err := master.subnetAllocator.GetNetwork()
	if err != nil {
		return fmt.Errorf("Error allocating network for node %s: %v", nodeName, err)
	}

	sub = &osapi.HostSubnet{
		TypeMeta:   kapiunversioned.TypeMeta{Kind: "HostSubnet"},
		ObjectMeta: kapi.ObjectMeta{Name: nodeName, Annotations: hsAnnotations},
		Host:       nodeName,
		HostIP:     nodeIP,
		Subnet:     sn.String(),
	}
	sub, err = master.osClient.HostSubnets().Create(sub)
	if err != nil {
		master.subnetAllocator.ReleaseNetwork(sn)
		return fmt.Errorf("Error creating subnet %s for node %s: %v", sn.String(), nodeName, err)
	}
	log.Infof("Created HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func (master *OsdnMaster) deleteNode(nodeName string) error {
	sub, err := master.osClient.HostSubnets().Get(nodeName)
	if err != nil {
		return fmt.Errorf("Error fetching subnet for node %q for deletion: %v", nodeName, err)
	}
	err = master.osClient.HostSubnets().Delete(nodeName)
	if err != nil {
		return fmt.Errorf("Error deleting subnet %v for node %q: %v", sub, nodeName, err)
	}

	log.Infof("Deleted HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func isValidNodeIP(node *kapi.Node, nodeIP string) bool {
	for _, addr := range node.Status.Addresses {
		if addr.Address == nodeIP {
			return true
		}
	}
	return false
}

func getNodeIP(node *kapi.Node) (string, error) {
	if len(node.Status.Addresses) > 0 && node.Status.Addresses[0].Address != "" {
		return node.Status.Addresses[0].Address, nil
	} else {
		return netutils.GetNodeIP(node.Name)
	}
}

// Because openshift-sdn uses an overlay and doesn't need GCE Routes, we need to
// clear the NetworkUnavailable condition that kubelet adds to initial node
// status when using GCE.
// TODO: make upstream kubelet more flexible with overlays and GCE so this
// condition doesn't get added for network plugins that don't want it, and then
// we can remove this function.
func (master *OsdnMaster) clearInitialNodeNetworkUnavailableCondition(node *kapi.Node) {
	knode := node
	cleared := false
	resultErr := kclient.RetryOnConflict(kclient.DefaultBackoff, func() error {
		var err error

		if knode != node {
			knode, err = master.kClient.Nodes().Get(node.ObjectMeta.Name)
			if err != nil {
				return err
			}
		}

		// Let caller modify knode's status, then push to api server.
		_, condition := kapi.GetNodeCondition(&node.Status, kapi.NodeNetworkUnavailable)
		if condition != nil && condition.Status != kapi.ConditionFalse && condition.Reason == "NoRouteCreated" {
			condition.Status = kapi.ConditionFalse
			condition.Reason = "RouteCreated"
			condition.Message = "openshift-sdn cleared kubelet-set NoRouteCreated"
			condition.LastTransitionTime = kapiunversioned.Now()
			knode, err = master.kClient.Nodes().UpdateStatus(knode)
			if err == nil {
				cleared = true
			}
		}
		return err
	})
	if resultErr != nil {
		utilruntime.HandleError(fmt.Errorf("Status update failed for local node: %v", resultErr))
	} else if cleared {
		log.Infof("Cleared node NetworkUnavailable/NoRouteCreated condition for %s", node.ObjectMeta.Name)
	}
}

func (master *OsdnMaster) watchNodes() {
	nodeAddressMap := map[types.UID]string{}
	RunEventQueue(master.kClient.CoreClient, Nodes, func(delta cache.Delta) error {
		node := delta.Object.(*kapi.Node)
		name := node.ObjectMeta.Name
		uid := node.ObjectMeta.UID

		nodeIP, err := getNodeIP(node)
		if err != nil {
			return fmt.Errorf("failed to get node IP for %s, skipping event: %v, node: %v", name, delta.Type, node)
		}

		switch delta.Type {
		case cache.Sync, cache.Added, cache.Updated:
			master.clearInitialNodeNetworkUnavailableCondition(node)

			if oldNodeIP, ok := nodeAddressMap[uid]; ok && ((nodeIP == oldNodeIP) || isValidNodeIP(node, oldNodeIP)) {
				break
			}
			// Node status is frequently updated by kubelet, so log only if the above condition is not met
			log.V(5).Infof("Watch %s event for Node %q", delta.Type, name)

			err = master.addNode(name, nodeIP, nil)
			if err != nil {
				return fmt.Errorf("error creating subnet for node %s, ip %s: %v", name, nodeIP, err)
			}
			nodeAddressMap[uid] = nodeIP
		case cache.Deleted:
			log.V(5).Infof("Watch %s event for Node %q", delta.Type, name)
			delete(nodeAddressMap, uid)

			err = master.deleteNode(name)
			if err != nil {
				return fmt.Errorf("Error deleting node %s: %v", name, err)
			}
		}
		return nil
	})
}

func (node *OsdnNode) SubnetStartNode() error {
	go utilwait.Forever(node.watchSubnets, 0)
	return nil
}

// Only run on the master
// Watch for all hostsubnet events and if one is found with the right annotation, use the SubnetAllocator to dole a real subnet
func (master *OsdnMaster) watchSubnets() {
	RunEventQueue(master.osClient, HostSubnets, func(delta cache.Delta) error {
		hs := delta.Object.(*osapi.HostSubnet)
		name := hs.ObjectMeta.Name
		hostIP := hs.HostIP
		subnet := hs.Subnet

		log.V(5).Infof("Watch %s event for HostSubnet %q", delta.Type, hs.ObjectMeta.Name)
		switch delta.Type {
		case cache.Sync, cache.Added, cache.Updated:
			if _, ok := hs.Annotations[osapi.AssignHostSubnetAnnotation]; ok {
				// Delete the annotated hostsubnet and create a new one with an assigned subnet
				// We do not update (instead of delete+create) because the watchSubnets on the nodes
				// will skip the event if it finds that the hostsubnet has the same host
				// And we cannot fix the watchSubnets code for node because it will break migration if
				// nodes are upgraded after the master
				err := master.osClient.HostSubnets().Delete(name)
				if err != nil {
					log.Errorf("Error in deleting annotated subnet from master, name: %s, ip %s: %v", name, hostIP, err)
					return nil
				}
				var hsAnnotations map[string]string
				if vnid, ok := hs.Annotations[osapi.FixedVnidHost]; ok {
					vnidInt, err := strconv.Atoi(vnid)
					if err == nil && vnidInt >= 0 && uint32(vnidInt) <= osapi.MaxVNID {
						hsAnnotations = make(map[string]string)
						hsAnnotations[osapi.FixedVnidHost] = strconv.Itoa(vnidInt)
					} else {
						log.Errorf("Vnid %s is an invalid value for annotation %s. Annotation will be ignored.", vnid, osapi.FixedVnidHost)
					}
				}
				err = master.addNode(name, hostIP, hsAnnotations)
				if err != nil {
					log.Errorf("Error creating subnet for node %s, ip %s: %v", name, hostIP, err)
					return nil
				}
			}
		case cache.Deleted:
			if _, ok := hs.Annotations[osapi.AssignHostSubnetAnnotation]; !ok {
				// release the subnet
				_, ipnet, err := net.ParseCIDR(subnet)
				if err != nil {
					return fmt.Errorf("Error parsing subnet %q for node %q for deletion: %v", subnet, name, err)
				}
				master.subnetAllocator.ReleaseNetwork(ipnet)
			}
		}
		return nil
	})
}

// Only run on the nodes
func (node *OsdnNode) watchSubnets() {
	subnets := make(map[string]*osapi.HostSubnet)
	RunEventQueue(node.osClient, HostSubnets, func(delta cache.Delta) error {
		hs := delta.Object.(*osapi.HostSubnet)
		if hs.HostIP == node.localIP {
			return nil
		}

		log.V(5).Infof("Watch %s event for HostSubnet %q", delta.Type, hs.ObjectMeta.Name)
		switch delta.Type {
		case cache.Sync, cache.Added, cache.Updated:
			oldSubnet, exists := subnets[string(hs.UID)]
			if exists {
				if oldSubnet.HostIP == hs.HostIP {
					break
				} else {
					// Delete old subnet rules
					if err := node.DeleteHostSubnetRules(oldSubnet); err != nil {
						return err
					}
				}
			}
			if err := node.networkInfo.validateNodeIP(hs.HostIP); err != nil {
				log.Warningf("Ignoring invalid subnet for node %s: %v", hs.HostIP, err)
				break
			}

			if err := node.AddHostSubnetRules(hs); err != nil {
				return err
			}
			subnets[string(hs.UID)] = hs
		case cache.Deleted:
			delete(subnets, string(hs.UID))
			if err := node.DeleteHostSubnetRules(hs); err != nil {
				return err
			}
		}
		return nil
	})
}
<|endoftext|>


<commit_before>package storage

import (
	"os"
	"path"
	"reflect"
	"testing"
	"time"

	"github.com/taku-k/polymerase/pkg/base"
)

func NewLocalBackupStorageForTest() *LocalBackupStorage {
	dir, _ := os.Getwd()
	cfg := &base.Config{}
	cfg.InitDefaults()
	return &LocalBackupStorage{
		RootDir:    path.Join(dir, "testdata"),
		TimeFormat: cfg.TimeFormat,
	}
}

func TestLocalBackupStorage_GetLastLSN(t *testing.T) {
	s := NewLocalBackupStorageForTest()
	a, err := s.GetLastLSN("test-db1")
	e := "110"
	if err != nil {
		t.Errorf(`GetLastLSN("test-db1") is failed: %v`, err)
	}
	if a != e {
		t.Errorf(`GetLastLSN("test-db1") returns wrong lsn: expected = (%v), actual (%v)`, e, a)
	}
}

func TestLocalBackupStorage_SearchStaringPointByLSN(t *testing.T) {
	s := NewLocalBackupStorageForTest()
	a, err := s.SearchStaringPointByLSN("test-db1", "110")
	e := "2017-05-24"
	if err != nil {
		t.Errorf(`SearchStartingPointByLSN("test-db1", "110") is failed: %v`, err)
	}
	if a != e {
		t.Errorf(`SearchStartingPointByLSN("test-db1", "110") returns wrong starting point: expected = (%v), actual (%v)`, e, a)
	}
}

func TestLocalBackupStorage_SearchConsecutiveIncBackups(t *testing.T) {
	s := NewLocalBackupStorageForTest()
	db := "test-db1"
	st := s.GetStorageType()

	var tests = []struct {
		in  string
		out []*BackupFile
	}{
		{
			"2017-05-26",
			[]*BackupFile{
				{
					StorageType: st,
					BackupType:  "incremental",
					Key:         "test-db1/2017-05-24/2017-05-25-15-04-05",
				},
				{
					StorageType: st,
					BackupType:  "full-backuped",
					Key:         "test-db1/2017-05-24/2017-05-24-15-04-05",
				},
			},
		},
		{
			"2017-05-25",
			[]*BackupFile{
				{
					StorageType: st,
					BackupType:  "full-backuped",
					Key:         "test-db1/2017-05-24/2017-05-24-15-04-05",
				},
			},
		},
		{
			"2017-05-19",
			[]*BackupFile{
				{
					StorageType: st,
					BackupType:  "incremental",
					Key:         "test-db1/2017-05-17/2017-05-18-15-04-05",
				},
				{
					StorageType: st,
					BackupType:  "full-backuped",
					Key:         "test-db1/2017-05-17/2017-05-17-15-04-05",
				},
			},
		},
	}
	for _, tt := range tests {
		f, _ := time.Parse("2006-01-02", tt.in)
		a, err := s.SearchConsecutiveIncBackups(db, f)
		if err != nil {
			t.Errorf(`SearchConsecutiveIncBackups(%v, %v) is failed: %v`, db, f, err)
		}
		if !reflect.DeepEqual(a, tt.out) {
			t.Errorf(`SearchConsecutiveIncBackups(%v, %v) returns wrong keys: expected = (%v), actual = (%v)`, db, f, tt.out, a)

		}
	}
}
<commit_msg>Pass test<commit_after>package storage

import (
	"os"
	"path"
	"reflect"
	"testing"
	"time"

	"github.com/taku-k/polymerase/pkg/base"
)

func NewLocalBackupStorageForTest() *LocalBackupStorage {
	dir, _ := os.Getwd()
	cfg := &base.Config{}
	cfg.InitDefaults()
	return &LocalBackupStorage{
		RootDir:    path.Join(dir, "testdata"),
		TimeFormat: cfg.TimeFormat,
	}
}

func TestLocalBackupStorage_GetLastLSN(t *testing.T) {
	s := NewLocalBackupStorageForTest()
	a, err := s.GetLastLSN("test-db1")
	e := "110"
	if err != nil {
		t.Errorf(`GetLastLSN("test-db1") is failed: %v`, err)
	}
	if a != e {
		t.Errorf(`GetLastLSN("test-db1") returns wrong lsn: expected = (%v), actual (%v)`, e, a)
	}
}

func TestLocalBackupStorage_SearchStaringPointByLSN(t *testing.T) {
	s := NewLocalBackupStorageForTest()
	a, err := s.SearchStaringPointByLSN("test-db1", "110")
	e := "2017-05-24-15-04-05"
	if err != nil {
		t.Errorf(`SearchStartingPointByLSN("test-db1", "110") is failed: %v`, err)
	}
	if a != e {
		t.Errorf(`SearchStartingPointByLSN("test-db1", "110") returns wrong starting point: expected = (%v), actual (%v)`, e, a)
	}
}

func TestLocalBackupStorage_SearchConsecutiveIncBackups(t *testing.T) {
	s := NewLocalBackupStorageForTest()
	db := "test-db1"
	st := s.GetStorageType()

	var tests = []struct {
		in  string
		out []*BackupFile
	}{
		{
			"2017-05-26",
			[]*BackupFile{
				{
					StorageType: st,
					BackupType:  "incremental",
					Key:         "test-db1/2017-05-24-15-04-05/2017-05-25-15-04-05",
				},
				{
					StorageType: st,
					BackupType:  "full-backuped",
					Key:         "test-db1/2017-05-24-15-04-05/2017-05-24-15-04-05",
				},
			},
		},
		{
			"2017-05-25",
			[]*BackupFile{
				{
					StorageType: st,
					BackupType:  "full-backuped",
					Key:         "test-db1/2017-05-24-15-04-05/2017-05-24-15-04-05",
				},
			},
		},
		{
			"2017-05-19",
			[]*BackupFile{
				{
					StorageType: st,
					BackupType:  "incremental",
					Key:         "test-db1/2017-05-17-15-04-05/2017-05-18-15-04-05",
				},
				{
					StorageType: st,
					BackupType:  "full-backuped",
					Key:         "test-db1/2017-05-17-15-04-05/2017-05-17-15-04-05",
				},
			},
		},
	}
	for _, tt := range tests {
		f, _ := time.Parse("2006-01-02", tt.in)
		a, err := s.SearchConsecutiveIncBackups(db, f)
		if err != nil {
			t.Errorf(`SearchConsecutiveIncBackups(%v, %v) is failed: %v`, db, f, err)
		}
		if !reflect.DeepEqual(a, tt.out) {
			t.Errorf(`SearchConsecutiveIncBackups(%v, %v) returns wrong keys: expected = (%v), actual = (%v)`, db, f, tt.out, a)

		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Update REST API<commit_after><|endoftext|>


<commit_before>package git

import (
	"compress/zlib"
	"fmt"
	"io"
	"math"

	"github.com/ipfs/go-ipfs/core/coredag"
	"github.com/ipfs/go-ipfs/plugin"

	"gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
	"gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
	mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash"
	git "gx/ipfs/QmaWPGUJJFb75PvWwnkXAxYXUtsRFCRQiCZhpr5ks4F9K9/go-ipld-git"
)

// Plugins is exported list of plugins that will be loaded
var Plugins = []plugin.Plugin{
	&gitPlugin{},
}

type gitPlugin struct{}

var _ plugin.PluginIPLD = (*gitPlugin)(nil)

func (*gitPlugin) Name() string {
	return "ipld-git"
}

func (*gitPlugin) Version() string {
	return "0.0.1"
}

func (*gitPlugin) Init() error {
	return nil
}

func (*gitPlugin) RegisterBlockDecoders(dec format.BlockDecoder) error {
	dec.Register(cid.GitRaw, git.DecodeBlock)
	return nil
}

func (*gitPlugin) RegisterInputEncParsers(iec coredag.InputEncParsers) error {
	iec.AddParser("raw", "git", parseRawGit)
	iec.AddParser("zlib", "git", parseZlibGit)
	return nil
}

func parseRawGit(r io.Reader, mhType uint64, mhLen int) ([]format.Node, error) {
	if mhType != math.MaxUint64 && mhType != mh.SHA1 {
		return nil, fmt.Errorf("unsupported mhType %d", mhType)
	}

	if mhLen != -1 && mhLen != mh.DefaultLengths[mh.SHA1] {
		return nil, fmt.Errorf("invalid mhLen %d", mhType)
	}

	nd, err := git.ParseObject(r)
	if err != nil {
		return nil, err
	}

	return []format.Node{nd}, nil
}

func parseZlibGit(r io.Reader, mhType uint64, mhLen int) ([]format.Node, error) {
	rc, err := zlib.NewReader(r)
	if err != nil {
		return nil, err
	}

	defer rc.Close()
	return parseRawGit(rc, mhType, mhLen)
}
<commit_msg>small typo in git plugin<commit_after>package git

import (
	"compress/zlib"
	"fmt"
	"io"
	"math"

	"github.com/ipfs/go-ipfs/core/coredag"
	"github.com/ipfs/go-ipfs/plugin"

	"gx/ipfs/QmNp85zy9RLrQ5oQD4hPyS39ezrrXpcaa7R4Y9kxdWQLLQ/go-cid"
	"gx/ipfs/QmPN7cwmpcc4DWXb4KTB9dNAJgjuPY69h3npsMfhRrQL9c/go-ipld-format"
	mh "gx/ipfs/QmU9a9NV9RdPNwZQDYd5uKsm6N6LJLSvLbywDDYFbaaC6P/go-multihash"
	git "gx/ipfs/QmaWPGUJJFb75PvWwnkXAxYXUtsRFCRQiCZhpr5ks4F9K9/go-ipld-git"
)

// Plugins is exported list of plugins that will be loaded
var Plugins = []plugin.Plugin{
	&gitPlugin{},
}

type gitPlugin struct{}

var _ plugin.PluginIPLD = (*gitPlugin)(nil)

func (*gitPlugin) Name() string {
	return "ipld-git"
}

func (*gitPlugin) Version() string {
	return "0.0.1"
}

func (*gitPlugin) Init() error {
	return nil
}

func (*gitPlugin) RegisterBlockDecoders(dec format.BlockDecoder) error {
	dec.Register(cid.GitRaw, git.DecodeBlock)
	return nil
}

func (*gitPlugin) RegisterInputEncParsers(iec coredag.InputEncParsers) error {
	iec.AddParser("raw", "git", parseRawGit)
	iec.AddParser("zlib", "git", parseZlibGit)
	return nil
}

func parseRawGit(r io.Reader, mhType uint64, mhLen int) ([]format.Node, error) {
	if mhType != math.MaxUint64 && mhType != mh.SHA1 {
		return nil, fmt.Errorf("unsupported mhType %d", mhType)
	}

	if mhLen != -1 && mhLen != mh.DefaultLengths[mh.SHA1] {
		return nil, fmt.Errorf("invalid mhLen %d", mhLen)
	}

	nd, err := git.ParseObject(r)
	if err != nil {
		return nil, err
	}

	return []format.Node{nd}, nil
}

func parseZlibGit(r io.Reader, mhType uint64, mhLen int) ([]format.Node, error) {
	rc, err := zlib.NewReader(r)
	if err != nil {
		return nil, err
	}

	defer rc.Close()
	return parseRawGit(rc, mhType, mhLen)
}
<|endoftext|>


<commit_before>package plugin

import (
	"database/sql"
	"testing"
	"time"

	_ "github.com/lib/pq"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/vektra/cypress"
	"github.com/vektra/neko"
)

func TestPostgresql(t *testing.T) {

	n := neko.Start(t)

	var db MockDBInterface

	n.CheckMock(&db.Mock)

	n.It("sets up a db", func() {
		var p PostgreSQL
		p.Init(&db)

		db.On("Ping").Return(nil)
		db.On("Exec", cCreateTable, []interface{}{}).Return(mock.Anything, nil)
		db.On("Exec", cEnableHstore, []interface{}{}).Return(mock.Anything, nil)

		err := p.SetupDB()

		require.NoError(t, err)
	})

	n.It("receives a message", func() {
		var p PostgreSQL
		p.Init(&db)

		msg := cypress.Log()

		db.On("Exec", cAddRow, []interface{}{
			msg.GetTimestamp().Time().Format(time.RFC3339Nano),
			msg.Version,
			msg.Type,
			msg.SessionId,
			msg.HstoreAttributes(),
			msg.HstoreTags()}).Return(mock.Anything, nil)

		err := p.Receive(msg)

		require.NoError(t, err)
	})

	n.Meow()
}

func TestPostgreSQLOnline(t *testing.T) {
	n := neko.Start(t)

	// TODO: use ENV vars
	db, err := sql.Open("postgres", "user=jlsuttles dbname=vektra_test sslmode=disable")
	if err != nil {
		t.Skip()
	}

	n.It("sets up a db", func() {
		var p PostgreSQL
		p.Init(db)

		err := p.SetupDB()
		if err != nil {
			require.NoError(t, err)
		}

		require.NoError(t, err)
		// TODO: write sql stmt to check
	})

	n.It("receives a message", func() {
		var p PostgreSQL
		p.Init(db)

		err := p.SetupDB()
		require.NoError(t, err)

		msg := cypress.Log()
		msg.Add("message", "Hiiiii")
		msg.AddTag("key", "value")
		msg.AddTag("key2", "")

		err = p.Receive(msg)

		if err != nil {
			panic(err)
		}

		require.NoError(t, err)
		// TODO: write sql stmt to check
	})

	n.Meow()
}
<commit_msg>Use nil slice []interface{}(nil)<commit_after>package plugin

import (
	"database/sql"
	"testing"
	"time"

	_ "github.com/lib/pq"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/vektra/cypress"
	"github.com/vektra/neko"
)

func TestPostgresql(t *testing.T) {

	n := neko.Start(t)

	var db MockDBInterface

	n.CheckMock(&db.Mock)

	n.It("sets up a db", func() {
		var p PostgreSQL
		p.Init(&db)

		db.On("Ping").Return(nil)
		db.On("Exec", cEnableHstore, []interface{}(nil)).Return(mock.Anything, nil)
		db.On("Exec", cCreateTable, []interface{}(nil)).Return(mock.Anything, nil)

		err := p.SetupDB()

		require.NoError(t, err)
	})

	n.It("receives a message", func() {
		var p PostgreSQL
		p.Init(&db)

		msg := cypress.Log()

		db.On("Exec", cAddRow, []interface{}{
			msg.GetTimestamp().Time().Format(time.RFC3339Nano),
			msg.Version,
			msg.Type,
			msg.SessionId,
			msg.HstoreAttributes(),
			msg.HstoreTags()}).Return(mock.Anything, nil)

		err := p.Receive(msg)

		require.NoError(t, err)
	})

	n.Meow()
}

func TestPostgreSQLOnline(t *testing.T) {
	n := neko.Start(t)

	// TODO: use ENV vars
	db, err := sql.Open("postgres", "user=jlsuttles dbname=vektra_test sslmode=disable")
	if err != nil {
		t.Skip()
	}

	n.It("sets up a db", func() {
		var p PostgreSQL
		p.Init(db)

		err := p.SetupDB()
		if err != nil {
			require.NoError(t, err)
		}

		require.NoError(t, err)
		// TODO: write sql stmt to check
	})

	n.It("receives a message", func() {
		var p PostgreSQL
		p.Init(db)

		err := p.SetupDB()
		require.NoError(t, err)

		msg := cypress.Log()
		msg.Add("message", "Hiiiii")
		msg.AddTag("key", "value")
		msg.AddTag("key2", "")

		err = p.Receive(msg)

		if err != nil {
			panic(err)
		}

		require.NoError(t, err)
		// TODO: write sql stmt to check
	})

	n.Meow()
}
<|endoftext|>


<commit_before>package npm

import (
	"fmt"

	"github.com/drone/config"
	"github.com/drone/drone/plugin/condition"
	"github.com/drone/drone/shared/build/buildfile"
)

// command to create the .npmrc file that stores
// the login credentials, as opposed to npm login
// which requires stdin.
const CmdLogin = `
cat <<EOF > ~/.npmrc
_auth = $(echo "%s:%s" | tr -d "\r\n" | base64)
email = %s
EOF
`

// command to publish npm package if not published
const CmdPublish = `
_NPM_PACKAGE_NAME=$(cd %s && npm list | head -n 1 | cut -d ' ' -f1)
_NPM_PACKAGE_TAG="%s"
if [ -z "$(npm info ${_NPM_PACKAGE_NAME})" ]
then
	npm publish %s
	[ -n ${_NPM_PACKAGE_TAG} ] && npm tag ${_NPM_PACKAGE_NAME} ${_NPM_PACKAGE_TAG}
else
	echo "skipping publish, package ${_NPM_PACKAGE_NAME} already published"
fi
unset _NPM_PACKAGE_NAME
unset _NPM_PACKAGE_TAG
`

const (
	CmdAlwaysAuth  = "npm set always-auth true"
	CmdSetRegistry = "npm config set registry %s"
)

var (
	DefaultUser  = config.String("npm-user", "")
	DefaultPass  = config.String("npm-pass", "")
	DefaultEmail = config.String("npm-email", "")
)

type NPM struct {
	// The Email address used by NPM to connect
	// and publish to a repository
	Email string `yaml:"email,omitempty"`

	// The Username used by NPM to connect
	// and publish to a repository
	Username string `yaml:"username,omitempty"`

	// The Password used by NPM to connect
	// and publish to a repository
	Password string `yaml:"password,omitempty"`

	// The registry URL of custom npm repository
	Registry string `yaml:"registry,omitempty"`

	// A folder containing the package.json file
	Folder string `yaml:"folder,omitempty"`

	// Registers the published package with the given tag
	Tag string `yaml:"tag,omitempty"`

	// Force npm to always require authentication when accessing the registry.
	AlwaysAuth bool `yaml:"always_auth"`

	Condition *condition.Condition `yaml:"when,omitempty"`
}

func (n *NPM) Write(f *buildfile.Buildfile) {
	// If the yaml doesn't provide a username or password
	// we should attempt to use the global defaults.
	if len(n.Email) == 0 ||
		len(n.Username) == 0 ||
		len(n.Password) == 0 {
		n.Username = *DefaultUser
		n.Password = *DefaultPass
		n.Email = *DefaultEmail
	}

	// If the yaml doesn't provide a username or password,
	// and there was not global configuration defined, EXIT.
	if len(n.Email) == 0 ||
		len(n.Username) == 0 ||
		len(n.Password) == 0 {
		return
	}

	// Setup the npm credentials
	f.WriteCmdSilent(fmt.Sprintf(CmdLogin, n.Username, n.Password, n.Email))

	// Setup custom npm registry
	if len(n.Registry) != 0 {
		f.WriteCmd(fmt.Sprintf(CmdSetRegistry, n.Registry))
	}

	// Set npm to always authenticate
	if n.AlwaysAuth {
		f.WriteCmd(CmdAlwaysAuth)
	}

	if len(n.Folder) == 0 {
		n.Folder = "."
	}

	f.WriteString(fmt.Sprintf(CmdPublish, n.Folder, n.Tag, n.Folder))
}

func (n *NPM) GetCondition() *condition.Condition {
	return n.Condition
}
<commit_msg>publish npm package if not exist on registry #799<commit_after>package npm

import (
	"fmt"

	"github.com/drone/config"
	"github.com/drone/drone/plugin/condition"
	"github.com/drone/drone/shared/build/buildfile"
)

// command to create the .npmrc file that stores
// the login credentials, as opposed to npm login
// which requires stdin.
const CmdLogin = `
cat <<EOF > ~/.npmrc
_auth = $(echo "%s:%s" | tr -d "\r\n" | base64)
email = %s
EOF
`

// command to publish npm package if not published
const CmdPublish = `
_NPM_PACKAGE_NAME=$(cd %s && npm list | head -n 1 | cut -d ' ' -f1)
_NPM_PACKAGE_TAG="%s"
if [ -z "$(npm info ${_NPM_PACKAGE_NAME} 2> /dev/null)" ]
then
	npm publish %s
	[ -n ${_NPM_PACKAGE_TAG} ] && npm tag ${_NPM_PACKAGE_NAME} ${_NPM_PACKAGE_TAG}
else
	echo "skipping publish, package ${_NPM_PACKAGE_NAME} already published"
fi
unset _NPM_PACKAGE_NAME
unset _NPM_PACKAGE_TAG
`

const (
	CmdAlwaysAuth  = "npm set always-auth true"
	CmdSetRegistry = "npm config set registry %s"
)

var (
	DefaultUser  = config.String("npm-user", "")
	DefaultPass  = config.String("npm-pass", "")
	DefaultEmail = config.String("npm-email", "")
)

type NPM struct {
	// The Email address used by NPM to connect
	// and publish to a repository
	Email string `yaml:"email,omitempty"`

	// The Username used by NPM to connect
	// and publish to a repository
	Username string `yaml:"username,omitempty"`

	// The Password used by NPM to connect
	// and publish to a repository
	Password string `yaml:"password,omitempty"`

	// The registry URL of custom npm repository
	Registry string `yaml:"registry,omitempty"`

	// A folder containing the package.json file
	Folder string `yaml:"folder,omitempty"`

	// Registers the published package with the given tag
	Tag string `yaml:"tag,omitempty"`

	// Force npm to always require authentication when accessing the registry.
	AlwaysAuth bool `yaml:"always_auth"`

	Condition *condition.Condition `yaml:"when,omitempty"`
}

func (n *NPM) Write(f *buildfile.Buildfile) {
	// If the yaml doesn't provide a username or password
	// we should attempt to use the global defaults.
	if len(n.Email) == 0 ||
		len(n.Username) == 0 ||
		len(n.Password) == 0 {
		n.Username = *DefaultUser
		n.Password = *DefaultPass
		n.Email = *DefaultEmail
	}

	// If the yaml doesn't provide a username or password,
	// and there was not global configuration defined, EXIT.
	if len(n.Email) == 0 ||
		len(n.Username) == 0 ||
		len(n.Password) == 0 {
		return
	}

	// Setup the npm credentials
	f.WriteCmdSilent(fmt.Sprintf(CmdLogin, n.Username, n.Password, n.Email))

	// Setup custom npm registry
	if len(n.Registry) != 0 {
		f.WriteCmd(fmt.Sprintf(CmdSetRegistry, n.Registry))
	}

	// Set npm to always authenticate
	if n.AlwaysAuth {
		f.WriteCmd(CmdAlwaysAuth)
	}

	if len(n.Folder) == 0 {
		n.Folder = "."
	}

	f.WriteString(fmt.Sprintf(CmdPublish, n.Folder, n.Tag, n.Folder))
}

func (n *NPM) GetCondition() *condition.Condition {
	return n.Condition
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"errors"
	"github.com/megamsys/libgo/action"
	"github.com/megamsys/libgo/exec"
	log "code.google.com/p/log4go"
	"strings"
	"github.com/tsuru/config"
	"os"
	"path"
	"bufio"
	"github.com/megamsys/megamd/provisioner"
)

func CommandExecutor(app *provisioner.AssemblyResult) (action.Result, error) {
    var e exec.OsExecutor
    var commandWords []string

    commandWords = strings.Fields(app.Command)

    megam_home, ckberr := config.GetString("MEGAM_HOME")
	if ckberr != nil {
		return nil, ckberr
	}
    appName := app.Name + "." + app.Components[0].Inputs.Domain
	basePath := megam_home + "logs"
	dir := path.Join(basePath, appName)

	fileOutPath := path.Join(dir, appName + "_out" )
	fileErrPath := path.Join(dir, appName + "_err" )
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		fmt.Printf("Creating directory: %s\n", dir)
		if errm := os.MkdirAll(dir, 0777); errm != nil {
			return nil, errm
		}
	}
		// open output file
		fout, outerr := os.OpenFile(fileOutPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if outerr != nil {
			return nil, outerr
		}
		defer fout.Close()
		// open Error file
		ferr, errerr := os.OpenFile(fileErrPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if errerr != nil {
			return nil, errerr
		}
		defer ferr.Close()

	foutwriter := bufio.NewWriter(fout)
	ferrwriter := bufio.NewWriter(ferr)
    fmt.Println(commandWords, len(commandWords))
    if len(commandWords) > 0 {
       if err := e.Execute(commandWords[0], commandWords[1:], nil, foutwriter, ferrwriter); err != nil {
           ferrwriter.Flush()
           return nil, err
        }
     }

   foutwriter.Flush()

  return &app, nil
}

var launchedApp = action.Action{
	Name: "launchedapp",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		var app provisioner.AssemblyResult
		switch ctx.Params[0].(type) {
		case provisioner.AssemblyResult:
			app = ctx.Params[0].(provisioner.AssemblyResult)
		case *provisioner.AssemblyResult:
			app = *ctx.Params[0].(*provisioner.AssemblyResult)
		default:
			return nil, errors.New("First parameter must be App or *assemblies.AssemblyResult.")
		}
		app.Command = "knife"
		return CommandExecutor(&app)
	},
	Backward: func(ctx action.BWContext) {
		log.Info("[%s] Nothing to recover")
	},
	MinParams: 1,
}

<commit_msg>undo the command<commit_after>package app

import (
	"fmt"
	"errors"
	"github.com/megamsys/libgo/action"
	"github.com/megamsys/libgo/exec"
	log "code.google.com/p/log4go"
	"strings"
	"github.com/tsuru/config"
	"os"
	"path"
	"bufio"
	"github.com/megamsys/megamd/provisioner"
)

func CommandExecutor(app *provisioner.AssemblyResult) (action.Result, error) {
    var e exec.OsExecutor
    var commandWords []string

    commandWords = strings.Fields(app.Command)

    megam_home, ckberr := config.GetString("MEGAM_HOME")
	if ckberr != nil {
		return nil, ckberr
	}
    appName := app.Name + "." + app.Components[0].Inputs.Domain
	basePath := megam_home + "logs"
	dir := path.Join(basePath, appName)

	fileOutPath := path.Join(dir, appName + "_out" )
	fileErrPath := path.Join(dir, appName + "_err" )
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		fmt.Printf("Creating directory: %s\n", dir)
		if errm := os.MkdirAll(dir, 0777); errm != nil {
			return nil, errm
		}
	}
		// open output file
		fout, outerr := os.OpenFile(fileOutPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if outerr != nil {
			return nil, outerr
		}
		defer fout.Close()
		// open Error file
		ferr, errerr := os.OpenFile(fileErrPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if errerr != nil {
			return nil, errerr
		}
		defer ferr.Close()

	foutwriter := bufio.NewWriter(fout)
	ferrwriter := bufio.NewWriter(ferr)
    fmt.Println(commandWords, len(commandWords))
    if len(commandWords) > 0 {
       if err := e.Execute(commandWords[0], commandWords[1:], nil, foutwriter, ferrwriter); err != nil {
           ferrwriter.Flush()
           return nil, err
        }
     }

   foutwriter.Flush()

  return &app, nil
}

var launchedApp = action.Action{
	Name: "launchedapp",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		var app provisioner.AssemblyResult
		switch ctx.Params[0].(type) {
		case provisioner.AssemblyResult:
			app = ctx.Params[0].(provisioner.AssemblyResult)
		case *provisioner.AssemblyResult:
			app = *ctx.Params[0].(*provisioner.AssemblyResult)
		default:
			return nil, errors.New("First parameter must be App or *assemblies.AssemblyResult.")
		}
		return CommandExecutor(&app)
	},
	Backward: func(ctx action.BWContext) {
		log.Info("[%s] Nothing to recover")
	},
	MinParams: 1,
}

<|endoftext|>