<commit_before>package todoist

import (
	"context"
	"errors"
	"fmt"
	"github.com/fatih/color"
	"net/http"
	"net/url"
	"strings"
)

type Project struct {
	Entity
	Name         string `json:"name"`
	Color        int    `json:"color"`
	Indent       int    `json:"indent"`
	ItemOrder    int    `json:"item_order"`
	Collapsed    int    `json:"collapsed"`
	Shared       bool   `json:"shared"`
	IsArchived   int    `json:"is_archived"`
	InboxProject bool   `json:"inbox_project"`
	TeamInbox    bool   `json:"team_inbox"`
}

func (p Project) String() string {
	return strings.Repeat(" ", p.Indent-1) + "#" + p.Name
}

func (p Project) ColorString() string {
	var attr color.Attribute
	switch p.Color {
	case 20, 21:
		attr = color.FgHiBlack
	case 1, 8, 14:
		attr = color.FgHiRed
	case 0, 15, 16:
		attr = color.FgHiGreen
	case 2, 3, 9:
		attr = color.FgHiYellow
	case 17, 18, 19:
		attr = color.FgHiBlue
	case 6, 12, 13:
		attr = color.FgHiMagenta
	case 4, 10, 11:
		attr = color.FgHiCyan
	case 5, 7:
	default:
		attr = color.FgWhite
	}
	return color.New(attr).Sprint(p.String())
}

type ProjectClient struct {
	*Client
	cache *projectCache
}

func (c *ProjectClient) Add(project Project) (*Project, error) {
	if len(project.Name) == 0 {
		return nil, errors.New("New project requires a name")
	}
	project.ID = GenerateTempID()
	c.cache.store(project)
	command := Command{
		Type:   "project_add",
		Args:   project,
		UUID:   GenerateUUID(),
		TempID: project.ID,
	}
	c.queue = append(c.queue, command)
	return &project, nil
}

func (c *ProjectClient) Update(project Project) (*Project, error) {
	if !IsValidID(project.ID) {
		return nil, fmt.Errorf("Invalid id: %s", project.ID)
	}
	command := Command{
		Type: "project_update",
		Args: project,
		UUID: GenerateUUID(),
	}
	c.queue = append(c.queue, command)
	return &project, nil
}

