<commit_before>package protocol

import (
	"bytes"
	"reflect"
	"testing"
)

type testType struct {
	Field1   string        `kafka:"min=v0,max=v4,nullable"`
	Field2   int16         `kafka:"min=v2,max=v4"`
	Field3   []byte        `kafka:"min=v2,max=v4,nullable"`
	SubTypes []testSubType `kafka:"min=v1,max=v4"`

	TaggedField1 int8   `kafka:"min=v3,max=v4,tag=0"`
	TaggedField2 string `kafka:"min=v4,max=v4,tag=1"`
}

type testSubType struct {
	SubField1 int8 `kafka:"min=v1,max=v4"`
}

func TestMakeFlexibleTypes(t *testing.T) {
	types := makeTypes(reflect.TypeOf(&testType{}).Elem())
	if len(types) != 5 {
		t.Error(
			"Wrong number of types",
			"expected", 5,
			"got", len(types),
		)
	}

	fv := []int16{}

	for _, to := range types {
		if to.flexible {
			fv = append(fv, to.version)
		}
	}

	if !reflect.DeepEqual([]int16{3, 4}, fv) {
		t.Error(
			"Unexpected flexible versions",
			"expected", []int16{3, 4},
			"got", fv,
		)
	}
}

func TestEncodeDecodeFlexibleType(t *testing.T) {
	f := &testType{
		Field1: "value1",
		Field2: 15,
		Field3: []byte("hello"),
		SubTypes: []testSubType{
			{
				SubField1: 2,
			},
			{
				SubField1: 3,
			},
		},

		TaggedField1: 34,
		TaggedField2: "taggedValue2",
	}

	b := &bytes.Buffer{}
	e := &encoder{writer: b}

	types := makeTypes(reflect.TypeOf(&testType{}).Elem())
	ft := types[4]
	ft.encode(e, valueOf(f))
	if e.err != nil {
		t.Error(
			"Error during encoding",
			"expected", nil,
			"got", e.err,
		)
	}

	exp := []byte{
		// size of "value1" + 1
		7,
		// "value1"
		118, 97, 108, 117, 101, 49,
		// 15 as 16-bit int
		0, 15,
		// size of []byte("hello") + 1
		6,
		// []byte("hello")
		104, 101, 108, 108, 111,
		// size of []SubTypes + 1
		3,
		// 2 as 8-bit int
		2,
		// tag buffer for first SubType struct
		0,
		// 3 as 8-bit int
		3,
		// tag buffer for second SubType struct
		0,
		// number of tagged fields
		2,
		// id of first tagged field
		0,
		// size of first tagged field
		1,
		// 34 as 8-bit int
		34,
		// id of second tagged field
		1,
		// size of second tagged field
		13,
		// size of "taggedValue2" + 1
		13,
		// "taggedValue2"
		116, 97, 103, 103, 101, 100, 86, 97, 108, 117, 101, 50,
	}

	if !reflect.DeepEqual(exp, b.Bytes()) {
		t.Error(
			"Wrong encoded output",
			"expected", exp,
			"got", b.Bytes(),
		)
	}

	b = &bytes.Buffer{}
	b.Write(exp)
	d := &decoder{reader: b, remain: len(exp)}

	f2 := &testType{}
	ft.decode(d, valueOf(f2))
	if d.err != nil {
		t.Error(
			"Error during decoding",
			"expected", nil,
			"got", e.err,
		)
	}

	if !reflect.DeepEqual(f, f2) {
		t.Error(
			"Decoded value does not equal encoded one",
			"expected", *f,
			"got", *f2,
		)
	}
}

func TestVarInts(t *testing.T) {
	type tc struct {
		input      int64
		expVarInt  []byte
		expUVarInt []byte
	}

	tcs := []tc{
		{
			input:      12,
			expVarInt:  []byte{24},
			expUVarInt: []byte{12},
		},
		{
			input:      63,
			expVarInt:  []byte{126},
			expUVarInt: []byte{63},
		},
		{
			input:      -64,
			expVarInt:  []byte{127},
			expUVarInt: []byte{192, 255, 255, 255, 255, 255, 255, 255, 255, 1},
		},
		{
			input:      64,
			expVarInt:  []byte{128, 1},
			expUVarInt: []byte{64},
		},
		{
			input:      127,
			expVarInt:  []byte{254, 1},
			expUVarInt: []byte{127},
		},
		{
			input:      128,
			expVarInt:  []byte{128, 2},
			expUVarInt: []byte{128, 1},
		},
		{
			input:      129,
			expVarInt:  []byte{130, 2},
			expUVarInt: []byte{129, 1},
		},
		{
			input:      12345,
			expVarInt:  []byte{242, 192, 1},
			expUVarInt: []byte{185, 96},
		},
	}

	for _, tc := range tcs {
		b := &bytes.Buffer{}
		e := &encoder{writer: b}
		e.writeVarInt(tc.input)
		if e.err != nil {
			t.Errorf(
				"Unexpected error encoding %d as varInt: %+v",
				tc.input,
				e.err,
			)
		}
		if !reflect.DeepEqual(b.Bytes(), tc.expVarInt) {
			t.Error(
				"Wrong output encoding value", tc.input, "as varInt",
				"expected", tc.expVarInt,
				"got", b.Bytes(),
			)
		}
		d := &decoder{reader: b, remain: len(b.Bytes())}
		v := d.readVarInt()
		if v != tc.input {
			t.Error(
				"Decoded varInt value does not equal encoded one",
				"expected", tc.input,
				"got", v,
			)
		}

		b = &bytes.Buffer{}
		e = &encoder{writer: b}
		e.writeUnsignedVarInt(uint64(tc.input))
		if e.err != nil {
			t.Errorf(
				"Unexpected error encoding %d as unsignedVarInt: %+v",
				tc.input,
				e.err,
			)
		}
		if !reflect.DeepEqual(b.Bytes(), tc.expUVarInt) {
			t.Error(
				"Wrong output encoding value", tc.input, "as unsignedVarInt",
				"expected", tc.expUVarInt,
				"got", b.Bytes(),
			)
		}
		d = &decoder{reader: b, remain: len(b.Bytes())}
		v = int64(d.readUnsignedVarInt())
		if v != tc.input {
			t.Error(
				"Decoded unsignedVarInt value does not equal encoded one",
				"expected", tc.input,
				"got", v,
			)
		}

	}
}
<commit_msg>Also test sizeOf functions in protocol test<commit_after>package protocol

import (
	"bytes"
	"reflect"
	"testing"
)

type testType struct {
	Field1   string        `kafka:"min=v0,max=v4,nullable"`
	Field2   int16         `kafka:"min=v2,max=v4"`
	Field3   []byte        `kafka:"min=v2,max=v4,nullable"`
	SubTypes []testSubType `kafka:"min=v1,max=v4"`

	TaggedField1 int8   `kafka:"min=v3,max=v4,tag=0"`
	TaggedField2 string `kafka:"min=v4,max=v4,tag=1"`
}

type testSubType struct {
	SubField1 int8 `kafka:"min=v1,max=v4"`
}

func TestMakeFlexibleTypes(t *testing.T) {
	types := makeTypes(reflect.TypeOf(&testType{}).Elem())
	if len(types) != 5 {
		t.Error(
			"Wrong number of types",
			"expected", 5,
			"got", len(types),
		)
	}

	fv := []int16{}

	for _, to := range types {
		if to.flexible {
			fv = append(fv, to.version)
		}
	}

	if !reflect.DeepEqual([]int16{3, 4}, fv) {
		t.Error(
			"Unexpected flexible versions",
			"expected", []int16{3, 4},
			"got", fv,
		)
	}
}

func TestEncodeDecodeFlexibleType(t *testing.T) {
	f := &testType{
		Field1: "value1",
		Field2: 15,
		Field3: []byte("hello"),
		SubTypes: []testSubType{
			{
				SubField1: 2,
			},
			{
				SubField1: 3,
			},
		},

		TaggedField1: 34,
		TaggedField2: "taggedValue2",
	}

	b := &bytes.Buffer{}
	e := &encoder{writer: b}

	types := makeTypes(reflect.TypeOf(&testType{}).Elem())
	ft := types[4]
	ft.encode(e, valueOf(f))
	if e.err != nil {
		t.Error(
			"Error during encoding",
			"expected", nil,
			"got", e.err,
		)
	}

	exp := []byte{
		// size of "value1" + 1
		7,
		// "value1"
		118, 97, 108, 117, 101, 49,
		// 15 as 16-bit int
		0, 15,
		// size of []byte("hello") + 1
		6,
		// []byte("hello")
		104, 101, 108, 108, 111,
		// size of []SubTypes + 1
		3,
		// 2 as 8-bit int
		2,
		// tag buffer for first SubType struct
		0,
		// 3 as 8-bit int
		3,
		// tag buffer for second SubType struct
		0,
		// number of tagged fields
		2,
		// id of first tagged field
		0,
		// size of first tagged field
		1,
		// 34 as 8-bit int
		34,
		// id of second tagged field
		1,
		// size of second tagged field
		13,
		// size of "taggedValue2" + 1
		13,
		// "taggedValue2"
		116, 97, 103, 103, 101, 100, 86, 97, 108, 117, 101, 50,
	}

	if !reflect.DeepEqual(exp, b.Bytes()) {
		t.Error(
			"Wrong encoded output",
			"expected", exp,
			"got", b.Bytes(),
		)
	}

	b = &bytes.Buffer{}
	b.Write(exp)
	d := &decoder{reader: b, remain: len(exp)}

	f2 := &testType{}
	ft.decode(d, valueOf(f2))
	if d.err != nil {
		t.Error(
			"Error during decoding",
			"expected", nil,
			"got", e.err,
		)
	}

	if !reflect.DeepEqual(f, f2) {
		t.Error(
			"Decoded value does not equal encoded one",
			"expected", *f,
			"got", *f2,
		)
	}
}

func TestVarInts(t *testing.T) {
	type tc struct {
		input      int64
		expVarInt  []byte
		expUVarInt []byte
	}

	tcs := []tc{
		{
			input:      12,
			expVarInt:  []byte{24},
			expUVarInt: []byte{12},
		},
		{
			input:      63,
			expVarInt:  []byte{126},
			expUVarInt: []byte{63},
		},
		{
			input:      -64,
			expVarInt:  []byte{127},
			expUVarInt: []byte{192, 255, 255, 255, 255, 255, 255, 255, 255, 1},
		},
		{
			input:      64,
			expVarInt:  []byte{128, 1},
			expUVarInt: []byte{64},
		},
		{
			input:      127,
			expVarInt:  []byte{254, 1},
			expUVarInt: []byte{127},
		},
		{
			input:      128,
			expVarInt:  []byte{128, 2},
			expUVarInt: []byte{128, 1},
		},
		{
			input:      129,
			expVarInt:  []byte{130, 2},
			expUVarInt: []byte{129, 1},
		},
		{
			input:      12345,
			expVarInt:  []byte{242, 192, 1},
			expUVarInt: []byte{185, 96},
		},
		{
			input:      123456789101112,
			expVarInt:  []byte{240, 232, 249, 224, 144, 146, 56},
			expUVarInt: []byte{184, 244, 188, 176, 136, 137, 28},
		},
	}

	for _, tc := range tcs {
		b := &bytes.Buffer{}
		e := &encoder{writer: b}
		e.writeVarInt(tc.input)
		if e.err != nil {
			t.Errorf(
				"Unexpected error encoding %d as varInt: %+v",
				tc.input,
				e.err,
			)
		}
		if !reflect.DeepEqual(b.Bytes(), tc.expVarInt) {
			t.Error(
				"Wrong output encoding value", tc.input, "as varInt",
				"expected", tc.expVarInt,
				"got", b.Bytes(),
			)
		}
		expLen := sizeOfVarInt(tc.input)
		if expLen != len(b.Bytes()) {
			t.Error(
				"Wrong sizeOf for", tc.input, "as varInt",
				"expected", expLen,
				"got", len(b.Bytes()),
			)
		}

		d := &decoder{reader: b, remain: len(b.Bytes())}
		v := d.readVarInt()
		if v != tc.input {
			t.Error(
				"Decoded varInt value does not equal encoded one",
				"expected", tc.input,
				"got", v,
			)
		}

		b = &bytes.Buffer{}
		e = &encoder{writer: b}
		e.writeUnsignedVarInt(uint64(tc.input))
		if e.err != nil {
			t.Errorf(
				"Unexpected error encoding %d as unsignedVarInt: %+v",
				tc.input,
				e.err,
			)
		}
		if !reflect.DeepEqual(b.Bytes(), tc.expUVarInt) {
			t.Error(
				"Wrong output encoding value", tc.input, "as unsignedVarInt",
				"expected", tc.expUVarInt,
				"got", b.Bytes(),
			)
		}
		expLen = sizeOfUnsignedVarInt(uint64(tc.input))
		if expLen != len(b.Bytes()) {
			t.Error(
				"Wrong sizeOf for", tc.input, "as unsignedVarInt",
				"expected", expLen,
				"got", len(b.Bytes()),
			)
		}

		d = &decoder{reader: b, remain: len(b.Bytes())}
		v = int64(d.readUnsignedVarInt())
		if v != tc.input {
			t.Error(
				"Decoded unsignedVarInt value does not equal encoded one",
				"expected", tc.input,
				"got", v,
			)
		}

	}
}
<|endoftext|>


