<commit_before>package apps

import (
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var (
	// ErrNoAppLinked means no app was linked to the project
	ErrNoAppLinked = errors.New("No Leancloud Application was linked to the project")
)

func appDirPath(projectPath string) string {
	return filepath.Join(projectPath, ".leancloud")
}

func currentAppIDFilePath(projectPath string) string {
	return filepath.Join(appDirPath(projectPath), "current_app_id")
}

func currentGroupFilePath(projectPath string) string {
	return filepath.Join(appDirPath(projectPath), "current_group")
}

// LinkApp will write the specific appID to ${projectPath}/.leancloud/current_app_id
func LinkApp(projectPath string, appID string) error {
	err := os.Mkdir(appDirPath(projectPath), 0775)
	if err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(currentAppIDFilePath(projectPath), []byte(appID), 0644)
}

// LinkGroup will write the specific groupName to ${projectPath}/.leancloud/current_group
func LinkGroup(projectPath string, groupName string) error {
	err := os.Mkdir(appDirPath(projectPath), 0775)
	if err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(currentGroupFilePath(projectPath), []byte(groupName), 0644)
}

// GetCurrentAppID will return the content of ${projectPath}/.leancloud/current_app_id
func GetCurrentAppID(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(currentAppIDFilePath(projectPath))
	if err != nil {
		return "", err
	}
	appID := strings.TrimSpace(string(content))
	if appID == "" {
		msg := "Invalid app, please check the `.leancloud/current_app_id`'s content."
		return "", errors.New(msg)
	}

	if _, err = GetAppRegion(appID); err != nil {
		return "", err
	}

	return appID, nil
}

// GetCurrentGroup returns the content of ${projectPath}/.leancloud/current_group if it exists,
// or migrate the project's primary group.
func GetCurrentGroup(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(currentGroupFilePath(projectPath))
	if err != nil {
		return "", err
	}
	groupName := strings.TrimSpace(string(content))
	if groupName == "" {
		msg := "Invalid group, please check the `.leancloud/current_group`'s content."
		return "", errors.New(msg)
	}
	return groupName, nil
}
<commit_msg>:bug: Fix `lean switch`<commit_after>package apps

import (
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var (
	// ErrNoAppLinked means no app was linked to the project
	ErrNoAppLinked = errors.New("No Leancloud Application was linked to the project")
)

func appDirPath(projectPath string) string {
	return filepath.Join(projectPath, ".leancloud")
}

func currentAppIDFilePath(projectPath string) string {
	return filepath.Join(appDirPath(projectPath), "current_app_id")
}

func currentGroupFilePath(projectPath string) string {
	return filepath.Join(appDirPath(projectPath), "current_group")
}

// LinkApp will write the specific appID to ${projectPath}/.leancloud/current_app_id
func LinkApp(projectPath string, appID string) error {
	err := os.Mkdir(appDirPath(projectPath), 0775)
	if err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(currentAppIDFilePath(projectPath), []byte(appID), 0644)
}

// LinkGroup will write the specific groupName to ${projectPath}/.leancloud/current_group
func LinkGroup(projectPath string, groupName string) error {
	err := os.Mkdir(appDirPath(projectPath), 0775)
	if err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(currentGroupFilePath(projectPath), []byte(groupName), 0644)
}

// GetCurrentAppID will return the content of ${projectPath}/.leancloud/current_app_id
func GetCurrentAppID(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(currentAppIDFilePath(projectPath))
	if err != nil && os.IsNotExist(err) {
		return "", ErrNoAppLinked
	} else if err != nil {
		return "", err
	}
	appID := strings.TrimSpace(string(content))
	if appID == "" {
		msg := "Invalid app, please check the `.leancloud/current_app_id`'s content."
		return "", errors.New(msg)
	}

	if _, err = GetAppRegion(appID); err != nil {
		return "", err
	}

	return appID, nil
}

// GetCurrentGroup returns the content of ${projectPath}/.leancloud/current_group if it exists,
// or migrate the project's primary group.
func GetCurrentGroup(projectPath string) (string, error) {
	content, err := ioutil.ReadFile(currentGroupFilePath(projectPath))
	if err != nil {
		return "", err
	}
	groupName := strings.TrimSpace(string(content))
	if groupName == "" {
		msg := "Invalid group, please check the `.leancloud/current_group`'s content."
		return "", errors.New(msg)
	}
	return groupName, nil
}
<|endoftext|>


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

package utils

import (
	"os"
	"testing"
)

func TestConfig(t *testing.T) {
	LoadConfig("config.json")
}

/*
func TestEnvOverride(t *testing.T) {
	os.Setenv("MATTERMOST_DOMAIN", "testdomain.com")

	LoadConfig("config_docker.json")
	if Cfg.ServiceSettings.Domain != "testdomain.com" {
		t.Fail()
	}

	LoadConfig("config.json")
	if Cfg.ServiceSettings.Domain == "testdomain.com" {
		t.Fail()
	}
}
*/
<commit_msg>fixing ubild<commit_after>// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.

package utils

import (
	//"os"
	"testing"
)

func TestConfig(t *testing.T) {
	LoadConfig("config.json")
}

/*
func TestEnvOverride(t *testing.T) {
	os.Setenv("MATTERMOST_DOMAIN", "testdomain.com")

	LoadConfig("config_docker.json")
	if Cfg.ServiceSettings.Domain != "testdomain.com" {
		t.Fail()
	}

	LoadConfig("config.json")
	if Cfg.ServiceSettings.Domain == "testdomain.com" {
		t.Fail()
	}
}
*/
<|endoftext|>


<commit_before>package utils

import (
	"fmt"

	"github.com/zouyx/agollo/v2/agcache"
)

const (
	propertiesFormat = "%s=%s\n"

	defaultContentKey = "content"
)

//ContentParser 内容转换
type ContentParser interface {
	Parse(cache agcache.CacheInterface) (string, error)
}

//DefaultParser 默认内容转换器
type DefaultParser struct {
}

func (d *DefaultParser) Parse(cache agcache.CacheInterface) (string, error) {
	value, err := cache.Get(defaultContentKey)
	if err != nil {
		return "", err
	}
	return string(value), nil
}

//PropertiesParser properties转换器
type PropertiesParser struct {
}

func (d *PropertiesParser) Parse(cache agcache.CacheInterface) (string, error) {
	properties := convertToProperties(cache)
	return properties, nil
}

func convertToProperties(cache agcache.CacheInterface) string {
	properties := ""
	if cache == nil {
		return properties
	}
	cache.Range(func(key, value interface{}) bool {
		properties += fmt.Sprintf(propertiesFormat, key, string(value.([]byte)))
		return true
	})
	return properties
}
<commit_msg>add test case<commit_after>package utils

import (
	. "github.com/tevid/gohamcrest"
	"github.com/zouyx/agollo/v2/agcache"
	"testing"
)

var (
	testDefaultCache agcache.CacheInterface
	defaultParser    ContentParser
	propertiesParser ContentParser
)

func init() {
	factory := &agcache.DefaultCacheFactory{}
	testDefaultCache = factory.Create()

	defaultParser = &DefaultParser{}

	propertiesParser = &PropertiesParser{}

	testDefaultCache.Set("a", []byte("b"), 100)
	testDefaultCache.Set("c", []byte("d"), 100)
	testDefaultCache.Set("content", []byte("content"), 100)
}

func TestDefaultParser(t *testing.T) {
	s, err := defaultParser.Parse(testDefaultCache)
	Assert(t, err, NilVal())
	Assert(t, s, Equal("content"))
}

func TestPropertiesParser(t *testing.T) {
	s, err := propertiesParser.Parse(testDefaultCache)
	Assert(t, err, NilVal())
	Assert(t, s, Equal(`a=b
c=d
content=content
`))
}
<|endoftext|>


<commit_before>package ase

import (
	"bytes"
	"testing"
)

var testColors = []Color{
	Color{
		Name:   "RGB",
		Model:  "RGB",
		Values: []float32{1, 1, 1},
		Type:   "Normal",
	},
	Color{
		Name:   "Grayscale",
		Model:  "CMYK",
		Values: []float32{0, 0, 0, 0.47},
		Type:   "Spot",
	},
	Color{
		Name:   "cmyk",
		Model:  "CMYK",
		Values: []float32{0, 1, 0, 0},
		Type:   "Spot",
	},
	Color{
		Name:   "LAB",
		Model:  "RGB",
		Values: []float32{0, 0.6063648, 0.524658},
		Type:   "Global",
	},
	Color{
		Name:   "PANTONE P 1-8 C",
		Model:  "LAB",
		Values: []float32{0.9137255, -5, 94},
		Type:   "Spot",
	},
	Color{
		Name:   "Red",
		Model:  "RGB",
		Values: []float32{1, 0, 0},
		Type:   "Global",
	},
	Color{
		Name:   "Green",
		Model:  "RGB",
		Values: []float32{0, 1, 0},
		Type:   "Global",
	},
	Color{
		Name:   "Blue",
		Model:  "RGB",
		Values: []float32{0, 0, 1},
		Type:   "Global",
	},
}

var testGroup = Group{
	Name: "A Color Group",
	Colors: []Color{
		Color{
			Name:   "Red",
			Model:  "RGB",
			Values: []float32{1, 0, 0},
			Type:   "Global",
		},
		Color{
			Name:   "Green",
			Model:  "RGB",
			Values: []float32{0, 1, 0},
			Type:   "Global",
		},
		Color{
			Name:   "Blue",
			Model:  "RGB",
			Values: []float32{0, 0, 1},
			Type:   "Global",
		},
	},
}

func TestSignature(t *testing.T) {
	testFile := "samples/test.ase"

	ase, err := DecodeFile(testFile)
	if err != nil {
		t.Error(err)
	}

	expectedSignature := "ASEF"
	if ase.Signature() != expectedSignature {
		t.Error("expected signature of", expectedSignature, ", got:", ase.Signature())
	}
}

func TestVersion(t *testing.T) {
	testFile := "samples/test.ase"

	ase, err := DecodeFile(testFile)
	if err != nil {
		t.Error(err)
	}

	expectedVersion := "1.0"
	if ase.Version() != expectedVersion {
		t.Error("expected version of", expectedVersion, ", got:", ase.Version())
	}
}

func TestDecode(t *testing.T) {
	testFile := "samples/test.ase"

	ase, err := DecodeFile(testFile)
	if err != nil {
		t.Error(err)
	}

	expectedNumBlocks := int32(10)
	if ase.numBlocks != expectedNumBlocks {
		t.Error("expected ", expectedNumBlocks, " numBlocks, got ", ase.numBlocks)
	}
}

func TestEncode(t *testing.T) {

	// Initialize a sample ASE
	sampleAse := ASE{}
	sampleAse.Colors = testColors
	sampleAse.Groups = append(sampleAse.Groups, testGroup)

	// Encode the sampleAse into the buffer and immediately decode it.
	b := new(bytes.Buffer)
	Encode(sampleAse, b)
	ase, _ := Decode(b)

	// Check the ASE's decoded values.
	if string(ase.signature[0:]) != "ASEF" {
		t.Error("ase: file not an ASE file")
	}

	if ase.version[0] != 1 && ase.version[1] != 0 {
		t.Error("ase: version is not 1.0")
	}

	expectedNumBlocks := int32(13)
	actualNumBlocks := ase.numBlocks
	if actualNumBlocks != expectedNumBlocks {
		t.Error("ase: expected", expectedNumBlocks,
			" blocks to be present, got: ", actualNumBlocks)
	}

	expectedAmountOfColors := 8
	if len(ase.Colors) != expectedAmountOfColors {
		t.Error("ase: expected", expectedAmountOfColors, " colors to be present")
	}

	for i, color := range ase.Colors {
		expectedColor := testColors[i]

		if color.Name != expectedColor.Name {
			t.Error("expected initial color with name ", expectedColor.Name,
				"got ", color.Name)
		}

		if color.Model != expectedColor.Model {
			t.Error("expected initial color of Model ", expectedColor.Model,
				"got ", color.Model)
		}

		for j, _ := range expectedColor.Values {
			if color.Values[j] != expectedColor.Values[j] {
				t.Error("expected color value ", expectedColor.Values[j],
					"got ", color.Values[j])
			}
		}

		if color.Type != expectedColor.Type {
			t.Error("expected color type ", expectedColor.Type,
				"got ", color.Type)
		}
	}

	expectedAmountOfGroups := 1
	actualAmountOfGroups := len(ase.Groups)
	if actualAmountOfGroups != expectedAmountOfGroups {
		t.Error("expected ", expectedAmountOfGroups,
			"amount of groups, got: ", actualAmountOfGroups)
	}

	group := ase.Groups[0]

	if group.Name != testGroup.Name {
		t.Error("expected group name to be ", testGroup.Name,
			", got: ", group.Name)
	}

	for i, color := range group.Colors {
		expectedColor := testGroup.Colors[i]

		if color.Name != expectedColor.Name {
			t.Error("expected initial color with name ", expectedColor.Name,
				"got ", color.Name)
		}

		if color.Model != expectedColor.Model {
			t.Error("expected initial color of Model ", expectedColor.Model,
				"got ", color.Model)
		}

		for j, _ := range expectedColor.Values {
			if color.Values[j] != expectedColor.Values[j] {
				t.Error("expected color value ", expectedColor.Values[j],
					"got ", color.Values[j])
			}
		}

		if color.Type != expectedColor.Type {
			t.Error("expected color type ", expectedColor.Type,
				"got ", color.Type)
		}
	}

}
<commit_msg>(encode) include units for a decoded ASE's colors<commit_after>package ase

import (
	"bytes"
	"testing"
)

var testColors = []Color{
	Color{
		Name:   "RGB",
		Model:  "RGB",
		Values: []float32{1, 1, 1},
		Type:   "Normal",
	},
	Color{
		Name:   "Grayscale",
		Model:  "CMYK",
		Values: []float32{0, 0, 0, 0.47},
		Type:   "Spot",
	},
	Color{
		Name:   "cmyk",
		Model:  "CMYK",
		Values: []float32{0, 1, 0, 0},
		Type:   "Spot",
	},
	Color{
		Name:   "LAB",
		Model:  "RGB",
		Values: []float32{0, 0.6063648, 0.524658},
		Type:   "Global",
	},
	Color{
		Name:   "PANTONE P 1-8 C",
		Model:  "LAB",
		Values: []float32{0.9137255, -5, 94},
		Type:   "Spot",
	},
	Color{
		Name:   "Red",
		Model:  "RGB",
		Values: []float32{1, 0, 0},
		Type:   "Global",
	},
	Color{
		Name:   "Green",
		Model:  "RGB",
		Values: []float32{0, 1, 0},
		Type:   "Global",
	},
	Color{
		Name:   "Blue",
		Model:  "RGB",
		Values: []float32{0, 0, 1},
		Type:   "Global",
	},
}

var testGroup = Group{
	Name: "A Color Group",
	Colors: []Color{
		Color{
			Name:   "Red",
			Model:  "RGB",
			Values: []float32{1, 0, 0},
			Type:   "Global",
		},
		Color{
			Name:   "Green",
			Model:  "RGB",
			Values: []float32{0, 1, 0},
			Type:   "Global",
		},
		Color{
			Name:   "Blue",
			Model:  "RGB",
			Values: []float32{0, 0, 1},
			Type:   "Global",
		},
	},
}

func TestSignature(t *testing.T) {
	testFile := "samples/test.ase"

	ase, err := DecodeFile(testFile)
	if err != nil {
		t.Error(err)
	}

	expectedSignature := "ASEF"
	if ase.Signature() != expectedSignature {
		t.Error("expected signature of", expectedSignature, ", got:", ase.Signature())
	}
}

func TestVersion(t *testing.T) {
	testFile := "samples/test.ase"

	ase, err := DecodeFile(testFile)
	if err != nil {
		t.Error(err)
	}

	expectedVersion := "1.0"
	if ase.Version() != expectedVersion {
		t.Error("expected version of", expectedVersion, ", got:", ase.Version())
	}
}

func TestDecode(t *testing.T) {
	testFile := "samples/test.ase"

	ase, err := DecodeFile(testFile)
	if err != nil {
		t.Error(err)
	}

	expectedNumBlocks := int32(10)
	if ase.numBlocks != expectedNumBlocks {
		t.Error("expected ", expectedNumBlocks, " numBlocks, got ", ase.numBlocks)
	}

	expectedColors := testColors[0:5]
	expectedNumColors := len(expectedColors)
	actualNumColors := len(ase.Colors)

	if actualNumColors != expectedNumColors {
		t.Error("expected number of colors to be", expectedNumColors,
			"got ", actualNumColors)
	}

	for i, color := range ase.Colors {
		expectedColor := expectedColors[i]

		if color.Name != expectedColor.Name {
			t.Error("expected initial color with name ", expectedColor.Name,
				"got ", color.Name)
		}

		if color.Model != expectedColor.Model {
			t.Error("expected initial color of Model ", expectedColor.Model,
				"got ", color.Model)
		}

		for j, _ := range expectedColor.Values {
			if color.Values[j] != expectedColor.Values[j] {
				t.Error("expected color value ", expectedColor.Values[j],
					"got ", color.Values[j])
			}
		}

		if color.Type != expectedColor.Type {
			t.Error("expected color type ", expectedColor.Type,
				"got ", color.Type)
		}
	}
}

func TestEncode(t *testing.T) {

	// Initialize a sample ASE
	sampleAse := ASE{}
	sampleAse.Colors = testColors
	sampleAse.Groups = append(sampleAse.Groups, testGroup)

	// Encode the sampleAse into the buffer and immediately decode it.
	b := new(bytes.Buffer)
	Encode(sampleAse, b)
	ase, _ := Decode(b)

	// Check the ASE's decoded values.
	if string(ase.signature[0:]) != "ASEF" {
		t.Error("ase: file not an ASE file")
	}

	if ase.version[0] != 1 && ase.version[1] != 0 {
		t.Error("ase: version is not 1.0")
	}

	expectedNumBlocks := int32(13)
	actualNumBlocks := ase.numBlocks
	if actualNumBlocks != expectedNumBlocks {
		t.Error("ase: expected", expectedNumBlocks,
			" blocks to be present, got: ", actualNumBlocks)
	}

	expectedAmountOfColors := 8
	if len(ase.Colors) != expectedAmountOfColors {
		t.Error("ase: expected", expectedAmountOfColors, " colors to be present")
	}

	for i, color := range ase.Colors {
		expectedColor := testColors[i]

		if color.Name != expectedColor.Name {
			t.Error("expected initial color with name ", expectedColor.Name,
				"got ", color.Name)
		}

		if color.Model != expectedColor.Model {
			t.Error("expected initial color of Model ", expectedColor.Model,
				"got ", color.Model)
		}

		for j, _ := range expectedColor.Values {
			if color.Values[j] != expectedColor.Values[j] {
				t.Error("expected color value ", expectedColor.Values[j],
					"got ", color.Values[j])
			}
		}

		if color.Type != expectedColor.Type {
			t.Error("expected color type ", expectedColor.Type,
				"got ", color.Type)
		}
	}

	expectedAmountOfGroups := 1
	actualAmountOfGroups := len(ase.Groups)
	if actualAmountOfGroups != expectedAmountOfGroups {
		t.Error("expected ", expectedAmountOfGroups,
			"amount of groups, got: ", actualAmountOfGroups)
	}

	group := ase.Groups[0]

	if group.Name != testGroup.Name {
		t.Error("expected group name to be ", testGroup.Name,
			", got: ", group.Name)
	}

	for i, color := range group.Colors {
		expectedColor := testGroup.Colors[i]

		if color.Name != expectedColor.Name {
			t.Error("expected initial color with name ", expectedColor.Name,
				"got ", color.Name)
		}

		if color.Model != expectedColor.Model {
			t.Error("expected initial color of Model ", expectedColor.Model,
				"got ", color.Model)
		}

		for j, _ := range expectedColor.Values {
			if color.Values[j] != expectedColor.Values[j] {
				t.Error("expected color value ", expectedColor.Values[j],
					"got ", color.Values[j])
			}
		}

		if color.Type != expectedColor.Type {
			t.Error("expected color type ", expectedColor.Type,
				"got ", color.Type)
		}
	}

}
<|endoftext|>


<commit_before>// +build gofuzz

package ast

import (
	"regexp"
)

// nested { and [ tokens cause the parse time to explode.
// see: https://github.com/mna/pigeon/issues/75
var blacklistRegexp = regexp.MustCompile(`[{\[]{5,}`)

func Fuzz(data []byte) int {

	if blacklistRegexp.Match(data) {
		return -1
	}

	str := string(data)
	_, _, err := ParseStatements("", str)

	if err == nil {
		CompileModules(map[string]string{"": str})
		return 1
	}

	return 0
}
<commit_msg>ast: Fix fuzzer blacklist to include (<commit_after>// +build gofuzz

package ast

import (
	"regexp"
)

// nested { and [ tokens cause the parse time to explode.
// see: https://github.com/mna/pigeon/issues/75
var blacklistRegexp = regexp.MustCompile(`[{(\[]{5,}`)

func Fuzz(data []byte) int {

	if blacklistRegexp.Match(data) {
		return -1
	}

	str := string(data)
	_, _, err := ParseStatements("", str)

	if err == nil {
		CompileModules(map[string]string{"": str})
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"time"
)

func SleepSort(arr []int) []int {
	gather := make(chan int)
	for _, num := range arr {
		emit(num, gather)
	}
	out := make([]int, 0, len(arr))
	for x := 0; x < 10; x++ {
		out = append(out, <-gather)
	}
	return out
}

func emit(val int, to chan int) {
	go func() {
		ch := time.After(time.Duration(val) * time.Millisecond)
		<-ch
		to <- val
	}()
}

func main() {
	var randints []int

	for i := 0; i < 10; i++ {
		randints = append(randints, rand.Intn(100))
	}

	for _, item := range SleepSort(randints) {
		fmt.Println(item)
	}
}
<commit_msg>Added isSorted to verify SleepSort<commit_after>package main

import (
	"fmt"
	"math/rand"
	"time"
)

func SleepSort(arr []int) []int {
	gather := make(chan int)
	for _, num := range arr {
		emit(num, gather)
	}
	out := make([]int, 0, len(arr))
	for x := 0; x < 10; x++ {
		out = append(out, <-gather)
	}
	return out
}

func emit(val int, to chan int) {
	go func() {
		ch := time.After(time.Duration(val) * time.Microsecond)
		<-ch
		to <- val
	}()
}

func isSorted(nums []int) bool {

	old := nums[0]
	for _, num := range nums {
		if num < old {
			fmt.Println(num, old)
			return false
		}
	}
	return true
}

func main() {
	var randints []int

	for i := 0; i < 100000; i++ {
		randints = append(randints, rand.Intn(10000))
	}

	fmt.Println(isSorted(SleepSort(randints)))
}
<|endoftext|>


<commit_before>package httpexpect

// Object provides methods to inspect attached map[string]interface{} object
// (Go representation of JSON object).
type Object struct {
	checker Checker
	value   map[string]interface{}
}

// NewObject returns a new Object given a checker used to report failures
// and value to be inspected.
//
// Both checker and value should not be nil. If value is nil, failure is reported.
//
// Example:
//  object := NewObject(NewAssertChecker(t), map[string]interface{}{"foo": 123})
func NewObject(checker Checker, value map[string]interface{}) *Object {
	if value == nil {
		checker.Fail("expected non-nil map value")
	} else {
		value, _ = canonMap(checker, value)
	}
	return &Object{checker, value}
}

// Raw returns underlying value attached to Object.
// This is the value originally passed to NewObject, converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  assert.Equal(t, map[string]interface{}{"foo": 123.0}, object.Raw())
func (o *Object) Raw() map[string]interface{} {
	return o.value
}

// Keys returns a new Array object that may be used to inspect objects keys.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.Keys().ElementsAnyOrder("foo", "bar")
func (o *Object) Keys() *Array {
	keys := []interface{}{}
	for k := range o.value {
		keys = append(keys, k)
	}
	return NewArray(o.checker.Clone(), keys)
}

// Values returns a new Array object that may be used to inspect objects values.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.Values().ElementsAnyOrder(123, 456)
func (o *Object) Values() *Array {
	values := []interface{}{}
	for _, v := range o.value {
		values = append(values, v)
	}
	return NewArray(o.checker.Clone(), values)
}

// Value returns a new Value object that may be used to inspect single value
// for given key.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.Value("foo").Number().Equal(123)
func (o *Object) Value(key string) *Value {
	value, ok := o.value[key]
	if !ok {
		o.checker.Fail("expected map containing '%v' key, got %v", key, o.value)
		return NewValue(o.checker.Clone(), nil)
	}
	return NewValue(o.checker.Clone(), value)
}

// Empty succeedes if object is empty.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{})
//  object.Empty()
func (o *Object) Empty() *Object {
	expected := make(map[string]interface{})
	o.checker.Equal(expected, o.value)
	return o
}

// NotEmpty succeedes if object is non-empty.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.NotEmpty()
func (o *Object) NotEmpty() *Object {
	expected := make(map[string]interface{})
	o.checker.NotEqual(expected, o.value)
	return o
}

// Equal succeedes if object is equal to another object.
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.Equal(map[string]interface{}{"foo": 123})
func (o *Object) Equal(v map[string]interface{}) *Object {
	expected, ok := canonMap(o.checker, v)
	if !ok {
		return o
	}
	o.checker.Equal(expected, o.value)
	return o
}

// NotEqual succeedes if object is not equal to another object.
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.Equal(map[string]interface{}{"bar": 123})
func (o *Object) NotEqual(v map[string]interface{}) *Object {
	expected, ok := canonMap(o.checker, v)
	if !ok {
		return o
	}
	o.checker.NotEqual(expected, o.value)
	return o
}

// ContainsKey succeedes if object contains given key.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.ContainsKey("foo")
func (o *Object) ContainsKey(key string) *Object {
	if !o.containsKey(key) {
		o.checker.Fail("expected map containing '%v' key, got %v", key, o.value)
	}
	return o
}

// NotContainsKey succeedes if object doesn't contain given key.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.NotContainsKey("bar")
func (o *Object) NotContainsKey(key string) *Object {
	if o.containsKey(key) {
		o.checker.Fail("expected map NOT containing '%v' key, got %v", key, o.value)
	}
	return o
}

// ContainsMap succeedes if object contains given "subobject".
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.ContainsMap(map[string]interface{}{"foo": 123})
//
// This calls are equivalent:
//  object.ContainsMap(m)
//
//  // is equivalent to...
//  for k, v := range m {
//      object.ContainsKey(k).ValueEqual(k, v)
//  }
func (o *Object) ContainsMap(submap map[string]interface{}) *Object {
	if !o.containsMap(submap) {
		o.checker.Fail("expected map containing submap %v, got %v", submap, o.value)
	}
	return o
}

// NotContainsMap succeedes if object doesn't contain given "subobject" exactly.
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.NotContainsMap(map[string]interface{}{"foo": 123, "bar": "no-no-no"})
func (o *Object) NotContainsMap(submap map[string]interface{}) *Object {
	if o.containsMap(submap) {
		o.checker.Fail("expected map NOT containing submap %v, got %v", submap, o.value)
	}
	return o
}

// ValueEqual succeedes if object's value for given key is equal to given value.
// Before comparison, both values are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.ValueEqual("foo", 123)
func (o *Object) ValueEqual(k string, v interface{}) *Object {
	if !o.containsKey(k) {
		o.checker.Fail("expected map containing '%v' key, got %v", k, o.value)
		return o
	}
	expected, ok := canonValue(o.checker, v)
	if !ok {
		return o
	}
	o.checker.Equal(expected, o.value[k])
	return o
}

// ValueNotEqual succeedes if object's value for given key is not equal to given value.
// Before comparison, both values are converted to canonical form.
//
// If object doesn't contain any value for given key, failure is reported.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.ValueNotEqual("foo", "bad value")  // success
//  object.ValueNotEqual("bar", "bad value")  // failure! (key is missing)
func (o *Object) ValueNotEqual(k string, v interface{}) *Object {
	if !o.containsKey(k) {
		o.checker.Fail("expected map containing '%v' key, got %v", k, o.value)
		return o
	}
	expected, ok := canonValue(o.checker, v)
	if !ok {
		return o
	}
	o.checker.NotEqual(expected, o.value[k])
	return o
}

func (o *Object) containsKey(key string) bool {
	for k := range o.value {
		if k == key {
			return true
		}
	}
	return false
}

func (o *Object) containsMap(sm map[string]interface{}) bool {
	submap, ok := canonMap(o.checker, sm)
	if !ok {
		return false
	}
	return checkContainsMap(o.checker, o.value, submap)
}

func checkContainsMap(checker Checker, outer, inner map[string]interface{}) bool {
	for k, iv := range inner {
		ov, ok := outer[k]
		if !ok {
			return false
		}
		if ovm, ok := ov.(map[string]interface{}); ok {
			if ivm, ok := iv.(map[string]interface{}); ok {
				if !checkContainsMap(checker, ovm, ivm) {
					return false
				}
				continue
			}
		}
		if !checker.Compare(ov, iv) {
			return false
		}
	}
	return true
}
<commit_msg>Fix documentation for ContainsMap<commit_after>package httpexpect

// Object provides methods to inspect attached map[string]interface{} object
// (Go representation of JSON object).
type Object struct {
	checker Checker
	value   map[string]interface{}
}

// NewObject returns a new Object given a checker used to report failures
// and value to be inspected.
//
// Both checker and value should not be nil. If value is nil, failure is reported.
//
// Example:
//  object := NewObject(NewAssertChecker(t), map[string]interface{}{"foo": 123})
func NewObject(checker Checker, value map[string]interface{}) *Object {
	if value == nil {
		checker.Fail("expected non-nil map value")
	} else {
		value, _ = canonMap(checker, value)
	}
	return &Object{checker, value}
}

// Raw returns underlying value attached to Object.
// This is the value originally passed to NewObject, converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  assert.Equal(t, map[string]interface{}{"foo": 123.0}, object.Raw())
func (o *Object) Raw() map[string]interface{} {
	return o.value
}

// Keys returns a new Array object that may be used to inspect objects keys.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.Keys().ElementsAnyOrder("foo", "bar")
func (o *Object) Keys() *Array {
	keys := []interface{}{}
	for k := range o.value {
		keys = append(keys, k)
	}
	return NewArray(o.checker.Clone(), keys)
}

// Values returns a new Array object that may be used to inspect objects values.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.Values().ElementsAnyOrder(123, 456)
func (o *Object) Values() *Array {
	values := []interface{}{}
	for _, v := range o.value {
		values = append(values, v)
	}
	return NewArray(o.checker.Clone(), values)
}

// Value returns a new Value object that may be used to inspect single value
// for given key.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.Value("foo").Number().Equal(123)
func (o *Object) Value(key string) *Value {
	value, ok := o.value[key]
	if !ok {
		o.checker.Fail("expected map containing '%v' key, got %v", key, o.value)
		return NewValue(o.checker.Clone(), nil)
	}
	return NewValue(o.checker.Clone(), value)
}

// Empty succeedes if object is empty.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{})
//  object.Empty()
func (o *Object) Empty() *Object {
	expected := make(map[string]interface{})
	o.checker.Equal(expected, o.value)
	return o
}

// NotEmpty succeedes if object is non-empty.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.NotEmpty()
func (o *Object) NotEmpty() *Object {
	expected := make(map[string]interface{})
	o.checker.NotEqual(expected, o.value)
	return o
}

// Equal succeedes if object is equal to another object.
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.Equal(map[string]interface{}{"foo": 123})
func (o *Object) Equal(v map[string]interface{}) *Object {
	expected, ok := canonMap(o.checker, v)
	if !ok {
		return o
	}
	o.checker.Equal(expected, o.value)
	return o
}

// NotEqual succeedes if object is not equal to another object.
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.Equal(map[string]interface{}{"bar": 123})
func (o *Object) NotEqual(v map[string]interface{}) *Object {
	expected, ok := canonMap(o.checker, v)
	if !ok {
		return o
	}
	o.checker.NotEqual(expected, o.value)
	return o
}

// ContainsKey succeedes if object contains given key.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.ContainsKey("foo")
func (o *Object) ContainsKey(key string) *Object {
	if !o.containsKey(key) {
		o.checker.Fail("expected map containing '%v' key, got %v", key, o.value)
	}
	return o
}

// NotContainsKey succeedes if object doesn't contain given key.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.NotContainsKey("bar")
func (o *Object) NotContainsKey(key string) *Object {
	if o.containsKey(key) {
		o.checker.Fail("expected map NOT containing '%v' key, got %v", key, o.value)
	}
	return o
}

// ContainsMap succeedes if object contains given "subobject".
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{
//      "foo": 123,
//      "bar": []interface{}{"x", "y"},
//      "bar": map[string]interface{}{
//          "a": true,
//          "b": false,
//      },
//  })
//
//  object.ContainsMap(map[string]interface{}{  // success
//      "foo": 123,
//      "bar": map[string]interface{}{
//          "a": true,
//      },
//  })
//
//  object.ContainsMap(map[string]interface{}{  // failure
//      "foo": 123,
//      "qux": 456,
//  })
//
//  object.ContainsMap(map[string]interface{}{  // failure, slices should match exactly
//      "bar": []interface{}{"x"},
//  })
func (o *Object) ContainsMap(submap map[string]interface{}) *Object {
	if !o.containsMap(submap) {
		o.checker.Fail("expected map containing submap %v, got %v", submap, o.value)
	}
	return o
}

// NotContainsMap succeedes if object doesn't contain given "subobject" exactly.
// Before comparison, both objects are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123, "bar": 456})
//  object.NotContainsMap(map[string]interface{}{"foo": 123, "bar": "no-no-no"})
func (o *Object) NotContainsMap(submap map[string]interface{}) *Object {
	if o.containsMap(submap) {
		o.checker.Fail("expected map NOT containing submap %v, got %v", submap, o.value)
	}
	return o
}

// ValueEqual succeedes if object's value for given key is equal to given value.
// Before comparison, both values are converted to canonical form.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.ValueEqual("foo", 123)
func (o *Object) ValueEqual(k string, v interface{}) *Object {
	if !o.containsKey(k) {
		o.checker.Fail("expected map containing '%v' key, got %v", k, o.value)
		return o
	}
	expected, ok := canonValue(o.checker, v)
	if !ok {
		return o
	}
	o.checker.Equal(expected, o.value[k])
	return o
}

// ValueNotEqual succeedes if object's value for given key is not equal to given value.
// Before comparison, both values are converted to canonical form.
//
// If object doesn't contain any value for given key, failure is reported.
//
// Example:
//  object := NewObject(checker, map[string]interface{}{"foo": 123})
//  object.ValueNotEqual("foo", "bad value")  // success
//  object.ValueNotEqual("bar", "bad value")  // failure! (key is missing)
func (o *Object) ValueNotEqual(k string, v interface{}) *Object {
	if !o.containsKey(k) {
		o.checker.Fail("expected map containing '%v' key, got %v", k, o.value)
		return o
	}
	expected, ok := canonValue(o.checker, v)
	if !ok {
		return o
	}
	o.checker.NotEqual(expected, o.value[k])
	return o
}

func (o *Object) containsKey(key string) bool {
	for k := range o.value {
		if k == key {
			return true
		}
	}
	return false
}

func (o *Object) containsMap(sm map[string]interface{}) bool {
	submap, ok := canonMap(o.checker, sm)
	if !ok {
		return false
	}
	return checkContainsMap(o.checker, o.value, submap)
}

func checkContainsMap(checker Checker, outer, inner map[string]interface{}) bool {
	for k, iv := range inner {
		ov, ok := outer[k]
		if !ok {
			return false
		}
		if ovm, ok := ov.(map[string]interface{}); ok {
			if ivm, ok := iv.(map[string]interface{}); ok {
				if !checkContainsMap(checker, ovm, ivm) {
					return false
				}
				continue
			}
		}
		if !checker.Compare(ov, iv) {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package gitgo

import (
	"bufio"
	"bytes"
	"compress/zlib"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

const (
	RFC2822 = "Mon Jan 2 15:04:05 2006 -0700"
)

// GitObject represents a commit, tree, or blob.
// Under the hood, these may be objects stored directly
// or through packfiles
type GitObject interface {
	Type() string
	//Contents() string
}

type gitObject struct {
	Type string

	// Commit fields
	Tree      string
	Parents   []string
	Author    string
	Committer string
	Message   []byte
	Size      string

	// Tree
	Blobs []objectMeta
	Trees []objectMeta

	// Blob
	Contents []byte
}

// A Blob compresses content from a file
type Blob struct {
	_type    string
	size     string
	Contents []byte
	rawData  []byte
}

func (b Blob) Type() string {
	return b._type
}

type Commit struct {
	_type         string
	Name          SHA
	Tree          string
	Parents       []SHA
	Author        string
	AuthorDate    time.Time
	Committer     string
	CommitterDate time.Time
	Message       []byte
	size          string
	rawData       []byte
}

func (c Commit) Type() string {
	return c._type
}

type Tree struct {
	_type string
	Blobs []objectMeta
	Trees []objectMeta
	size  string
}

func (t Tree) Type() string {
	return t._type
}

// objectMeta contains the metadata
// (hash, permissions, and filename)
// corresponding either to a blob (leaf) or another tree
type objectMeta struct {
	Hash     SHA
	Perms    string
	filename string
}

func NewObject(input SHA, basedir string) (obj GitObject, err error) {
	repo := Repository{Basedir: basedir}
	return repo.Object(input)
}

func newObject(input SHA, basedir string, packfiles []*packfile) (obj GitObject, err error) {
	if path.Base(basedir) != ".git" {
		basedir = path.Join(basedir, ".git")
	}

	candidate := basedir
	for {
		_, err := os.Stat(candidate)
		if err == nil {
			basedir = candidate
			break
		}
		if !os.IsNotExist(err) {
			return nil, err
		}

		// This should not be the main condition of the for loop
		// just in case the filesystem root directory contains
		// a .git subdirectory
		// TODO check for mountpoint
		if candidate == "/" {
			return nil, fmt.Errorf("not a git repository (or any parent up to root /")
		}
		candidate = path.Join(candidate, "..", "..", ".git")
	}

	if len(input) < 4 {
		return nil, fmt.Errorf("input SHA must be at least 4 characters")
	}

	filename := path.Join(basedir, "objects", string(input[:2]), string(input[2:]))
	_, err = os.Stat(filename)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}

		// check the directory for a file with the SHA as a prefix
		_, err = os.Stat(path.Join(basedir, "objects", string(input[:2])))
		if err != nil {
			if !os.IsNotExist(err) {
				return nil, err
			}
		} else {
			dirname := path.Join(basedir, "objects", string(input[:2]))
			files, err := ioutil.ReadDir(dirname)
			if err != nil {
				return nil, err
			}
			for _, file := range files {
				if strings.HasPrefix(file.Name(), string(input[2:])) {
					return objectFromFile(path.Join(dirname, file.Name()), input, basedir)
				}
			}
		}

		// try the packfile
		for _, pack := range packfiles {
			if p, ok := pack.objects[input]; ok {
				return p.normalize(basedir)
			}
			for _, object := range pack.objects {
				if strings.HasPrefix(string(object.Name), string(input)) {
					return object.normalize(basedir)
				}
			}
		}
		return nil, fmt.Errorf("object not in any packfile: %s", input)
	}

	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r, err := zlib.NewReader(f)
	if err != nil {
		return nil, err
	}
	return parseObj(r, input, basedir)

}

func objectFromFile(filename string, name SHA, basedir string) (GitObject, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r, err := zlib.NewReader(f)
	if err != nil {
		return nil, err
	}
	return parseObj(r, name, basedir)
}

func normalizePerms(perms string) string {
	// TODO don't store permissions as a string
	for len(perms) < 6 {
		perms = "0" + perms
	}
	return perms
}

func parseObj(r io.Reader, name SHA, basedir string) (result GitObject, err error) {
	// TODO fixme
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		return result, err
	}
	obj := bts

	parts := bytes.Split(obj, []byte("\x00"))
	parts = bytes.Fields(parts[0])
	resultType := string(parts[0])
	resultSize := string(parts[1])
	nullIndex := bytes.Index(obj, []byte("\x00"))

	switch resultType {
	case "commit":
		return parseCommit(bytes.NewReader(obj[nullIndex+1:]), resultSize, name)
	case "tree":
		return parseTree(bytes.NewReader(obj), resultSize, basedir)

	case "blob":
		return parseBlob(bytes.NewReader(obj[nullIndex+1:]), resultSize)
	default:
		err = fmt.Errorf("Received unknown object type %s", resultType)
	}

	return
}

// ScanNullLines is like bufio.ScanLines, except it uses the null character as the delimiter
// instead of a newline
func ScanNullLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\x00'); i >= 0 {
		// We have a full null-terminated line.
		return i + 1, data[0:i], nil
	}
	// If we're at EOF, we have a final, non-terminated "line". Return it.
	if atEOF {
		return len(data), data, nil
	}
	// Request more data.
	return 0, nil, nil
}

func parseCommit(r io.Reader, resultSize string, name SHA) (Commit, error) {
	var commit = Commit{_type: "commit", size: resultSize}
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		return commit, err
	}
	lines := bytes.Split(bts, []byte("\n"))
	for i, line := range lines {
		// The next line is the commit message
		if len(bytes.Fields(line)) == 0 {
			commit.Message = bytes.Join(lines[i+1:], []byte("\n"))
			break
		}
		parts := bytes.Fields(line)
		key := parts[0]
		switch keyType(key) {
		case treeKey:
			commit.Tree = string(parts[1])
		case parentKey:
			commit.Parents = append(commit.Parents, SHA(string(parts[1])))
		case authorKey:
			authorline := string(bytes.Join(parts[1:], []byte(" ")))
			author, date, err := parseAuthorString(authorline)
			if err != nil {
				return commit, err
			}
			commit.Author = author
			commit.AuthorDate = date
		case committerKey:
			committerline := string(bytes.Join(parts[1:], []byte(" ")))
			committer, date, err := parseCommitterString(committerline)
			if err != nil {
				return commit, err
			}
			commit.Committer = committer
			commit.CommitterDate = date
		default:
			err = fmt.Errorf("encountered unknown field in commit: %s", key)
			return commit, err
		}
	}
	commit.Name = name
	return commit, nil
}

func parseTree(r io.Reader, resultSize string, basedir string) (Tree, error) {
	var tree = Tree{_type: "tree", size: resultSize}

	scanner := bufio.NewScanner(r)
	scanner.Split(ScanNullLines)

	var tmp objectMeta

	var resultObjs []objectMeta

	for count := 0; ; count++ {
		done := !scanner.Scan()
		if done {
			break
		}

		txt := scanner.Text()

		if count == 0 {
			// the first time through, scanner.Text() will be
			// "tree <size>"
			continue
		}
		if count == 1 {
			// the second time through, scanner.Text() will be
			// <perms> <filename>
			// separated by a space
			fields := strings.Fields(txt)
			tmp.Perms = normalizePerms(fields[0])
			tmp.filename = fields[1]
			continue
		}

		// after the second time through, scanner.Text() will be
		// <sha><perms2> <file2>
		// where perms2 and file2 refer to the permissions and filename (respectively)
		// of the NEXT object, and <sha> is the first 20 bytes exactly.
		// If there is no next object (this is the last object)
		// then scanner.Text() will yield exactly 20 bytes.

		// decode the next 20 bytes to get the SHA
		tmp.Hash = SHA(hex.EncodeToString([]byte(txt[:20])))
		resultObjs = append(resultObjs, tmp)
		if len(txt) <= 20 {
			// We've read the last line
			break
		}

		// Now, tmp points to the next object in the tree listing
		tmp = objectMeta{}
		remainder := txt[20:]
		fields := strings.Fields(remainder)
		tmp.Perms = normalizePerms(fields[0])
		tmp.filename = fields[1]
	}

	if err := scanner.Err(); err != nil && err != io.EOF {
		return tree, err
	}

	for _, part := range resultObjs {
		obj, err := NewObject(part.Hash, basedir)
		if err != nil {
			return tree, err
		}

		if o, ok := obj.(*packObject); ok {
			obj, err = o.normalize(basedir)
			if err != nil {
				return tree, err
			}
		}

		switch obj.Type() {
		case "tree":
			tree.Trees = append(tree.Trees, part)
		case "blob":
			tree.Blobs = append(tree.Blobs, part)
		default:
			return tree, fmt.Errorf("Unknown type found: %s", obj.Type())
		}
	}
	return tree, nil
}

func parseBlob(r io.Reader, resultSize string) (Blob, error) {
	var blob = Blob{_type: "blob", size: resultSize}
	bts, err := ioutil.ReadAll(r)
	blob.Contents = bts
	return blob, err
}

func findUniquePrefix(prefix SHA, files []os.FileInfo) (os.FileInfo, error) {
	var result os.FileInfo
	for _, file := range files {
		if file.IsDir() {
			continue
		}
		if strings.HasPrefix(file.Name(), string(prefix)) {
			if result != nil {
				return nil, fmt.Errorf("prefix is not unique: %s", prefix)
			}
			result = file
		}
	}
	if result == nil {
		return nil, os.ErrNotExist
	}
	return result, nil
}

// The ommitter string is in the same format as
// the author string, and oftentimes shares
// the same value as the author string.

func parseCommitterString(str string) (committer string, date time.Time, err error) {
	return parseAuthorString(str)
}

// parseAuthorString parses the author string.
func parseAuthorString(str string) (author string, date time.Time, err error) {
	const layout = "Mon Jan _2 15:04:05 2006 -0700"
	const layout2 = "Mon Jan _2 15:04:05 2006"
	var authorW bytes.Buffer
	var dateW bytes.Buffer

	s := bufio.NewScanner(strings.NewReader(str))
	s.Split(bufio.ScanBytes)

	// git will ignore '<' if it appears in an author's name
	// so we can safely use it as a delimiter
	for s.Scan() {
		authorW.Write(s.Bytes())
		if s.Text() == ">" {
			break
		}
	}
	for s.Scan() {
		dateW.Write(s.Bytes())
	}
	if s.Err() != nil {
		err = s.Err()
		return
	}

	timestamp, err := strconv.Atoi(strings.Fields(dateW.String())[0])
	if err != nil {
		return
	}

	timezone := strings.Fields(dateW.String())[1]

	hours, err := strconv.Atoi(timezone)
	if err != nil {
		return
	}
	t := time.Unix(int64(timestamp), 0).In(time.FixedZone("", hours*60*60/100))
	date, err = time.Parse(layout, fmt.Sprintf("%s %s", t.Format(layout2), timezone))

	return strings.TrimSpace(authorW.String()), date, err
}
<commit_msg>Refactor parseObj to use io.Reader interface instead of ioutil<commit_after>package gitgo

import (
	"bufio"
	"bytes"
	"compress/zlib"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

type scanner struct {
	r    io.Reader
	data []byte
	err  error
}

func (s *scanner) scan() bool {
	if s.err != nil {
		return false
	}
	s.data = s.read()
	return s.err == nil
}

func (s *scanner) Err() error {
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

func (s *scanner) read() []byte {
	if s.err != nil {
		return nil
	}
	result := make([]byte, 1)
	n, err := s.r.Read(result)
	if err != nil {
		s.err = err
		return nil
	}
	if n == 0 {
		s.err = fmt.Errorf("read zero bytes")
	}
	return result
}

const (
	RFC2822 = "Mon Jan 2 15:04:05 2006 -0700"
)

// GitObject represents a commit, tree, or blob.
// Under the hood, these may be objects stored directly
// or through packfiles
type GitObject interface {
	Type() string
	//Contents() string
}

type gitObject struct {
	Type string

	// Commit fields
	Tree      string
	Parents   []string
	Author    string
	Committer string
	Message   []byte
	Size      string

	// Tree
	Blobs []objectMeta
	Trees []objectMeta

	// Blob
	Contents []byte
}

// A Blob compresses content from a file
type Blob struct {
	_type    string
	size     string
	Contents []byte
	rawData  []byte
}

func (b Blob) Type() string {
	return b._type
}

type Commit struct {
	_type         string
	Name          SHA
	Tree          string
	Parents       []SHA
	Author        string
	AuthorDate    time.Time
	Committer     string
	CommitterDate time.Time
	Message       []byte
	size          string
	rawData       []byte
}

func (c Commit) Type() string {
	return c._type
}

type Tree struct {
	_type string
	Blobs []objectMeta
	Trees []objectMeta
	size  string
}

func (t Tree) Type() string {
	return t._type
}

// objectMeta contains the metadata
// (hash, permissions, and filename)
// corresponding either to a blob (leaf) or another tree
type objectMeta struct {
	Hash     SHA
	Perms    string
	filename string
}

func NewObject(input SHA, basedir string) (obj GitObject, err error) {
	repo := Repository{Basedir: basedir}
	return repo.Object(input)
}

func newObject(input SHA, basedir string, packfiles []*packfile) (obj GitObject, err error) {
	if path.Base(basedir) != ".git" {
		basedir = path.Join(basedir, ".git")
	}

	candidate := basedir
	for {
		_, err := os.Stat(candidate)
		if err == nil {
			basedir = candidate
			break
		}
		if !os.IsNotExist(err) {
			return nil, err
		}

		// This should not be the main condition of the for loop
		// just in case the filesystem root directory contains
		// a .git subdirectory
		// TODO check for mountpoint
		if candidate == "/" {
			return nil, fmt.Errorf("not a git repository (or any parent up to root /")
		}
		candidate = path.Join(candidate, "..", "..", ".git")
	}

	if len(input) < 4 {
		return nil, fmt.Errorf("input SHA must be at least 4 characters")
	}

	filename := path.Join(basedir, "objects", string(input[:2]), string(input[2:]))
	_, err = os.Stat(filename)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}

		// check the directory for a file with the SHA as a prefix
		_, err = os.Stat(path.Join(basedir, "objects", string(input[:2])))
		if err != nil {
			if !os.IsNotExist(err) {
				return nil, err
			}
		} else {
			dirname := path.Join(basedir, "objects", string(input[:2]))
			files, err := ioutil.ReadDir(dirname)
			if err != nil {
				return nil, err
			}
			for _, file := range files {
				if strings.HasPrefix(file.Name(), string(input[2:])) {
					return objectFromFile(path.Join(dirname, file.Name()), input, basedir)
				}
			}
		}

		// try the packfile
		for _, pack := range packfiles {
			if p, ok := pack.objects[input]; ok {
				return p.normalize(basedir)
			}
			for _, object := range pack.objects {
				if strings.HasPrefix(string(object.Name), string(input)) {
					return object.normalize(basedir)
				}
			}
		}
		return nil, fmt.Errorf("object not in any packfile: %s", input)
	}

	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r, err := zlib.NewReader(f)
	if err != nil {
		return nil, err
	}
	return parseObj(r, input, basedir)

}

func objectFromFile(filename string, name SHA, basedir string) (GitObject, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	r, err := zlib.NewReader(f)
	if err != nil {
		return nil, err
	}
	return parseObj(r, name, basedir)
}

func normalizePerms(perms string) string {
	// TODO don't store permissions as a string
	for len(perms) < 6 {
		perms = "0" + perms
	}
	return perms
}

func parseObj(r io.Reader, name SHA, basedir string) (result GitObject, err error) {

	var resultType string
	var resultSize string
	scnr := scanner{r, nil, nil}
	for scnr.scan() {
		txt := string(scnr.data)
		if txt == " " {
			break
		}
		resultType += txt
	}

	for scnr.scan() {
		txt := string(scnr.data)
		if txt == "\x00" {
			break
		}
		resultSize += txt
	}

	if scnr.Err() != nil {
		return nil, scnr.Err()
	}

	switch resultType {
	case "commit":
		return parseCommit(r, resultSize, name)
	case "tree":
		return parseTree(r, resultSize, basedir)
	case "blob":
		return parseBlob(r, resultSize)
	default:
		err = fmt.Errorf("Received unknown object type %s", resultType)
	}

	return
}

// ScanNullLines is like bufio.ScanLines, except it uses the null character as the delimiter
// instead of a newline
func ScanNullLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	if i := bytes.IndexByte(data, '\x00'); i >= 0 {
		// We have a full null-terminated line.
		return i + 1, data[0:i], nil
	}
	// If we're at EOF, we have a final, non-terminated "line". Return it.
	if atEOF {
		return len(data), data, nil
	}
	// Request more data.
	return 0, nil, nil
}

func parseCommit(r io.Reader, resultSize string, name SHA) (Commit, error) {
	var commit = Commit{_type: "commit", size: resultSize}
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		return commit, err
	}
	lines := bytes.Split(bts, []byte("\n"))
	for i, line := range lines {
		// The next line is the commit message
		if len(bytes.Fields(line)) == 0 {
			commit.Message = bytes.Join(lines[i+1:], []byte("\n"))
			break
		}
		parts := bytes.Fields(line)
		key := parts[0]
		switch keyType(key) {
		case treeKey:
			commit.Tree = string(parts[1])
		case parentKey:
			commit.Parents = append(commit.Parents, SHA(string(parts[1])))
		case authorKey:
			authorline := string(bytes.Join(parts[1:], []byte(" ")))
			author, date, err := parseAuthorString(authorline)
			if err != nil {
				return commit, err
			}
			commit.Author = author
			commit.AuthorDate = date
		case committerKey:
			committerline := string(bytes.Join(parts[1:], []byte(" ")))
			committer, date, err := parseCommitterString(committerline)
			if err != nil {
				return commit, err
			}
			commit.Committer = committer
			commit.CommitterDate = date
		default:
			err = fmt.Errorf("encountered unknown field in commit: %s", key)
			return commit, err
		}
	}
	commit.Name = name
	return commit, nil
}

func parseTree(r io.Reader, resultSize string, basedir string) (Tree, error) {
	var tree = Tree{_type: "tree", size: resultSize}

	scanner := bufio.NewScanner(r)
	scanner.Split(ScanNullLines)

	var tmp objectMeta

	var resultObjs []objectMeta

	for count := 0; ; count++ {
		done := !scanner.Scan()
		if done {
			break
		}

		txt := scanner.Text()

		if count == 0 {
			// the first time through, scanner.Text() will be
			// <perms> <filename>
			// separated by a space
			fields := strings.Fields(txt)
			tmp.Perms = normalizePerms(fields[0])
			tmp.filename = fields[1]
			continue
		}

		// after the first time through, scanner.Text() will be
		// <sha><perms2> <file2>
		// where perms2 and file2 refer to the permissions and filename (respectively)
		// of the NEXT object, and <sha> is the first 20 bytes exactly.
		// If there is no next object (this is the last object)
		// then scanner.Text() will yield exactly 20 bytes.

		// decode the next 20 bytes to get the SHA
		tmp.Hash = SHA(hex.EncodeToString([]byte(txt[:20])))
		resultObjs = append(resultObjs, tmp)
		if len(txt) <= 20 {
			// We've read the last line
			break
		}

		// Now, tmp points to the next object in the tree listing
		tmp = objectMeta{}
		remainder := txt[20:]
		fields := strings.Fields(remainder)
		tmp.Perms = normalizePerms(fields[0])
		tmp.filename = fields[1]
	}

	if err := scanner.Err(); err != nil && err != io.EOF {
		return tree, err
	}

	for _, part := range resultObjs {
		obj, err := NewObject(part.Hash, basedir)
		if err != nil {
			return tree, err
		}

		if o, ok := obj.(*packObject); ok {
			obj, err = o.normalize(basedir)
			if err != nil {
				return tree, err
			}
		}

		switch obj.Type() {
		case "tree":
			tree.Trees = append(tree.Trees, part)
		case "blob":
			tree.Blobs = append(tree.Blobs, part)
		default:
			return tree, fmt.Errorf("Unknown type found: %s", obj.Type())
		}
	}
	return tree, nil
}

func parseBlob(r io.Reader, resultSize string) (Blob, error) {
	var blob = Blob{_type: "blob", size: resultSize}
	bts, err := ioutil.ReadAll(r)
	blob.Contents = bts
	return blob, err
}

func findUniquePrefix(prefix SHA, files []os.FileInfo) (os.FileInfo, error) {
	var result os.FileInfo
	for _, file := range files {
		if file.IsDir() {
			continue
		}
		if strings.HasPrefix(file.Name(), string(prefix)) {
			if result != nil {
				return nil, fmt.Errorf("prefix is not unique: %s", prefix)
			}
			result = file
		}
	}
	if result == nil {
		return nil, os.ErrNotExist
	}
	return result, nil
}

// The ommitter string is in the same format as
// the author string, and oftentimes shares
// the same value as the author string.

func parseCommitterString(str string) (committer string, date time.Time, err error) {
	return parseAuthorString(str)
}

// parseAuthorString parses the author string.
func parseAuthorString(str string) (author string, date time.Time, err error) {
	const layout = "Mon Jan _2 15:04:05 2006 -0700"
	const layout2 = "Mon Jan _2 15:04:05 2006"
	var authorW bytes.Buffer
	var dateW bytes.Buffer

	s := bufio.NewScanner(strings.NewReader(str))
	s.Split(bufio.ScanBytes)

	// git will ignore '<' if it appears in an author's name
	// so we can safely use it as a delimiter
	for s.Scan() {
		authorW.Write(s.Bytes())
		if s.Text() == ">" {
			break
		}
	}
	for s.Scan() {
		dateW.Write(s.Bytes())
	}
	if s.Err() != nil {
		err = s.Err()
		return
	}

	timestamp, err := strconv.Atoi(strings.Fields(dateW.String())[0])
	if err != nil {
		return
	}

	timezone := strings.Fields(dateW.String())[1]

	hours, err := strconv.Atoi(timezone)
	if err != nil {
		return
	}
	t := time.Unix(int64(timestamp), 0).In(time.FixedZone("", hours*60*60/100))
	date, err = time.Parse(layout, fmt.Sprintf("%s %s", t.Format(layout2), timezone))

	return strings.TrimSpace(authorW.String()), date, err
}
<|endoftext|>


<commit_before>package orm

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	"strings"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
)