func (c *ProjectClient) Delete(ids []ID) error {
	command := Command{
		Type: "project_delete",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ProjectClient) Archive(ids []ID) error {
	command := Command{
		Type: "project_archive",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ProjectClient) Unarchive(ids []ID) error {
	command := Command{
		Type: "project_unarchive",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

type ProjectGetResponse struct {
	Project Project
	Notes   []Note
}

func (c *ProjectClient) Get(ctx context.Context, id ID) (*ProjectGetResponse, error) {
	values := url.Values{"project_id": {id.String()}}
	req, err := c.newRequest(ctx, http.MethodGet, "projects/get", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out ProjectGetResponse
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

type ProjectGetDataResponse struct {
	Project Project
	Items   []Item
}

func (c *ProjectClient) GetData(ctx context.Context, id ID) (*ProjectGetDataResponse, error) {
	values := url.Values{"project_id": {id.String()}}
	req, err := c.newRequest(ctx, http.MethodGet, "projects/get_data", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out ProjectGetDataResponse
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ProjectClient) GetArchived(ctx context.Context) (*[]Project, error) {
	values := url.Values{}
	req, err := c.newRequest(ctx, http.MethodGet, "projects/get_archived", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out []Project
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ProjectClient) GetAll() []Project {
	return c.cache.getAll()
}

func (c *ProjectClient) Resolve(id ID) *Project {
	return c.cache.resolve(id)
}

func (c ProjectClient) FindByName(substr string) []Project {
	if r := []rune(substr); len(r) > 0 && string(r[0]) == "#" {
		substr = string(r[1:])
	}
	var res []Project
	for _, p := range c.GetAll() {
		if strings.Contains(p.Name, substr) {
			res = append(res, p)
		}
	}
	return res
}

func (c ProjectClient) FindOneByName(substr string) *Project {
	projects := c.FindByName(substr)
	for _, project := range projects {
		if project.Name == substr {
			return &project
		}
	}
	if len(projects) > 0 {
		return &projects[0]
	}
	return nil
}

type projectCache struct {
	cache *[]Project
}

func (c *projectCache) getAll() []Project {
	return *c.cache
}

func (c *projectCache) resolve(id ID) *Project {
	for _, project := range *c.cache {
		if project.ID == id {
			return &project
		}
	}
	return nil
}

func (c *projectCache) store(project Project) {
	var res []Project
	isNew := true
	for _, p := range *c.cache {
		if p.Equal(project) {
			if !project.IsDeleted {
				res = append(res, project)
			}
			isNew = false
		} else {
			res = append(res, p)
		}
	}
	if isNew && !project.IsDeleted.Bool() {
		res = append(res, project)
	}
	c.cache = &res
}

func (c *projectCache) remove(project Project) {
	var res []Project
	for _, p := range *c.cache {
		if !p.Equal(project) {
			res = append(res, p)
		}
	}
	c.cache = &res
}
<commit_msg>change color values<commit_after>package todoist

import (
	"context"
	"errors"
	"fmt"
	"github.com/fatih/color"
	"net/http"
	"net/url"
	"strings"
)

type Project struct {
	Entity
	Name         string `json:"name"`
	Color        int    `json:"color"`
	Indent       int    `json:"indent"`
	ItemOrder    int    `json:"item_order"`
	Collapsed    int    `json:"collapsed"`
	Shared       bool   `json:"shared"`
	IsArchived   int    `json:"is_archived"`
	InboxProject bool   `json:"inbox_project"`
	TeamInbox    bool   `json:"team_inbox"`
}

func (p Project) String() string {
	return strings.Repeat(" ", p.Indent-1) + "#" + p.Name
}

func (p Project) ColorString() string {
	var attr color.Attribute
	switch p.Color {
	case 30, 31:
		attr = color.FgHiRed
	case 32, 33:
		attr = color.FgHiYellow
	case 34, 35, 36:
		attr = color.FgHiGreen
	case 37, 38, 39:
		attr = color.FgHiCyan
	case 40, 41, 42:
		attr = color.FgHiBlue
	case 43, 44, 45, 46:
		attr = color.FgHiMagenta
	case 47, 48, 49:
		attr = color.FgHiBlack
	default:
		attr = color.FgWhite
	}
	return color.New(attr).Sprint(p.String())
}

type ProjectClient struct {
	*Client
	cache *projectCache
}

func (c *ProjectClient) Add(project Project) (*Project, error) {
	if len(project.Name) == 0 {
		return nil, errors.New("New project requires a name")
	}
	project.ID = GenerateTempID()
	c.cache.store(project)
	command := Command{
		Type:   "project_add",
		Args:   project,
		UUID:   GenerateUUID(),
		TempID: project.ID,
	}
	c.queue = append(c.queue, command)
	return &project, nil
}

func (c *ProjectClient) Update(project Project) (*Project, error) {
	if !IsValidID(project.ID) {
		return nil, fmt.Errorf("Invalid id: %s", project.ID)
	}
	command := Command{
		Type: "project_update",
		Args: project,
		UUID: GenerateUUID(),
	}
	c.queue = append(c.queue, command)
	return &project, nil
}

func (c *ProjectClient) Delete(ids []ID) error {
	command := Command{
		Type: "project_delete",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ProjectClient) Archive(ids []ID) error {
	command := Command{
		Type: "project_archive",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ProjectClient) Unarchive(ids []ID) error {
	command := Command{
		Type: "project_unarchive",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

type ProjectGetResponse struct {
	Project Project
	Notes   []Note
}

func (c *ProjectClient) Get(ctx context.Context, id ID) (*ProjectGetResponse, error) {
	values := url.Values{"project_id": {id.String()}}
	req, err := c.newRequest(ctx, http.MethodGet, "projects/get", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out ProjectGetResponse
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

type ProjectGetDataResponse struct {
	Project Project
	Items   []Item
}

func (c *ProjectClient) GetData(ctx context.Context, id ID) (*ProjectGetDataResponse, error) {
	values := url.Values{"project_id": {id.String()}}
	req, err := c.newRequest(ctx, http.MethodGet, "projects/get_data", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out ProjectGetDataResponse
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ProjectClient) GetArchived(ctx context.Context) (*[]Project, error) {
	values := url.Values{}
	req, err := c.newRequest(ctx, http.MethodGet, "projects/get_archived", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out []Project
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ProjectClient) GetAll() []Project {
	return c.cache.getAll()
}

func (c *ProjectClient) Resolve(id ID) *Project {
	return c.cache.resolve(id)
}

func (c ProjectClient) FindByName(substr string) []Project {
	if r := []rune(substr); len(r) > 0 && string(r[0]) == "#" {
		substr = string(r[1:])
	}
	var res []Project
	for _, p := range c.GetAll() {
		if strings.Contains(p.Name, substr) {
			res = append(res, p)
		}
	}
	return res
}

func (c ProjectClient) FindOneByName(substr string) *Project {
	projects := c.FindByName(substr)
	for _, project := range projects {
		if project.Name == substr {
			return &project
		}
	}
	if len(projects) > 0 {
		return &projects[0]
	}
	return nil
}

type projectCache struct {
	cache *[]Project
}

func (c *projectCache) getAll() []Project {
	return *c.cache
}

func (c *projectCache) resolve(id ID) *Project {
	for _, project := range *c.cache {
		if project.ID == id {
			return &project
		}
	}
	return nil
}

func (c *projectCache) store(project Project) {
	var res []Project
	isNew := true
	for _, p := range *c.cache {
		if p.Equal(project) {
			if !project.IsDeleted {
				res = append(res, project)
			}
			isNew = false
		} else {
			res = append(res, p)
		}
	}
	if isNew && !project.IsDeleted.Bool() {
		res = append(res, project)
	}
	c.cache = &res
}

func (c *projectCache) remove(project Project) {
	var res []Project
	for _, p := range *c.cache {
		if !p.Equal(project) {
			res = append(res, p)
		}
	}
	c.cache = &res
}
<|endoftext|>


<commit_before>package main

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

var Memory map[string]*Merge

func init() {
	Memory = make(map[string]*Merge, 20)
}

func Store(m *Merge) (string, error) {
	key := fmt.Sprintf("%x", rand.Int())
	Memory[key] = m
	log.Printf("stored %s in memory for sharing", key)
	return key, nil
}

func Retrieve(key string) (*Merge, error) {
	if m, ok := Memory[key]; ok {
		return m, nil
	}
	return nil, fmt.Errorf("not found")
}
<commit_msg>Implement github/gist backend for sharing<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

type GistFile struct {
	Content string `json:"content"`
}
type Gist struct {
	ID          string              `json:"id,omitempty"`
	Description string              `json:"description"`
	Public      bool                `json:"public"`
	Files       map[string]GistFile `json:"files"`
}

func parseGist(r *http.Response) (*Gist, error) {
	raw, err := ioutil.ReadAll(r.Body)
	gist := Gist{}
	err = json.Unmarshal(raw, &gist)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal JSON response: %s", err)
	}

	return &gist, nil
}

func Store(m *Merge) (string, error) {
	data, err := json.Marshal(m)
	if err != nil {
		return "", err
	}
	gist := Gist{
		Description: "a bit o' spruce, from http://play.spruce.cf",
		Public:      true,
		Files: map[string]GistFile{
			"spruce.json": GistFile{Content: string(data)},
		},
	}
	encoded, err := json.Marshal(gist)
	if err != nil {
		return "", err
	}
	body := strings.NewReader(string(encoded))
	resp, err := http.Post("https://api.github.com/gists", "application/json", body)
	if err != nil {
		return "", err
	}
	log.Printf("got a response: %v", resp)
	if resp.StatusCode != 201 {
		return "", fmt.Errorf("failed to create gist: API returned %s", resp.Status)
	}

	created, err := parseGist(resp)
	if err != nil {
		return "", err
	}
	return created.ID, nil
}

func Retrieve(key string) (*Merge, error) {
	resp, err := http.Get(fmt.Sprintf("https://api.github.com/gists/%s", key))
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("not found")
	}

	gist, err := parseGist(resp)
	if err != nil {
		return nil, err
	}

	f, ok := gist.Files["spruce.json"]
	if !ok {
		return nil, err
	}

	var m Merge
	err = json.Unmarshal([]byte(f.Content), &m)
	if err != nil {
		return nil, err
	}
	return &m, nil
}
<|endoftext|>


<commit_before>package fonts

var Font8x8 [][]byte

func Load8x8() {

	Font8x8 = [][]byte{
		{
			0x00,
			0x00,
		},
	}
}
<commit_msg>update font example<commit_after>package fonts

var Font8x8 [][]byte

func Load8x8() {

	Font8x8 = [][]byte{
		{
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
		},
		{
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
			0x00,
		},
	}
}
<|endoftext|>


<commit_before>package audit

import (
	"github.com/stretchr/testify/assert"
	"testing"

	"github.com/eirka/eirka-libs/db"
)

func TestAudit(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	mock.ExpectExec(`INSERT INTO audit \(user_id,ib_id,audit_type,audit_ip,audit_time,audit_action,audit_info\)`).
		WithArgs(1, 1, UserLog, "10.0.0.1", AuditEmailUpdate, "meta info")

	audit := Audit{
		User:   1,
		Ib:     1,
		Type:   UserLog,
		Ip:     "10.0.0.1",
		Action: AuditEmailUpdate,
		Info:   "meta info",
	}

	// submit audit
	err = audit.Submit()
	assert.NoError(t, err, "An error was not expected")

}
<commit_msg>add audit test<commit_after>package audit

import (
	"github.com/stretchr/testify/assert"
	"testing"

	"github.com/eirka/eirka-libs/db"
)

func TestAudit(t *testing.T) {

	var err error

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	mock.ExpectExec(`INSERT INTO audit \(user_id,ib_id,audit_type,audit_ip,audit_time,audit_action,audit_info\)`).
		WithArgs(1, 1, UserLog, "10.0.0.1", AuditEmailUpdate, "meta info").
		WillReturnResult(sqlmock.NewResult(1, 1))

	audit := Audit{
		User:   1,
		Ib:     1,
		Type:   UserLog,
		Ip:     "10.0.0.1",
		Action: AuditEmailUpdate,
		Info:   "meta info",
	}

	// submit audit
	err = audit.Submit()
	assert.NoError(t, err, "An error was not expected")

}
<|endoftext|>


<commit_before>package handler

import (
	"fullerite/metric"

	"fmt"
	"testing"
	"time"

	l "github.com/Sirupsen/logrus"
	"github.com/stretchr/testify/assert"
)

func assertEmpty(t *testing.T, channel chan metric.Metric) {
	close(channel)
	for range channel {
		t.Fatal("The channel was not empty")
	}
}

func TestNewHandler(t *testing.T) {
	names := []string{"Graphite", "Kairos", "SignalFx", "Datadog", "Log"}
	for _, name := range names {
		h := New(name)
		assert.NotNil(t, h, "should create a Handler for "+name)
		assert.NotNil(t, h.Channel(), "should create a channel")
		assert.Equal(t, name, h.Name())
		assert.Equal(t, "", h.Prefix(), "")
		assert.Equal(t, 0, len(h.DefaultDimensions()))
		assert.Equal(t, DefaultBufferSize, h.MaxBufferSize())
		assert.Equal(t, DefaultInterval, h.Interval())
		assert.Equal(t, name+"Handler", fmt.Sprintf("%s", h), "String() should append Handler to the name for "+name)

		// Test Set* functions
		h.SetInterval(999)
		assert.Equal(t, 999, h.Interval())

		h.SetMaxBufferSize(999)
		assert.Equal(t, 999, h.MaxBufferSize())

		dims := map[string]string{"test": "test value"}
		h.SetDefaultDimensions(dims)
		assert.Equal(t, 1, len(h.DefaultDimensions()))
	}
}

// If configured, per handler dimensions should over write default dimensions
func TestPerHandlerDimensions(t *testing.T) {
	b := new(BaseHandler)
	dims := map[string]string{"test": "test value", "host": "test host"}
	b.SetDefaultDimensions(dims)
	assert.Equal(t, 2, len(b.DefaultDimensions()))

	handlerLevelDimensions := "{ \"test\" : \"updated value\", \"runtimeenv\": \"dev\", \"region\":\"uswest1-devc\"}"
	configMap := map[string]interface{}{
		"defaultDimensions": handlerLevelDimensions,
	}

	b.configureCommonParams(configMap)
	assert.Equal(t, 3, len(b.DefaultDimensions()))
	assert.Equal(t, "updated value", b.DefaultDimensions()["test"])
	assert.Equal(t, "", b.DefaultDimensions()["host"])
}

func TestCollectorBlackList(t *testing.T) {
	b := new(BaseHandler)
	collectorBlackList := "[\"TestCollector1\", \"TestCollector2\"]"
	configMap := map[string]interface{}{
		"collectorBlackList": collectorBlackList,
	}

	b.configureCommonParams(configMap)
	assert.Equal(t, 2, len(b.CollectorBlackList()))

	val, _ := b.IsCollectorBlackListed("TestCollector1")
	assert.Equal(t, true, val)

	val, _ = b.IsCollectorBlackListed("WhiteListed")
	assert.Equal(t, false, val)
}

func TestCommonKeepAliveConfig(t *testing.T) {
	b := new(BaseHandler)

	configMap := map[string]interface{}{
		"keepAliveInterval":         100,
		"maxIdleConnectionsPerHost": 5,
	}
	b.configureCommonParams(configMap)
	assert.Equal(t, 5, b.MaxIdleConnectionsPerHost())
	assert.Equal(t, 100, b.KeepAliveInterval())
}

func TestEmissionAndRecord(t *testing.T) {
	emitCalled := false

	callbackChannel := make(chan emissionTiming)
	emitFunc := func([]metric.Metric) bool {
		emitCalled = true
		return true
	}
	metrics := []metric.Metric{metric.New("example")}

	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_emit")
	go base.emitAndTime(metrics, emitFunc, callbackChannel)

	select {
	case timing := <-callbackChannel:
		assert.NotNil(t, timing)
		assert.Equal(t, 1, timing.metricsSent)
		assert.NotNil(t, timing.timestamp)
		assert.NotNil(t, timing.duration)
	case <-time.After(2 * time.Second):
		t.Fatal("Failed to read from the callback channel after 2 seconds")
	}

	assert.True(t, emitCalled)
	callbackChannel = nil
}

func TestRecordTimings(t *testing.T) {
	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_record")
	base.interval = 2

	minusFiveSec := -1 * 5 * time.Second
	minusSixSec := -1 * 6 * time.Second
	someDur := time.Duration(5)
	now := time.Now()

	// create a list of emissions in order with some older than 1 second
	timingsChannel := make(chan emissionTiming)
	base.emissionTimes.PushBack(emissionTiming{now.Add(minusSixSec), someDur, 0})
	base.emissionTimes.PushBack(emissionTiming{now.Add(minusFiveSec), someDur, 0})

	go base.recordEmissions(timingsChannel)
	timingsChannel <- emissionTiming{now, someDur, 0}

	assert.Equal(t, 1, base.emissionTimes.Len())
	timingsChannel = nil
}

func TestHandlerRunFlushInterval(t *testing.T) {
	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_flush")
	base.interval = 1
	base.maxBufferSize = 2
	base.channel = make(chan metric.Metric)

	emitCalledOnce := false
	emitCalledTwice := false
	emitCalledThrice := false
	emitFunc := func(metrics []metric.Metric) bool {
		if emitCalledOnce && emitCalledTwice {
			emitCalledThrice = true
			close(base.channel)
		}
		if emitCalledOnce && !emitCalledTwice {
			assert.Equal(t, 1, len(metrics))
			emitCalledTwice = true
		} else {
			assert.Equal(t, 2, len(metrics))
			emitCalledOnce = true
		}
		return true
	}

	// now we are waiting for some metrics
	go base.run(emitFunc)

	base.channel <- metric.New("testMetric")
	base.channel <- metric.New("testMetric1")
	base.channel <- metric.New("testMetric2")
	time.Sleep(2 * time.Second)
	assert.True(t, emitCalledOnce)
	assert.True(t, emitCalledTwice)
	assert.False(t, emitCalledThrice)
	assert.Equal(t, 1, base.emissionTimes.Len())
	assert.Equal(t, uint64(3), base.metricsSent)
	assert.Equal(t, uint64(0), base.metricsDropped)
	assert.Equal(t, uint64(2), base.totalEmissions)
}

func TestHandlerRun(t *testing.T) {
	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_run")
	base.interval = 1
	base.maxBufferSize = 1
	base.channel = make(chan metric.Metric)

	emitCalled := false
	emitFunc := func(metrics []metric.Metric) bool {
		assert.Equal(t, 1, len(metrics))
		emitCalled = true
		close(base.channel)
		return true
	}

	// now we are waiting for some metrics
	go base.run(emitFunc)

	base.channel <- metric.New("testMetric")
	time.Sleep(1 * time.Second)
	assert.True(t, emitCalled)
	assert.Equal(t, 1, base.emissionTimes.Len())
	assert.Equal(t, uint64(1), base.metricsSent)
	assert.Equal(t, uint64(0), base.metricsDropped)
	assert.Equal(t, uint64(1), base.totalEmissions)
}

func TestInternalMetrics(t *testing.T) {
	base := BaseHandler{}
	base.totalEmissions = 10
	base.metricsDropped = 100
	base.metricsSent = 2
	base.interval = 4

	timing := emissionTiming{time.Now(), 5 * time.Second, 0}
	base.emissionTimes.PushBack(timing)
	timing = emissionTiming{time.Now(), 10 * time.Second, 0}
	base.emissionTimes.PushBack(timing)
	timing = emissionTiming{time.Now(), 6 * time.Second, 0}
	base.emissionTimes.PushBack(timing)

	results := base.InternalMetrics()
	expected := InternalMetrics{
		Counters: map[string]float64{
			"metricsDropped": 100,
			"metricsSent":    2,
			"totalEmissions": 10,
		},
		Gauges: map[string]float64{
			"averageEmissionTiming": 7,
			"emissionsInWindow":     3,
			"intervalLength":        4,
			"maxEmissionTiming":     10,
		},
	}
	assert.Equal(t, expected, results)
}

func TestInternalMetricsWithNan(t *testing.T) {
	base := BaseHandler{}

	expected := InternalMetrics{
		Counters: map[string]float64{
			"metricsDropped": 0,
			"metricsSent":    0,
			"totalEmissions": 0,
		},
		// specifically missing the averageEmissionTiming
		// because we have no emissions yet
		Gauges: map[string]float64{
			"emissionsInWindow": 0,
			"intervalLength":    0,
		},
	}
	im := base.InternalMetrics()
	assert.Equal(t, expected, im)
}

func TestKeepAliveConfig(t *testing.T) {
	base := BaseHandler{}

	assert.Equal(t, 0, base.KeepAliveInterval())
	assert.Equal(t, 0, base.MaxIdleConnectionsPerHost())
}
<commit_msg>remove close channe;<commit_after>package handler

import (
	"fullerite/metric"

	"fmt"
	"testing"
	"time"

	l "github.com/Sirupsen/logrus"
	"github.com/stretchr/testify/assert"
)

func assertEmpty(t *testing.T, channel chan metric.Metric) {
	close(channel)
	for range channel {
		t.Fatal("The channel was not empty")
	}
}

func TestNewHandler(t *testing.T) {
	names := []string{"Graphite", "Kairos", "SignalFx", "Datadog", "Log"}
	for _, name := range names {
		h := New(name)
		assert.NotNil(t, h, "should create a Handler for "+name)
		assert.NotNil(t, h.Channel(), "should create a channel")
		assert.Equal(t, name, h.Name())
		assert.Equal(t, "", h.Prefix(), "")
		assert.Equal(t, 0, len(h.DefaultDimensions()))
		assert.Equal(t, DefaultBufferSize, h.MaxBufferSize())
		assert.Equal(t, DefaultInterval, h.Interval())
		assert.Equal(t, name+"Handler", fmt.Sprintf("%s", h), "String() should append Handler to the name for "+name)

		// Test Set* functions
		h.SetInterval(999)
		assert.Equal(t, 999, h.Interval())

		h.SetMaxBufferSize(999)
		assert.Equal(t, 999, h.MaxBufferSize())

		dims := map[string]string{"test": "test value"}
		h.SetDefaultDimensions(dims)
		assert.Equal(t, 1, len(h.DefaultDimensions()))
	}
}

// If configured, per handler dimensions should over write default dimensions
func TestPerHandlerDimensions(t *testing.T) {
	b := new(BaseHandler)
	dims := map[string]string{"test": "test value", "host": "test host"}
	b.SetDefaultDimensions(dims)
	assert.Equal(t, 2, len(b.DefaultDimensions()))

	handlerLevelDimensions := "{ \"test\" : \"updated value\", \"runtimeenv\": \"dev\", \"region\":\"uswest1-devc\"}"
	configMap := map[string]interface{}{
		"defaultDimensions": handlerLevelDimensions,
	}

	b.configureCommonParams(configMap)
	assert.Equal(t, 3, len(b.DefaultDimensions()))
	assert.Equal(t, "updated value", b.DefaultDimensions()["test"])
	assert.Equal(t, "", b.DefaultDimensions()["host"])
}

func TestCollectorBlackList(t *testing.T) {
	b := new(BaseHandler)
	collectorBlackList := "[\"TestCollector1\", \"TestCollector2\"]"
	configMap := map[string]interface{}{
		"collectorBlackList": collectorBlackList,
	}

	b.configureCommonParams(configMap)
	assert.Equal(t, 2, len(b.CollectorBlackList()))

	val, _ := b.IsCollectorBlackListed("TestCollector1")
	assert.Equal(t, true, val)

	val, _ = b.IsCollectorBlackListed("WhiteListed")
	assert.Equal(t, false, val)
}

func TestCommonKeepAliveConfig(t *testing.T) {
	b := new(BaseHandler)

	configMap := map[string]interface{}{
		"keepAliveInterval":         100,
		"maxIdleConnectionsPerHost": 5,
	}
	b.configureCommonParams(configMap)
	assert.Equal(t, 5, b.MaxIdleConnectionsPerHost())
	assert.Equal(t, 100, b.KeepAliveInterval())
}

func TestEmissionAndRecord(t *testing.T) {
	emitCalled := false

	callbackChannel := make(chan emissionTiming)
	emitFunc := func([]metric.Metric) bool {
		emitCalled = true
		return true
	}
	metrics := []metric.Metric{metric.New("example")}

	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_emit")
	go base.emitAndTime(metrics, emitFunc, callbackChannel)

	select {
	case timing := <-callbackChannel:
		assert.NotNil(t, timing)
		assert.Equal(t, 1, timing.metricsSent)
		assert.NotNil(t, timing.timestamp)
		assert.NotNil(t, timing.duration)
	case <-time.After(2 * time.Second):
		t.Fatal("Failed to read from the callback channel after 2 seconds")
	}

	assert.True(t, emitCalled)
	callbackChannel = nil
}

func TestRecordTimings(t *testing.T) {
	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_record")
	base.interval = 2

	minusFiveSec := -1 * 5 * time.Second
	minusSixSec := -1 * 6 * time.Second
	someDur := time.Duration(5)
	now := time.Now()

	// create a list of emissions in order with some older than 1 second
	timingsChannel := make(chan emissionTiming)
	base.emissionTimes.PushBack(emissionTiming{now.Add(minusSixSec), someDur, 0})
	base.emissionTimes.PushBack(emissionTiming{now.Add(minusFiveSec), someDur, 0})

	go base.recordEmissions(timingsChannel)
	timingsChannel <- emissionTiming{now, someDur, 0}

	assert.Equal(t, 1, base.emissionTimes.Len())
	timingsChannel = nil
}

func TestHandlerRunFlushInterval(t *testing.T) {
	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_flush")
	base.interval = 1
	base.maxBufferSize = 2
	base.channel = make(chan metric.Metric)

	emitCalledOnce := false
	emitCalledTwice := false
	emitCalledThrice := false
	emitFunc := func(metrics []metric.Metric) bool {
		if emitCalledOnce && !emitCalledTwice {
			assert.Equal(t, 1, len(metrics))
			emitCalledTwice = true
		} else {
			assert.Equal(t, 2, len(metrics))
			emitCalledOnce = true
		}
		return true
	}

	// now we are waiting for some metrics
	go base.run(emitFunc)

	base.channel <- metric.New("testMetric")
	base.channel <- metric.New("testMetric1")
	base.channel <- metric.New("testMetric2")
	time.Sleep(2 * time.Second)
	assert.True(t, emitCalledOnce)
	assert.True(t, emitCalledTwice)
	assert.False(t, emitCalledThrice)
	assert.Equal(t, 1, base.emissionTimes.Len())
	assert.Equal(t, uint64(3), base.metricsSent)
	assert.Equal(t, uint64(0), base.metricsDropped)
	assert.Equal(t, uint64(2), base.totalEmissions)
}

func TestHandlerRun(t *testing.T) {
	base := BaseHandler{}
	base.log = l.WithField("testing", "basehandler_run")
	base.interval = 1
	base.maxBufferSize = 1
	base.channel = make(chan metric.Metric)

	emitCalled := false
	emitFunc := func(metrics []metric.Metric) bool {
		assert.Equal(t, 1, len(metrics))
		emitCalled = true
		return true
	}

	// now we are waiting for some metrics
	go base.run(emitFunc)

	base.channel <- metric.New("testMetric")
	time.Sleep(1 * time.Second)
	assert.True(t, emitCalled)
	assert.Equal(t, 1, base.emissionTimes.Len())
	assert.Equal(t, uint64(1), base.metricsSent)
	assert.Equal(t, uint64(0), base.metricsDropped)
	assert.Equal(t, uint64(1), base.totalEmissions)
}

func TestInternalMetrics(t *testing.T) {
	base := BaseHandler{}
	base.totalEmissions = 10
	base.metricsDropped = 100
	base.metricsSent = 2
	base.interval = 4

	timing := emissionTiming{time.Now(), 5 * time.Second, 0}
	base.emissionTimes.PushBack(timing)
	timing = emissionTiming{time.Now(), 10 * time.Second, 0}
	base.emissionTimes.PushBack(timing)
	timing = emissionTiming{time.Now(), 6 * time.Second, 0}
	base.emissionTimes.PushBack(timing)

	results := base.InternalMetrics()
	expected := InternalMetrics{
		Counters: map[string]float64{
			"metricsDropped": 100,
			"metricsSent":    2,
			"totalEmissions": 10,
		},
		Gauges: map[string]float64{
			"averageEmissionTiming": 7,
			"emissionsInWindow":     3,
			"intervalLength":        4,
			"maxEmissionTiming":     10,
		},
	}
	assert.Equal(t, expected, results)
}

func TestInternalMetricsWithNan(t *testing.T) {
	base := BaseHandler{}

	expected := InternalMetrics{
		Counters: map[string]float64{
			"metricsDropped": 0,
			"metricsSent":    0,
			"totalEmissions": 0,
		},
		// specifically missing the averageEmissionTiming
		// because we have no emissions yet
		Gauges: map[string]float64{
			"emissionsInWindow": 0,
			"intervalLength":    0,
		},
	}
	im := base.InternalMetrics()
	assert.Equal(t, expected, im)
}

func TestKeepAliveConfig(t *testing.T) {
	base := BaseHandler{}

	assert.Equal(t, 0, base.KeepAliveInterval())
	assert.Equal(t, 0, base.MaxIdleConnectionsPerHost())
}
<|endoftext|>


<commit_before>package handlers

import (
	"strings"

	"github.com/colegion/goal/internal/reflect"
	"github.com/colegion/goal/internal/routes"
)

// controllers stores information about application's controllers
// and its "Init" function.
type controllers struct {
	accessor string

	list []*controller
	init *reflect.Func
}

// controller is a type that represents application controller,
// a structure that has actions.
type controller struct {
	Name string // Name of the controller, e.g. "App" or "Templates".

	Actions reflect.Funcs // Actions are methods that implement action.Result interface.
	After   *reflect.Func // Magic method that is executed after actions if they return nil.
	Before  *reflect.Func // Magic method that is executed before every action.

	Comments reflect.Comments // A group of comments right above the controller declaration.
	File     string           // Name of the file where this controller is located.
	Parents  parents          // A list of embedded structs that should be parsed.

	Fields []field          // A list of fields that require binding.
	Routes [][]routes.Route // Routes concatenated with prefixes. len(Routes) = len(Actions)
}

// Controller gets a controller name and returns it if it
// does exist. Nil is returned otherwise.
func (cs controllers) Controller(name string) *controller {
	for i := 0; i < len(cs.list); i++ {
		if cs.list[i].Name == name {
			return cs.list[i]
		}
	}
	return nil
}

// IgnoredArgs gets an action Func as input parameter
// and returns blank identifiers for parameters
// other than the first one.
// E.g. if the action returns action.Result, error, bool,
// this method will return ", _, _".
// So it can be used during code generation.
func (c controller) IgnoredArgs(f *reflect.Func) (s string) {
	n := len(f.Results) - 1 // Ignore action.Result.
	if n > 0 {
		s = strings.Repeat(", _", n)
	}
	return
}
<commit_msg>Update Routes field of the controller type<commit_after>package handlers

import (
	"strings"

	"github.com/colegion/goal/internal/reflect"
	"github.com/colegion/goal/internal/routes"
)

// controllers stores information about application's controllers
// and its "Init" function.
type controllers struct {
	accessor string

	list []*controller
	init *reflect.Func
}

// controller is a type that represents application controller,
// a structure that has actions.
type controller struct {
	Name string // Name of the controller, e.g. "App" or "Templates".

	Actions reflect.Funcs // Actions are methods that implement action.Result interface.
	After   *reflect.Func // Magic method that is executed after actions if they return nil.
	Before  *reflect.Func // Magic method that is executed before every action.

	Comments reflect.Comments // A group of comments right above the controller declaration.
	File     string           // Name of the file where this controller is located.
	Parents  parents          // A list of embedded structs that should be parsed.

	Fields []field        // A list of fields that require binding.
	Routes []routes.Route // Routes concatenated with prefixes.
}

// Controller gets a controller name and returns it if it
// does exist. Nil is returned otherwise.
func (cs controllers) Controller(name string) *controller {
	for i := 0; i < len(cs.list); i++ {
		if cs.list[i].Name == name {
			return cs.list[i]
		}
	}
	return nil
}

// IgnoredArgs gets an action Func as input parameter
// and returns blank identifiers for parameters
// other than the first one.
// E.g. if the action returns action.Result, error, bool,
// this method will return ", _, _".
// So it can be used during code generation.
func (c controller) IgnoredArgs(f *reflect.Func) (s string) {
	n := len(f.Results) - 1 // Ignore action.Result.
	if n > 0 {
		s = strings.Repeat(", _", n)
	}
	return
}
<|endoftext|>


<commit_before>package vsphere

import (
	// "fmt"
	// "time"

	"github.com/hashicorp/terraform/helper/resource"
	// "github.com/hashicorp/terraform/terraform"

	"testing"
)

const testAccCheckVsphereVmConfig_basic = `
resource "vsphere_vm" "testingvm1" {
  template_name = "packer-stemcell-vsphere-1432631533-vm"
  vm_name = "testingvm1"
  memory_mb = "8192"
  cpus = "4"
  customization_specification = "Ubuntu"
}
`

func TestAccVsphereVm_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckVsphereVmConfig_basic,
			},
		},
	})
}
<commit_msg>test: check that vm is destroyed<commit_after>package vsphere

import (
	"fmt"

	"github.com/vmware/govmomi/find"
	"golang.org/x/net/context"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"

	"testing"
)

const testAccCheckVsphereVmConfig_basic = `
resource "vsphere_vm" "testingvm1" {
  vm_name = "testingvm1"

  template_name = "packer-stemcell-vsphere-1432631533-vm"
  memory_mb = "8192"
  cpus = "4"
  customization_specification = "Ubuntu"
}
`

func TestAccVsphereVm_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckVsphereVmDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckVsphereVmConfig_basic,
			},
		},
	})
}

func testAccCheckVsphereVmDestroy(s *terraform.State) error {
	client, err := testAccProvider.Meta().(*Config).Client()
	if err != nil {
		return err
	}
	finder := find.NewFinder(client.Client, false)
	datacenter, err := finder.DefaultDatacenter(context.TODO())
	if err != nil {
		return err
	}
	finder.SetDatacenter(datacenter)
	found, err := finder.VirtualMachine(context.TODO(), "testingvm1")
	if found != nil {
		return fmt.Errorf("Expected to not find %s: #%v, #%v", "testingvm1", found, err)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package noderesources

import (
	"context"
	"fmt"
	"math"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/features"
	framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
)

// BalancedAllocation is a score plugin that calculates the difference between the cpu and memory fraction
// of capacity, and prioritizes the host based on how close the two metrics are to each other.
type BalancedAllocation struct {
	handle framework.FrameworkHandle
	resourceAllocationScorer
}

var _ = framework.ScorePlugin(&BalancedAllocation{})

// BalancedAllocationName is the name of the plugin used in the plugin registry and configurations.
const BalancedAllocationName = "NodeResourcesBalancedAllocation"

// Name returns name of the plugin. It is used in logs, etc.
func (ba *BalancedAllocation) Name() string {
	return BalancedAllocationName
}

// Score invoked at the score extension point.
func (ba *BalancedAllocation) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
	nodeInfo, err := ba.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
	if err != nil {
		return 0, framework.NewStatus(framework.Error, fmt.Sprintf("getting node %q from Snapshot: %v", nodeName, err))
	}

	// ba.score favors nodes with balanced resource usage rate.
	// It should **NOT** be used alone, and **MUST** be used together
	// with NodeResourcesLeastAllocated plugin. It calculates the difference between the cpu and memory fraction
	// of capacity, and prioritizes the host based on how close the two metrics are to each other.
	// Detail: score = (1 - variance(cpuFraction,memoryFraction,volumeFraction)) * MaxNodeScore. The algorithm is partly inspired by:
	// "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced
	// Resource Utilization"
	return ba.score(pod, nodeInfo)
}

// ScoreExtensions of the Score plugin.
func (ba *BalancedAllocation) ScoreExtensions() framework.ScoreExtensions {
	return nil
}

// NewBalancedAllocation initializes a new plugin and returns it.
func NewBalancedAllocation(_ runtime.Object, h framework.FrameworkHandle) (framework.Plugin, error) {
	return &BalancedAllocation{
		handle: h,
		resourceAllocationScorer: resourceAllocationScorer{
			BalancedAllocationName,
			balancedResourceScorer,
			defaultRequestedRatioResources,
		},
	}, nil
}

// todo: use resource weights in the scorer function
func balancedResourceScorer(requested, allocable resourceToValueMap, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 {
	cpuFraction := fractionOfCapacity(requested[v1.ResourceCPU], allocable[v1.ResourceCPU])
	memoryFraction := fractionOfCapacity(requested[v1.ResourceMemory], allocable[v1.ResourceMemory])
	// This to find a node which has most balanced CPU, memory and volume usage.
	if cpuFraction >= 1 || memoryFraction >= 1 {
		// if requested >= capacity, the corresponding host should never be preferred.
		return 0
	}

	if includeVolumes && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && allocatableVolumes > 0 {
		volumeFraction := float64(requestedVolumes) / float64(allocatableVolumes)
		if volumeFraction >= 1 {
			// if requested >= capacity, the corresponding host should never be preferred.
			return 0
		}
		// Compute variance for all the three fractions.
		mean := (cpuFraction + memoryFraction + volumeFraction) / float64(3)
		variance := float64((((cpuFraction - mean) * (cpuFraction - mean)) + ((memoryFraction - mean) * (memoryFraction - mean)) + ((volumeFraction - mean) * (volumeFraction - mean))) / float64(3))
		// Since the variance is between positive fractions, it will be positive fraction. 1-variance lets the
		// score to be higher for node which has least variance and multiplying it with `MaxNodeScore` provides the scaling
		// factor needed.
		return int64((1 - variance) * float64(framework.MaxNodeScore))
	}

	// Upper and lower boundary of difference between cpuFraction and memoryFraction are -1 and 1
	// respectively. Multiplying the absolute value of the difference by `MaxNodeScore` scales the value to
	// 0-MaxNodeScore with 0 representing well balanced allocation and `MaxNodeScore` poorly balanced. Subtracting it from
	// `MaxNodeScore` leads to the score which also scales from 0 to `MaxNodeScore` while `MaxNodeScore` representing well balanced.
	diff := math.Abs(cpuFraction - memoryFraction)
	return int64((1 - diff) * float64(framework.MaxNodeScore))
}

func fractionOfCapacity(requested, capacity int64) float64 {
	if capacity == 0 {
		return 1
	}
	return float64(requested) / float64(capacity)
}
<commit_msg>Scheduler: remove the misleading comments in `NodeResourcesBalancedAllocation`<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package noderesources

import (
	"context"
	"fmt"
	"math"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/features"
	framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
)

// BalancedAllocation is a score plugin that calculates the difference between the cpu and memory fraction
// of capacity, and prioritizes the host based on how close the two metrics are to each other.
type BalancedAllocation struct {
	handle framework.FrameworkHandle
	resourceAllocationScorer
}

var _ = framework.ScorePlugin(&BalancedAllocation{})

// BalancedAllocationName is the name of the plugin used in the plugin registry and configurations.
const BalancedAllocationName = "NodeResourcesBalancedAllocation"

// Name returns name of the plugin. It is used in logs, etc.
func (ba *BalancedAllocation) Name() string {
	return BalancedAllocationName
}

// Score invoked at the score extension point.
func (ba *BalancedAllocation) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
	nodeInfo, err := ba.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
	if err != nil {
		return 0, framework.NewStatus(framework.Error, fmt.Sprintf("getting node %q from Snapshot: %v", nodeName, err))
	}

	// ba.score favors nodes with balanced resource usage rate.
	// It calculates the difference between the cpu and memory fraction of capacity,
	// and prioritizes the host based on how close the two metrics are to each other.
	// Detail: score = (1 - variance(cpuFraction,memoryFraction,volumeFraction)) * MaxNodeScore. The algorithm is partly inspired by:
	// "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced
	// Resource Utilization"
	return ba.score(pod, nodeInfo)
}

// ScoreExtensions of the Score plugin.
func (ba *BalancedAllocation) ScoreExtensions() framework.ScoreExtensions {
	return nil
}

// NewBalancedAllocation initializes a new plugin and returns it.
func NewBalancedAllocation(_ runtime.Object, h framework.FrameworkHandle) (framework.Plugin, error) {
	return &BalancedAllocation{
		handle: h,
		resourceAllocationScorer: resourceAllocationScorer{
			BalancedAllocationName,
			balancedResourceScorer,
			defaultRequestedRatioResources,
		},
	}, nil
}

// todo: use resource weights in the scorer function
func balancedResourceScorer(requested, allocable resourceToValueMap, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 {
	cpuFraction := fractionOfCapacity(requested[v1.ResourceCPU], allocable[v1.ResourceCPU])
	memoryFraction := fractionOfCapacity(requested[v1.ResourceMemory], allocable[v1.ResourceMemory])
	// This to find a node which has most balanced CPU, memory and volume usage.
	if cpuFraction >= 1 || memoryFraction >= 1 {
		// if requested >= capacity, the corresponding host should never be preferred.
		return 0
	}

	if includeVolumes && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && allocatableVolumes > 0 {
		volumeFraction := float64(requestedVolumes) / float64(allocatableVolumes)
		if volumeFraction >= 1 {
			// if requested >= capacity, the corresponding host should never be preferred.
			return 0
		}
		// Compute variance for all the three fractions.
		mean := (cpuFraction + memoryFraction + volumeFraction) / float64(3)
		variance := float64((((cpuFraction - mean) * (cpuFraction - mean)) + ((memoryFraction - mean) * (memoryFraction - mean)) + ((volumeFraction - mean) * (volumeFraction - mean))) / float64(3))
		// Since the variance is between positive fractions, it will be positive fraction. 1-variance lets the
		// score to be higher for node which has least variance and multiplying it with `MaxNodeScore` provides the scaling
		// factor needed.
		return int64((1 - variance) * float64(framework.MaxNodeScore))
	}

	// Upper and lower boundary of difference between cpuFraction and memoryFraction are -1 and 1
	// respectively. Multiplying the absolute value of the difference by `MaxNodeScore` scales the value to
	// 0-MaxNodeScore with 0 representing well balanced allocation and `MaxNodeScore` poorly balanced. Subtracting it from
	// `MaxNodeScore` leads to the score which also scales from 0 to `MaxNodeScore` while `MaxNodeScore` representing well balanced.
	diff := math.Abs(cpuFraction - memoryFraction)
	return int64((1 - diff) * float64(framework.MaxNodeScore))
}

func fractionOfCapacity(requested, capacity int64) float64 {
	if capacity == 0 {
		return 1
	}
	return float64(requested) / float64(capacity)
}
<|endoftext|>


<commit_before>package schroot

import (
	"fmt"
	"strings"

	"os/exec"
)

func getOutputLine(cmd *exec.Cmd) (string, error) {
	out, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return strings.Trim(string(out), " \n\t\r"), nil
}

type Schroot struct {
	location string
	name     string
	session  string
	active   bool
}

func (schroot *Schroot) End() error {
	return exec.Command("schroot", "-e", "-c", schroot.session).Run()
}

func (schroot *Schroot) Run(cmd string, args ...string) *exec.Cmd {
	/* The semantics of foo(bar, baz, quix...) are so fucked up here
	 * it's not even funny. Let's do an append and unpack that. Sorry
	 * this looks like garbage, but it's either explicitly passing the
	 * elements into the call site, or use a foo... with nothing prefixing
	 * it. Sooo. Yeah.
	 *    -- PRT */
	return exec.Command(
		"schroot",
		append(
			[]string{
				"-r",
				"-c", schroot.session,
				"--directory", "/",
				"--",
				cmd,
			}, args...)...,
	)
}

func NewSchroot(name string) (*Schroot, error) {
	schroot := Schroot{}
	out, err := getOutputLine(exec.Command("schroot", "-b", "-c", name))
	if err != nil {
		return nil, err
	}
	schroot.session = out

	out, err = getOutputLine(exec.Command(
		"schroot", "--location",
		"-c", fmt.Sprintf("session:%s", schroot.session),
	))
	if err != nil {
		return nil, err
	}
	schroot.location = out

	return &schroot, nil
}
<commit_msg>revise the interface, add active<commit_after>package schroot

import (
	"fmt"
	"strings"

	"os/exec"
)

func getOutputLine(cmd *exec.Cmd) (string, error) {
	out, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return strings.Trim(string(out), " \n\t\r"), nil
}

type Schroot struct {
	location string
	name     string
	session  string
	active   bool
}

func (schroot *Schroot) End() error {
	err := exec.Command("schroot", "-e", "-c", schroot.session).Run()
	schroot.active = false
	return err
}

func (schroot *Schroot) Command(cmd string, args ...string) (*exec.Cmd, error) {
	/* The semantics of foo(bar, baz, quix...) are so fucked up here
	 * it's not even funny. Let's do an append and unpack that. Sorry
	 * this looks like garbage, but it's either explicitly passing the
	 * elements into the call site, or use a foo... with nothing prefixing
	 * it. Sooo. Yeah.
	 *    -- PRT */
	if !schroot.active {
		return nil, fmt.Errorf("Error: Schroot is not online")
	}
	return exec.Command(
		"schroot",
		append(
			[]string{
				"-r",
				"-c", schroot.session,
				"--directory", "/",
				"--",
				cmd,
			}, args...)...,
	), nil
}

func NewSchroot(name string) (*Schroot, error) {
	schroot := Schroot{
		name:   name,
		active: false,
	}
	out, err := getOutputLine(exec.Command("schroot", "-b", "-c", name))
	if err != nil {
		return nil, err
	}
	schroot.session = out
	schroot.active = true

	out, err = getOutputLine(exec.Command(
		"schroot", "--location",
		"-c", fmt.Sprintf("session:%s", schroot.session),
	))
	if err != nil {
		return nil, err
	}
	schroot.location = out

	return &schroot, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"

	log "github.com/Sirupsen/logrus"
	"github.com/elazarl/goproxy"
	"github.com/garyburd/redigo/redis"
)

type DBClient struct {
	cache Cache
	http  *http.Client
}

// request holds structure for request
type request struct {
	details requestDetails
}

var emptyResp = &http.Response{}

// requestDetails stores information about request, it's used for creating unique hash and also as a payload structure
type requestDetails struct {
	Path        string `json:"path"`
	Method      string `json:"method"`
	Destination string `json:"destination"`
	Query       string `json:"query"`
}

// hash returns unique hash key for request
func (r *request) hash() string {
	h := md5.New()
	io.WriteString(h, fmt.Sprintf("%s%s%s%s", r.details.Destination, r.details.Path, r.details.Method, r.details.Query))
	return fmt.Sprintf("%x", h.Sum(nil))
}

// res structure hold response body from external service, body is not decoded and is supposed
// to be bytes, however headers should provide all required information for later decoding
// by the client.
type response struct {
	Status  int               `json:"status"`
	Body    []byte            `json:"body"`
	Headers map[string]string `json:"headers"`
}

// Payload structure holds request and response structure
type Payload struct {
	Response response       `json:"response"`
	Request  requestDetails `json:"request"`
	ID       string         `json:"id"`
}

// recordRequest saves request for later playback
func (d *DBClient) recordRequest(req *http.Request) (*http.Response, error) {

	// forwarding request
	resp, err := d.doRequest(req)

	if err == nil {

		// getting response body
		body, err := httputil.DumpResponse(resp, true)
		if err != nil {
			// copying the response body did not work
			if err != nil {
				log.WithFields(log.Fields{
					"error": err.Error(),
				}).Error("Failed to copy response body.")
			}
		}

		// saving response body with request/response meta to cache
		go d.save(req, resp, body)
	}

	// return new response or error here
	return resp, err
}

// doRequest performs original request and returns response that should be returned to client and error (if there is one)
func (d *DBClient) doRequest(request *http.Request) (*http.Response, error) {
	// We can't have this set. And it only contains "/pkg/net/http/" anyway
	request.RequestURI = ""

	resp, err := d.http.Do(request)

	if err != nil {
		log.WithFields(log.Fields{
			"error":  err.Error(),
			"host":   request.Host,
			"method": request.Method,
			"path":   request.URL.Path,
		}).Error("Could not forward request.")
		return nil, err
	}

	log.WithFields(log.Fields{
		"host":   request.Host,
		"method": request.Method,
		"path":   request.URL.Path,
	}).Info("Response got successfuly!")

	resp.Header.Set("Gen-proxy", "Was-Here")
	return resp, nil

}

// save gets request fingerprint, extracts request body, status code and headers, then saves it to cache
func (d *DBClient) save(req *http.Request, resp *http.Response, respBody []byte) {
	// record request here
	key := getRequestFingerprint(req)

	if resp == nil {
		resp = emptyResp
	} else {
		responseObj := response{
			Status:  resp.StatusCode,
			Body:    respBody,
			Headers: getHeadersMap(resp.Header),
		}

		log.WithFields(log.Fields{
			"path":          req.URL.Path,
			"rawQuery":      req.URL.RawQuery,
			"requestMethod": req.Method,
			"destination":   req.Host,
			"hashKey":       key,
		}).Info("Recording")

		requestObj := requestDetails{
			Path:        req.URL.Path,
			Method:      req.Method,
			Destination: req.Host,
			Query:       req.URL.RawQuery,
		}

		payload := Payload{
			Response: responseObj,
			Request:  requestObj,
			ID:       key,
		}
		// converting it to json bytes
		bts, err := json.Marshal(payload)

		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to marshal json")
		} else {
			d.cache.set(key, bts)
		}
	}

}

// getAllRecordsRaw returns raw (json string) for all records
func (d *DBClient) getAllRecordsRaw() ([]string, error) {
	keys, err := d.cache.getAllKeys()

	if err == nil {

		// checking if there are any records
		if len(keys) == 0 {
			return nil, nil
		}

		jsonStrs, err := d.cache.getAllValues(keys)

		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to get all values (raw)")
			return nil, err
		} else {
			return jsonStrs, nil
		}

	} else {
		return nil, err
	}
}

// getAllRecords returns all stored
func (d *DBClient) getAllRecords() ([]Payload, error) {
	var payloads []Payload

	jsonStrs, err := d.getAllRecordsRaw()

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to get all values")
	} else {

		if jsonStrs != nil {
			for _, v := range jsonStrs {
				var pl Payload
				err = json.Unmarshal([]byte(v), &pl)
				if err != nil {
					log.WithFields(log.Fields{
						"error": err.Error(),
						"json":  v,
					}).Warning("Failed to deserialize json")
				} else {
					payloads = append(payloads, pl)
				}
			}
		}
	}

	return payloads, err

}

// deleteAllRecords deletes all recorded requests
func (d *DBClient) deleteAllRecords() error {
	keys, err := d.cache.getAllKeys()

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Warning("Failed to get keys, cannot delete all records")
		return err
	} else {
		for _, v := range keys {
			d.cache.delete(v)
		}
		return nil
	}
}

// getRequestFingerprint returns request hash
func getRequestFingerprint(req *http.Request) string {
	details := requestDetails{Path: req.URL.Path, Method: req.Method, Destination: req.Host, Query: req.URL.RawQuery}
	r := request{details: details}
	return r.hash()
}

// getHeadersMap converts map[string][]string to map[string]string structure
func getHeadersMap(hds map[string][]string) map[string]string {
	headers := make(map[string]string)
	for key, value := range hds {
		headers[key] = value[0]
	}
	return headers
}

// getResponse returns stored response from cache
func (d *DBClient) getResponse(req *http.Request) *http.Response {
	log.Info("Returning response")

	key := getRequestFingerprint(req)
	var payload Payload

	payloadBts, err := redis.Bytes(d.cache.get(key))

	if err == nil {
		log.Info("Decoding bytes")
		// getting cache response
		err = json.Unmarshal(payloadBts, &payload)
		if err != nil {
			log.Error(err)
			// what now?
		}

		newResponse := &http.Response{}
		newResponse.Request = req
		// adding headers
		newResponse.Header = make(http.Header)
		if len(payload.Response.Headers) > 0 {
			for k, v := range payload.Response.Headers {
				newResponse.Header.Set(k, v)
			}
		}
		newResponse.Header.Set("Gen-Proxy", "Playback")
		// adding body
		buf := bytes.NewBuffer(payload.Response.Body)
		newResponse.ContentLength = int64(buf.Len())
		newResponse.Body = ioutil.NopCloser(buf)

		newResponse.StatusCode = payload.Response.Status

		log.WithFields(log.Fields{
			"key":        key,
			"status":     payload.Response.Status,
			"bodyLength": newResponse.ContentLength,
		}).Info("Response found, returning")

		return newResponse

	} else {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to retrieve response from cache")
		// return error? if we return nil - proxy forwards request to original destination
		return goproxy.NewResponse(req,
			goproxy.ContentTypeText, http.StatusPreconditionFailed,
			"Coudldn't find recorded request, please record it first!")
	}

}
<commit_msg>changed how header map is stored and then recreated<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"

	log "github.com/Sirupsen/logrus"
	"github.com/elazarl/goproxy"
	"github.com/garyburd/redigo/redis"
)

type DBClient struct {
	cache Cache
	http  *http.Client
}

// request holds structure for request
type request struct {
	details requestDetails
}

var emptyResp = &http.Response{}

// requestDetails stores information about request, it's used for creating unique hash and also as a payload structure
type requestDetails struct {
	Path        string `json:"path"`
	Method      string `json:"method"`
	Destination string `json:"destination"`
	Query       string `json:"query"`
}

// hash returns unique hash key for request
func (r *request) hash() string {
	h := md5.New()
	io.WriteString(h, fmt.Sprintf("%s%s%s%s", r.details.Destination, r.details.Path, r.details.Method, r.details.Query))
	return fmt.Sprintf("%x", h.Sum(nil))
}

// res structure hold response body from external service, body is not decoded and is supposed
// to be bytes, however headers should provide all required information for later decoding
// by the client.
type response struct {
	Status  int                 `json:"status"`
	Body    []byte              `json:"body"`
	Headers map[string][]string `json:"headers"`
}

// Payload structure holds request and response structure
type Payload struct {
	Response response       `json:"response"`
	Request  requestDetails `json:"request"`
	ID       string         `json:"id"`
}

// recordRequest saves request for later playback
func (d *DBClient) recordRequest(req *http.Request) (*http.Response, error) {

	// forwarding request
	resp, err := d.doRequest(req)

	if err == nil {

		// getting response body
		body, err := httputil.DumpResponse(resp, true)
		if err != nil {
			// copying the response body did not work
			if err != nil {
				log.WithFields(log.Fields{
					"error": err.Error(),
				}).Error("Failed to copy response body.")
			}
		}

		// saving response body with request/response meta to cache
		go d.save(req, resp, body)
	}

	// return new response or error here
	return resp, err
}

// doRequest performs original request and returns response that should be returned to client and error (if there is one)
func (d *DBClient) doRequest(request *http.Request) (*http.Response, error) {
	// We can't have this set. And it only contains "/pkg/net/http/" anyway
	request.RequestURI = ""

	resp, err := d.http.Do(request)

	if err != nil {
		log.WithFields(log.Fields{
			"error":  err.Error(),
			"host":   request.Host,
			"method": request.Method,
			"path":   request.URL.Path,
		}).Error("Could not forward request.")
		return nil, err
	}

	log.WithFields(log.Fields{
		"host":   request.Host,
		"method": request.Method,
		"path":   request.URL.Path,
	}).Info("Response got successfuly!")

	resp.Header.Set("Gen-proxy", "Was-Here")
	return resp, nil

}

// save gets request fingerprint, extracts request body, status code and headers, then saves it to cache
func (d *DBClient) save(req *http.Request, resp *http.Response, respBody []byte) {
	// record request here
	key := getRequestFingerprint(req)

	if resp == nil {
		resp = emptyResp
	} else {
		responseObj := response{
			Status: resp.StatusCode,
			Body:   respBody,
			//			Headers: getHeadersMap(resp.Header),
			Headers: resp.Header,
		}

		log.WithFields(log.Fields{
			"path":          req.URL.Path,
			"rawQuery":      req.URL.RawQuery,
			"requestMethod": req.Method,
			"destination":   req.Host,
			"hashKey":       key,
		}).Info("Recording")

		requestObj := requestDetails{
			Path:        req.URL.Path,
			Method:      req.Method,
			Destination: req.Host,
			Query:       req.URL.RawQuery,
		}

		payload := Payload{
			Response: responseObj,
			Request:  requestObj,
			ID:       key,
		}
		// converting it to json bytes
		bts, err := json.Marshal(payload)

		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to marshal json")
		} else {
			d.cache.set(key, bts)
		}
	}

}