<commit_before>package iniflags

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strings"
)

type Arg struct {
	key, value string
}

var (
	config = flag.String("config", "dev.ini", "Path to config.")
)

var (
	LINES_REGEXP = regexp.MustCompile("[\\r\\n]")
	KV_REGEXP    = regexp.MustCompile("\\s*=\\s*")
)

func Parse() {
	flag.Parse()
	parsedArgs := getArgsFromConfig(*config)
	not_set_flags := getNotSetFlags()
	for _, arg := range parsedArgs {
		if _, found := not_set_flags[arg.key]; found {
			flag.Set(arg.key, arg.value)
		}
	}
}

func getArgsFromConfig(configPath string) []Arg {
	file, err := os.Open(configPath)
	if err != nil {
		log.Fatalf("cannot open config file at [%s]: [%s]\n", configPath, err)
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatalf("Error when reading config file [%s]: [%s]\n", configPath, err)
	}

	var args []Arg
	for _, line := range LINES_REGEXP.Split(string(data), -1) {
		if line == "" || line[0] == ';' || line[0] == '#' || line[0] == '[' {
			continue
		}
		parts := KV_REGEXP.Split(line, 2)
		if len(parts) != 2 {
			log.Fatalf("Cannot split line=[%s] into key and value in config file [%s]", line, configPath)
		}
		key := parts[0]
		value := unquoteValue(parts[1])
		args = append(args, Arg{key: key, value: value})
	}
	return args
}

func getNotSetFlags() map[string]bool {
	not_set_flags := make(map[string]bool, 0)
	flag.VisitAll(func(f *flag.Flag) {
		not_set_flags[f.Name] = true
	})
	flag.Visit(func(f *flag.Flag) {
		delete(not_set_flags, f.Name)
	})
	return not_set_flags
}

func unquoteValue(v string) string {
	if v[0] != '"' {
		return v
	}
	n := strings.LastIndex(v, "\"")
	if n == -1 {
		return v
	}
	v = v[1:n]
	v = strings.Replace(v, "\\\"", "\"", -1)
	return strings.Replace(v, "\\n", "\n", -1)
}
<commit_msg>Set relative path to config relative to the executable<commit_after>package iniflags

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"path"
	"regexp"
	"strings"
)

type Arg struct {
	key, value string
}

var (
	config = flag.String("config", "dev.ini", "Path to config.")
)

var (
	LINES_REGEXP = regexp.MustCompile("[\\r\\n]")
	KV_REGEXP    = regexp.MustCompile("\\s*=\\s*")
)

func Parse() {
	flag.Parse()
	configPath := *config
	if configPath[0] != '/' {
		configPath = path.Join(path.Dir(os.Args[0]), configPath)
	}
	parsedArgs := getArgsFromConfig(configPath)
	missingFlags := getMissingFlags()
	for _, arg := range parsedArgs {
		if _, found := missingFlags[arg.key]; found {
			flag.Set(arg.key, arg.value)
		}
	}
}

func getArgsFromConfig(configPath string) []Arg {
	file, err := os.Open(configPath)
	if err != nil {
		log.Fatalf("cannot open config file at [%s]: [%s]\n", configPath, err)
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatalf("Error when reading config file [%s]: [%s]\n", configPath, err)
	}

	var args []Arg
	for _, line := range LINES_REGEXP.Split(string(data), -1) {
		if line == "" || line[0] == ';' || line[0] == '#' || line[0] == '[' {
			continue
		}
		parts := KV_REGEXP.Split(line, 2)
		if len(parts) != 2 {
			log.Fatalf("Cannot split line=[%s] into key and value in config file [%s]", line, configPath)
		}
		key := parts[0]
		value := unquoteValue(parts[1])
		args = append(args, Arg{key: key, value: value})
	}
	return args
}

func getMissingFlags() map[string]bool {
	missingFlags := make(map[string]bool, 0)
	flag.VisitAll(func(f *flag.Flag) {
		missingFlags[f.Name] = true
	})
	flag.Visit(func(f *flag.Flag) {
		delete(missingFlags, f.Name)
	})
	return missingFlags
}

func unquoteValue(v string) string {
	if v[0] != '"' {
		return v
	}
	n := strings.LastIndex(v, "\"")
	if n == -1 {
		return v
	}
	v = v[1:n]
	v = strings.Replace(v, "\\\"", "\"", -1)
	return strings.Replace(v, "\\n", "\n", -1)
}
<|endoftext|>


<commit_before>package iniflags

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"time"
)

var (
	config               = flag.String("config", "", "Path to ini config for using in go flags. May be relative to the current executable path.")
	configUpdateInterval = flag.Duration("configUpdateInterval", 0, "Update interval for re-reading config file set via -config flag. Zero disables config file re-reading.")
	dumpflags            = flag.Bool("dumpflags", false, "Dumps values for all flags defined in the app into stdout in ini-compatible syntax and terminates the app.")
)

var (
	flagChangeCallbacks = make(map[string][]FlagChangeCallback)
	importStack         []string
	parsed              bool
)

// Generation is flags' generation number.
//
// It is modified on each flags' modification
// via either -configUpdateInterval or SIGHUP.
var Generation int

// Parse() obtains flag values from config file set via -config.
//
// It obtains flag values from command line like flag.Parse(), then overrides
// them by values parsed from config file set via -config.
//
// Path to config file can also be set via SetConfigFile() before Parse() call.
func Parse() {
	if parsed {
		panic("iniflags: duplicate call to iniflags.Parse() detected")
	}

	parsed = true
	flag.Parse()
	_, ok := parseConfigFlags()
	if !ok {
		os.Exit(1)
	}

	if *dumpflags {
		dumpFlags()
		os.Exit(0)
	}

	for flagName, _ := range flagChangeCallbacks {
		verifyFlagChangeFlagName(flagName)
	}
	Generation++
	issueAllFlagChangeCallbacks()

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGHUP)
	go sighupHandler(ch)

	go configUpdater()
}

func configUpdater() {
	if *configUpdateInterval != 0 {
		for {
			// Use time.Sleep() instead of time.Tick() for the sake of dynamic flag update.
			time.Sleep(*configUpdateInterval)
			updateConfig()
		}
	}
}

func updateConfig() {
	if oldFlagValues, ok := parseConfigFlags(); ok && len(oldFlagValues) > 0 {
		modifiedFlags := make(map[string]string)
		for k, _ := range oldFlagValues {
			modifiedFlags[k] = flag.Lookup(k).Value.String()
		}
		log.Printf("iniflags: read updated config. Modified flags are: %v\n", modifiedFlags)
		Generation++
		issueFlagChangeCallbacks(oldFlagValues)
	}
}

// FlagChangeCallback is called when the given flag is changed.
//
// The callback may be registered for any flag via OnFlagChange().
type FlagChangeCallback func()

// OnFlagChange registers the callback, which is called after the given flag
// value is initialized and/or changed.
//
// Flag values are initialized during iniflags.Parse() call.
// Flag value can be changed on config re-read after obtaining SIGHUP signal
// or if periodic config re-read is enabled with -configUpdateInterval flag.
//
// Note that flags set via command-line cannot be overriden via config file modifications.
func OnFlagChange(flagName string, callback FlagChangeCallback) {
	if parsed {
		verifyFlagChangeFlagName(flagName)
	}
	flagChangeCallbacks[flagName] = append(flagChangeCallbacks[flagName], callback)
}

func verifyFlagChangeFlagName(flagName string) {
	if flag.Lookup(flagName) == nil {
		log.Fatalf("iniflags: cannot register FlagChangeCallback for non-existing flag [%s]\n", flagName)
	}
}

func issueFlagChangeCallbacks(oldFlagValues map[string]string) {
	for flagName := range oldFlagValues {
		if fs, ok := flagChangeCallbacks[flagName]; ok {
			for _, f := range fs {
				f()
			}
		}
	}
}

func issueAllFlagChangeCallbacks() {
	for _, fs := range flagChangeCallbacks {
		for _, f := range fs {
			f()
		}
	}
}

func sighupHandler(ch <-chan os.Signal) {
	for _ = range ch {
		updateConfig()
	}
}

func parseConfigFlags() (oldFlagValues map[string]string, ok bool) {
	configPath := *config
	if !strings.HasPrefix(configPath, "./") {
		if configPath, ok = combinePath(os.Args[0], *config); !ok {
			return nil, false
		}
	}
	if configPath == "" {
		return nil, true
	}
	parsedArgs, ok := getArgsFromConfig(configPath)
	if !ok {
		return nil, false
	}
	missingFlags := getMissingFlags()

	ok = true
	oldFlagValues = make(map[string]string)
	for _, arg := range parsedArgs {
		f := flag.Lookup(arg.Key)
		if f == nil {
			log.Printf("iniflags: unknown flag name=[%s] found at line [%d] of file [%s]\n", arg.Key, arg.LineNum, arg.FilePath)
			ok = false
			continue
		}

		if _, found := missingFlags[f.Name]; found {
			oldValue := f.Value.String()
			if oldValue == arg.Value {
				continue
			}
			if err := f.Value.Set(arg.Value); err != nil {
				log.Printf("iniflags: error when parsing flag [%s] value [%s] at line [%d] of file [%s]: [%s]\n", arg.Key, arg.Value, arg.LineNum, arg.FilePath, err)
				ok = false
				continue
			}
			if oldValue != f.Value.String() {
				oldFlagValues[arg.Key] = oldValue
			}
		}
	}

	if !ok {
		// restore old flag values
		for k, v := range oldFlagValues {
			flag.Set(k, v)
		}
		oldFlagValues = nil
	}

	return oldFlagValues, ok
}

func checkImportRecursion(configPath string) bool {
	for _, path := range importStack {
		if path == configPath {
			log.Printf("iniflags: import recursion found for [%s]: %v\n", configPath, importStack)
			return false
		}
	}
	return true
}

type flagArg struct {
	Key      string
	Value    string
	FilePath string
	LineNum  int
}