type DB interface {
	Query(sql string, args ...interface{}) (*sql.Rows, error)
	Exec(sql string, args ...interface{}) (sql.Result, error)
}

type DBStore struct {
	*sql.DB
	debug   bool
	slowlog time.Duration
}

func NewDBStore(driver, host string, port int, database, username, password string) (*DBStore, error) {
	var dsn string
	switch strings.ToLower(driver) {
	case "mysql":
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&autocommit=true&parseTime=True",
			username,
			password,
			host,
			port,
			database)
	case "mssql":
		dsn = fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s",
			host, username, password, port, database)
	default:
		return nil, fmt.Errorf("unsupport db driver: %s", driver)
	}
	db, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}
	return &DBStore{db, false, time.Duration(0)}, nil
}

func (store *DBStore) Debug(b bool) {
	store.debug = b
}

func (store *DBStore) SlowLog(duration time.Duration) {
	store.slowlog = duration
}

func (store *DBStore) Query(sql string, args ...interface{}) (*sql.Rows, error) {
	t1 := time.Now()
	if store.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > store.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if store.debug {
		log.Println("DEBUG: ", sql, args)
	}
	return store.DB.Query(sql, args...)
}

func (store *DBStore) Exec(sql string, args ...interface{}) (sql.Result, error) {
	t1 := time.Now()
	if store.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > store.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if store.debug {
		log.Println("DEBUG: ", sql, args)
	}
	return store.DB.Exec(sql, args...)
}