// getAllRecordsRaw returns raw (json string) for all records
func (d *DBClient) getAllRecordsRaw() ([]string, error) {
	keys, err := d.cache.getAllKeys()

	if err == nil {

		// checking if there are any records
		if len(keys) == 0 {
			return nil, nil
		}

		jsonStrs, err := d.cache.getAllValues(keys)

		if err != nil {
			log.WithFields(log.Fields{
				"error": err.Error(),
			}).Error("Failed to get all values (raw)")
			return nil, err
		} else {
			return jsonStrs, nil
		}

	} else {
		return nil, err
	}
}

// getAllRecords returns all stored
func (d *DBClient) getAllRecords() ([]Payload, error) {
	var payloads []Payload

	jsonStrs, err := d.getAllRecordsRaw()

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to get all values")
	} else {

		if jsonStrs != nil {
			for _, v := range jsonStrs {
				var pl Payload
				err = json.Unmarshal([]byte(v), &pl)
				if err != nil {
					log.WithFields(log.Fields{
						"error": err.Error(),
						"json":  v,
					}).Warning("Failed to deserialize json")
				} else {
					payloads = append(payloads, pl)
				}
			}
		}
	}

	return payloads, err

}

// deleteAllRecords deletes all recorded requests
func (d *DBClient) deleteAllRecords() error {
	keys, err := d.cache.getAllKeys()

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Warning("Failed to get keys, cannot delete all records")
		return err
	} else {
		for _, v := range keys {
			d.cache.delete(v)
		}
		return nil
	}
}