func getArgsFromConfig(configPath string) (args []flagArg, ok bool) {
	if !checkImportRecursion(configPath) {
		return nil, false
	}
	importStack = append(importStack, configPath)
	defer func() {
		importStack = importStack[:len(importStack)-1]
	}()

	file := openConfigFile(configPath)
	if file == nil {
		return nil, false
	}
	defer file.Close()
	r := bufio.NewReader(file)

	var lineNum int
	for {
		lineNum++
		line, err := r.ReadString('\n')
		if err != nil && line == "" {
			if err == io.EOF {
				break
			}
			log.Printf("iniflags: error when reading file [%s] at line %d: [%s]\n", configPath, lineNum, err)
			return nil, false
		}
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, "#import ") {
			importPath, ok := unquoteValue(line[7:], lineNum, configPath)
			if !ok {
				return nil, false
			}
			if importPath, ok = combinePath(configPath, importPath); !ok {
				return nil, false
			}
			importArgs, ok := getArgsFromConfig(importPath)
			if !ok {
				return nil, false
			}
			args = append(args, importArgs...)
			continue
		}

        /* ignore utf-8 BOM */
        if len(line) > 3 && line[0] == '\xef' {
            line = line[3:]
        }

		if line == "" || line[0] == ';' || line[0] == '#' || line[0] == '[' {
			continue
		}
		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			log.Printf("iniflags: cannot split [%s] at line %d into key and value in config file [%s]\n", line, lineNum, configPath)
			return nil, false
		}
		key := strings.TrimSpace(parts[0])
		value, ok := unquoteValue(parts[1], lineNum, configPath)
		if !ok {
			return nil, false
		}
		args = append(args, flagArg{Key: key, Value: value, FilePath: configPath, LineNum: lineNum})
	}

	return args, true
}

func openConfigFile(path string) io.ReadCloser {
	if isHttp(path) {
		resp, err := http.Get(path)
		if err != nil {
			log.Printf("iniflags: cannot load config file at [%s]: [%s]\n", path, err)
			return nil
		}
		if resp.StatusCode != http.StatusOK {
			log.Printf("iniflags: unexpected http status code when obtaining config file [%s]: %d. Expected %d\n", path, resp.StatusCode, http.StatusOK)
			return nil
		}
		return resp.Body
	}

	file, err := os.Open(path)
	if err != nil {
		log.Printf("iniflags: cannot open config file at [%s]: [%s]\n", path, err)
		return nil
	}
	return file
}

func combinePath(basePath, relPath string) (string, bool) {
	if isHttp(basePath) {
		base, err := url.Parse(basePath)
		if err != nil {
			log.Printf("iniflags: error when parsing http base path [%s]: %s\n", basePath, err)
			return "", false
		}
		rel, err := url.Parse(relPath)
		if err != nil {
			log.Printf("iniflags: error when parsing http rel path [%s] for base [%s]: %s\n", relPath, basePath, err)
			return "", false
		}
		return base.ResolveReference(rel).String(), true
	}

	if relPath == "" || relPath[0] == '/' || isHttp(relPath) {
		return relPath, true
	}
	return path.Join(path.Dir(basePath), relPath), true
}

func isHttp(path string) bool {
	return strings.HasPrefix(strings.ToLower(path), "http://") || strings.HasPrefix(strings.ToLower(path), "https://")
}

func getMissingFlags() map[string]bool {
	setFlags := make(map[string]bool)
	flag.Visit(func(f *flag.Flag) {
		setFlags[f.Name] = true
	})

	missingFlags := make(map[string]bool)
	flag.VisitAll(func(f *flag.Flag) {
		if _, ok := setFlags[f.Name]; !ok {
			missingFlags[f.Name] = true
		}
	})
	return missingFlags
}

func dumpFlags() {
	flag.VisitAll(func(f *flag.Flag) {
		if f.Name != "config" && f.Name != "dumpflags" {
			fmt.Printf("%s = %s  # %s\n", f.Name, quoteValue(f.Value.String()), escapeUsage(f.Usage))
		}
	})
}

func escapeUsage(s string) string {
	return strings.Replace(s, "\n", "\n    # ", -1)
}

func quoteValue(v string) string {
	if !strings.ContainsAny(v, "\n#;") && strings.TrimSpace(v) == v {
		return v
	}
	v = strings.Replace(v, "\\", "\\\\", -1)
	v = strings.Replace(v, "\n", "\\n", -1)
	v = strings.Replace(v, "\"", "\\\"", -1)
	return fmt.Sprintf("\"%s\"", v)
}

func unquoteValue(v string, lineNum int, configPath string) (string, bool) {
	v = strings.TrimSpace(v)
	if len(v) == 0 {
		return "", true
	}
	if v[0] != '"' {
		return removeTrailingComments(v), true
	}
	n := strings.LastIndex(v, "\"")
	if n == -1 {
		log.Printf("iniflags: unclosed string found [%s] at line %d in config file [%s]\n", v, lineNum, configPath)
		return "", false
	}
	v = v[1:n]
	v = strings.Replace(v, "\\\"", "\"", -1)
	v = strings.Replace(v, "\\n", "\n", -1)
	return strings.Replace(v, "\\\\", "\\", -1), true
}

func removeTrailingComments(v string) string {
	v = strings.Split(v, "#")[0]
	v = strings.Split(v, ";")[0]
	return strings.TrimSpace(v)
}

// SetConfigFile sets path to config file.
//
// Call this function before Parse() if you need default path to config file
// when -config command-line flag is not set.
func SetConfigFile(path string) {
	if parsed {
		panic("iniflags: SetConfigFile() must be called before Parse()")
	}
	*config = path
}
<commit_msg>go fmt<commit_after>package iniflags

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"time"
)

var (
	config               = flag.String("config", "", "Path to ini config for using in go flags. May be relative to the current executable path.")
	configUpdateInterval = flag.Duration("configUpdateInterval", 0, "Update interval for re-reading config file set via -config flag. Zero disables config file re-reading.")
	dumpflags            = flag.Bool("dumpflags", false, "Dumps values for all flags defined in the app into stdout in ini-compatible syntax and terminates the app.")
)

var (
	flagChangeCallbacks = make(map[string][]FlagChangeCallback)
	importStack         []string
	parsed              bool
)

// Generation is flags' generation number.
//
// It is modified on each flags' modification
// via either -configUpdateInterval or SIGHUP.
var Generation int

// Parse() obtains flag values from config file set via -config.
//
// It obtains flag values from command line like flag.Parse(), then overrides
// them by values parsed from config file set via -config.
//
// Path to config file can also be set via SetConfigFile() before Parse() call.
func Parse() {
	if parsed {
		panic("iniflags: duplicate call to iniflags.Parse() detected")
	}

	parsed = true
	flag.Parse()
	_, ok := parseConfigFlags()
	if !ok {
		os.Exit(1)
	}

	if *dumpflags {
		dumpFlags()
		os.Exit(0)
	}

	for flagName, _ := range flagChangeCallbacks {
		verifyFlagChangeFlagName(flagName)
	}
	Generation++
	issueAllFlagChangeCallbacks()

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGHUP)
	go sighupHandler(ch)

	go configUpdater()
}

func configUpdater() {
	if *configUpdateInterval != 0 {
		for {
			// Use time.Sleep() instead of time.Tick() for the sake of dynamic flag update.
			time.Sleep(*configUpdateInterval)
			updateConfig()
		}
	}
}

func updateConfig() {
	if oldFlagValues, ok := parseConfigFlags(); ok && len(oldFlagValues) > 0 {
		modifiedFlags := make(map[string]string)
		for k, _ := range oldFlagValues {
			modifiedFlags[k] = flag.Lookup(k).Value.String()
		}
		log.Printf("iniflags: read updated config. Modified flags are: %v\n", modifiedFlags)
		Generation++
		issueFlagChangeCallbacks(oldFlagValues)
	}
}

// FlagChangeCallback is called when the given flag is changed.
//
// The callback may be registered for any flag via OnFlagChange().
type FlagChangeCallback func()

// OnFlagChange registers the callback, which is called after the given flag
// value is initialized and/or changed.
//
// Flag values are initialized during iniflags.Parse() call.
// Flag value can be changed on config re-read after obtaining SIGHUP signal
// or if periodic config re-read is enabled with -configUpdateInterval flag.
//
// Note that flags set via command-line cannot be overriden via config file modifications.
func OnFlagChange(flagName string, callback FlagChangeCallback) {
	if parsed {
		verifyFlagChangeFlagName(flagName)
	}
	flagChangeCallbacks[flagName] = append(flagChangeCallbacks[flagName], callback)
}

func verifyFlagChangeFlagName(flagName string) {
	if flag.Lookup(flagName) == nil {
		log.Fatalf("iniflags: cannot register FlagChangeCallback for non-existing flag [%s]\n", flagName)
	}
}

func issueFlagChangeCallbacks(oldFlagValues map[string]string) {
	for flagName := range oldFlagValues {
		if fs, ok := flagChangeCallbacks[flagName]; ok {
			for _, f := range fs {
				f()
			}
		}
	}
}

func issueAllFlagChangeCallbacks() {
	for _, fs := range flagChangeCallbacks {
		for _, f := range fs {
			f()
		}
	}
}

func sighupHandler(ch <-chan os.Signal) {
	for _ = range ch {
		updateConfig()
	}
}

func parseConfigFlags() (oldFlagValues map[string]string, ok bool) {
	configPath := *config
	if !strings.HasPrefix(configPath, "./") {
		if configPath, ok = combinePath(os.Args[0], *config); !ok {
			return nil, false
		}
	}
	if configPath == "" {
		return nil, true
	}
	parsedArgs, ok := getArgsFromConfig(configPath)
	if !ok {
		return nil, false
	}
	missingFlags := getMissingFlags()

	ok = true
	oldFlagValues = make(map[string]string)
	for _, arg := range parsedArgs {
		f := flag.Lookup(arg.Key)
		if f == nil {
			log.Printf("iniflags: unknown flag name=[%s] found at line [%d] of file [%s]\n", arg.Key, arg.LineNum, arg.FilePath)
			ok = false
			continue
		}

		if _, found := missingFlags[f.Name]; found {
			oldValue := f.Value.String()
			if oldValue == arg.Value {
				continue
			}
			if err := f.Value.Set(arg.Value); err != nil {
				log.Printf("iniflags: error when parsing flag [%s] value [%s] at line [%d] of file [%s]: [%s]\n", arg.Key, arg.Value, arg.LineNum, arg.FilePath, err)
				ok = false
				continue
			}
			if oldValue != f.Value.String() {
				oldFlagValues[arg.Key] = oldValue
			}
		}
	}

	if !ok {
		// restore old flag values
		for k, v := range oldFlagValues {
			flag.Set(k, v)
		}
		oldFlagValues = nil
	}

	return oldFlagValues, ok
}

func checkImportRecursion(configPath string) bool {
	for _, path := range importStack {
		if path == configPath {
			log.Printf("iniflags: import recursion found for [%s]: %v\n", configPath, importStack)
			return false
		}
	}
	return true
}

type flagArg struct {
	Key      string
	Value    string
	FilePath string
	LineNum  int
}

func getArgsFromConfig(configPath string) (args []flagArg, ok bool) {
	if !checkImportRecursion(configPath) {
		return nil, false
	}
	importStack = append(importStack, configPath)
	defer func() {
		importStack = importStack[:len(importStack)-1]
	}()

	file := openConfigFile(configPath)
	if file == nil {
		return nil, false
	}
	defer file.Close()
	r := bufio.NewReader(file)

	var lineNum int
	for {
		lineNum++
		line, err := r.ReadString('\n')
		if err != nil && line == "" {
			if err == io.EOF {
				break
			}
			log.Printf("iniflags: error when reading file [%s] at line %d: [%s]\n", configPath, lineNum, err)
			return nil, false
		}
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, "#import ") {
			importPath, ok := unquoteValue(line[7:], lineNum, configPath)
			if !ok {
				return nil, false
			}
			if importPath, ok = combinePath(configPath, importPath); !ok {
				return nil, false
			}
			importArgs, ok := getArgsFromConfig(importPath)
			if !ok {
				return nil, false
			}
			args = append(args, importArgs...)
			continue
		}

		/* ignore utf-8 BOM */
		if len(line) > 3 && line[0] == '\xef' {
			line = line[3:]
		}

		if line == "" || line[0] == ';' || line[0] == '#' || line[0] == '[' {
			continue
		}
		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			log.Printf("iniflags: cannot split [%s] at line %d into key and value in config file [%s]\n", line, lineNum, configPath)
			return nil, false
		}
		key := strings.TrimSpace(parts[0])
		value, ok := unquoteValue(parts[1], lineNum, configPath)
		if !ok {
			return nil, false
		}
		args = append(args, flagArg{Key: key, Value: value, FilePath: configPath, LineNum: lineNum})
	}

	return args, true
}