func (store *DBStore) Close() error {
	if err := store.DB.Close(); err != nil {
		return err
	}
	store.DB = nil
	return nil
}

type DBTx struct {
	tx           *sql.Tx
	debug        bool
	slowlog      time.Duration
	err          error
	rowsAffected int64
}

func (store *DBStore) BeginTx() (*DBTx, error) {
	tx, err := store.Begin()
	if err != nil {
		return nil, err
	}

	return &DBTx{
		tx:      tx,
		debug:   store.debug,
		slowlog: store.slowlog,
	}, nil
}

func (tx *DBTx) Close() error {
	if tx.err != nil {
		return tx.tx.Rollback()
	}
	return tx.tx.Commit()
}

func (tx *DBTx) Query(sql string, args ...interface{}) (*sql.Rows, error) {
	t1 := time.Now()
	if tx.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > tx.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if tx.debug {
		log.Println("DEBUG: ", sql, args)
	}
	result, err := tx.tx.Query(sql, args...)
	tx.err = err
	return result, tx.err
}

func (tx *DBTx) Exec(sql string, args ...interface{}) (sql.Result, error) {
	t1 := time.Now()
	if tx.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > tx.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if tx.debug {
		log.Println("DEBUG: ", sql, args)
	}
	result, err := tx.tx.Exec(sql, args...)
	tx.err = err
	return result, tx.err
}
<commit_msg>add SetError orm DB<commit_after>package orm

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	"strings"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
)