// getRequestFingerprint returns request hash
func getRequestFingerprint(req *http.Request) string {
	details := requestDetails{Path: req.URL.Path, Method: req.Method, Destination: req.Host, Query: req.URL.RawQuery}
	r := request{details: details}
	return r.hash()
}

// getResponse returns stored response from cache
func (d *DBClient) getResponse(req *http.Request) *http.Response {
	log.Info("Returning response")

	key := getRequestFingerprint(req)
	var payload Payload

	payloadBts, err := redis.Bytes(d.cache.get(key))

	if err == nil {
		log.Info("Decoding bytes")
		// getting cache response
		err = json.Unmarshal(payloadBts, &payload)
		if err != nil {
			log.Error(err)
			// what now?
		}

		newResponse := &http.Response{}
		newResponse.Request = req
		// adding headers
		newResponse.Header = make(http.Header)
		if len(payload.Response.Headers) > 0 {
			for k, values := range payload.Response.Headers {
				// headers is a map, appending each value
				for _, v := range values {
					newResponse.Header.Add(k, v)
				}

			}
		}
		newResponse.Header.Set("Gen-Proxy", "Playback")
		// adding body
		buf := bytes.NewBuffer(payload.Response.Body)
		newResponse.ContentLength = int64(buf.Len())
		newResponse.Body = ioutil.NopCloser(buf)

		newResponse.StatusCode = payload.Response.Status

		log.WithFields(log.Fields{
			"key":        key,
			"status":     payload.Response.Status,
			"bodyLength": newResponse.ContentLength,
		}).Info("Response found, returning")

		return newResponse

	} else {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to retrieve response from cache")
		// return error? if we return nil - proxy forwards request to original destination
		return goproxy.NewResponse(req,
			goproxy.ContentTypeText, http.StatusPreconditionFailed,
			"Coudldn't find recorded request, please record it first!")
	}

}
<|endoftext|>