func openConfigFile(path string) io.ReadCloser {
	if isHttp(path) {
		resp, err := http.Get(path)
		if err != nil {
			log.Printf("iniflags: cannot load config file at [%s]: [%s]\n", path, err)
			return nil
		}
		if resp.StatusCode != http.StatusOK {
			log.Printf("iniflags: unexpected http status code when obtaining config file [%s]: %d. Expected %d\n", path, resp.StatusCode, http.StatusOK)
			return nil
		}
		return resp.Body
	}

	file, err := os.Open(path)
	if err != nil {
		log.Printf("iniflags: cannot open config file at [%s]: [%s]\n", path, err)
		return nil
	}
	return file
}

func combinePath(basePath, relPath string) (string, bool) {
	if isHttp(basePath) {
		base, err := url.Parse(basePath)
		if err != nil {
			log.Printf("iniflags: error when parsing http base path [%s]: %s\n", basePath, err)
			return "", false
		}
		rel, err := url.Parse(relPath)
		if err != nil {
			log.Printf("iniflags: error when parsing http rel path [%s] for base [%s]: %s\n", relPath, basePath, err)
			return "", false
		}
		return base.ResolveReference(rel).String(), true
	}

	if relPath == "" || relPath[0] == '/' || isHttp(relPath) {
		return relPath, true
	}
	return path.Join(path.Dir(basePath), relPath), true
}

func isHttp(path string) bool {
	return strings.HasPrefix(strings.ToLower(path), "http://") || strings.HasPrefix(strings.ToLower(path), "https://")
}

func getMissingFlags() map[string]bool {
	setFlags := make(map[string]bool)
	flag.Visit(func(f *flag.Flag) {
		setFlags[f.Name] = true
	})

	missingFlags := make(map[string]bool)
	flag.VisitAll(func(f *flag.Flag) {
		if _, ok := setFlags[f.Name]; !ok {
			missingFlags[f.Name] = true
		}
	})
	return missingFlags
}

func dumpFlags() {
	flag.VisitAll(func(f *flag.Flag) {
		if f.Name != "config" && f.Name != "dumpflags" {
			fmt.Printf("%s = %s  # %s\n", f.Name, quoteValue(f.Value.String()), escapeUsage(f.Usage))
		}
	})
}

func escapeUsage(s string) string {
	return strings.Replace(s, "\n", "\n    # ", -1)
}

func quoteValue(v string) string {
	if !strings.ContainsAny(v, "\n#;") && strings.TrimSpace(v) == v {
		return v
	}
	v = strings.Replace(v, "\\", "\\\\", -1)
	v = strings.Replace(v, "\n", "\\n", -1)
	v = strings.Replace(v, "\"", "\\\"", -1)
	return fmt.Sprintf("\"%s\"", v)
}

func unquoteValue(v string, lineNum int, configPath string) (string, bool) {
	v = strings.TrimSpace(v)
	if len(v) == 0 {
		return "", true
	}
	if v[0] != '"' {
		return removeTrailingComments(v), true
	}
	n := strings.LastIndex(v, "\"")
	if n == -1 {
		log.Printf("iniflags: unclosed string found [%s] at line %d in config file [%s]\n", v, lineNum, configPath)
		return "", false
	}
	v = v[1:n]
	v = strings.Replace(v, "\\\"", "\"", -1)
	v = strings.Replace(v, "\\n", "\n", -1)
	return strings.Replace(v, "\\\\", "\\", -1), true
}

func removeTrailingComments(v string) string {
	v = strings.Split(v, "#")[0]
	v = strings.Split(v, ";")[0]
	return strings.TrimSpace(v)
}

// SetConfigFile sets path to config file.
//
// Call this function before Parse() if you need default path to config file
// when -config command-line flag is not set.
func SetConfigFile(path string) {
	if parsed {
		panic("iniflags: SetConfigFile() must be called before Parse()")
	}
	*config = path
}
<|endoftext|>


<commit_before>package gitmedia

import (
	"fmt"
	"github.com/github/git-media/gitconfig"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const Version = "0.2.2"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}

	gitVersion, err := gitconfig.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (%s; git %s; go %s)", Version,
		runtime.GOOS,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<commit_msg>ンンー ンンンン ンーンン<commit_after>package gitmedia

import (
	"fmt"
	"github.com/github/git-media/gitconfig"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const Version = "0.2.2"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}

	gitVersion, err := gitconfig.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (%s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

// Package size contains a Prow plugin which counts the number of lines changed
// in a pull request, buckets this number into a few size classes (S, L, XL, etc),
// and finally labels the pull request with this size.
package size

import (
	"fmt"
	"strings"

	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/prow/genfiles"
	"k8s.io/test-infra/prow/gitattributes"
	"k8s.io/test-infra/prow/github"
	"k8s.io/test-infra/prow/pluginhelp"
	"k8s.io/test-infra/prow/plugins"
)

// The sizes are configurable in the `plugins.yaml` config file; the line constants
// in here represent default values used as fallback if none are provided.
const pluginName = "size"

var defaultSizes = plugins.Size{
	S:   10,
	M:   30,
	L:   100,
	Xl:  500,
	Xxl: 1000,
}

func init() {
	plugins.RegisterPullRequestHandler(pluginName, handlePullRequest, helpProvider)
}

func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) {
	sizes := sizesOrDefault(config.Size)
	return &pluginhelp.PluginHelp{
			Description: "The size plugin manages the 'size/*' labels, maintaining the appropriate label on each pull request as it is updated. Generated files identified by the config file '.generated_files' at the repo root are ignored. Labels are applied based on the total number of lines of changes (additions and deletions).",
			Config: map[string]string{
				"": fmt.Sprintf(`The plugin has the following thresholds:

size/XS:  0-%d

size/S:   %d-%d

size/M:   %d-%d

size/L:   %d-%d

size/XL:  %d-%d

size/XXL: %d+

`, sizes.S-1, sizes.S, sizes.M-1, sizes.M, sizes.L-1, sizes.L, sizes.Xl-1, sizes.Xl, sizes.Xxl-1, sizes.Xxl),
			},
		},
		nil
}

func handlePullRequest(pc plugins.Agent, pe github.PullRequestEvent) error {
	return handlePR(pc.GitHubClient, sizesOrDefault(pc.PluginConfig.Size), pc.Logger, pe)
}

// Strict subset of github.Client methods.
type githubClient interface {
	AddLabel(owner, repo string, number int, label string) error
	RemoveLabel(owner, repo string, number int, label string) error
	GetIssueLabels(org, repo string, number int) ([]github.Label, error)
	GetFile(org, repo, filepath, commit string) ([]byte, error)
	GetPullRequestChanges(org, repo string, number int) ([]github.PullRequestChange, error)
}

func handlePR(gc githubClient, sizes plugins.Size, le *logrus.Entry, pe github.PullRequestEvent) error {
	if !isPRChanged(pe) {
		return nil
	}

	var (
		owner = pe.PullRequest.Base.Repo.Owner.Login
		repo  = pe.PullRequest.Base.Repo.Name
		num   = pe.PullRequest.Number
		sha   = pe.PullRequest.Base.SHA
	)

	gf, err := genfiles.NewGroup(gc, owner, repo, sha)
	if err != nil {
		switch err.(type) {
		case *genfiles.ParseError:
			// Continue on parse errors, but warn that something is wrong.
			le.Warnf("error while parsing .generated_files: %v", err)
		default:
			return err
		}
	}

	ga, err := gitattributes.NewGroup(func() ([]byte, error) { return gc.GetFile(owner, repo, ".gitattributes", sha) })
	if err != nil {
		return err
	}

	changes, err := gc.GetPullRequestChanges(owner, repo, num)
	if err != nil {
		return fmt.Errorf("can not get PR changes for size plugin: %v", err)
	}

	var count int
	for _, change := range changes {
		// Skip generated and linguist-generated files.
		if gf.Match(change.Filename) || ga.IsLinguistGenerated(change.Filename) {
			continue
		}

		count += change.Additions + change.Deletions
	}

	labels, err := gc.GetIssueLabels(owner, repo, num)
	if err != nil {
		le.Warnf("while retrieving labels, error: %v", err)
	}

	newLabel := bucket(count, sizes).label()
	var hasLabel bool

	for _, label := range labels {
		if label.Name == newLabel {
			hasLabel = true
			continue
		}

		if strings.HasPrefix(label.Name, labelPrefix) {
			if err := gc.RemoveLabel(owner, repo, num, label.Name); err != nil {
				le.Warnf("error while removing label %q: %v", label.Name, err)
			}
		}
	}

	if hasLabel {
		return nil
	}

	if err := gc.AddLabel(owner, repo, num, newLabel); err != nil {
		return fmt.Errorf("error adding label to %s/%s PR #%d: %v", owner, repo, num, err)
	}

	return nil
}

// One of a set of discrete buckets.
type size int

const (
	sizeXS size = iota
	sizeS
	sizeM
	sizeL
	sizeXL
	sizeXXL
)

const (
	labelPrefix = "size/"

	labelXS     = "size/XS"
	labelS      = "size/S"
	labelM      = "size/M"
	labelL      = "size/L"
	labelXL     = "size/XL"
	labelXXL    = "size/XXL"
	labelUnkown = "size/?"
)

func (s size) label() string {
	switch s {
	case sizeXS:
		return labelXS
	case sizeS:
		return labelS
	case sizeM:
		return labelM
	case sizeL:
		return labelL
	case sizeXL:
		return labelXL
	case sizeXXL:
		return labelXXL
	}

	return labelUnkown
}

func bucket(lineCount int, sizes plugins.Size) size {
	if lineCount < sizes.S {
		return sizeXS
	} else if lineCount < sizes.M {
		return sizeS
	} else if lineCount < sizes.L {
		return sizeM
	} else if lineCount < sizes.Xl {
		return sizeL
	} else if lineCount < sizes.Xxl {
		return sizeXL
	}

	return sizeXXL
}

// These are the only actions indicating the code diffs may have changed.
func isPRChanged(pe github.PullRequestEvent) bool {
	switch pe.Action {
	case github.PullRequestActionOpened:
		return true
	case github.PullRequestActionReopened:
		return true
	case github.PullRequestActionSynchronize:
		return true
	case github.PullRequestActionEdited:
		return true
	default:
		return false
	}
}

func defaultIfZero(value, defaultValue int) int {
	if value == 0 {
		return defaultValue
	}
	return value
}

func sizesOrDefault(sizes plugins.Size) plugins.Size {
	sizes.S = defaultIfZero(sizes.S, defaultSizes.S)
	sizes.M = defaultIfZero(sizes.M, defaultSizes.M)
	sizes.L = defaultIfZero(sizes.L, defaultSizes.L)
	sizes.Xl = defaultIfZero(sizes.Xl, defaultSizes.Xl)
	sizes.Xxl = defaultIfZero(sizes.Xxl, defaultSizes.Xxl)
	return sizes
}
<commit_msg>s/Unkown/Unknown/<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

// Package size contains a Prow plugin which counts the number of lines changed
// in a pull request, buckets this number into a few size classes (S, L, XL, etc),
// and finally labels the pull request with this size.
package size

import (
	"fmt"
	"strings"

	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/prow/genfiles"
	"k8s.io/test-infra/prow/gitattributes"
	"k8s.io/test-infra/prow/github"
	"k8s.io/test-infra/prow/pluginhelp"
	"k8s.io/test-infra/prow/plugins"
)

// The sizes are configurable in the `plugins.yaml` config file; the line constants
// in here represent default values used as fallback if none are provided.
const pluginName = "size"