type DB interface {
	Query(sql string, args ...interface{}) (*sql.Rows, error)
	Exec(sql string, args ...interface{}) (sql.Result, error)
	SetError(err error)
}

type DBStore struct {
	*sql.DB
	debug   bool
	slowlog time.Duration
}

func NewDBStore(driver, host string, port int, database, username, password string) (*DBStore, error) {
	var dsn string
	switch strings.ToLower(driver) {
	case "mysql":
		dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&autocommit=true&parseTime=True",
			username,
			password,
			host,
			port,
			database)
	case "mssql":
		dsn = fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s",
			host, username, password, port, database)
	default:
		return nil, fmt.Errorf("unsupport db driver: %s", driver)
	}
	db, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}
	return &DBStore{db, false, time.Duration(0)}, nil
}

func (store *DBStore) Debug(b bool) {
	store.debug = b
}

func (store *DBStore) SlowLog(duration time.Duration) {
	store.slowlog = duration
}

func (store *DBStore) Query(sql string, args ...interface{}) (*sql.Rows, error) {
	t1 := time.Now()
	if store.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > store.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if store.debug {
		log.Println("DEBUG: ", sql, args)
	}
	return store.DB.Query(sql, args...)
}

func (store *DBStore) Exec(sql string, args ...interface{}) (sql.Result, error) {
	t1 := time.Now()
	if store.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > store.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if store.debug {
		log.Println("DEBUG: ", sql, args)
	}
	return store.DB.Exec(sql, args...)
}