<commit_before>package knx

import (
	"bytes"
	"errors"
	"net"
	"sync"
	"time"
)

//
type Socket interface {
	Send(payload OutgoingPayload) error
	Inbound() <-chan interface{}
	Close() error
}

// NewClientSocket creates a new Socket which can used to exchange KNXnet/IP packets with a gateway.
func NewClientSocket(gatewayAddress string) (Socket, error) {
	addr, err := net.ResolveUDPAddr("udp4", gatewayAddress)
	if err != nil { return nil, err }

	conn, err := net.DialUDP("udp4", nil, addr)
	if err != nil { return nil, err }

	return makeUdpSocket(conn, addr), nil
}

// NewRoutingSocket creates a new Socket which can be used to exchange KNXnet/IP packets with a
// router.
func NewRoutingSocket(multicastAddress string) (Socket, error) {
	addr, err := net.ResolveUDPAddr("udp4", multicastAddress)
	if err != nil { return nil, err }

	conn, err := net.ListenMulticastUDP("udp4", nil, addr)
	if err != nil { return nil, err }

	return makeUdpSocket(conn, nil), nil
}

// UDP socket for KNXnet/IP packet exchange
type udpSocket struct {
	conn    *net.UDPConn
	inbound <-chan interface{}
}

// makeUdpSocket configures the UDPConn and launches the receiver and sender workers.
func makeUdpSocket(conn *net.UDPConn, addr *net.UDPAddr) *udpSocket {
	conn.SetDeadline(time.Time{})

	inbound := make(chan interface{})
	go udpSocketReceiver(conn, addr, inbound)

	return &udpSocket{conn, inbound}
}