var defaultSizes = plugins.Size{
	S:   10,
	M:   30,
	L:   100,
	Xl:  500,
	Xxl: 1000,
}

func init() {
	plugins.RegisterPullRequestHandler(pluginName, handlePullRequest, helpProvider)
}

func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) {
	sizes := sizesOrDefault(config.Size)
	return &pluginhelp.PluginHelp{
			Description: "The size plugin manages the 'size/*' labels, maintaining the appropriate label on each pull request as it is updated. Generated files identified by the config file '.generated_files' at the repo root are ignored. Labels are applied based on the total number of lines of changes (additions and deletions).",
			Config: map[string]string{
				"": fmt.Sprintf(`The plugin has the following thresholds:

size/XS:  0-%d

size/S:   %d-%d

size/M:   %d-%d

size/L:   %d-%d

size/XL:  %d-%d

size/XXL: %d+

`, sizes.S-1, sizes.S, sizes.M-1, sizes.M, sizes.L-1, sizes.L, sizes.Xl-1, sizes.Xl, sizes.Xxl-1, sizes.Xxl),
			},
		},
		nil
}

func handlePullRequest(pc plugins.Agent, pe github.PullRequestEvent) error {
	return handlePR(pc.GitHubClient, sizesOrDefault(pc.PluginConfig.Size), pc.Logger, pe)
}

// Strict subset of github.Client methods.
type githubClient interface {
	AddLabel(owner, repo string, number int, label string) error
	RemoveLabel(owner, repo string, number int, label string) error
	GetIssueLabels(org, repo string, number int) ([]github.Label, error)
	GetFile(org, repo, filepath, commit string) ([]byte, error)
	GetPullRequestChanges(org, repo string, number int) ([]github.PullRequestChange, error)
}

func handlePR(gc githubClient, sizes plugins.Size, le *logrus.Entry, pe github.PullRequestEvent) error {
	if !isPRChanged(pe) {
		return nil
	}

	var (
		owner = pe.PullRequest.Base.Repo.Owner.Login
		repo  = pe.PullRequest.Base.Repo.Name
		num   = pe.PullRequest.Number
		sha   = pe.PullRequest.Base.SHA
	)

	gf, err := genfiles.NewGroup(gc, owner, repo, sha)
	if err != nil {
		switch err.(type) {
		case *genfiles.ParseError:
			// Continue on parse errors, but warn that something is wrong.
			le.Warnf("error while parsing .generated_files: %v", err)
		default:
			return err
		}
	}

	ga, err := gitattributes.NewGroup(func() ([]byte, error) { return gc.GetFile(owner, repo, ".gitattributes", sha) })
	if err != nil {
		return err
	}

	changes, err := gc.GetPullRequestChanges(owner, repo, num)
	if err != nil {
		return fmt.Errorf("can not get PR changes for size plugin: %v", err)
	}

	var count int
	for _, change := range changes {
		// Skip generated and linguist-generated files.
		if gf.Match(change.Filename) || ga.IsLinguistGenerated(change.Filename) {
			continue
		}

		count += change.Additions + change.Deletions
	}

	labels, err := gc.GetIssueLabels(owner, repo, num)
	if err != nil {
		le.Warnf("while retrieving labels, error: %v", err)
	}

	newLabel := bucket(count, sizes).label()
	var hasLabel bool

	for _, label := range labels {
		if label.Name == newLabel {
			hasLabel = true
			continue
		}

		if strings.HasPrefix(label.Name, labelPrefix) {
			if err := gc.RemoveLabel(owner, repo, num, label.Name); err != nil {
				le.Warnf("error while removing label %q: %v", label.Name, err)
			}
		}
	}

	if hasLabel {
		return nil
	}

	if err := gc.AddLabel(owner, repo, num, newLabel); err != nil {
		return fmt.Errorf("error adding label to %s/%s PR #%d: %v", owner, repo, num, err)
	}

	return nil
}

// One of a set of discrete buckets.
type size int

const (
	sizeXS size = iota
	sizeS
	sizeM
	sizeL
	sizeXL
	sizeXXL
)

const (
	labelPrefix = "size/"

	labelXS      = "size/XS"
	labelS       = "size/S"
	labelM       = "size/M"
	labelL       = "size/L"
	labelXL      = "size/XL"
	labelXXL     = "size/XXL"
	labelUnknown = "size/?"
)

func (s size) label() string {
	switch s {
	case sizeXS:
		return labelXS
	case sizeS:
		return labelS
	case sizeM:
		return labelM
	case sizeL:
		return labelL
	case sizeXL:
		return labelXL
	case sizeXXL:
		return labelXXL
	}

	return labelUnknown
}

func bucket(lineCount int, sizes plugins.Size) size {
	if lineCount < sizes.S {
		return sizeXS
	} else if lineCount < sizes.M {
		return sizeS
	} else if lineCount < sizes.L {
		return sizeM
	} else if lineCount < sizes.Xl {
		return sizeL
	} else if lineCount < sizes.Xxl {
		return sizeXL
	}

	return sizeXXL
}

// These are the only actions indicating the code diffs may have changed.
func isPRChanged(pe github.PullRequestEvent) bool {
	switch pe.Action {
	case github.PullRequestActionOpened:
		return true
	case github.PullRequestActionReopened:
		return true
	case github.PullRequestActionSynchronize:
		return true
	case github.PullRequestActionEdited:
		return true
	default:
		return false
	}
}

func defaultIfZero(value, defaultValue int) int {
	if value == 0 {
		return defaultValue
	}
	return value
}

func sizesOrDefault(sizes plugins.Size) plugins.Size {
	sizes.S = defaultIfZero(sizes.S, defaultSizes.S)
	sizes.M = defaultIfZero(sizes.M, defaultSizes.M)
	sizes.L = defaultIfZero(sizes.L, defaultSizes.L)
	sizes.Xl = defaultIfZero(sizes.Xl, defaultSizes.Xl)
	sizes.Xxl = defaultIfZero(sizes.Xxl, defaultSizes.Xxl)
	return sizes
}
<|endoftext|>


<commit_before>package hypervisor

import (
	"encoding/json"
	"github.com/golang/glog"
	"github.com/hyperhq/runv/hypervisor/pod"
	"github.com/hyperhq/runv/hypervisor/types"
	"os"
	"sync"
	"time"
)

type VmOnDiskInfo struct {
	QmpSockName     string
	HyperSockName   string
	TtySockName     string
	ConsoleSockName string
	ShareDir        string
}

type VmHwStatus struct {
	PciAddr  int    //next available pci addr for pci hotplug
	ScsiId   int    //next available scsi id for scsi hotplug
	AttachId uint64 //next available attachId for attached tty
}

type VmContext struct {
	Id string

	Paused bool
	Boot   *BootConfig

	// Communication Context
	Hub    chan VmEvent
	client chan *types.VmResponse
	vm     chan *DecodedMessage

	DCtx DriverContext

	HomeDir         string
	HyperSockName   string
	TtySockName     string
	ConsoleSockName string
	ShareDir        string

	pciAddr  int    //next available pci addr for pci hotplug
	scsiId   int    //next available scsi id for scsi hotplug
	attachId uint64 //next available attachId for attached tty

	InterfaceCount int

	ptys        *pseudoTtys
	ttySessions map[string]uint64
	pendingTtys []*AttachCommand

	// Specification
	userSpec *pod.UserPod
	vmSpec   *VmPod
	devices  *deviceMap

	progress *processingList

	// Internal Helper
	handler stateHandler
	current string
	timer   *time.Timer

	lock *sync.Mutex //protect update of context
	wg   *sync.WaitGroup
	wait bool
	Keep int
}

type stateHandler func(ctx *VmContext, event VmEvent)

func InitContext(id string, hub chan VmEvent, client chan *types.VmResponse, dc DriverContext, boot *BootConfig, keep int) (*VmContext, error) {
	var err error = nil

	vmChannel := make(chan *DecodedMessage, 128)

	//dir and sockets:
	homeDir := BaseDir + "/" + id + "/"
	hyperSockName := homeDir + HyperSockName
	ttySockName := homeDir + TtySockName
	consoleSockName := homeDir + ConsoleSockName
	shareDir := homeDir + ShareDirTag

	if dc == nil {
		dc = HDriver.InitContext(homeDir)
	}
	err = os.MkdirAll(shareDir, 0755)
	if err != nil {
		glog.Error("cannot make dir", shareDir, err.Error())
		return nil, err
	}
	defer func() {
		if err != nil {
			os.Remove(homeDir)
		}
	}()

	return &VmContext{
		Id:              id,
		Boot:            boot,
		Paused:          false,
		pciAddr:         PciAddrFrom,
		scsiId:          0,
		attachId:        1,
		Hub:             hub,
		client:          client,
		DCtx:            dc,
		vm:              vmChannel,
		ptys:            newPts(),
		ttySessions:     make(map[string]uint64),
		pendingTtys:     []*AttachCommand{},
		HomeDir:         homeDir,
		HyperSockName:   hyperSockName,
		TtySockName:     ttySockName,
		ConsoleSockName: consoleSockName,
		ShareDir:        shareDir,
		InterfaceCount:  InterfaceCount,
		timer:           nil,
		handler:         stateInit,
		userSpec:        nil,
		vmSpec:          nil,
		devices:         newDeviceMap(),
		progress:        newProcessingList(),
		lock:            &sync.Mutex{},
		wait:            false,
		Keep:            keep,
	}, nil
}

func (ctx *VmContext) setTimeout(seconds int) {
	if ctx.timer != nil {
		ctx.unsetTimeout()
	}
	ctx.timer = time.AfterFunc(time.Duration(seconds)*time.Second, func() {
		ctx.Hub <- &VmTimeout{}
	})
}

func (ctx *VmContext) unsetTimeout() {
	if ctx.timer != nil {
		ctx.timer.Stop()
		ctx.timer = nil
	}
}

func (ctx *VmContext) reset() {
	ctx.lock.Lock()

	ctx.ClosePendingTtys()

	ctx.pciAddr = PciAddrFrom
	ctx.scsiId = 0
	//do not reset attach id here, let it increase

	ctx.userSpec = nil
	ctx.vmSpec = nil
	ctx.devices = newDeviceMap()
	ctx.progress = newProcessingList()

	ctx.lock.Unlock()
}

func (ctx *VmContext) nextScsiId() int {
	ctx.lock.Lock()
	id := ctx.scsiId
	ctx.scsiId++
	ctx.lock.Unlock()
	return id
}

func (ctx *VmContext) nextPciAddr() int {
	ctx.lock.Lock()
	addr := ctx.pciAddr
	ctx.pciAddr++
	ctx.lock.Unlock()
	return addr
}

func (ctx *VmContext) nextAttachId() uint64 {
	ctx.lock.Lock()
	id := ctx.attachId
	ctx.attachId++
	ctx.lock.Unlock()
	return id
}

func (ctx *VmContext) clientReg(tag string, session uint64) {
	ctx.lock.Lock()
	ctx.ttySessions[tag] = session
	ctx.lock.Unlock()
}

func (ctx *VmContext) clientDereg(tag string) {
	if tag == "" {
		return
	}
	ctx.lock.Lock()
	if _, ok := ctx.ttySessions[tag]; ok {
		delete(ctx.ttySessions, tag)
	}
	ctx.lock.Unlock()
}

func (ctx *VmContext) Lookup(container string) int {
	if container == "" || ctx.vmSpec == nil {
		return -1
	}
	for idx, c := range ctx.vmSpec.Containers {
		if c.Id == container {
			glog.V(1).Infof("found container %s at %d", container, idx)
			return idx
		}
	}
	glog.V(1).Infof("can not found container %s", container)
	return -1
}

func (ctx *VmContext) ClosePendingTtys() {
	for _, tty := range ctx.pendingTtys {
		tty.Streams.Close(255)
	}
	ctx.pendingTtys = []*AttachCommand{}
}