func (store *DBStore) SetError(err error) {}

func (store *DBStore) Close() error {
	if err := store.DB.Close(); err != nil {
		return err
	}
	store.DB = nil
	return nil
}

type DBTx struct {
	tx           *sql.Tx
	debug        bool
	slowlog      time.Duration
	err          error
	rowsAffected int64
}

func (store *DBStore) BeginTx() (*DBTx, error) {
	tx, err := store.Begin()
	if err != nil {
		return nil, err
	}

	return &DBTx{
		tx:      tx,
		debug:   store.debug,
		slowlog: store.slowlog,
	}, nil
}

func (tx *DBTx) Close() error {
	if tx.err != nil {
		return tx.tx.Rollback()
	}
	return tx.tx.Commit()
}

func (tx *DBTx) Query(sql string, args ...interface{}) (*sql.Rows, error) {
	t1 := time.Now()
	if tx.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > tx.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if tx.debug {
		log.Println("DEBUG: ", sql, args)
	}
	result, err := tx.tx.Query(sql, args...)
	tx.err = err
	return result, tx.err
}

func (tx *DBTx) Exec(sql string, args ...interface{}) (sql.Result, error) {
	t1 := time.Now()
	if tx.slowlog > 0 {
		defer func(t time.Time) {
			span := time.Now().Sub(t1)
			if span > tx.slowlog {
				log.Println("SLOW: ", span.String(), sql, args)
			}
		}(t1)
	}
	if tx.debug {
		log.Println("DEBUG: ", sql, args)
	}
	result, err := tx.tx.Exec(sql, args...)
	tx.err = err
	return result, tx.err
}