// Send transmits a KNXnet/IP packet.
func (sock *udpSocket) Send(payload OutgoingPayload) error {
	buffer := &bytes.Buffer{}

	// Packet serialization
	err := WritePacket(buffer, payload)
	if err != nil { return err }

	log(sock.conn, "udpSocket", "<- %T %+v", payload, payload)

	// Transmission of the buffer contents
	_, err = sock.conn.Write(buffer.Bytes())
	if err != nil { return err }

	return nil
}

// Inbound provides a channel from which you can retrieve incoming packets.
func (sock *udpSocket) Inbound() <-chan interface{} {
	return sock.inbound
}

// Close shuts the socket down. This will indirectly terminate the associated workers.
func (sock *udpSocket) Close() error {
	return sock.conn.Close()
}

// udpSocketReceiver is the receiver worker for udpSocket.
func udpSocketReceiver(conn *net.UDPConn, addr *net.UDPAddr, inbound chan<- interface{}) {
	log(conn, "udpSocket", "Started receiver")
	defer log(conn, "udpSocket", "Stopped receiver")

	defer close(inbound)

	buffer := [1024]byte{}
	reader := bytes.NewReader(buffer[:])

	for {
		len, sender, err := conn.ReadFromUDP(buffer[:])
		if err != nil {
			log(conn, "udpSocket", "Error during read: %v", err)
			return
		}

		// Validate sender origin if necessary
		if addr != nil && (!addr.IP.Equal(sender.IP) || addr.Port != sender.Port) {
			log(conn, "udpSocket", "Origin validation failed: %v (expected %v)", sender, addr)
			continue
		}

		reader.Reset(buffer[:len])

		payload, err := ReadPacket(reader)
		if err != nil {
			log(conn, "udpSocket", "Error during packet parsing: %v", err)
			continue
		}

		log(conn, "udpSocket", "-> %T %+v", payload, payload)

		inbound <- payload
	}
}

//
type dummySocket struct {
	mu      sync.Mutex
	outOpen bool
	inOpen  bool

	out     chan OutgoingPayload
	in      chan interface{}
}

func makeDummySocket() *dummySocket {
	return &dummySocket{
		sync.Mutex{},
		true,
		true,
		make(chan OutgoingPayload, 10),
		make(chan interface{}, 10),
	}
}

//
func (sock *dummySocket) gatewaySend(payload interface{}) error {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if !sock.inOpen {
		return errors.New("Socket is closed")
	}

	sock.in <- payload

	return nil
}

//
func (sock *dummySocket) gatewayInbound() <-chan OutgoingPayload {
	return sock.out
}

//
func (sock *dummySocket) closeOut() {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if sock.outOpen {
		close(sock.out)
		sock.outOpen = false
	}
}

//
func (sock *dummySocket) closeIn() {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if sock.inOpen {
		close(sock.in)
		sock.inOpen = false
	}
}

//
func (sock *dummySocket) Send(payload OutgoingPayload) error {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if !sock.outOpen {
		return errors.New("Socket is closed")
	}

	sock.out <- payload

	return nil
}

//
func (sock *dummySocket) Inbound() <-chan interface{} {
	return sock.in
}

//
func (sock *dummySocket) Close() error {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if sock.outOpen {
		close(sock.out)
		sock.outOpen = false
	}

	if sock.inOpen {
		close(sock.in)
		sock.inOpen = false
	}

	return nil
}
<commit_msg>Fix dummySocket, so that a sender can't block a closer<commit_after>package knx

import (
	"bytes"
	"errors"
	"net"
	"sync"
	"time"
)

//
type Socket interface {
	Send(payload OutgoingPayload) error
	Inbound() <-chan interface{}
	Close() error
}

// NewClientSocket creates a new Socket which can used to exchange KNXnet/IP packets with a gateway.
func NewClientSocket(gatewayAddress string) (Socket, error) {
	addr, err := net.ResolveUDPAddr("udp4", gatewayAddress)
	if err != nil { return nil, err }

	conn, err := net.DialUDP("udp4", nil, addr)
	if err != nil { return nil, err }

	return makeUdpSocket(conn, addr), nil
}

// NewRoutingSocket creates a new Socket which can be used to exchange KNXnet/IP packets with a
// router.
func NewRoutingSocket(multicastAddress string) (Socket, error) {
	addr, err := net.ResolveUDPAddr("udp4", multicastAddress)
	if err != nil { return nil, err }

	conn, err := net.ListenMulticastUDP("udp4", nil, addr)
	if err != nil { return nil, err }

	return makeUdpSocket(conn, nil), nil
}

// UDP socket for KNXnet/IP packet exchange
type udpSocket struct {
	conn    *net.UDPConn
	inbound <-chan interface{}
}

// makeUdpSocket configures the UDPConn and launches the receiver and sender workers.
func makeUdpSocket(conn *net.UDPConn, addr *net.UDPAddr) *udpSocket {
	conn.SetDeadline(time.Time{})

	inbound := make(chan interface{})
	go udpSocketReceiver(conn, addr, inbound)

	return &udpSocket{conn, inbound}
}

// Send transmits a KNXnet/IP packet.
func (sock *udpSocket) Send(payload OutgoingPayload) error {
	buffer := &bytes.Buffer{}

	// Packet serialization
	err := WritePacket(buffer, payload)
	if err != nil { return err }

	log(sock.conn, "udpSocket", "<- %T %+v", payload, payload)

	// Transmission of the buffer contents
	_, err = sock.conn.Write(buffer.Bytes())
	if err != nil { return err }

	return nil
}

// Inbound provides a channel from which you can retrieve incoming packets.
func (sock *udpSocket) Inbound() <-chan interface{} {
	return sock.inbound
}

// Close shuts the socket down. This will indirectly terminate the associated workers.
func (sock *udpSocket) Close() error {
	return sock.conn.Close()
}

// udpSocketReceiver is the receiver worker for udpSocket.
func udpSocketReceiver(conn *net.UDPConn, addr *net.UDPAddr, inbound chan<- interface{}) {
	log(conn, "udpSocket", "Started receiver")
	defer log(conn, "udpSocket", "Stopped receiver")

	defer close(inbound)

	buffer := [1024]byte{}
	reader := bytes.NewReader(buffer[:])

	for {
		len, sender, err := conn.ReadFromUDP(buffer[:])
		if err != nil {
			log(conn, "udpSocket", "Error during read: %v", err)
			return
		}

		// Validate sender origin if necessary
		if addr != nil && (!addr.IP.Equal(sender.IP) || addr.Port != sender.Port) {
			log(conn, "udpSocket", "Origin validation failed: %v (expected %v)", sender, addr)
			continue
		}

		reader.Reset(buffer[:len])

		payload, err := ReadPacket(reader)
		if err != nil {
			log(conn, "udpSocket", "Error during packet parsing: %v", err)
			continue
		}

		log(conn, "udpSocket", "-> %T %+v", payload, payload)

		inbound <- payload
	}
}

//
type dummySocket struct {
	mu      sync.Mutex
	outOpen bool
	inOpen  bool

	out     chan OutgoingPayload
	in      chan interface{}
}

func makeDummySocket() *dummySocket {
	return &dummySocket{
		sync.Mutex{},
		true,
		true,
		make(chan OutgoingPayload, 10),
		make(chan interface{}, 10),
	}
}

//
func (sock *dummySocket) gatewaySend(payload interface{}) error {
	for {
		sock.mu.Lock()

		if !sock.inOpen {
			sock.mu.Unlock()
			return errors.New("Socket is closed")
		}

		select {
			case sock.in <- payload:
				sock.mu.Unlock()
				return nil

			default:
				sock.mu.Unlock()
		}
	}
}

//
func (sock *dummySocket) gatewayInbound() <-chan OutgoingPayload {
	return sock.out
}

//
func (sock *dummySocket) closeOut() {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if sock.outOpen {
		close(sock.out)
		sock.outOpen = false
	}
}

//
func (sock *dummySocket) closeIn() {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if sock.inOpen {
		close(sock.in)
		sock.inOpen = false
	}
}

//
func (sock *dummySocket) Send(payload OutgoingPayload) error {
	for {
		sock.mu.Lock()

		if !sock.outOpen {
			sock.mu.Unlock()
			return errors.New("Socket is closed")
		}

		select {
			case sock.out <- payload:
				sock.mu.Unlock()
				return nil

			default:
				sock.mu.Unlock()
		}
	}
}

//
func (sock *dummySocket) Inbound() <-chan interface{} {
	return sock.in
}