func (ctx *VmContext) Close() {
	ctx.lock.Lock()
	defer ctx.lock.Unlock()
	ctx.ClosePendingTtys()
	ctx.unsetTimeout()
	ctx.DCtx.Close()
	close(ctx.vm)
	close(ctx.client)
	os.Remove(ctx.ShareDir)
	ctx.handler = nil
	ctx.current = "None"
}

func (ctx *VmContext) tryClose() bool {
	if ctx.deviceReady() {
		glog.V(1).Info("no more device to release/remove/umount, quit")
		ctx.Close()
		return true
	}
	return false
}

func (ctx *VmContext) Become(handler stateHandler, desc string) {
	orig := ctx.current
	ctx.lock.Lock()
	ctx.handler = handler
	ctx.current = desc
	ctx.lock.Unlock()
	glog.V(1).Infof("VM %s: state change from %s to '%s'", ctx.Id, orig, desc)
}

// InitDeviceContext will init device info in context
func (ctx *VmContext) InitDeviceContext(spec *pod.UserPod, wg *sync.WaitGroup,
	cInfo []*ContainerInfo, vInfo []*VolumeInfo) {

	ctx.lock.Lock()
	defer ctx.lock.Unlock()

	/* Update interface count accourding to user pod */
	ret := len(spec.Interfaces)
	if ret != 0 {
		ctx.InterfaceCount = ret
	}

	for i := 0; i < ctx.InterfaceCount; i++ {
		ctx.progress.adding.networks[i] = true
	}

	if cInfo == nil {
		cInfo = []*ContainerInfo{}
	}

	if vInfo == nil {
		vInfo = []*VolumeInfo{}
	}

	ctx.initVolumeMap(spec)

	if glog.V(3) {
		for i, c := range cInfo {
			glog.Infof("#%d Container Info:", i)
			b, err := json.MarshalIndent(c, "...|", "    ")
			if err == nil {
				glog.Info("\n", string(b))
			}
		}
	}

	containers := make([]VmContainer, len(spec.Containers))

	for i, container := range spec.Containers {
		ctx.initContainerInfo(i, &containers[i], &container)
		ctx.setContainerInfo(i, &containers[i], cInfo[i])

		containers[i].Sysctl = container.Sysctl
		containers[i].Tty = ctx.attachId
		ctx.attachId++
		ctx.ptys.ttys[containers[i].Tty] = newAttachments(i, true)
		if !spec.Tty {
			containers[i].Stderr = ctx.attachId
			ctx.attachId++
			ctx.ptys.ttys[containers[i].Stderr] = newAttachments(i, true)
		}
	}

	hostname := spec.Hostname
	if len(hostname) == 0 {
		hostname = spec.Name
	}
	if len(hostname) > 64 {
		hostname = spec.Name[:64]
	}

	ctx.vmSpec = &VmPod{
		Hostname:   hostname,
		Containers: containers,
		Dns:        spec.Dns,
		Interfaces: nil,
		Routes:     nil,
		ShareDir:   ShareDirTag,
	}

	for _, vol := range vInfo {
		ctx.setVolumeInfo(vol)
	}

	ctx.userSpec = spec
	ctx.wg = wg
}
<commit_msg>remove unused VmOnDiskInfo<commit_after>package hypervisor

import (
	"encoding/json"
	"github.com/golang/glog"
	"github.com/hyperhq/runv/hypervisor/pod"
	"github.com/hyperhq/runv/hypervisor/types"
	"os"
	"sync"
	"time"
)

type VmHwStatus struct {
	PciAddr  int    //next available pci addr for pci hotplug
	ScsiId   int    //next available scsi id for scsi hotplug
	AttachId uint64 //next available attachId for attached tty
}

type VmContext struct {
	Id string

	Paused bool
	Boot   *BootConfig

	// Communication Context
	Hub    chan VmEvent
	client chan *types.VmResponse
	vm     chan *DecodedMessage

	DCtx DriverContext

	HomeDir         string
	HyperSockName   string
	TtySockName     string
	ConsoleSockName string
	ShareDir        string

	pciAddr  int    //next available pci addr for pci hotplug
	scsiId   int    //next available scsi id for scsi hotplug
	attachId uint64 //next available attachId for attached tty

	InterfaceCount int

	ptys        *pseudoTtys
	ttySessions map[string]uint64
	pendingTtys []*AttachCommand

	// Specification
	userSpec *pod.UserPod
	vmSpec   *VmPod
	devices  *deviceMap

	progress *processingList

	// Internal Helper
	handler stateHandler
	current string
	timer   *time.Timer

	lock *sync.Mutex //protect update of context
	wg   *sync.WaitGroup
	wait bool
	Keep int
}

type stateHandler func(ctx *VmContext, event VmEvent)

func InitContext(id string, hub chan VmEvent, client chan *types.VmResponse, dc DriverContext, boot *BootConfig, keep int) (*VmContext, error) {
	var err error = nil

	vmChannel := make(chan *DecodedMessage, 128)

	//dir and sockets:
	homeDir := BaseDir + "/" + id + "/"
	hyperSockName := homeDir + HyperSockName
	ttySockName := homeDir + TtySockName
	consoleSockName := homeDir + ConsoleSockName
	shareDir := homeDir + ShareDirTag

	if dc == nil {
		dc = HDriver.InitContext(homeDir)
	}
	err = os.MkdirAll(shareDir, 0755)
	if err != nil {
		glog.Error("cannot make dir", shareDir, err.Error())
		return nil, err
	}
	defer func() {
		if err != nil {
			os.Remove(homeDir)
		}
	}()

	return &VmContext{
		Id:              id,
		Boot:            boot,
		Paused:          false,
		pciAddr:         PciAddrFrom,
		scsiId:          0,
		attachId:        1,
		Hub:             hub,
		client:          client,
		DCtx:            dc,
		vm:              vmChannel,
		ptys:            newPts(),
		ttySessions:     make(map[string]uint64),
		pendingTtys:     []*AttachCommand{},
		HomeDir:         homeDir,
		HyperSockName:   hyperSockName,
		TtySockName:     ttySockName,
		ConsoleSockName: consoleSockName,
		ShareDir:        shareDir,
		InterfaceCount:  InterfaceCount,
		timer:           nil,
		handler:         stateInit,
		userSpec:        nil,
		vmSpec:          nil,
		devices:         newDeviceMap(),
		progress:        newProcessingList(),
		lock:            &sync.Mutex{},
		wait:            false,
		Keep:            keep,
	}, nil
}

func (ctx *VmContext) setTimeout(seconds int) {
	if ctx.timer != nil {
		ctx.unsetTimeout()
	}
	ctx.timer = time.AfterFunc(time.Duration(seconds)*time.Second, func() {
		ctx.Hub <- &VmTimeout{}
	})
}

func (ctx *VmContext) unsetTimeout() {
	if ctx.timer != nil {
		ctx.timer.Stop()
		ctx.timer = nil
	}
}

func (ctx *VmContext) reset() {
	ctx.lock.Lock()

	ctx.ClosePendingTtys()

	ctx.pciAddr = PciAddrFrom
	ctx.scsiId = 0
	//do not reset attach id here, let it increase

	ctx.userSpec = nil
	ctx.vmSpec = nil
	ctx.devices = newDeviceMap()
	ctx.progress = newProcessingList()

	ctx.lock.Unlock()
}

func (ctx *VmContext) nextScsiId() int {
	ctx.lock.Lock()
	id := ctx.scsiId
	ctx.scsiId++
	ctx.lock.Unlock()
	return id
}

func (ctx *VmContext) nextPciAddr() int {
	ctx.lock.Lock()
	addr := ctx.pciAddr
	ctx.pciAddr++
	ctx.lock.Unlock()
	return addr
}

func (ctx *VmContext) nextAttachId() uint64 {
	ctx.lock.Lock()
	id := ctx.attachId
	ctx.attachId++
	ctx.lock.Unlock()
	return id
}

func (ctx *VmContext) clientReg(tag string, session uint64) {
	ctx.lock.Lock()
	ctx.ttySessions[tag] = session
	ctx.lock.Unlock()
}

func (ctx *VmContext) clientDereg(tag string) {
	if tag == "" {
		return
	}
	ctx.lock.Lock()
	if _, ok := ctx.ttySessions[tag]; ok {
		delete(ctx.ttySessions, tag)
	}
	ctx.lock.Unlock()
}

func (ctx *VmContext) Lookup(container string) int {
	if container == "" || ctx.vmSpec == nil {
		return -1
	}
	for idx, c := range ctx.vmSpec.Containers {
		if c.Id == container {
			glog.V(1).Infof("found container %s at %d", container, idx)
			return idx
		}
	}
	glog.V(1).Infof("can not found container %s", container)
	return -1
}

func (ctx *VmContext) ClosePendingTtys() {
	for _, tty := range ctx.pendingTtys {
		tty.Streams.Close(255)
	}
	ctx.pendingTtys = []*AttachCommand{}
}

func (ctx *VmContext) Close() {
	ctx.lock.Lock()
	defer ctx.lock.Unlock()
	ctx.ClosePendingTtys()
	ctx.unsetTimeout()
	ctx.DCtx.Close()
	close(ctx.vm)
	close(ctx.client)
	os.Remove(ctx.ShareDir)
	ctx.handler = nil
	ctx.current = "None"
}

func (ctx *VmContext) tryClose() bool {
	if ctx.deviceReady() {
		glog.V(1).Info("no more device to release/remove/umount, quit")
		ctx.Close()
		return true
	}
	return false
}

func (ctx *VmContext) Become(handler stateHandler, desc string) {
	orig := ctx.current
	ctx.lock.Lock()
	ctx.handler = handler
	ctx.current = desc
	ctx.lock.Unlock()
	glog.V(1).Infof("VM %s: state change from %s to '%s'", ctx.Id, orig, desc)
}

// InitDeviceContext will init device info in context
func (ctx *VmContext) InitDeviceContext(spec *pod.UserPod, wg *sync.WaitGroup,
	cInfo []*ContainerInfo, vInfo []*VolumeInfo) {

	ctx.lock.Lock()
	defer ctx.lock.Unlock()

	/* Update interface count accourding to user pod */
	ret := len(spec.Interfaces)
	if ret != 0 {
		ctx.InterfaceCount = ret
	}

	for i := 0; i < ctx.InterfaceCount; i++ {
		ctx.progress.adding.networks[i] = true
	}

	if cInfo == nil {
		cInfo = []*ContainerInfo{}
	}

	if vInfo == nil {
		vInfo = []*VolumeInfo{}
	}

	ctx.initVolumeMap(spec)

	if glog.V(3) {
		for i, c := range cInfo {
			glog.Infof("#%d Container Info:", i)
			b, err := json.MarshalIndent(c, "...|", "    ")
			if err == nil {
				glog.Info("\n", string(b))
			}
		}
	}

	containers := make([]VmContainer, len(spec.Containers))

	for i, container := range spec.Containers {
		ctx.initContainerInfo(i, &containers[i], &container)
		ctx.setContainerInfo(i, &containers[i], cInfo[i])

		containers[i].Sysctl = container.Sysctl
		containers[i].Tty = ctx.attachId
		ctx.attachId++
		ctx.ptys.ttys[containers[i].Tty] = newAttachments(i, true)
		if !spec.Tty {
			containers[i].Stderr = ctx.attachId
			ctx.attachId++
			ctx.ptys.ttys[containers[i].Stderr] = newAttachments(i, true)
		}
	}

	hostname := spec.Hostname
	if len(hostname) == 0 {
		hostname = spec.Name
	}
	if len(hostname) > 64 {
		hostname = spec.Name[:64]
	}

	ctx.vmSpec = &VmPod{
		Hostname:   hostname,
		Containers: containers,
		Dns:        spec.Dns,
		Interfaces: nil,
		Routes:     nil,
		ShareDir:   ShareDirTag,
	}

	for _, vol := range vInfo {
		ctx.setVolumeInfo(vol)
	}

	ctx.userSpec = spec
	ctx.wg = wg
}
<|endoftext|>