func (tx *DBTx) SetError(err error) {
	tx.err = err
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Intel Corporation
//
// 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 main

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"
	"time"

	goudev "github.com/jochenvg/go-udev"
)

const mountPerm = os.FileMode(0755)
const devPath = "/dev"

// bindMount bind mounts a source in to a destination, with the recursive
// flag if needed.
func bindMount(source, destination string, recursive bool) error {
	flags := syscall.MS_BIND

	if recursive == true {
		flags |= syscall.MS_REC
	}

	return mount(source, destination, "bind", flags)
}

// mount mounts a source in to a destination. This will do some bookkeeping:
// * evaluate all symlinks
// * ensure the source exists
func mount(source, destination, fsType string, flags int) error {
	var options string
	if fsType == "xfs" {
		options = "nouuid"
	}

	absSource, err := filepath.EvalSymlinks(source)
	if err != nil {
		return fmt.Errorf("Could not resolve symlink for source %v", source)
	}

	if err := ensureDestinationExists(absSource, destination, fsType); err != nil {
		return fmt.Errorf("Could not create destination mount point: %v: %v", destination, err)
	}

	if err := syscall.Mount(absSource, destination, fsType, uintptr(flags), options); err != nil {
		return fmt.Errorf("Could not bind mount %v to %v: %v", absSource, destination, err)
	}

	return nil
}

// ensureDestinationExists will recursively create a given mountpoint. If directories
// are created, their permissions are initialized to mountPerm
func ensureDestinationExists(source, destination string, fsType string) error {
	fileInfo, err := os.Stat(source)
	if err != nil {
		return fmt.Errorf("could not stat source location: %v", source)
	}

	targetPathParent, _ := filepath.Split(destination)
	if err := os.MkdirAll(targetPathParent, mountPerm); err != nil {
		return fmt.Errorf("could not create parent directory: %v", targetPathParent)
	}

	if fsType != "bind" || fileInfo.IsDir() {
		if err := os.Mkdir(destination, mountPerm); !os.IsExist(err) {
			return err
		}
	} else {
		file, err := os.OpenFile(destination, os.O_CREATE, mountPerm)
		if err != nil {
			return err
		}

		file.Close()
	}
	return nil
}

func mountShareDir(tag string) error {
	if tag == "" {
		return fmt.Errorf("Invalid mount tag, should not be empty")
	}

	if err := os.MkdirAll(mountShareDirDest, os.FileMode(0755)); err != nil {
		return err
	}

	return syscall.Mount(tag, mountShareDirDest, type9pFs, syscall.MS_MGC_VAL|syscall.MS_NODEV, "trans=virtio,version=9p2000.L,posixacl,cache=mmap")

}

func unmountShareDir() error {
	if err := syscall.Unmount(mountShareDirDest, 0); err != nil {
		return err
	}

	return os.RemoveAll(containerMountDest)
}

func waitForBlockDevice(deviceName string) error {
	devicePath := filepath.Join(devPath, deviceName)

	if _, err := os.Stat(devicePath); err == nil {
		return nil
	}

	u := goudev.Udev{}

	// Create a monitor listening on a NetLink socket.
	monitor := u.NewMonitorFromNetlink("udev")

	// Add filter to watch for just block devices.
	if err := monitor.FilterAddMatchSubsystemDevtype("block", "disk"); err != nil {
		return err
	}

	// Create done signal channel for signalling epoll loop on the monitor socket.
	done := make(chan struct{})

	// Create channel to signal when desired udev event has been received.
	doneListening := make(chan bool)

	// Start monitor goroutine.
	ch, _ := monitor.DeviceChan(done)

	go func() {
		agentLog.Infof("Started listening for udev events for block device hotplug")

		// Check if the device already exists.
		if _, err := os.Stat(devicePath); err == nil {
			agentLog.Infof("Device %s already hotplugged, quit listening", deviceName)
		} else {

			for d := range ch {
				agentLog.Infof("Event:", d.Syspath(), d.Action())
				if d.Action() == "add" && filepath.Base(d.Devpath()) == deviceName {
					agentLog.Infof("Hotplug event received for device %s", deviceName)
					break
				}
			}
		}
		close(doneListening)
	}()

	select {
	case <-doneListening:
		close(done)
	case <-time.After(time.Duration(1) * time.Second):
		close(done)
		return fmt.Errorf("Timed out waiting for device %s", deviceName)
	}

	return nil
}

func mountContainerRootFs(containerID, image, rootFs, fsType string) (string, error) {
	dest := filepath.Join(containerMountDest, containerID, "root")
	if err := os.MkdirAll(dest, os.FileMode(0755)); err != nil {
		return "", err
	}

	var source string
	if fsType != "" {
		source = filepath.Join(devPath, image)
		if err := waitForBlockDevice(image); err != nil {
			return "", err
		}

		if err := mount(source, dest, fsType, 0); err != nil {
			return "", err
		}
	} else {
		source = filepath.Join(mountShareDirDest, image)
		if err := bindMount(source, dest, false); err != nil {
			return "", err
		}
	}

	mountingPath := filepath.Join(dest, rootFs)
	if err := bindMount(mountingPath, mountingPath, true); err != nil {
		return "", err
	}

	return mountingPath, nil
}

func unmountContainerRootFs(containerID, mountingPath string) error {
	if err := syscall.Unmount(mountingPath, 0); err != nil {
		return err
	}

	containerPath := filepath.Join(containerMountDest, containerID, "root")
	if err := syscall.Unmount(containerPath, 0); err != nil {
		return err
	}

	if err := os.RemoveAll(containerPath); err != nil {
		return err
	}

	return nil
}

func ioctl(fd uintptr, flag, data uintptr) error {
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 {
		return err
	}

	return nil
}
<commit_msg>Revert "agent: update 9p mount syscall so mmap is rw"<commit_after>//
// Copyright (c) 2017 Intel Corporation
//
// 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 main

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"
	"time"

	goudev "github.com/jochenvg/go-udev"
)

const mountPerm = os.FileMode(0755)
const devPath = "/dev"

// bindMount bind mounts a source in to a destination, with the recursive
// flag if needed.
func bindMount(source, destination string, recursive bool) error {
	flags := syscall.MS_BIND

	if recursive == true {
		flags |= syscall.MS_REC
	}

	return mount(source, destination, "bind", flags)
}

// mount mounts a source in to a destination. This will do some bookkeeping:
// * evaluate all symlinks
// * ensure the source exists
func mount(source, destination, fsType string, flags int) error {
	var options string
	if fsType == "xfs" {
		options = "nouuid"
	}

	absSource, err := filepath.EvalSymlinks(source)
	if err != nil {
		return fmt.Errorf("Could not resolve symlink for source %v", source)
	}

	if err := ensureDestinationExists(absSource, destination, fsType); err != nil {
		return fmt.Errorf("Could not create destination mount point: %v: %v", destination, err)
	}

	if err := syscall.Mount(absSource, destination, fsType, uintptr(flags), options); err != nil {
		return fmt.Errorf("Could not bind mount %v to %v: %v", absSource, destination, err)
	}

	return nil
}

// ensureDestinationExists will recursively create a given mountpoint. If directories
// are created, their permissions are initialized to mountPerm
func ensureDestinationExists(source, destination string, fsType string) error {
	fileInfo, err := os.Stat(source)
	if err != nil {
		return fmt.Errorf("could not stat source location: %v", source)
	}

	targetPathParent, _ := filepath.Split(destination)
	if err := os.MkdirAll(targetPathParent, mountPerm); err != nil {
		return fmt.Errorf("could not create parent directory: %v", targetPathParent)
	}

	if fsType != "bind" || fileInfo.IsDir() {
		if err := os.Mkdir(destination, mountPerm); !os.IsExist(err) {
			return err
		}
	} else {
		file, err := os.OpenFile(destination, os.O_CREATE, mountPerm)
		if err != nil {
			return err
		}

		file.Close()
	}
	return nil
}

func mountShareDir(tag string) error {
	if tag == "" {
		return fmt.Errorf("Invalid mount tag, should not be empty")
	}

	if err := os.MkdirAll(mountShareDirDest, os.FileMode(0755)); err != nil {
		return err
	}

	return syscall.Mount(tag, mountShareDirDest, type9pFs, syscall.MS_MGC_VAL|syscall.MS_NODEV, "trans=virtio")
}