//
func (sock *dummySocket) Close() error {
	sock.mu.Lock()
	defer sock.mu.Unlock()

	if sock.outOpen {
		close(sock.out)
		sock.outOpen = false
	}

	if sock.inOpen {
		close(sock.in)
		sock.inOpen = false
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"errors"
	"os"
	"path"
	"strings"

	"github.com/MJKWoolnough/byteio"
)

func (t Transfer) server(r *byteio.StickyReader, w *byteio.StickyWriter, f *os.File) error {
	stat, err := f.Stat()
	if err != nil {
		return err
	}
	zr, err := zip.NewReader(f, stat.Size())
	if err != nil {
		return err
	}
	name := readString(r)
	jars := make([]*zip.File, 0, 16)
	for _, file := range zr.File {
		if strings.HasSuffix(file.Name, ".jar") {
			jars = append(jars, file)
		}
	}
	s := t.c.NewServer()
	done := false
	defer func() {
		if !done {
			t.c.RemoveServer(s.ID)
		}
		go t.c.Save()
	}()
	if s == nil {
		return errors.New("error creating server")
	}
	s.Lock()
	s.Name = name
	d := s.Path
	s.Unlock()
	if len(jars) == 0 {
		err = moveFile(f.Name(), path.Join(d, "server.jar"))
	} else {
		if len(jars) > 1 {
			w.WriteUint8(1)
			w.WriteInt16(int16(len(jars)))
			for _, jar := range jars {
				writeString(w, jar.Name)
			}
			if w.Err != nil {
				return w.Err
			}
			p := r.ReadInt16()
			if r.Err != nil {
				return r.Err
			}
			if int(p) >= len(jars) || p < 0 {
				return errors.New("error selecting server jar")
			} else {
				jars[0] = jars[p]
			}
		}
		if err == nil {
			err = unzip(zr, d)
			if err == nil {
				err = os.Rename(path.Join(d, jars[0].Name), path.Join(d, "server.jar"))
			}
		}
	}
	if err != nil {
		return err
	}
	serverProperties := DefaultServerSettings()
	ps, err := os.OpenFile(path.Join(d, "properties.server"), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
	defer ps.Close()
	if err != nil {
		if !os.IsExist(err) {
			return err
		}
	} else {
		err = serverProperties.WriteTo(ps)
		if err != nil {
			return err
		}
	}
	done = true
	return nil
}
<commit_msg>Added early reader error check<commit_after>package main

import (
	"archive/zip"
	"errors"
	"os"
	"path"
	"strings"

	"github.com/MJKWoolnough/byteio"
)

func (t Transfer) server(r *byteio.StickyReader, w *byteio.StickyWriter, f *os.File) error {
	stat, err := f.Stat()
	if err != nil {
		return err
	}
	zr, err := zip.NewReader(f, stat.Size())
	if err != nil {
		return err
	}
	name := readString(r)
	if r.Err != nil {
		return r.Err
	}
	jars := make([]*zip.File, 0, 16)
	for _, file := range zr.File {
		if strings.HasSuffix(file.Name, ".jar") {
			jars = append(jars, file)
		}
	}
	s := t.c.NewServer()
	done := false
	defer func() {
		if !done {
			t.c.RemoveServer(s.ID)
		}
		go t.c.Save()
	}()
	if s == nil {
		return errors.New("error creating server")
	}
	s.Lock()
	s.Name = name
	d := s.Path
	s.Unlock()
	if len(jars) == 0 {
		err = moveFile(f.Name(), path.Join(d, "server.jar"))
	} else {
		if len(jars) > 1 {
			w.WriteUint8(1)
			w.WriteInt16(int16(len(jars)))
			for _, jar := range jars {
				writeString(w, jar.Name)
			}
			if w.Err != nil {
				return w.Err
			}
			p := r.ReadInt16()
			if r.Err != nil {
				return r.Err
			}
			if int(p) >= len(jars) || p < 0 {
				return errors.New("error selecting server jar")
			} else {
				jars[0] = jars[p]
			}
		}
		if err == nil {
			err = unzip(zr, d)
			if err == nil {
				err = os.Rename(path.Join(d, jars[0].Name), path.Join(d, "server.jar"))
			}
		}
	}
	if err != nil {
		return err
	}
	serverProperties := DefaultServerSettings()
	ps, err := os.OpenFile(path.Join(d, "properties.server"), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
	defer ps.Close()
	if err != nil {
		if !os.IsExist(err) {
			return err
		}
	} else {
		err = serverProperties.WriteTo(ps)
		if err != nil {
			return err
		}
	}
	done = true
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"bytes"
	"go/parser"
	"go/ast"
	"go/token"
	"go/scanner"
	"fmt"
	"os"
	"io"
	"io/ioutil"
)

type ModuleCache struct {
	name     string
	filename string
	mtime    int64
	defalias string

	// used as a temporary for foreignifying package contents
	scope  *Scope
	main   *Decl // module declaration
	others map[string]*Decl

	// map which has that kind of entries:
	// ast -> go/ast
	// parser -> go/parser
	// etc.
	// used for replacing "" module names in .a files
	pathToAlias map[string]string
}

func NewModuleCache(name, filename string) *ModuleCache {
	m := new(ModuleCache)
	m.name = name
	m.filename = filename
	m.mtime = 0
	m.defalias = ""
	return m
}

func NewModuleCacheForever(name, defalias string) *ModuleCache {
	m := new(ModuleCache)
	m.name = name
	m.mtime = -1
	m.defalias = defalias
	return m
}

func (self *ModuleCache) updateCache() {
	if self.mtime == -1 {
		return
	}
	stat, err := os.Stat(self.filename)
	if err != nil {
		return
	}

	if self.mtime != stat.Mtime_ns {
		// clear tmp scope
		self.mtime = stat.Mtime_ns

		// try load new
		data, err := ioutil.ReadFile(self.filename)
		if err != nil {
			return
		}
		self.processPackageData(string(data))
	}
}

func (self *ModuleCache) processPackageData(s string) {
	self.scope = NewScope(nil)
	i := strings.Index(s, "import\n$$\n")
	if i == -1 {
		panic("Can't find the import section in the archive file")
	}
	s = s[i+len("import\n$$\n"):]
	i = strings.Index(s, "$$\n")
	if i == -1 {
		panic("Can't find the end of the import section in the archive file")
	}
	s = s[0:i] // leave only import section

	i = strings.Index(s, "\n")
	if i == -1 {
		panic("Wrong file")
	}

	self.defalias = s[len("package ") : i-1]
	s = s[i+1:]

	self.pathToAlias = make(map[string]string)
	self.addFakeModuleToScope(self.defalias, self.name)
	internalPackages := make(map[string]*bytes.Buffer)
	for {
		// for each line
		i := strings.Index(s, "\n")
		if i == -1 {
			break
		}
		decl := strings.TrimSpace(s[0:i])
		if len(decl) == 0 {
			s = s[i+1:]
			continue
		}
		decl2, pkg := self.processExport(decl)
		if len(decl2) == 0 {
			s = s[i+1:]
			continue
		}

		buf := internalPackages[pkg]
		if buf == nil {
			buf = bytes.NewBuffer(make([]byte, 0, 4096))
			internalPackages[pkg] = buf
		}
		buf.WriteString(decl2)
		buf.WriteString("\n")
		s = s[i+1:]
	}
	self.others = make(map[string]*Decl)
	for key, value := range internalPackages {
		tmpbuf := bytes.NewBuffer(make([]byte, 0, value.Len()))
		self.expandPackages(value.Bytes(), tmpbuf)

		decls, err := parser.ParseDeclList("", tmpbuf.Bytes(), nil)
		tmpbuf = nil

		if err != nil {
			panic(fmt.Sprintf("failure in:\n%s\n%s\n", value, err.String()))
		} else {
			if key == self.name {
				// main package
				self.main = NewDecl(self.name, DECL_MODULE, nil)
				addAstDeclsToModule(self.main, decls, self.scope)
			} else {
				// others
				self.others[key] = NewDecl(key, DECL_MODULE, nil)
				addAstDeclsToModule(self.others[key], decls, self.scope)
			}
		}
	}
	self.pathToAlias = nil
	for key, value := range self.scope.entities {
		m, ok := self.others[value.Name]
		if !ok && value.Name == self.name {
			m = self.main
		}
		self.scope.entities[key] = m
	}
}

// feed one definition line from .a file here
// returns:
// 1. a go/parser parsable string representing one Go declaration
// 2. and a package name this declaration belongs to
func (self *ModuleCache) processExport(s string) (string, string) {
	i := 0
	pkg := ""

	// skip to a decl type: (type | func | const | var | import)
	i = skipSpaces(i, s)
	if i == len(s) {
		return "", pkg
	}
	b := i
	i = skipToSpace(i, s)
	if i == len(s) {
		return "", pkg
	}
	e := i

	switch s[b:e] {
	case "import":
		// skip import decls, we don't need them
		self.processImportStatement(s)
		return "", pkg
	case "const":
		s = preprocessConstDecl(s)
	}
	i++ // skip space after a decl type

	// extract a package this decl belongs to
	switch s[i] {
	case '(':
		s, pkg = extractPackageFromMethod(i, s)
	case '"':
		s, pkg = extractPackage(i, s)
	}

	// make everything parser friendly
	s = strings.Replace(s, "?", "", -1)

	// skip system functions (Init, etc.)
	i = strings.Index(s, "·")
	if i != -1 {
		return "", ""
	}

	if pkg == "" {
		pkg = self.name
	}

	return s, pkg
}

func (self *ModuleCache) processImportStatement(s string) {
	var scan scanner.Scanner
	scan.Init("", []byte(s), nil, 0)

	var alias, path string
	for i := 0; i < 3; i++ {
		_, tok, lit := scan.Scan()
		str := string(lit)
		switch tok {
		case token.IDENT:
			if str == "import" {
				continue
			} else {
				alias = str
			}
		case token.STRING:
			path = str[1 : len(str)-1]
		}
	}
	self.pathToAlias[path] = alias
	self.addFakeModuleToScope(alias, path)
}

func (self *ModuleCache) expandPackages(s []byte, out io.Writer) {
	i := 0
	for {
		begin := i
		for i < len(s) && s[i] != '"' {
			i++
		}

		if i == len(s) {
			out.Write(s[begin:])
			return
		}

		b := i // first '"'
		i++

		for i < len(s) && !(s[i] == '"' && s[i-1] != '\\') {
			i++
		}

		if i == len(s) {
			out.Write(s[begin:])
			return
		}

		e := i // second '"'
		i++
		if s[b-1] == ':' {
			// special case, struct attribute literal, just remove ':'
			out.Write(s[begin : b-1])
			out.Write(s[b : i])
		} else if b+1 != e {
			// wow, we actually have something here
			alias, ok := self.pathToAlias[string(s[b+1 : e])]
			if ok {
				out.Write(s[begin : b])
				out.Write([]byte(alias))
			} else {
				out.Write(s[begin : i])
			}
		} else {
			out.Write(s[begin : b])
			out.Write([]byte(self.defalias))
		}

	}
	panic("unreachable")
}

func (self *ModuleCache) addFakeModuleToScope(alias, realname string) {
	d := NewDecl(realname, DECL_MODULE, nil)
	self.scope.addDecl(alias, d)
}

func addAstDeclsToModule(module *Decl, decls []ast.Decl, scope *Scope) {
	for _, decl := range decls {
		decls := splitDecls(decl)
		for _, decl := range decls {
			names := declNames(decl)
			values := declValues(decl)

			for i, name := range names {
				var value ast.Expr = nil
				valueindex := -1
				if values != nil {
					if len(values) > 1 {
						value = values[i]
					} else {
						value = values[0]
						valueindex = i
					}
				}

				d := NewDeclFromAstDecl(name, DECL_FOREIGN, decl, value, valueindex, scope)
				if d == nil {
					continue
				}

				if !ast.IsExported(name) {
					// We need types here, because embeddeing may
					// refer to unexported types which contain
					// exported methods, like in reflect package.
					if d.Class != DECL_TYPE {
						continue
					}
				}

				methodof := MethodOf(decl)
				if methodof != "" {
					decl := module.FindChild(methodof)
					if decl != nil {
						decl.AddChild(d)
					} else {
						decl = NewDecl(methodof, DECL_METHODS_STUB, scope)
						decl.AddChild(d)
						module.AddChild(decl)
					}
				} else {
					decl := module.FindChild(d.Name)
					if decl != nil {
						decl.ExpandOrReplace(d)
					} else {
						module.AddChild(d)
					}
				}
			}
		}
	}
}

// TODO: probably change hand-written string literals processing to a
// "scanner"-based one

func skipSpaces(i int, s string) int {
	for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
		i++
	}
	return i
}

func skipToSpace(i int, s string) int {
	for i < len(s) && s[i] != ' ' && s[i] != '\t' {
		i++
	}
	return i
}

func extractPackage(i int, s string) (string, string) {
	pkg := ""

	b := i // first '"'
	i++

	for i < len(s) && s[i] != '"' {
		i++
	}

	if i == len(s) {
		return s, pkg
	}

	e := i // second '"'
	if b+1 != e {
		// wow, we actually have something here
		pkg = s[b+1 : e]
	}

	i += 2             // skip to a first symbol after dot
	s = s[0:b] + s[i:] // strip package clause completely

	return s, pkg
}

// returns modified 's' with package stripped from the method and the package name
func extractPackageFromMethod(i int, s string) (string, string) {
	pkg := ""
	for {
		for i < len(s) && s[i] != ')' && s[i] != '"' {
			i++
		}

		if s[i] == ')' || i == len(s) {
			return s, pkg
		}

		b := i // first '"'
		i++

		for i < len(s) && s[i] != ')' && s[i] != '"' {
			i++
		}

		if s[i] == ')' || i == len(s) {
			return s, pkg
		}

		e := i // second '"'
		if b+1 != e {
			// wow, we actually have something here
			pkg = s[b+1 : e]
		}

		i += 2             // skip to a first symbol after dot
		s = s[0:b] + s[i:] // strip package clause completely

		i = b
	}
	panic("unreachable")
	return "", ""
}

func preprocessConstDecl(s string) string {
	i := strings.Index(s, "=")
	if i == -1 {
		return s
	}

	for i < len(s) && !(s[i] >= '0' && s[i] <= '9') && s[i] != '"' && s[i] != '\'' {
		i++
	}

	if i == len(s) || s[i] == '"' || s[i] == '\'' {
		return s
	}

	// ok, we have a digit!
	b := i
	for i < len(s) && ((s[i] >= '0' && s[i] <= '9') || s[i] == 'p' || s[i] == '-' || s[i] == '+') {
		i++
	}
	e := i

	return s[0:b] + "0" + s[e:]
}

func declNames(d ast.Decl) []string {
	var names []string

	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.CONST:
			c := t.Specs[0].(*ast.ValueSpec)
			names = make([]string, len(c.Names))
			for i, name := range c.Names {
				names[i] = name.Name()
			}
		case token.TYPE:
			t := t.Specs[0].(*ast.TypeSpec)
			names = make([]string, 1)
			names[0] = t.Name.Name()
		case token.VAR:
			v := t.Specs[0].(*ast.ValueSpec)
			names = make([]string, len(v.Names))
			for i, name := range v.Names {
				names[i] = name.Name()
			}
		}
	case *ast.FuncDecl:
		names = make([]string, 1)
		names[0] = t.Name.Name()
	}

	return names
}