<commit_before>package lxstate_test

import (
	. "github.com/layer-x/layerx-core_v2/lxstate"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/layer-x/layerx-mesos-rpi_v2/fakes"
	"github.com/layer-x/layerx-commons/lxdatabase"
	"encoding/json"
)

var _ = Describe("TaskPool", func() {
	Describe("GetTask(taskId)", func(){
		It("returns the task if it exists, else returns err", func(){
			state := NewState()
			state.InitializeState("http://127.0.0.1:4001")
			PurgeState()
			err := state.InitializeState("http://127.0.0.1:4001")
			Expect(err).To(BeNil())
			pendingTasks := state.PendingTaskPool
			fakeTask := fakes.FakeTask("fake_task_id_1")
			task, err := pendingTasks.GetTask(fakeTask.TaskId)
			Expect(err).NotTo(BeNil())
			Expect(task).To(BeNil())
			err = pendingTasks.AddTask(fakeTask)
			Expect(err).To(BeNil())
			task, err = pendingTasks.GetTask(fakeTask.TaskId)
			Expect(err).To(BeNil())
			Expect(task).To(Equal(fakeTask))
		})
	})
	Describe("AddTask", func(){
		Context("the task is new", func(){
			It("adds the task to etcd state", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeTask("fake_task_id_1")
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJsonBytes, err := json.Marshal(fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJson := string(expectedTaskJsonBytes)
				actualTaskJson, err := lxdatabase.Get(state.PendingTaskPool.GetKey() + "/"+fakeTask.TaskId)
				Expect(err).To(BeNil())
				Expect(actualTaskJson).To(Equal(expectedTaskJson))
			})
		})
		Context("the task is not new", func(){
			It("returns an error", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeTask("fake_task_id_1")
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).To(BeNil())
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).NotTo(BeNil())
			})
		})
	})
	Describe("ModifyTask", func(){
		Context("the exists", func(){
			It("modifies the task", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeTask("fake_task_id_1")
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).To(BeNil())
				fakeTask.Mem = 666
				fakeTask.Cpus = 666
				fakeTask.Disk = 666
				err = pendingTasks.ModifyTask(fakeTask.TaskId, fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJsonBytes, err := json.Marshal(fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJson := string(expectedTaskJsonBytes)
				actualTaskJson, err := lxdatabase.Get(state.PendingTaskPool.GetKey() + "/"+fakeTask.TaskId)
				Expect(err).To(BeNil())
				Expect(actualTaskJson).To(Equal(expectedTaskJson))
			})
		})
		Context("the task doest exist", func(){
			It("returns an error", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeTask("fake_task_id_1")
				err = pendingTasks.ModifyTask(fakeTask.TaskId, fakeTask)
				Expect(err).NotTo(BeNil())
			})
		})
	})
	Describe("GetTasks()", func(){
		It("returns all known tasks in the pool", func(){
			state := NewState()
			state.InitializeState("http://127.0.0.1:4001")
			PurgeState()
			err := state.InitializeState("http://127.0.0.1:4001")
			Expect(err).To(BeNil())
			pendingTasks := state.PendingTaskPool
			fakeTask1 := fakes.FakeTask("fake_task_id_1")
			fakeTask2 := fakes.FakeTask("fake_task_id_2")
			fakeTask3 := fakes.FakeTask("fake_task_id_3")
			err = pendingTasks.AddTask(fakeTask1)
			Expect(err).To(BeNil())
			err = pendingTasks.AddTask(fakeTask2)
			Expect(err).To(BeNil())
			err = pendingTasks.AddTask(fakeTask3)
			Expect(err).To(BeNil())
			tasks, err := pendingTasks.GetTasks()
			Expect(err).To(BeNil())
			Expect(tasks[fakeTask1.TaskId]).To(Equal(fakeTask1))
			Expect(tasks[fakeTask2.TaskId]).To(Equal(fakeTask2))
			Expect(tasks[fakeTask3.TaskId]).To(Equal(fakeTask3))
		})
	})
	Describe("DeleteTask(taskId)", func(){
		Context("task exists", func(){
			It("deletes the task", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask1 := fakes.FakeTask("fake_task_id_1")
				fakeTask2 := fakes.FakeTask("fake_task_id_2")
				fakeTask3 := fakes.FakeTask("fake_task_id_3")
				err = pendingTasks.AddTask(fakeTask1)
				Expect(err).To(BeNil())
				err = pendingTasks.AddTask(fakeTask2)
				Expect(err).To(BeNil())
				err = pendingTasks.AddTask(fakeTask3)
				Expect(err).To(BeNil())
				err = pendingTasks.DeleteTask(fakeTask1.TaskId)
				Expect(err).To(BeNil())
				tasks, err := pendingTasks.GetTasks()
				Expect(err).To(BeNil())
				Expect(tasks[fakeTask1.TaskId]).To(BeNil())
				Expect(tasks[fakeTask2.TaskId]).To(Equal(fakeTask2))
				Expect(tasks[fakeTask3.TaskId]).To(Equal(fakeTask3))
			})
		})
		Context("task does not exist", func(){
			It("throws error", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				err = pendingTasks.DeleteTask("nonexistent_task_id")
				Expect(err).NotTo(BeNil())
			})
		})
	})
})
<commit_msg>copy some fakes over from tpi<commit_after>package lxstate_test

import (
	. "github.com/layer-x/layerx-core_v2/lxstate"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/layer-x/layerx-commons/lxdatabase"
	"encoding/json"
"github.com/layer-x/layerx-core_v2/fakes"
)