func unmountShareDir() error {
	if err := syscall.Unmount(mountShareDirDest, 0); err != nil {
		return err
	}

	return os.RemoveAll(containerMountDest)
}

func waitForBlockDevice(deviceName string) error {
	devicePath := filepath.Join(devPath, deviceName)

	if _, err := os.Stat(devicePath); err == nil {
		return nil
	}

	u := goudev.Udev{}

	// Create a monitor listening on a NetLink socket.
	monitor := u.NewMonitorFromNetlink("udev")

	// Add filter to watch for just block devices.
	if err := monitor.FilterAddMatchSubsystemDevtype("block", "disk"); err != nil {
		return err
	}

	// Create done signal channel for signalling epoll loop on the monitor socket.
	done := make(chan struct{})

	// Create channel to signal when desired udev event has been received.
	doneListening := make(chan bool)

	// Start monitor goroutine.
	ch, _ := monitor.DeviceChan(done)

	go func() {
		agentLog.Infof("Started listening for udev events for block device hotplug")

		// Check if the device already exists.
		if _, err := os.Stat(devicePath); err == nil {
			agentLog.Infof("Device %s already hotplugged, quit listening", deviceName)
		} else {

			for d := range ch {
				agentLog.Infof("Event:", d.Syspath(), d.Action())
				if d.Action() == "add" && filepath.Base(d.Devpath()) == deviceName {
					agentLog.Infof("Hotplug event received for device %s", deviceName)
					break
				}
			}
		}
		close(doneListening)
	}()

	select {
	case <-doneListening:
		close(done)
	case <-time.After(time.Duration(1) * time.Second):
		close(done)
		return fmt.Errorf("Timed out waiting for device %s", deviceName)
	}

	return nil
}

func mountContainerRootFs(containerID, image, rootFs, fsType string) (string, error) {
	dest := filepath.Join(containerMountDest, containerID, "root")
	if err := os.MkdirAll(dest, os.FileMode(0755)); err != nil {
		return "", err
	}

	var source string
	if fsType != "" {
		source = filepath.Join(devPath, image)
		if err := waitForBlockDevice(image); err != nil {
			return "", err
		}

		if err := mount(source, dest, fsType, 0); err != nil {
			return "", err
		}
	} else {
		source = filepath.Join(mountShareDirDest, image)
		if err := bindMount(source, dest, false); err != nil {
			return "", err
		}
	}

	mountingPath := filepath.Join(dest, rootFs)
	if err := bindMount(mountingPath, mountingPath, true); err != nil {
		return "", err
	}

	return mountingPath, nil
}

func unmountContainerRootFs(containerID, mountingPath string) error {
	if err := syscall.Unmount(mountingPath, 0); err != nil {
		return err
	}

	containerPath := filepath.Join(containerMountDest, containerID, "root")
	if err := syscall.Unmount(containerPath, 0); err != nil {
		return err
	}

	if err := os.RemoveAll(containerPath); err != nil {
		return err
	}

	return nil
}

func ioctl(fd uintptr, flag, data uintptr) error {
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/mgood/resolvable/resolver"

	"github.com/coreos/go-systemd/dbus"
)

type service struct {
	name        string
	dir         string
	filepattern string
}

var defaultServices []service = []service{
	service{"systemd-resolved.service", "resolved.conf.d", "*.conf"},
	service{"systemd-networkd.service", "network", "*.network"},
}

type SystemdConfig struct {
	templatePath string
	destPath     string
	services     []service
	written      map[string][]string
}

type templateArgs struct {
	Address string
}

func getopt(name, def string) string {
	if env := os.Getenv(name); env != "" {
		return env
	}
	return def
}

func init() {
	systemdConf := getopt("SYSTEMD_CONF_PATH", "/tmp/systemd")
	resolver.HostResolverConfigs.Register(&SystemdConfig{
		templatePath: "/config/systemd",
		destPath:     systemdConf,
		services:     defaultServices,
		written:      make(map[string][]string),
	}, "systemd")
}

func (r *SystemdConfig) StoreAddress(address string) error {
	data := templateArgs{address}

	for _, s := range r.services {
		pattern := filepath.Join(r.templatePath, s.dir, s.filepattern)

		log.Printf("systemd: %s: loading config from %s", s.name, pattern)

		templates, err := template.ParseGlob(pattern)
		if err != nil {
			log.Println("systemd:", err)
			continue
		}

		var written []string

		for _, t := range templates.Templates() {
			dest := filepath.Join(r.destPath, s.dir, t.Name())
			log.Println("systemd: generating", dest)
			fp, err := os.Create(dest)
			if err != nil {
				log.Println("systemd:", err)
				continue
			}
			written = append(written, dest)
			t.Execute(fp, data)
			fp.Close()
		}

		if written != nil {
			r.written[s.name] = written
			reload(s.name)
		} else {
			log.Println("systemd: %s: no configs written, skipping reload", s.name)
		}
	}

	return nil
}

func (r *SystemdConfig) Clean() {
	for service, filenames := range r.written {
		log.Printf("systemd: %s: removing configs...", service)
		for _, filename := range filenames {
			os.Remove(filename)
		}
		reload(service)
	}
}

func reload(name string) error {
	conn, err := dbus.New()
	if err != nil {
		return err
	}

	log.Printf("systemd: %s: starting reload...", name)

	statusCh := make(chan string)
	_, err = conn.ReloadOrRestartUnit(name, "replace", statusCh)
	if err != nil {
		return err
	}

	status := <-statusCh
	log.Printf("systemd: %s: %s", name, status)
	if status != "done" {
		return fmt.Errorf("error reloading %s: %s", name, status)
	}
	return nil
}
<commit_msg>Change package to systemd<commit_after>package systemd

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/mgood/resolvable/resolver"

	"github.com/coreos/go-systemd/dbus"
)

type service struct {
	name        string
	dir         string
	filepattern string
}

var defaultServices []service = []service{
	service{"systemd-resolved.service", "resolved.conf.d", "*.conf"},
	service{"systemd-networkd.service", "network", "*.network"},
}

type SystemdConfig struct {
	templatePath string
	destPath     string
	services     []service
	written      map[string][]string
}

type templateArgs struct {
	Address string
}

func getopt(name, def string) string {
	if env := os.Getenv(name); env != "" {
		return env
	}
	return def
}

func init() {
	systemdConf := getopt("SYSTEMD_CONF_PATH", "/tmp/systemd")
	resolver.HostResolverConfigs.Register(&SystemdConfig{
		templatePath: "/config/systemd",
		destPath:     systemdConf,
		services:     defaultServices,
		written:      make(map[string][]string),
	}, "systemd")
}

func (r *SystemdConfig) StoreAddress(address string) error {
	data := templateArgs{address}

	for _, s := range r.services {
		pattern := filepath.Join(r.templatePath, s.dir, s.filepattern)

		log.Printf("systemd: %s: loading config from %s", s.name, pattern)

		templates, err := template.ParseGlob(pattern)
		if err != nil {
			log.Println("systemd:", err)
			continue
		}

		var written []string

		for _, t := range templates.Templates() {
			dest := filepath.Join(r.destPath, s.dir, t.Name())
			log.Println("systemd: generating", dest)
			fp, err := os.Create(dest)
			if err != nil {
				log.Println("systemd:", err)
				continue
			}
			written = append(written, dest)
			t.Execute(fp, data)
			fp.Close()
		}

		if written != nil {
			r.written[s.name] = written
			reload(s.name)
		} else {
			log.Println("systemd: %s: no configs written, skipping reload", s.name)
		}
	}

	return nil
}

func (r *SystemdConfig) Clean() {
	for service, filenames := range r.written {
		log.Printf("systemd: %s: removing configs...", service)
		for _, filename := range filenames {
			os.Remove(filename)
		}
		reload(service)
	}
}

func reload(name string) error {
	conn, err := dbus.New()
	if err != nil {
		return err
	}

	log.Printf("systemd: %s: starting reload...", name)

	statusCh := make(chan string)
	_, err = conn.ReloadOrRestartUnit(name, "replace", statusCh)
	if err != nil {
		return err
	}

	status := <-statusCh
	log.Printf("systemd: %s: %s", name, status)
	if status != "done" {
		return fmt.Errorf("error reloading %s: %s", name, status)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
The tag tool reads metadata from media files (as supported by the tag library).
*/
package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/dhowden/tag"
)

var raw bool

var usage = func() {
	fmt.Fprintf(os.Stderr, "usage: %s [optional flags] filename\n", os.Args[0])
	flag.PrintDefaults()
}

func init() {
	flag.BoolVar(&raw, "raw", false, "show raw tag data")

	flag.Usage = usage
}

func main() {
	flag.Parse()

	if flag.NArg() != 1 {
		usage()
		return
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Printf("error loading file: %v", err)
		return
	}
	defer f.Close()

	m, err := tag.ReadFrom(f)
	if err != nil {
		fmt.Printf("error reading file: %v\n", err)
		return
	}

	printMetadata(m)

	if raw {
		fmt.Println()
		fmt.Println()

		tags := m.Raw()
		for k, v := range tags {
			if _, ok := v.(*tag.Picture); ok {
				fmt.Printf("%#v: %v\n", k, v)
				continue
			}
			fmt.Printf("%#v: %#v\n", k, v)
		}
	}
}

func printMetadata(m tag.Metadata) {
	fmt.Printf("Metadata Format: %v\n", m.Format())
	fmt.Printf("File Type: %v\n", m.FileType())

	fmt.Printf(" Title: %v\n", m.Title())
	fmt.Printf(" Album: %v\n", m.Album())
	fmt.Printf(" Artist: %v\n", m.Artist())
	fmt.Printf(" Composer: %v\n", m.Composer())
	fmt.Printf(" Genre: %v\n", m.Genre())
	fmt.Printf(" Year: %v\n", m.Year())

	track, trackCount := m.Track()
	fmt.Printf(" Track: %v of %v\n", track, trackCount)

	disc, discCount := m.Disc()
	fmt.Printf(" Disc: %v of %v\n", disc, discCount)

	fmt.Printf(" Picture: %v\n", m.Picture())
	fmt.Printf(" Lyrics: %v\n", m.Lyrics())
}
<commit_msg>Added -mbz option to tag tool to output MusicBrainz information.<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
The tag tool reads metadata from media files (as supported by the tag library).
*/
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"

	"github.com/dhowden/tag"
	"github.com/dhowden/tag/mbz"
)

var raw bool
var extractMBZ bool

var usage = func() {
	fmt.Fprintf(os.Stderr, "usage: %s [optional flags] filename\n", os.Args[0])
	flag.PrintDefaults()
}

func init() {
	flag.BoolVar(&raw, "raw", false, "show raw tag data")
	flag.BoolVar(&extractMBZ, "mbz", false, "extract MusicBrainz tag data (if available)")

	flag.Usage = usage
}

func main() {
	flag.Parse()

	if flag.NArg() != 1 {
		usage()
		return
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Printf("error loading file: %v", err)
		return
	}
	defer f.Close()

	m, err := tag.ReadFrom(f)
	if err != nil {
		fmt.Printf("error reading file: %v\n", err)
		return
	}

	printMetadata(m)

	if raw {
		fmt.Println()
		fmt.Println()

		tags := m.Raw()
		for k, v := range tags {
			if _, ok := v.(*tag.Picture); ok {
				fmt.Printf("%#v: %v\n", k, v)
				continue
			}
			fmt.Printf("%#v: %#v\n", k, v)
		}
	}

	if extractMBZ {
		b, err := json.MarshalIndent(mbz.Extract(m), "", "  ")
		if err != nil {
			fmt.Printf("error marshalling MusicBrainz info: %v\n", err)
			return
		}

		fmt.Printf("\nMusicBrainz Info:\n%v\n", string(b))
	}
}