func declValues(d ast.Decl) []ast.Expr {
	// TODO: CONST values here too
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR:
			v := t.Specs[0].(*ast.ValueSpec)
			if v.Values != nil {
				return v.Values
			}
		}
	}
	return nil
}

func splitDecls(d ast.Decl) []ast.Decl {
	var decls []ast.Decl
	if t, ok := d.(*ast.GenDecl); ok {
		decls = make([]ast.Decl, len(t.Specs))
		for i, s := range t.Specs {
			decl := new(ast.GenDecl)
			*decl = *t
			decl.Specs = make([]ast.Spec, 1)
			decl.Specs[0] = s
			decls[i] = decl
		}
	} else {
		decls = make([]ast.Decl, 1)
		decls[0] = d
	}
	return decls
}
<commit_msg>Slightly change "expandPackages" function interface.<commit_after>package main

import (
	"strings"
	"bytes"
	"go/parser"
	"go/ast"
	"go/token"
	"go/scanner"
	"fmt"
	"os"
	"io/ioutil"
)

type ModuleCache struct {
	name     string
	filename string
	mtime    int64
	defalias string

	// used as a temporary for foreignifying package contents
	scope  *Scope
	main   *Decl // module declaration
	others map[string]*Decl

	// map which has that kind of entries:
	// ast -> go/ast
	// parser -> go/parser
	// etc.
	// used for replacing "" module names in .a files
	pathToAlias map[string]string
}

func NewModuleCache(name, filename string) *ModuleCache {
	m := new(ModuleCache)
	m.name = name
	m.filename = filename
	m.mtime = 0
	m.defalias = ""
	return m
}

func NewModuleCacheForever(name, defalias string) *ModuleCache {
	m := new(ModuleCache)
	m.name = name
	m.mtime = -1
	m.defalias = defalias
	return m
}

func (self *ModuleCache) updateCache() {
	if self.mtime == -1 {
		return
	}
	stat, err := os.Stat(self.filename)
	if err != nil {
		return
	}

	if self.mtime != stat.Mtime_ns {
		// clear tmp scope
		self.mtime = stat.Mtime_ns

		// try load new
		data, err := ioutil.ReadFile(self.filename)
		if err != nil {
			return
		}
		self.processPackageData(string(data))
	}
}

func (self *ModuleCache) processPackageData(s string) {
	self.scope = NewScope(nil)
	i := strings.Index(s, "import\n$$\n")
	if i == -1 {
		panic("Can't find the import section in the archive file")
	}
	s = s[i+len("import\n$$\n"):]
	i = strings.Index(s, "$$\n")
	if i == -1 {
		panic("Can't find the end of the import section in the archive file")
	}
	s = s[0:i] // leave only import section

	i = strings.Index(s, "\n")
	if i == -1 {
		panic("Wrong file")
	}

	self.defalias = s[len("package ") : i-1]
	s = s[i+1:]

	self.pathToAlias = make(map[string]string)
	self.addFakeModuleToScope(self.defalias, self.name)
	internalPackages := make(map[string]*bytes.Buffer)
	for {
		// for each line
		i := strings.Index(s, "\n")
		if i == -1 {
			break
		}
		decl := strings.TrimSpace(s[0:i])
		if len(decl) == 0 {
			s = s[i+1:]
			continue
		}
		decl2, pkg := self.processExport(decl)
		if len(decl2) == 0 {
			s = s[i+1:]
			continue
		}

		buf := internalPackages[pkg]
		if buf == nil {
			buf = bytes.NewBuffer(make([]byte, 0, 4096))
			internalPackages[pkg] = buf
		}
		buf.WriteString(decl2)
		buf.WriteString("\n")
		s = s[i+1:]
	}
	self.others = make(map[string]*Decl)
	for key, value := range internalPackages {
		tmp := self.expandPackages(value.Bytes())
		decls, err := parser.ParseDeclList("", tmp, nil)
		tmp = nil

		if err != nil {
			panic(fmt.Sprintf("failure in:\n%s\n%s\n", value, err.String()))
		} else {
			if key == self.name {
				// main package
				self.main = NewDecl(self.name, DECL_MODULE, nil)
				addAstDeclsToModule(self.main, decls, self.scope)
			} else {
				// others
				self.others[key] = NewDecl(key, DECL_MODULE, nil)
				addAstDeclsToModule(self.others[key], decls, self.scope)
			}
		}
	}
	self.pathToAlias = nil
	for key, value := range self.scope.entities {
		m, ok := self.others[value.Name]
		if !ok && value.Name == self.name {
			m = self.main
		}
		self.scope.entities[key] = m
	}
}

// feed one definition line from .a file here
// returns:
// 1. a go/parser parsable string representing one Go declaration
// 2. and a package name this declaration belongs to
func (self *ModuleCache) processExport(s string) (string, string) {
	i := 0
	pkg := ""

	// skip to a decl type: (type | func | const | var | import)
	i = skipSpaces(i, s)
	if i == len(s) {
		return "", pkg
	}
	b := i
	i = skipToSpace(i, s)
	if i == len(s) {
		return "", pkg
	}
	e := i

	switch s[b:e] {
	case "import":
		// skip import decls, we don't need them
		self.processImportStatement(s)
		return "", pkg
	case "const":
		s = preprocessConstDecl(s)
	}
	i++ // skip space after a decl type

	// extract a package this decl belongs to
	switch s[i] {
	case '(':
		s, pkg = extractPackageFromMethod(i, s)
	case '"':
		s, pkg = extractPackage(i, s)
	}

	// make everything parser friendly
	s = strings.Replace(s, "?", "", -1)

	// skip system functions (Init, etc.)
	i = strings.Index(s, "·")
	if i != -1 {
		return "", ""
	}

	if pkg == "" {
		pkg = self.name
	}

	return s, pkg
}

func (self *ModuleCache) processImportStatement(s string) {
	var scan scanner.Scanner
	scan.Init("", []byte(s), nil, 0)

	var alias, path string
	for i := 0; i < 3; i++ {
		_, tok, lit := scan.Scan()
		str := string(lit)
		switch tok {
		case token.IDENT:
			if str == "import" {
				continue
			} else {
				alias = str
			}
		case token.STRING:
			path = str[1 : len(str)-1]
		}
	}
	self.pathToAlias[path] = alias
	self.addFakeModuleToScope(alias, path)
}

func (self *ModuleCache) expandPackages(s []byte) []byte {
	out := bytes.NewBuffer(make([]byte, 0, len(s)))
	i := 0
	for {
		begin := i
		for i < len(s) && s[i] != '"' {
			i++
		}

		if i == len(s) {
			out.Write(s[begin:])
			return out.Bytes()
		}

		b := i // first '"'
		i++

		for i < len(s) && !(s[i] == '"' && s[i-1] != '\\') {
			i++
		}

		if i == len(s) {
			out.Write(s[begin:])
			return out.Bytes()
		}

		e := i // second '"'
		i++
		if s[b-1] == ':' {
			// special case, struct attribute literal, just remove ':'
			out.Write(s[begin : b-1])
			out.Write(s[b : i])
		} else if b+1 != e {
			// wow, we actually have something here
			alias, ok := self.pathToAlias[string(s[b+1 : e])]
			if ok {
				out.Write(s[begin : b])
				out.Write([]byte(alias))
			} else {
				out.Write(s[begin : i])
			}
		} else {
			out.Write(s[begin : b])
			out.Write([]byte(self.defalias))
		}

	}
	panic("unreachable")
}

func (self *ModuleCache) addFakeModuleToScope(alias, realname string) {
	d := NewDecl(realname, DECL_MODULE, nil)
	self.scope.addDecl(alias, d)
}

func addAstDeclsToModule(module *Decl, decls []ast.Decl, scope *Scope) {
	for _, decl := range decls {
		decls := splitDecls(decl)
		for _, decl := range decls {
			names := declNames(decl)
			values := declValues(decl)

			for i, name := range names {
				var value ast.Expr = nil
				valueindex := -1
				if values != nil {
					if len(values) > 1 {
						value = values[i]
					} else {
						value = values[0]
						valueindex = i
					}
				}

				d := NewDeclFromAstDecl(name, DECL_FOREIGN, decl, value, valueindex, scope)
				if d == nil {
					continue
				}

				if !ast.IsExported(name) {
					// We need types here, because embeddeing may
					// refer to unexported types which contain
					// exported methods, like in reflect package.
					if d.Class != DECL_TYPE {
						continue
					}
				}

				methodof := MethodOf(decl)
				if methodof != "" {
					decl := module.FindChild(methodof)
					if decl != nil {
						decl.AddChild(d)
					} else {
						decl = NewDecl(methodof, DECL_METHODS_STUB, scope)
						decl.AddChild(d)
						module.AddChild(decl)
					}
				} else {
					decl := module.FindChild(d.Name)
					if decl != nil {
						decl.ExpandOrReplace(d)
					} else {
						module.AddChild(d)
					}
				}
			}
		}
	}
}

// TODO: probably change hand-written string literals processing to a
// "scanner"-based one

func skipSpaces(i int, s string) int {
	for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
		i++
	}
	return i
}

func skipToSpace(i int, s string) int {
	for i < len(s) && s[i] != ' ' && s[i] != '\t' {
		i++
	}
	return i
}

func extractPackage(i int, s string) (string, string) {
	pkg := ""

	b := i // first '"'
	i++

	for i < len(s) && s[i] != '"' {
		i++
	}

	if i == len(s) {
		return s, pkg
	}

	e := i // second '"'
	if b+1 != e {
		// wow, we actually have something here
		pkg = s[b+1 : e]
	}

	i += 2             // skip to a first symbol after dot
	s = s[0:b] + s[i:] // strip package clause completely

	return s, pkg
}

// returns modified 's' with package stripped from the method and the package name
func extractPackageFromMethod(i int, s string) (string, string) {
	pkg := ""
	for {
		for i < len(s) && s[i] != ')' && s[i] != '"' {
			i++
		}

		if s[i] == ')' || i == len(s) {
			return s, pkg
		}

		b := i // first '"'
		i++

		for i < len(s) && s[i] != ')' && s[i] != '"' {
			i++
		}

		if s[i] == ')' || i == len(s) {
			return s, pkg
		}

		e := i // second '"'
		if b+1 != e {
			// wow, we actually have something here
			pkg = s[b+1 : e]
		}

		i += 2             // skip to a first symbol after dot
		s = s[0:b] + s[i:] // strip package clause completely

		i = b
	}
	panic("unreachable")
	return "", ""
}

func preprocessConstDecl(s string) string {
	i := strings.Index(s, "=")
	if i == -1 {
		return s
	}

	for i < len(s) && !(s[i] >= '0' && s[i] <= '9') && s[i] != '"' && s[i] != '\'' {
		i++
	}

	if i == len(s) || s[i] == '"' || s[i] == '\'' {
		return s
	}

	// ok, we have a digit!
	b := i
	for i < len(s) && ((s[i] >= '0' && s[i] <= '9') || s[i] == 'p' || s[i] == '-' || s[i] == '+') {
		i++
	}
	e := i

	return s[0:b] + "0" + s[e:]
}

func declNames(d ast.Decl) []string {
	var names []string

	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.CONST:
			c := t.Specs[0].(*ast.ValueSpec)
			names = make([]string, len(c.Names))
			for i, name := range c.Names {
				names[i] = name.Name()
			}
		case token.TYPE:
			t := t.Specs[0].(*ast.TypeSpec)
			names = make([]string, 1)
			names[0] = t.Name.Name()
		case token.VAR:
			v := t.Specs[0].(*ast.ValueSpec)
			names = make([]string, len(v.Names))
			for i, name := range v.Names {
				names[i] = name.Name()
			}
		}
	case *ast.FuncDecl:
		names = make([]string, 1)
		names[0] = t.Name.Name()
	}

	return names
}

func declValues(d ast.Decl) []ast.Expr {
	// TODO: CONST values here too
	switch t := d.(type) {
	case *ast.GenDecl:
		switch t.Tok {
		case token.VAR:
			v := t.Specs[0].(*ast.ValueSpec)
			if v.Values != nil {
				return v.Values
			}
		}
	}
	return nil
}

func splitDecls(d ast.Decl) []ast.Decl {
	var decls []ast.Decl
	if t, ok := d.(*ast.GenDecl); ok {
		decls = make([]ast.Decl, len(t.Specs))
		for i, s := range t.Specs {
			decl := new(ast.GenDecl)
			*decl = *t
			decl.Specs = make([]ast.Spec, 1)
			decl.Specs[0] = s
			decls[i] = decl
		}
	} else {
		decls = make([]ast.Decl, 1)
		decls[0] = d
	}
	return decls
}
<|endoftext|>