var _ = Describe("TaskPool", func() {
	Describe("GetTask(taskId)", func(){
		It("returns the task if it exists, else returns err", func(){
			state := NewState()
			state.InitializeState("http://127.0.0.1:4001")
			PurgeState()
			err := state.InitializeState("http://127.0.0.1:4001")
			Expect(err).To(BeNil())
			pendingTasks := state.PendingTaskPool
			fakeTask := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
			task, err := pendingTasks.GetTask(fakeTask.TaskId)
			Expect(err).NotTo(BeNil())
			Expect(task).To(BeNil())
			err = pendingTasks.AddTask(fakeTask)
			Expect(err).To(BeNil())
			task, err = pendingTasks.GetTask(fakeTask.TaskId)
			Expect(err).To(BeNil())
			Expect(task).To(Equal(fakeTask))
		})
	})
	Describe("AddTask", func(){
		Context("the task is new", func(){
			It("adds the task to etcd state", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJsonBytes, err := json.Marshal(fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJson := string(expectedTaskJsonBytes)
				actualTaskJson, err := lxdatabase.Get(state.PendingTaskPool.GetKey() + "/"+fakeTask.TaskId)
				Expect(err).To(BeNil())
				Expect(actualTaskJson).To(Equal(expectedTaskJson))
			})
		})
		Context("the task is not new", func(){
			It("returns an error", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).To(BeNil())
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).NotTo(BeNil())
			})
		})
	})
	Describe("ModifyTask", func(){
		Context("the exists", func(){
			It("modifies the task", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				err = pendingTasks.AddTask(fakeTask)
				Expect(err).To(BeNil())
				fakeTask.Mem = 666
				fakeTask.Cpus = 666
				fakeTask.Disk = 666
				err = pendingTasks.ModifyTask(fakeTask.TaskId, fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJsonBytes, err := json.Marshal(fakeTask)
				Expect(err).To(BeNil())
				expectedTaskJson := string(expectedTaskJsonBytes)
				actualTaskJson, err := lxdatabase.Get(state.PendingTaskPool.GetKey() + "/"+fakeTask.TaskId)
				Expect(err).To(BeNil())
				Expect(actualTaskJson).To(Equal(expectedTaskJson))
			})
		})
		Context("the task doest exist", func(){
			It("returns an error", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				err = pendingTasks.ModifyTask(fakeTask.TaskId, fakeTask)
				Expect(err).NotTo(BeNil())
			})
		})
	})
	Describe("GetTasks()", func(){
		It("returns all known tasks in the pool", func(){
			state := NewState()
			state.InitializeState("http://127.0.0.1:4001")
			PurgeState()
			err := state.InitializeState("http://127.0.0.1:4001")
			Expect(err).To(BeNil())
			pendingTasks := state.PendingTaskPool
			fakeTask1 := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
			fakeTask2 := fakes.FakeLXTask("fake_task_id_2", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
			fakeTask3 := fakes.FakeLXTask("fake_task_id_3", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
			err = pendingTasks.AddTask(fakeTask1)
			Expect(err).To(BeNil())
			err = pendingTasks.AddTask(fakeTask2)
			Expect(err).To(BeNil())
			err = pendingTasks.AddTask(fakeTask3)
			Expect(err).To(BeNil())
			tasks, err := pendingTasks.GetTasks()
			Expect(err).To(BeNil())
			Expect(tasks[fakeTask1.TaskId]).To(Equal(fakeTask1))
			Expect(tasks[fakeTask2.TaskId]).To(Equal(fakeTask2))
			Expect(tasks[fakeTask3.TaskId]).To(Equal(fakeTask3))
		})
	})
	Describe("DeleteTask(taskId)", func(){
		Context("task exists", func(){
			It("deletes the task", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				fakeTask1 := fakes.FakeLXTask("fake_task_id_1", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				fakeTask2 := fakes.FakeLXTask("fake_task_id_2", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				fakeTask3 := fakes.FakeLXTask("fake_task_id_3", "fake_task_name", "fake_slave_id", "echo FAKE_COMMAND")
				err = pendingTasks.AddTask(fakeTask1)
				Expect(err).To(BeNil())
				err = pendingTasks.AddTask(fakeTask2)
				Expect(err).To(BeNil())
				err = pendingTasks.AddTask(fakeTask3)
				Expect(err).To(BeNil())
				err = pendingTasks.DeleteTask(fakeTask1.TaskId)
				Expect(err).To(BeNil())
				tasks, err := pendingTasks.GetTasks()
				Expect(err).To(BeNil())
				Expect(tasks[fakeTask1.TaskId]).To(BeNil())
				Expect(tasks[fakeTask2.TaskId]).To(Equal(fakeTask2))
				Expect(tasks[fakeTask3.TaskId]).To(Equal(fakeTask3))
			})
		})
		Context("task does not exist", func(){
			It("throws error", func(){
				state := NewState()
				state.InitializeState("http://127.0.0.1:4001")
				PurgeState()
				err := state.InitializeState("http://127.0.0.1:4001")
				Expect(err).To(BeNil())
				pendingTasks := state.PendingTaskPool
				err = pendingTasks.DeleteTask("nonexistent_task_id")
				Expect(err).NotTo(BeNil())
			})
		})
	})
})
<|endoftext|>


<commit_before>package moskus

import (
	"errors"
	"time"
)

// TODO: Add support for more languages and locales

// A common interface for calendars for all languages and locales
type Calendar interface {
	DayName(time.Weekday) string
	RedDay(time.Time) (bool, string, bool)
	NotableDay(time.Time) (bool, string, bool)
	NormalDay() string
	NotablePeriod(date time.Time) (bool, string)
}

/* Creates a new calendar based on a given langauge string.
 *
 *  Supported strings:
 *  nb_NO (Norwegian Bokmål)
 *
 *  The calendar can be cached for faster lookups
 */
func NewCalendar(locCode string, cache bool) (Calendar, error) {
	var (
		cal       Calendar
		supported bool = true
	)

	// Find the corresponding calendar struct for the given locale
	switch locCode {
	case "nb_NO":
		cal = NewNorwegianCalendar()
	default:
		supported = false
	}

	if !supported {
		// Return an error
		return cal, errors.New("Locale not supported: " + locCode)
	}
	if !cache {
		// Return a calendar without cache
		return cal, nil
	}
	// Return a cached calendar
	return NewCachedCalendar(cal), nil
}

// Returns the third boolean argument given a time.Time value and
// a function that takes a time.Time and returns a bool, a string and a bool
func thirdBool(date time.Time, fn func(time.Time) (bool, string, bool)) bool {
	_, _, b := fn(date)
	return b
}

// Checks if a given date is a flag flying day or not
func FlagDay(cal Calendar, date time.Time) bool {
	return thirdBool(date, cal.RedDay) || thirdBool(date, cal.NotableDay)
}

// Describe what type of day a given date is
func Describe(cal Calendar, date time.Time) string {
	fulldesc := ""
	if red, desc, _ := cal.RedDay(date); red {
		fulldesc = desc
	}
	if notable, desc, _ := cal.NotableDay(date); notable {
		if fulldesc == "" {
			fulldesc = desc
		} else {
			fulldesc += ", " + desc
		}
	}
	if fulldesc != "" {
		return fulldesc
	}
	return cal.NormalDay()
}

// Get the week number, from 1 to 53
func WeekNum(date time.Time) int {
	_, weeknum := date.ISOWeek()
	return weeknum
}
<commit_msg>Added a description<commit_after>// Calendar package for finding public holidays ("red days"), easter, notable days, equinoxes, solstices and flag flying days.
package moskus

import (
	"errors"
	"time"
)

// TODO: Add support for more languages and locales

// A common interface for calendars for all languages and locales
type Calendar interface {
	DayName(time.Weekday) string
	RedDay(time.Time) (bool, string, bool)
	NotableDay(time.Time) (bool, string, bool)
	NormalDay() string
	NotablePeriod(date time.Time) (bool, string)
}

/* Creates a new calendar based on a given langauge string.
 *
 *  Supported strings:
 *  nb_NO (Norwegian Bokmål)
 *
 *  The calendar can be cached for faster lookups
 */
func NewCalendar(locCode string, cache bool) (Calendar, error) {
	var (
		cal       Calendar
		supported bool = true
	)

	// Find the corresponding calendar struct for the given locale
	switch locCode {
	case "nb_NO":
		cal = NewNorwegianCalendar()
	default:
		supported = false
	}

	if !supported {
		// Return an error
		return cal, errors.New("Locale not supported: " + locCode)
	}
	if !cache {
		// Return a calendar without cache
		return cal, nil
	}
	// Return a cached calendar
	return NewCachedCalendar(cal), nil
}

// Returns the third boolean argument given a time.Time value and
// a function that takes a time.Time and returns a bool, a string and a bool
func thirdBool(date time.Time, fn func(time.Time) (bool, string, bool)) bool {
	_, _, b := fn(date)
	return b
}

// Checks if a given date is a flag flying day or not
func FlagDay(cal Calendar, date time.Time) bool {
	return thirdBool(date, cal.RedDay) || thirdBool(date, cal.NotableDay)
}

// Describe what type of day a given date is
func Describe(cal Calendar, date time.Time) string {
	fulldesc := ""
	if red, desc, _ := cal.RedDay(date); red {
		fulldesc = desc
	}
	if notable, desc, _ := cal.NotableDay(date); notable {
		if fulldesc == "" {
			fulldesc = desc
		} else {
			fulldesc += ", " + desc
		}
	}
	if fulldesc != "" {
		return fulldesc
	}
	return cal.NormalDay()
}

// Get the week number, from 1 to 53
func WeekNum(date time.Time) int {
	_, weeknum := date.ISOWeek()
	return weeknum
}
<|endoftext|>


<commit_before><commit_msg>Attributes argument not mandatory<commit_after><|endoftext|>


<commit_before>package template

import (
	"bytes"
	html "html/template"
	"io"
	"sync"

	"github.com/omeid/slurp/s"
)

type executable interface {
	Execute(io.Writer, interface{}) error
}

func NewTemplateReadCloser(wg sync.WaitGroup, e executable, data interface{}) templateReadCloser {

	buf := new(bytes.Buffer)
	go func() {
		wg.Add(1)
		defer wg.Done()
		e.Execute(buf, data)
	}()

	return templateReadCloser{buf}
}

type templateReadCloser struct {
	io.Reader
}

func (t templateReadCloser) Close() error {
	return nil
}

func HTML(c *s.C, data interface{}) s.Job {
	return func(in <-chan s.File, out chan<- s.File) {

		templates := html.New("")

		var wg sync.WaitGroup
		defer wg.Wait() //Wait before all templates are executed.

		for f := range in {

			buf := new(bytes.Buffer)
			_, err := buf.ReadFrom(f.Content)
			f.Close()
			if err != nil {
				c.Println(err)
				break
			}

			template, err := templates.New(f.Stat.Name()).Parse(buf.String())
			if err != nil {
				c.Println(err)
				break
			}

			f.Content = NewTemplateReadCloser(wg, template, data)

			out <- f
		}
	}
}
<commit_msg>update pkg template<commit_after>package template

import (
	"bytes"
	html "html/template"
	"io"
	"sync"

	"github.com/omeid/slurp/s"
)

type executable interface {
	Execute(io.Writer, interface{}) error
}

func NewTemplateReadCloser(c *s.C, wg sync.WaitGroup, e executable, data interface{}) templateReadCloser {

	buf := new(bytes.Buffer)
	wg.Add(1)
	go func() {
		defer wg.Done()
		err := e.Execute(buf, data)
		if err != nil {
			c.Println(err)
		}
	}()

	return templateReadCloser{buf}
}

type templateReadCloser struct {
	io.Reader
}

func (t templateReadCloser) Close() error {
	return nil
}

func HTML(c *s.C, data interface{}) s.Job {
	return func(in <-chan s.File, out chan<- s.File) {

		templates := html.New("")

		var wg sync.WaitGroup
		defer wg.Wait() //Wait before all templates are executed.

		for f := range in {

			buf := new(bytes.Buffer)
			_, err := buf.ReadFrom(f.Content)
			f.Close()
			if err != nil {
				c.Println(err)
				break
			}

			template, err := templates.New(f.Stat.Name()).Parse(buf.String())
			if err != nil {
				c.Println(err)
				break
			}

			f.Content = NewTemplateReadCloser(c, wg, template, data)

			out <- f
		}
	}
}
<|endoftext|>


<commit_before>package m68k

import (
	// cs "github.com/bnagy/gapstone"
	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"

	"../../models"
)

var Arch = &models.Arch{
	Bits:   32,
	Radare: "m68k",
	// no capstone support for m68k
	CS_ARCH: 0,
	CS_MODE: 0,
	UC_ARCH: uc.UC_ARCH_M68K,
	UC_MODE: uc.UC_MODE_BIG_ENDIAN,
	SP:      uc.UC_M68K_REG_A7,
	Regs:    map[int]string{},
}
<commit_msg>add m68k regs<commit_after>package m68k

import (
	// cs "github.com/bnagy/gapstone"
	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"

	"../../models"
)

var Arch = &models.Arch{
	Bits:   32,
	Radare: "m68k",
	// no capstone support for m68k
	CS_ARCH: 0,
	CS_MODE: 0,
	UC_ARCH: uc.UC_ARCH_M68K,
	UC_MODE: uc.UC_MODE_BIG_ENDIAN,
	SP:      uc.UC_M68K_REG_A7,
	Regs: map[int]string{
		uc.UC_M68K_REG_D0: "d0",
		uc.UC_M68K_REG_D1: "d1",
		uc.UC_M68K_REG_D2: "d2",
		uc.UC_M68K_REG_D3: "d3",
		uc.UC_M68K_REG_D4: "d4",
		uc.UC_M68K_REG_D5: "d5",
		uc.UC_M68K_REG_D6: "d6",
		uc.UC_M68K_REG_D7: "d7",
		uc.UC_M68K_REG_A0: "a0",
		uc.UC_M68K_REG_A1: "a1",
		uc.UC_M68K_REG_A2: "a2",
		uc.UC_M68K_REG_A3: "a3",
		uc.UC_M68K_REG_A4: "a4",
		uc.UC_M68K_REG_A5: "a5",
		uc.UC_M68K_REG_A6: "a6",
		uc.UC_M68K_REG_A7: "sp",
		uc.UC_M68K_REG_PC: "pc",
	},
}
<|endoftext|>


<commit_before>package util

import ()

const (
	VERSION = "0.61 beta"
)
<commit_msg>released 0.61, prepare for 0.62 beta<commit_after>package util

import ()

const (
	VERSION = "0.62 beta"
)
<|endoftext|>


<commit_before>// Extensions to the go-check unittest framework.
//
// NOTE: see https://github.com/go-check/check/pull/6 for reasons why these
// checkers live here.
package gocheck2

import (
	"bytes"

	. "gopkg.in/check.v1"
)

// -----------------------------------------------------------------------
// IsTrue / IsFalse checker.

type isBoolValueChecker struct {
	*CheckerInfo
	expected bool
}

func (checker *isBoolValueChecker) Check(
	params []interface{},
	names []string) (
	result bool,
	error string) {

	obtained, ok := params[0].(bool)
	if !ok {
		return false, "Argument to " + checker.Name + " must be bool"
	}

	return obtained == checker.expected, ""
}

// The IsTrue checker verifies that the obtained value is true.
//
// For example:
//
//     c.Assert(value, IsTrue)
//
var IsTrue Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsTrue", Params: []string{"obtained"}},
	true,
}

// The IsFalse checker verifies that the obtained value is false.
//
// For example:
//
//     c.Assert(value, IsFalse)
//
var IsFalse Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsFalse", Params: []string{"obtained"}},
	false,
}

// -----------------------------------------------------------------------
// BytesEqual checker compares two bytes sequence using bytes.Equal

type bytesEquals struct{}

func (b *bytesEquals) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "BytesEqual takes 2 bytestring arguments"
	}
	b1, ok1 := params[0].([]byte)
	b2, ok2 := params[1].([]byte)

	if !(ok1 && ok2) {
		return false, "Arguments to BytesEqual must both be bytestrings"
	}

	if bytes.Equal(b1, b2) {
		return true, ""
	}
	return false, "Byte arrays were different"
}

func (b *bytesEquals) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "BytesEquals",
		Params: []string{"bytes_one", "bytes_two"},
	}
}

var BytesEquals = &bytesEquals{}
<commit_msg>Add comment and usage example<commit_after>// Extensions to the go-check unittest framework.
//
// NOTE: see https://github.com/go-check/check/pull/6 for reasons why these
// checkers live here.
package gocheck2

import (
	"bytes"

	. "gopkg.in/check.v1"
)

// -----------------------------------------------------------------------
// IsTrue / IsFalse checker.

type isBoolValueChecker struct {
	*CheckerInfo
	expected bool
}

func (checker *isBoolValueChecker) Check(
	params []interface{},
	names []string) (
	result bool,
	error string) {

	obtained, ok := params[0].(bool)
	if !ok {
		return false, "Argument to " + checker.Name + " must be bool"
	}

	return obtained == checker.expected, ""
}

// The IsTrue checker verifies that the obtained value is true.
//
// For example:
//
//     c.Assert(value, IsTrue)
//
var IsTrue Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsTrue", Params: []string{"obtained"}},
	true,
}

// The IsFalse checker verifies that the obtained value is false.
//
// For example:
//
//     c.Assert(value, IsFalse)
//
var IsFalse Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsFalse", Params: []string{"obtained"}},
	false,
}

// -----------------------------------------------------------------------
// BytesEqual checker.

type bytesEquals struct{}

func (b *bytesEquals) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "BytesEqual takes 2 bytestring arguments"
	}
	b1, ok1 := params[0].([]byte)
	b2, ok2 := params[1].([]byte)

	if !(ok1 && ok2) {
		return false, "Arguments to BytesEqual must both be bytestrings"
	}

	if bytes.Equal(b1, b2) {
		return true, ""
	}
	return false, "Byte arrays were different"
}

func (b *bytesEquals) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "BytesEquals",
		Params: []string{"bytes_one", "bytes_two"},
	}
}

// ByteEquals checker compares two bytes sequence using bytes.Equal.
//
// For example:
//
//     c.Assert(b, BytesEquals, []byte("bar"))
//
var BytesEquals = &bytesEquals{}
<|endoftext|>