func printMetadata(m tag.Metadata) {
	fmt.Printf("Metadata Format: %v\n", m.Format())
	fmt.Printf("File Type: %v\n", m.FileType())

	fmt.Printf(" Title: %v\n", m.Title())
	fmt.Printf(" Album: %v\n", m.Album())
	fmt.Printf(" Artist: %v\n", m.Artist())
	fmt.Printf(" Composer: %v\n", m.Composer())
	fmt.Printf(" Genre: %v\n", m.Genre())
	fmt.Printf(" Year: %v\n", m.Year())

	track, trackCount := m.Track()
	fmt.Printf(" Track: %v of %v\n", track, trackCount)

	disc, discCount := m.Disc()
	fmt.Printf(" Disc: %v of %v\n", disc, discCount)

	fmt.Printf(" Picture: %v\n", m.Picture())
	fmt.Printf(" Lyrics: %v\n", m.Lyrics())
}
<|endoftext|>


<commit_before>package main

import (
	"net"
	"net/url"
	"os"
	"sync"

	"github.com/BurntSushi/toml"
)

type (
	// Configuration keeps configuration for a core node.
	Configuration struct {
		sync.RWMutex
		BindPrivate string `toml:"private"`
		BindPublic  string `toml:"public"`
		Cert        string `toml:"cert"`
		Key         string `toml:"key"`
		DataDir     string `toml:"datadir"`
		Hostname    string `toml:"hostname"`
		Secret      string `toml:"secret"`
		LetsEncrypt bool   `toml:"letsencrypt"`
		Login       string `toml:"login"`
		Password    string `toml:"password"`
	}
)

var (
	configFile = "/etc/gansoi.conf"

	exampleConfig = `# Example configuration for gansoi.
private = ":4934"
public = "https://0.0.0.0/:443"
cert = "/etc/gansoi/me-cert.pem"
key = "/etc/gansoi/me-key.pem"
datadir = "/var/lib/gansoi"
hostname = "gansoi.example.com"

# cert and key are ignored if set
letsencrypt = true
`
)

// SetDefaults sets some sane configuration defaults.
func (c *Configuration) SetDefaults() {
	// By default we bind to port 443 (HTTPS) on all interfaces on both IPv4
	// and IPv6.
	c.BindPublic = ":443"

	c.BindPrivate = ":4934"

	// This makes sense on a unix system.
	c.DataDir = "/var/lib/gansoi"
}

// LoadFromFile loads a configuration from path.
func (c *Configuration) LoadFromFile(path string) error {
	c.Lock()
	defer c.Unlock()

	_, err := toml.DecodeFile(path, c)

	return err
}

// Bind will return a string suitable for binding.
func (c *Configuration) Bind() string {
	URL, _ := url.Parse(c.BindPublic)

	host, port, err := net.SplitHostPort(URL.Host)
	if err != nil {
		return ":443"
	}

	if port == "" {
		switch URL.Scheme {
		case "https":
			port = "443"
		case "http":
			port = "80"
		}
	}

	return net.JoinHostPort(host, port)
}

// Hostnames returns a list of hostnames exposed.
func (c *Configuration) Hostnames() []string {
	c.RLock()
	defer c.RUnlock()

	hostname, _ := os.Hostname()

	hostnames := []string{hostname}

	local, _, _ := net.SplitHostPort(c.BindPublic)
	if local != "" {
		hostnames = append(hostnames, local)
	}

	if c.Hostname != "" {
		hostnames = append(hostnames, c.Hostname)
	}

	return hostnames
}

// TLS will return true if we should set up TLS.
func (c *Configuration) TLS() bool {
	URL, _ := url.Parse(c.BindPublic)

	return URL.Scheme == "https"
}
<commit_msg>Removed unused member 'Secret'.<commit_after>package main

import (
	"net"
	"net/url"
	"os"
	"sync"

	"github.com/BurntSushi/toml"
)

type (
	// Configuration keeps configuration for a core node.
	Configuration struct {
		sync.RWMutex
		BindPrivate string `toml:"private"`
		BindPublic  string `toml:"public"`
		Cert        string `toml:"cert"`
		Key         string `toml:"key"`
		DataDir     string `toml:"datadir"`
		Hostname    string `toml:"hostname"`
		LetsEncrypt bool   `toml:"letsencrypt"`
		Login       string `toml:"login"`
		Password    string `toml:"password"`
	}
)

var (
	configFile = "/etc/gansoi.conf"

	exampleConfig = `# Example configuration for gansoi.
private = ":4934"
public = "https://0.0.0.0/:443"
cert = "/etc/gansoi/me-cert.pem"
key = "/etc/gansoi/me-key.pem"
datadir = "/var/lib/gansoi"
hostname = "gansoi.example.com"

# cert and key are ignored if set
letsencrypt = true
`
)

// SetDefaults sets some sane configuration defaults.
func (c *Configuration) SetDefaults() {
	// By default we bind to port 443 (HTTPS) on all interfaces on both IPv4
	// and IPv6.
	c.BindPublic = ":443"

	c.BindPrivate = ":4934"

	// This makes sense on a unix system.
	c.DataDir = "/var/lib/gansoi"
}

// LoadFromFile loads a configuration from path.
func (c *Configuration) LoadFromFile(path string) error {
	c.Lock()
	defer c.Unlock()

	_, err := toml.DecodeFile(path, c)

	return err
}

// Bind will return a string suitable for binding.
func (c *Configuration) Bind() string {
	URL, _ := url.Parse(c.BindPublic)

	host, port, err := net.SplitHostPort(URL.Host)
	if err != nil {
		return ":443"
	}

	if port == "" {
		switch URL.Scheme {
		case "https":
			port = "443"
		case "http":
			port = "80"
		}
	}

	return net.JoinHostPort(host, port)
}

// Hostnames returns a list of hostnames exposed.
func (c *Configuration) Hostnames() []string {
	c.RLock()
	defer c.RUnlock()

	hostname, _ := os.Hostname()

	hostnames := []string{hostname}

	local, _, _ := net.SplitHostPort(c.BindPublic)
	if local != "" {
		hostnames = append(hostnames, local)
	}

	if c.Hostname != "" {
		hostnames = append(hostnames, c.Hostname)
	}

	return hostnames
}

// TLS will return true if we should set up TLS.
func (c *Configuration) TLS() bool {
	URL, _ := url.Parse(c.BindPublic)

	return URL.Scheme == "https"
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Fission 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 kubewatcher

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"reflect"
	"strings"
	"time"

	"k8s.io/client-go/1.5/pkg/watch"
)

type (
	// A webhook publisher for a single URL. Satisifies the Publisher interface.
	WebhookPublisher struct {
		requestChannel chan *publishRequest

		maxRetries int
		retryDelay time.Duration

		baseUrl string
	}
	publishRequest struct {
		url        string
		watchEvent watch.Event
		retries    int
		retryDelay time.Duration
	}
)

func MakeWebhookPublisher(baseUrl string) *WebhookPublisher {
	p := &WebhookPublisher{
		baseUrl:        baseUrl,
		requestChannel: make(chan *publishRequest, 32), // buffered channel
		// TODO make this configurable
		maxRetries: 10,
		retryDelay: 500 * time.Millisecond,
	}
	go p.svc()
	return p
}

func (p *WebhookPublisher) Publish(watchEvent watch.Event, url string) {
	p.requestChannel <- &publishRequest{
		watchEvent: watchEvent,
		url:        url,
		retries:    p.maxRetries,
		retryDelay: p.retryDelay,
	}
}

func (p *WebhookPublisher) svc() {
	for {
		r := <-p.requestChannel
		p.makeHttpRequest(r)
	}
}

func (p *WebhookPublisher) makeHttpRequest(r *publishRequest) {

	url := p.baseUrl + "/" + strings.TrimPrefix(r.url, "/")
	log.Printf("Making HTTP request to %v", url)

	// Serialize the object
	var buf bytes.Buffer
	err := printKubernetesObject(r.watchEvent.Object, &buf)
	if err != nil {
		log.Println("Failed to serialize object: %v", err)
		// TODO send a POST request indicating error
	}

	// Create request
	req, err := http.NewRequest("POST", url, &buf)
	if err != nil {
		log.Printf("Failed to create request to %v", url)
		// can't do anything more, drop the event.
		return
	}

	// Event and object type aren't in the serialized object
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("X-Kubernetes-Event-Type", string(r.watchEvent.Type))
	req.Header.Add("X-Kubernetes-Object-Type", reflect.TypeOf(r.watchEvent.Object).Elem().Name())

	// Make the request
	resp, err := http.DefaultClient.Do(req)

	// All done if the request succeeded with 200 OK.
	if err == nil && resp.StatusCode == 200 {
		resp.Body.Close()
		return
	}

	// Log errors
	if err != nil {
		log.Printf("Request failed: %v", r)
	} else if resp.StatusCode != 200 {
		log.Printf("Request returned failure: %v", resp.StatusCode)
		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err == nil {
			log.Printf("request error: %v", string(body))
		}
	}

	// Schedule a retry, or give up if out of retries
	r.retries--
	if r.retries > 0 {
		r.retryDelay *= time.Duration(2)
		time.AfterFunc(r.retryDelay, func() {
			p.requestChannel <- r
		})
	} else {
		log.Printf("Final retry failed, giving up on %v", url)
		// Event dropped
	}
}
<commit_msg>Fix incorrect log printf<commit_after>/*
Copyright 2016 The Fission 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 kubewatcher

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"reflect"
	"strings"
	"time"

	"k8s.io/client-go/1.5/pkg/watch"
)

type (
	// A webhook publisher for a single URL. Satisifies the Publisher interface.
	WebhookPublisher struct {
		requestChannel chan *publishRequest

		maxRetries int
		retryDelay time.Duration

		baseUrl string
	}
	publishRequest struct {
		url        string
		watchEvent watch.Event
		retries    int
		retryDelay time.Duration
	}
)

func MakeWebhookPublisher(baseUrl string) *WebhookPublisher {
	p := &WebhookPublisher{
		baseUrl:        baseUrl,
		requestChannel: make(chan *publishRequest, 32), // buffered channel
		// TODO make this configurable
		maxRetries: 10,
		retryDelay: 500 * time.Millisecond,
	}
	go p.svc()
	return p
}

func (p *WebhookPublisher) Publish(watchEvent watch.Event, url string) {
	p.requestChannel <- &publishRequest{
		watchEvent: watchEvent,
		url:        url,
		retries:    p.maxRetries,
		retryDelay: p.retryDelay,
	}
}

func (p *WebhookPublisher) svc() {
	for {
		r := <-p.requestChannel
		p.makeHttpRequest(r)
	}
}

func (p *WebhookPublisher) makeHttpRequest(r *publishRequest) {

	url := p.baseUrl + "/" + strings.TrimPrefix(r.url, "/")
	log.Printf("Making HTTP request to %v", url)

	// Serialize the object
	var buf bytes.Buffer
	err := printKubernetesObject(r.watchEvent.Object, &buf)
	if err != nil {
		log.Printf("Failed to serialize object: %v", err)
		// TODO send a POST request indicating error
	}

	// Create request
	req, err := http.NewRequest("POST", url, &buf)
	if err != nil {
		log.Printf("Failed to create request to %v", url)
		// can't do anything more, drop the event.
		return
	}

	// Event and object type aren't in the serialized object
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("X-Kubernetes-Event-Type", string(r.watchEvent.Type))
	req.Header.Add("X-Kubernetes-Object-Type", reflect.TypeOf(r.watchEvent.Object).Elem().Name())

	// Make the request
	resp, err := http.DefaultClient.Do(req)

	// All done if the request succeeded with 200 OK.
	if err == nil && resp.StatusCode == 200 {
		resp.Body.Close()
		return
	}

	// Log errors
	if err != nil {
		log.Printf("Request failed: %v", r)
	} else if resp.StatusCode != 200 {
		log.Printf("Request returned failure: %v", resp.StatusCode)
		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err == nil {
			log.Printf("request error: %v", string(body))
		}
	}

	// Schedule a retry, or give up if out of retries
	r.retries--
	if r.retries > 0 {
		r.retryDelay *= time.Duration(2)
		time.AfterFunc(r.retryDelay, func() {
			p.requestChannel <- r
		})
	} else {
		log.Printf("Final retry failed, giving up on %v", url)
		// Event dropped
	}
}
<|endoftext|>