<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native"
	"log"
	"os"
)

const _DB_CONFIG_FILENAME = "db_config.SECRET.json"

type dbConfig struct {
	Url, Username, Password, DbName, SolvesTable, SolvesID, SolvesTotalTime, SolvesUser string
}

type solve struct {
	puzzleID  int
	totalTime int
}

type userSolvesCollection struct {
	solves []*solve
	max    int
	min    int
}

func (self *userSolvesCollection) addSolve(solve *solve) {
	self.solves = append(self.solves, solve)
	if len(self.solves) == 1 {
		self.max = solve.totalTime
		self.min = solve.totalTime
	} else {
		if self.max < solve.totalTime {
			self.max = solve.totalTime
		}
		if self.min > solve.totalTime {
			self.min = solve.totalTime
		}
	}
}

func (self *userSolvesCollection) relativeDifficulties() map[int]float32 {
	//Returns a map of puzzle id to relative difficulty, normalized by our max and min.
	avgSolveTimes := make(map[int]float32)
	//Keep track of how many times we've seen each puzzle solved by this user so we can do correct averaging.
	avgSolveTimesCount := make(map[int]int)

	//First, collect the average solve time (in case the same user has solved more than once the same puzzle)

	for _, solve := range self.solves {
		currentAvgSolveTime := avgSolveTimes[solve.puzzleID]

		avgSolveTimes[solve.puzzleID] = (currentAvgSolveTime*float32(avgSolveTimesCount[solve.puzzleID]) + float32(solve.totalTime)) / float32(avgSolveTimesCount[solve.puzzleID]+1)

		avgSolveTimesCount[solve.puzzleID]++
	}

	//Now, relativize all of the scores.

	result := make(map[int]float32)

	for puzzleID, avgSolveTime := range avgSolveTimes {
		result[puzzleID] = (avgSolveTime - float32(self.min)) / float32(self.max-self.min)
	}

	return result
}

func main() {
	file, err := os.Open(_DB_CONFIG_FILENAME)
	if err != nil {
		log.Fatal("Could not find the config file at ", _DB_CONFIG_FILENAME, ". You should copy the SAMPLE one to that filename and configure.")
		os.Exit(1)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	var config dbConfig
	if err := decoder.Decode(&config); err != nil {
		log.Fatal("There was an error parsing JSON from the config file: ", err)
		os.Exit(1)
	}

	db := mysql.New("tcp", "", config.Url, config.Username, config.Password, config.DbName)

	if err := db.Connect(); err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	res, err := db.Start("select %s, %s, %s from %s limit 100", config.SolvesUser, config.SolvesID, config.SolvesTotalTime, config.SolvesTable)

	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	solvesByUser := make(map[string]*userSolvesCollection)

	var userSolves *userSolvesCollection
	var ok bool
	var i int

	//First, process all user records in the DB to collect all solves by userName.
	for {

		row, _ := res.GetRow()

		if row == nil {
			break
		}

		userSolves, ok = solvesByUser[row.Str(0)]

		if !ok {
			userSolves = new(userSolvesCollection)
			solvesByUser[row.Str(0)] = userSolves
		}

		userSolves.addSolve(&solve{row.Int(1), row.Int(2)})
		i++
	}

	fmt.Println("Processed ", i, " solves by ", len(solvesByUser), " users.")

	//Now get the relative difficulty for each user's puzzles, and collect them.

	relativeDifficultiesByPuzzle := make(map[int][]float32)

	for _, collection := range solvesByUser {

		if len(collection.solves) < 2 {
			continue
		}

		for puzzleID, relativeDifficulty := range collection.relativeDifficulties() {
			relativeDifficultiesByPuzzle[puzzleID] = append(relativeDifficultiesByPuzzle[puzzleID], relativeDifficulty)
		}

	}

	//Now average all of the relative difficulties by puzzle.

}
<commit_msg>Get average relativeDifficulty by puzzle.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native"
	"log"
	"os"
)

const _DB_CONFIG_FILENAME = "db_config.SECRET.json"

type dbConfig struct {
	Url, Username, Password, DbName, SolvesTable, SolvesID, SolvesTotalTime, SolvesUser string
}

type solve struct {
	puzzleID  int
	totalTime int
}

type userSolvesCollection struct {
	solves []*solve
	max    int
	min    int
}

func (self *userSolvesCollection) addSolve(solve *solve) {
	self.solves = append(self.solves, solve)
	if len(self.solves) == 1 {
		self.max = solve.totalTime
		self.min = solve.totalTime
	} else {
		if self.max < solve.totalTime {
			self.max = solve.totalTime
		}
		if self.min > solve.totalTime {
			self.min = solve.totalTime
		}
	}
}

func (self *userSolvesCollection) relativeDifficulties() map[int]float32 {
	//Returns a map of puzzle id to relative difficulty, normalized by our max and min.
	avgSolveTimes := make(map[int]float32)
	//Keep track of how many times we've seen each puzzle solved by this user so we can do correct averaging.
	avgSolveTimesCount := make(map[int]int)

	//First, collect the average solve time (in case the same user has solved more than once the same puzzle)

	for _, solve := range self.solves {
		currentAvgSolveTime := avgSolveTimes[solve.puzzleID]

		avgSolveTimes[solve.puzzleID] = (currentAvgSolveTime*float32(avgSolveTimesCount[solve.puzzleID]) + float32(solve.totalTime)) / float32(avgSolveTimesCount[solve.puzzleID]+1)

		avgSolveTimesCount[solve.puzzleID]++
	}

	//Now, relativize all of the scores.

	result := make(map[int]float32)

	for puzzleID, avgSolveTime := range avgSolveTimes {
		result[puzzleID] = (avgSolveTime - float32(self.min)) / float32(self.max-self.min)
	}

	return result
}

func main() {
	file, err := os.Open(_DB_CONFIG_FILENAME)
	if err != nil {
		log.Fatal("Could not find the config file at ", _DB_CONFIG_FILENAME, ". You should copy the SAMPLE one to that filename and configure.")
		os.Exit(1)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	var config dbConfig
	if err := decoder.Decode(&config); err != nil {
		log.Fatal("There was an error parsing JSON from the config file: ", err)
		os.Exit(1)
	}

	db := mysql.New("tcp", "", config.Url, config.Username, config.Password, config.DbName)

	if err := db.Connect(); err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	res, err := db.Start("select %s, %s, %s from %s limit 100", config.SolvesUser, config.SolvesID, config.SolvesTotalTime, config.SolvesTable)

	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	solvesByUser := make(map[string]*userSolvesCollection)

	var userSolves *userSolvesCollection
	var ok bool
	var i int

	//First, process all user records in the DB to collect all solves by userName.
	for {

		row, _ := res.GetRow()

		if row == nil {
			break
		}

		userSolves, ok = solvesByUser[row.Str(0)]

		if !ok {
			userSolves = new(userSolvesCollection)
			solvesByUser[row.Str(0)] = userSolves
		}

		userSolves.addSolve(&solve{row.Int(1), row.Int(2)})
		i++
	}

	fmt.Println("Processed ", i, " solves by ", len(solvesByUser), " users.")

	//Now get the relative difficulty for each user's puzzles, and collect them.

	relativeDifficultiesByPuzzle := make(map[int][]float32)

	for _, collection := range solvesByUser {

		if len(collection.solves) < 2 {
			continue
		}

		for puzzleID, relativeDifficulty := range collection.relativeDifficulties() {
			relativeDifficultiesByPuzzle[puzzleID] = append(relativeDifficultiesByPuzzle[puzzleID], relativeDifficulty)
		}

	}

	//Now average all of the relative difficulties by puzzle.
	relativeDifficultyByPuzzle := make(map[int]float32)
	for puzzleID, difficulties := range relativeDifficultiesByPuzzle {
		var sum float32
		for _, difficulty := range difficulties {
			sum += difficulty
		}
		relativeDifficultyByPuzzle[puzzleID] = sum / float32(len(difficulties))
	}

}
<|endoftext|>


<commit_before>package bus

import (
	"fmt"
	"net"
	"sync"
	"time"

	proto "github.com/huin/mqtt"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/mqtt"
)

type TinyBus struct {
	baseBus
	connecting    sync.WaitGroup
	mqtt          *mqtt.ClientConn
	subscriptions []*Subscription
	host          string
	id            string
}

func ConnectTinyBus(host, id string) (*TinyBus, error) {

	bus := &TinyBus{
		subscriptions: make([]*Subscription, 0),
		host:          host,
		id:            id,
	}

	bus.connect()

	return bus, nil
}

type wrappedConn struct {
	net.Conn
	done chan bool
}

func (c wrappedConn) Close() error {
	log.Warningf("Connection closed!")
	c.done <- true
	c.Conn.Close()
	return nil
}

func (b *TinyBus) connect() {

	b.connecting.Add(1)
	defer func() {
		b.connecting.Done()

		b.publish(&proto.Publish{
			Header: proto.Header{
				Retain: true,
			},
			TopicName: fmt.Sprintf("node/%s/module/%s/state/connected", config.Serial(), b.id),
			Payload:   proto.BytesPayload([]byte("true")),
		})
	}()

	var conn wrappedConn
	for {
		tcpConn, err := net.Dial("tcp", b.host)
		if err == nil {
			conn = wrappedConn{
				Conn: tcpConn,
				done: make(chan bool, 1),
			}
			break
		}

		//log.Warningf("Failed to connect to: %s", err)
		time.Sleep(time.Millisecond * 500)
	}

	if b.mqtt != nil {
		log.Infof("Reconnected to mqtt server")
	}

	mqtt := mqtt.NewClientConn(conn)
	mqtt.ClientId = b.id

	err := mqtt.ConnectCustom(&proto.Connect{
		WillFlag:    true,
		WillQos:     0,
		WillRetain:  true,
		WillTopic:   fmt.Sprintf("$node/%s/module/%s/state/connected", config.Serial(), b.id),
		WillMessage: "false",
	})

	if err != nil {
		log.Fatalf("MQTT Failed to connect to: %s", err)
	}

	b.mqtt = mqtt

	b.connected()

	for _, s := range b.subscriptions {
		if !s.cancelled {
			b.subscribe(s)
		}
	}

	go func() {
		for m := range mqtt.Incoming {
			b.onIncoming(m)
		}
	}()

	go func() {
		<-conn.done
		b.disconnected()
		b.connect()
	}()
}

func (b *TinyBus) onIncoming(message *proto.Publish) {
	for _, sub := range b.subscriptions {
		if !sub.cancelled && matches(sub.topic, message.TopicName) {
			go sub.callback(message.TopicName, []byte(message.Payload.(proto.BytesPayload)))
		}
	}
}

func (b *TinyBus) Destroy() {
	b.destroyed = true
	b.mqtt.Disconnect()
}

func (b *TinyBus) Publish(topic string, payload []byte) {
	b.connecting.Wait()

	b.publish(&proto.Publish{
		TopicName: topic,
		Payload:   proto.BytesPayload(payload),
	})

}

func (b *TinyBus) publish(message *proto.Publish) {
	b.mqtt.Publish(message)
}

func (b *TinyBus) Subscribe(topic string, callback func(topic string, payload []byte)) (*Subscription, error) {

	subscription := &Subscription{
		topic:    topic,
		callback: callback,
	}

	subscription.Cancel = func() {
		// TODO: Actually unsubscribe if we were the only one listening
		// TODO: Remove from from b.subscriptions
		subscription.cancelled = true
	}

	err := b.subscribe(subscription)
	if err != nil {
		return nil, err
	}

	b.subscriptions = append(b.subscriptions, subscription)

	return subscription, nil
}

func (b *TinyBus) subscribe(subscription *Subscription) error {
	_ = b.mqtt.Subscribe([]proto.TopicQos{proto.TopicQos{subscription.topic, proto.QosAtMostOnce}})
	//spew.Dump("subscription ack", ack)
	// TODO: Check ack
	return nil
}
<commit_msg>bus: Don't try to reconnect after a call to .Destroy()<commit_after>package bus

import (
	"fmt"
	"net"
	"sync"
	"time"

	proto "github.com/huin/mqtt"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/mqtt"
)

type TinyBus struct {
	baseBus
	connecting    sync.WaitGroup
	mqtt          *mqtt.ClientConn
	subscriptions []*Subscription
	host          string
	id            string
}

func ConnectTinyBus(host, id string) (*TinyBus, error) {

	bus := &TinyBus{
		subscriptions: make([]*Subscription, 0),
		host:          host,
		id:            id,
	}

	bus.connect()

	return bus, nil
}

type wrappedConn struct {
	net.Conn
	done chan bool
}

func (c wrappedConn) Close() error {
	log.Warningf("Connection closed!")
	c.done <- true
	c.Conn.Close()
	return nil
}

func (b *TinyBus) connect() {

	b.connecting.Add(1)
	defer func() {
		b.connecting.Done()

		b.publish(&proto.Publish{
			Header: proto.Header{
				Retain: true,
			},
			TopicName: fmt.Sprintf("node/%s/module/%s/state/connected", config.Serial(), b.id),
			Payload:   proto.BytesPayload([]byte("true")),
		})
	}()

	var conn wrappedConn
	for {
		tcpConn, err := net.Dial("tcp", b.host)
		if err == nil {
			conn = wrappedConn{
				Conn: tcpConn,
				done: make(chan bool, 1),
			}
			break
		}

		//log.Warningf("Failed to connect to: %s", err)
		time.Sleep(time.Millisecond * 500)
	}

	if b.mqtt != nil {
		log.Infof("Reconnected to mqtt server")
	}

	mqtt := mqtt.NewClientConn(conn)
	mqtt.ClientId = b.id

	err := mqtt.ConnectCustom(&proto.Connect{
		WillFlag:    true,
		WillQos:     0,
		WillRetain:  true,
		WillTopic:   fmt.Sprintf("$node/%s/module/%s/state/connected", config.Serial(), b.id),
		WillMessage: "false",
	})

	if err != nil {
		log.Fatalf("MQTT Failed to connect to: %s", err)
	}

	b.mqtt = mqtt

	b.connected()

	for _, s := range b.subscriptions {
		if !s.cancelled {
			b.subscribe(s)
		}
	}

	go func() {
		for m := range mqtt.Incoming {
			b.onIncoming(m)
		}
	}()

	go func() {
		<-conn.done
		b.disconnected()
		if !b.destroyed {
			b.connect()
		}
	}()
}

func (b *TinyBus) onIncoming(message *proto.Publish) {
	for _, sub := range b.subscriptions {
		if !sub.cancelled && matches(sub.topic, message.TopicName) {
			go sub.callback(message.TopicName, []byte(message.Payload.(proto.BytesPayload)))
		}
	}
}

func (b *TinyBus) Destroy() {
	log.Infof("Destroy called")
	b.destroyed = true
	b.mqtt.Disconnect()
}

func (b *TinyBus) Publish(topic string, payload []byte) {
	b.connecting.Wait()

	b.publish(&proto.Publish{
		TopicName: topic,
		Payload:   proto.BytesPayload(payload),
	})

}

func (b *TinyBus) publish(message *proto.Publish) {
	b.mqtt.Publish(message)
}

func (b *TinyBus) Subscribe(topic string, callback func(topic string, payload []byte)) (*Subscription, error) {

	subscription := &Subscription{
		topic:    topic,
		callback: callback,
	}

	subscription.Cancel = func() {
		// TODO: Actually unsubscribe if we were the only one listening
		// TODO: Remove from from b.subscriptions
		subscription.cancelled = true
	}

	err := b.subscribe(subscription)
	if err != nil {
		return nil, err
	}

	b.subscriptions = append(b.subscriptions, subscription)

	return subscription, nil
}

func (b *TinyBus) subscribe(subscription *Subscription) error {
	_ = b.mqtt.Subscribe([]proto.TopicQos{proto.TopicQos{subscription.topic, proto.QosAtMostOnce}})
	//spew.Dump("subscription ack", ack)
	// TODO: Check ack
	return nil
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/zclconf/go-cty/cty"
)

func TestConfigValueFromHCL2(t *testing.T) {
	tests := []struct {
		Input cty.Value
		Want  interface{}
	}{
		{
			cty.True,
			true,
		},
		{
			cty.False,
			false,
		},
		{
			cty.NumberIntVal(12),
			int(12),
		},
		{
			cty.NumberFloatVal(12.5),
			float64(12.5),
		},
		{
			cty.StringVal("hello world"),
			"hello world",
		},
		{
			cty.ObjectVal(map[string]cty.Value{
				"name": cty.StringVal("Ermintrude"),
				"age":  cty.NumberIntVal(19),
				"address": cty.ObjectVal(map[string]cty.Value{
					"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
					"city":   cty.StringVal("Fridgewater"),
					"state":  cty.StringVal("MA"),
					"zip":    cty.StringVal("91037"),
				}),
			}),
			map[string]interface{}{
				"name": "Ermintrude",
				"age":  int(19),
				"address": map[string]interface{}{
					"street": []interface{}{"421 Shoreham Loop"},
					"city":   "Fridgewater",
					"state":  "MA",
					"zip":    "91037",
				},
			},
		},
		{
			cty.MapVal(map[string]cty.Value{
				"foo": cty.StringVal("bar"),
				"bar": cty.StringVal("baz"),
			}),
			map[string]interface{}{
				"foo": "bar",
				"bar": "baz",
			},
		},
		{
			cty.TupleVal([]cty.Value{
				cty.StringVal("foo"),
				cty.True,
			}),
			[]interface{}{
				"foo",
				true,
			},
		},
		{
			cty.NullVal(cty.String),
			nil,
		},
		{
			cty.UnknownVal(cty.String),
			UnknownVariableValue,
		},
	}

	for _, test := range tests {
		t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
			got := configValueFromHCL2(test.Input)
			if !reflect.DeepEqual(got, test.Want) {
				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, got, test.Want)
			}
		})
	}
}
<commit_msg>config: tests for HIL-to-HCL2 value shimming<commit_after>package config

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/zclconf/go-cty/cty"
)

func TestConfigValueFromHCL2(t *testing.T) {
	tests := []struct {
		Input cty.Value
		Want  interface{}
	}{
		{
			cty.True,
			true,
		},
		{
			cty.False,
			false,
		},
		{
			cty.NumberIntVal(12),
			int(12),
		},
		{
			cty.NumberFloatVal(12.5),
			float64(12.5),
		},
		{
			cty.StringVal("hello world"),
			"hello world",
		},
		{
			cty.ObjectVal(map[string]cty.Value{
				"name": cty.StringVal("Ermintrude"),
				"age":  cty.NumberIntVal(19),
				"address": cty.ObjectVal(map[string]cty.Value{
					"street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}),
					"city":   cty.StringVal("Fridgewater"),
					"state":  cty.StringVal("MA"),
					"zip":    cty.StringVal("91037"),
				}),
			}),
			map[string]interface{}{
				"name": "Ermintrude",
				"age":  int(19),
				"address": map[string]interface{}{
					"street": []interface{}{"421 Shoreham Loop"},
					"city":   "Fridgewater",
					"state":  "MA",
					"zip":    "91037",
				},
			},
		},
		{
			cty.MapVal(map[string]cty.Value{
				"foo": cty.StringVal("bar"),
				"bar": cty.StringVal("baz"),
			}),
			map[string]interface{}{
				"foo": "bar",
				"bar": "baz",
			},
		},
		{
			cty.TupleVal([]cty.Value{
				cty.StringVal("foo"),
				cty.True,
			}),
			[]interface{}{
				"foo",
				true,
			},
		},
		{
			cty.NullVal(cty.String),
			nil,
		},
		{
			cty.UnknownVal(cty.String),
			UnknownVariableValue,
		},
	}

	for _, test := range tests {
		t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
			got := configValueFromHCL2(test.Input)
			if !reflect.DeepEqual(got, test.Want) {
				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, got, test.Want)
			}
		})
	}
}

func TestHCL2ValueFromConfigValue(t *testing.T) {
	tests := []struct {
		Input interface{}
		Want  cty.Value
	}{
		{
			nil,
			cty.NullVal(cty.DynamicPseudoType),
		},
		{
			UnknownVariableValue,
			cty.DynamicVal,
		},
		{
			true,
			cty.True,
		},
		{
			false,
			cty.False,
		},
		{
			int(12),
			cty.NumberIntVal(12),
		},
		{
			int(0),
			cty.Zero,
		},
		{
			float64(12.5),
			cty.NumberFloatVal(12.5),
		},
		{
			"hello world",
			cty.StringVal("hello world"),
		},
		{
			"O\u0308",               // decomposed letter + diacritic
			cty.StringVal("\u00D6"), // NFC-normalized on entry into cty
		},
		{
			[]interface{}{},
			cty.EmptyTupleVal,
		},
		{
			[]interface{}(nil),
			cty.EmptyTupleVal,
		},
		{
			[]interface{}{"hello", "world"},
			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}),
		},
		{
			map[string]interface{}{},
			cty.EmptyObjectVal,
		},
		{
			map[string]interface{}(nil),
			cty.EmptyObjectVal,
		},
		{
			map[string]interface{}{
				"foo": "bar",
				"bar": "baz",
			},
			cty.ObjectVal(map[string]cty.Value{
				"foo": cty.StringVal("bar"),
				"bar": cty.StringVal("baz"),
			}),
		},
	}

	for _, test := range tests {
		t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) {
			got := hcl2ValueFromConfigValue(test.Input)
			if !got.RawEquals(test.Want) {
				t.Errorf("wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v", test.Input, got, test.Want)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh/terminal"
	"encoding/json"
	"fmt"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/errors"
	tsuruIo "github.com/tsuru/tsuru/io"
	"io"
	"launchpad.net/gnuflag"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"strings"
	"syscall"
)

var httpHeaderRegexp = regexp.MustCompile(`HTTP/.*? (\d+)`)

type moveContainersCmd struct{}

type progressFormatter struct{}

func (progressFormatter) Format(out io.Writer, data []byte) error {
	var logEntry progressLog
	err := json.Unmarshal(data, &logEntry)
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "%s\n", logEntry.Message)
	return nil
}

func (c *moveContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-move",
		Usage:   "containers-move <from host> <to host>",
		Desc:    "Move all containers from one host to another.\nThis command is especially useful for host maintenance.",
		MinArgs: 2,
	}
}

func (c *moveContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/containers/move")
	if err != nil {
		return err
	}
	params := map[string]string{
		"from": context.Args[0],
		"to":   context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type fixContainersCmd struct{}

func (fixContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "fix-containers",
		Usage: "fix-containers",
		Desc:  "Fix containers that are broken in the cluster.",
	}
}

func (fixContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/fix-containers")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	return err
}

type moveContainerCmd struct{}

func (c *moveContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "container-move",
		Usage:   "container-move <container id> <to host>",
		Desc:    "Move specified container to another host.",
		MinArgs: 2,
	}
}

func (c *moveContainerCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL(fmt.Sprintf("/docker/container/%s/move", context.Args[0]))
	if err != nil {
		return err
	}
	params := map[string]string{
		"to": context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type rebalanceContainersCmd struct {
	fs  *gnuflag.FlagSet
	dry bool
}

func (c *rebalanceContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-rebalance",
		Usage:   "containers-rebalance [--dry]",
		Desc:    "Move containers creating a more even distribution between docker nodes.",
		MinArgs: 0,
	}
}

func (c *rebalanceContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/containers/rebalance")
	if err != nil {
		return err
	}
	params := map[string]string{
		"dry": fmt.Sprintf("%t", c.dry),
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

func (c *rebalanceContainersCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = gnuflag.NewFlagSet("containers-rebalance", gnuflag.ExitOnError)
		c.fs.BoolVar(&c.dry, "dry", false, "Dry run, only shows what would be done")
	}
	return c.fs
}

type sshToContainerCmd struct{}

func (sshToContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "ssh",
		Usage:   "ssh <container-id>",
		Desc:    "Open a SSH shell to the given container.",
		MinArgs: 1,
	}
}

func (sshToContainerCmd) Run(context *cmd.Context, _ *cmd.Client) error {
	serverURL, err := cmd.GetURL("/docker/ssh/" + context.Args[0])
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", serverURL, nil)
	if err != nil {
		return err
	}
	request.Close = true
	token, err := cmd.ReadToken()
	if err == nil {
		request.Header.Set("Authorization", "bearer "+token)
	}
	parsedURL, _ := url.Parse(serverURL)
	conn, err := net.Dial("tcp", parsedURL.Host)
	if err != nil {
		return err
	}
	defer conn.Close()
	request.Write(conn)
	if stdin, ok := context.Stdin.(*os.File); ok {
		fd := int(stdin.Fd())
		if terminal.IsTerminal(fd) {
			oldState, err := terminal.MakeRaw(fd)
			if err != nil {
				return err
			}
			defer terminal.Restore(fd, oldState)
			sigChan := make(chan os.Signal, 2)
			go func(c <-chan os.Signal) {
				if _, ok := <-c; ok {
					terminal.Restore(fd, oldState)
				}
			}(sigChan)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		}
	}
	bytesLimit := 50
	var readStr string
	byteBuffer := make([]byte, 1)
	for i := 0; i < bytesLimit && byteBuffer[0] != '\n'; i++ {
		_, err := conn.Read(byteBuffer)
		if err != nil {
			break
		}
		readStr += string(byteBuffer)
	}
	matches := httpHeaderRegexp.FindAllStringSubmatch(readStr, -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		code, _ := strconv.Atoi(matches[0][1])
		return &errors.HTTP{
			Code:    code,
			Message: strings.TrimSpace(readStr),
		}
	} else {
		context.Stdout.Write([]byte(readStr))
	}
	errs := make(chan error, 2)
	quit := make(chan bool)
	go io.Copy(conn, context.Stdin)
	go func() {
		defer close(quit)
		_, err := io.Copy(context.Stdout, conn)
		if err != nil && err != io.EOF {
			errs <- err
		}
	}()
	<-quit
	close(errs)
	return <-errs
}
<commit_msg>provision/docker: do not forget to exit on signal handling<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh/terminal"
	"encoding/json"
	"fmt"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/errors"
	tsuruIo "github.com/tsuru/tsuru/io"
	"io"
	"launchpad.net/gnuflag"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strconv"
	"strings"
	"syscall"
)

var httpHeaderRegexp = regexp.MustCompile(`HTTP/.*? (\d+)`)

type moveContainersCmd struct{}

type progressFormatter struct{}

func (progressFormatter) Format(out io.Writer, data []byte) error {
	var logEntry progressLog
	err := json.Unmarshal(data, &logEntry)
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "%s\n", logEntry.Message)
	return nil
}

func (c *moveContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-move",
		Usage:   "containers-move <from host> <to host>",
		Desc:    "Move all containers from one host to another.\nThis command is especially useful for host maintenance.",
		MinArgs: 2,
	}
}

func (c *moveContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/containers/move")
	if err != nil {
		return err
	}
	params := map[string]string{
		"from": context.Args[0],
		"to":   context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type fixContainersCmd struct{}

func (fixContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "fix-containers",
		Usage: "fix-containers",
		Desc:  "Fix containers that are broken in the cluster.",
	}
}

func (fixContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/fix-containers")
	if err != nil {
		return err
	}
	request, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}
	_, err = client.Do(request)
	return err
}

type moveContainerCmd struct{}

func (c *moveContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "container-move",
		Usage:   "container-move <container id> <to host>",
		Desc:    "Move specified container to another host.",
		MinArgs: 2,
	}
}

func (c *moveContainerCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL(fmt.Sprintf("/docker/container/%s/move", context.Args[0]))
	if err != nil {
		return err
	}
	params := map[string]string{
		"to": context.Args[1],
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

type rebalanceContainersCmd struct {
	fs  *gnuflag.FlagSet
	dry bool
}

func (c *rebalanceContainersCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "containers-rebalance",
		Usage:   "containers-rebalance [--dry]",
		Desc:    "Move containers creating a more even distribution between docker nodes.",
		MinArgs: 0,
	}
}

func (c *rebalanceContainersCmd) Run(context *cmd.Context, client *cmd.Client) error {
	url, err := cmd.GetURL("/docker/containers/rebalance")
	if err != nil {
		return err
	}
	params := map[string]string{
		"dry": fmt.Sprintf("%t", c.dry),
	}
	b, err := json.Marshal(params)
	if err != nil {
		return err
	}
	buffer := bytes.NewBuffer(b)
	request, err := http.NewRequest("POST", url, buffer)
	if err != nil {
		return err
	}
	request.Header.Set("Content-Type", "application/json")
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	w := tsuruIo.NewStreamWriter(context.Stdout, progressFormatter{})
	for n := int64(1); n > 0 && err == nil; n, err = io.Copy(w, response.Body) {
	}
	return nil
}

func (c *rebalanceContainersCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = gnuflag.NewFlagSet("containers-rebalance", gnuflag.ExitOnError)
		c.fs.BoolVar(&c.dry, "dry", false, "Dry run, only shows what would be done")
	}
	return c.fs
}

type sshToContainerCmd struct{}

func (sshToContainerCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "ssh",
		Usage:   "ssh <container-id>",
		Desc:    "Open a SSH shell to the given container.",
		MinArgs: 1,
	}
}

func (sshToContainerCmd) Run(context *cmd.Context, _ *cmd.Client) error {
	serverURL, err := cmd.GetURL("/docker/ssh/" + context.Args[0])
	if err != nil {
		return err
	}
	request, err := http.NewRequest("GET", serverURL, nil)
	if err != nil {
		return err
	}
	request.Close = true
	token, err := cmd.ReadToken()
	if err == nil {
		request.Header.Set("Authorization", "bearer "+token)
	}
	parsedURL, _ := url.Parse(serverURL)
	conn, err := net.Dial("tcp", parsedURL.Host)
	if err != nil {
		return err
	}
	defer conn.Close()
	request.Write(conn)
	if stdin, ok := context.Stdin.(*os.File); ok {
		fd := int(stdin.Fd())
		if terminal.IsTerminal(fd) {
			oldState, err := terminal.MakeRaw(fd)
			if err != nil {
				return err
			}
			defer terminal.Restore(fd, oldState)
			sigChan := make(chan os.Signal, 2)
			go func(c <-chan os.Signal) {
				if _, ok := <-c; ok {
					terminal.Restore(fd, oldState)
					os.Exit(1)
				}
			}(sigChan)
			signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
		}
	}
	bytesLimit := 50
	var readStr string
	byteBuffer := make([]byte, 1)
	for i := 0; i < bytesLimit && byteBuffer[0] != '\n'; i++ {
		_, err := conn.Read(byteBuffer)
		if err != nil {
			break
		}
		readStr += string(byteBuffer)
	}
	matches := httpHeaderRegexp.FindAllStringSubmatch(readStr, -1)
	if len(matches) > 0 && len(matches[0]) > 1 {
		code, _ := strconv.Atoi(matches[0][1])
		return &errors.HTTP{
			Code:    code,
			Message: strings.TrimSpace(readStr),
		}
	} else {
		context.Stdout.Write([]byte(readStr))
	}
	errs := make(chan error, 2)
	quit := make(chan bool)
	go io.Copy(conn, context.Stdin)
	go func() {
		defer close(quit)
		_, err := io.Copy(context.Stdout, conn)
		if err != nil && err != io.EOF {
			errs <- err
		}
	}()
	<-quit
	close(errs)
	return <-errs
}
<|endoftext|>


<commit_before>package print_store

import (
	"fmt"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/receptor"
	"github.com/cloudfoundry-incubator/route-emitter/cfroutes"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	"github.com/onsi/gomega/format"
	"github.com/onsi/say"
	"github.com/pivotal-cf-experimental/veritas/veritas_models"
)

func printLRPS(verbose bool, lrps veritas_models.VeritasLRPS) {
	say.Println(0, say.Green("LRPs"))

	sortedLRPS := lrps.SortedByProcessGuid()
	for _, lrp := range sortedLRPS {
		if verbose {
			printVerboseLRP(lrp)
		} else {
			printLRP(lrp)
		}
	}
}

func printDomains(domains []string) {
	say.Println(0, say.Green("Domains"))
	if len(domains) == 0 {
		say.Println(1, say.Red("None"))
		return
	}
	for _, domain := range domains {
		say.Println(1, say.Green("%s", domain))
	}
}

func printVerboseLRP(lrp *veritas_models.VeritasLRP) {
	say.Println(0, format.Object(lrp, 1))
}

func printLRP(lrp *veritas_models.VeritasLRP) {
	say.Println(1, say.Green(lrp.ProcessGuid))
	if lrp.DesiredLRP.ProcessGuid != "" {
		privileged := ""
		if lrp.DesiredLRP.Privileged {
			privileged = say.Red(" PRIVILEGED")
		}

		routesString := routes(lrp.DesiredLRP.Routes)
		if routesString != "" {
			routesString = "\n" + say.Indent(1, routesString)
		}

		say.Println(
			2,
			"%s on %s%s (%d MB, %d MB, %d CPU)%s",
			say.Green("%d", lrp.DesiredLRP.Instances),
			say.Green(lrp.DesiredLRP.Stack),
			privileged,
			lrp.DesiredLRP.MemoryMB,
			lrp.DesiredLRP.DiskMB,
			lrp.DesiredLRP.CPUWeight,
			routesString,
		)
	} else {
		say.Println(2, say.Red("UNDESIRED"))
	}

	orderedActualIndices := lrp.OrderedActualLRPIndices()
	for _, index := range orderedActualIndices {
		actualLRPGroup := lrp.ActualLRPGroupsByIndex[index]
		if instance := actualLRPGroup.Instance; instance != nil {
			if instance.State == models.ActualLRPStateUnclaimed || instance.State == models.ActualLRPStateCrashed {
				say.Println(
					3,
					"%2s: [%s for %s]",
					index,
					actualState(instance),
					time.Since(time.Unix(0, instance.Since)),
				)
			} else {
				say.Println(
					3,
					"%2s: %s %s [%s for %s]",
					index,
					instance.InstanceGuid,
					say.Yellow(instance.CellID),
					actualState(instance),
					time.Since(time.Unix(0, instance.Since)),
				)
			}
		}
		if evacuating := actualLRPGroup.Evacuating; evacuating != nil {
			say.Println(
				3,
				"%s: %s %s [%s for %s] - %s",
				say.Red("%2s", index),
				say.Red(evacuating.InstanceGuid),
				say.Yellow(evacuating.CellID),
				actualState(evacuating),
				time.Since(time.Unix(0, evacuating.Since)),
				say.Red("EVACUATING"),
			)
		}
	}
}

func actualState(actual *models.ActualLRP) string {
	switch actual.State {
	case models.ActualLRPStateUnclaimed:
		if actual.PlacementError == "" {
			return say.LightGray("UNCLAIMED")
		} else {
			return say.Red("UNCLAIMED (%s)", actual.PlacementError)
		}
	case models.ActualLRPStateClaimed:
		return say.Yellow("CLAIMED")
	case models.ActualLRPStateRunning:
		return say.Green("RUNNING")
	case models.ActualLRPStateCrashed:
		return say.Red("CRASHED (%d - %s)", actual.CrashCount, actual.CrashReason)
	default:
		return say.Red("INVALID")
	}
}

func routes(info receptor.RoutingInfo) string {
	if info == nil {
		return ""
	}

	routes, _ := cfroutes.CFRoutesFromRoutingInfo(info)

	if routes == nil {
		return ""
	}

	out := ""

	for _, route := range routes {
		out += fmt.Sprintf("%s => %s ", say.Yellow("%d", route.Port), say.Green(strings.Join(route.Hostnames, " ")))
	}

	return out
}
<commit_msg>fix crash reason report<commit_after>package print_store

import (
	"fmt"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/receptor"
	"github.com/cloudfoundry-incubator/route-emitter/cfroutes"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	"github.com/onsi/gomega/format"
	"github.com/onsi/say"
	"github.com/pivotal-cf-experimental/veritas/veritas_models"
)

func printLRPS(verbose bool, lrps veritas_models.VeritasLRPS) {
	say.Println(0, say.Green("LRPs"))

	sortedLRPS := lrps.SortedByProcessGuid()
	for _, lrp := range sortedLRPS {
		if verbose {
			printVerboseLRP(lrp)
		} else {
			printLRP(lrp)
		}
	}
}

func printDomains(domains []string) {
	say.Println(0, say.Green("Domains"))
	if len(domains) == 0 {
		say.Println(1, say.Red("None"))
		return
	}
	for _, domain := range domains {
		say.Println(1, say.Green("%s", domain))
	}
}

func printVerboseLRP(lrp *veritas_models.VeritasLRP) {
	say.Println(0, format.Object(lrp, 1))
}

func printLRP(lrp *veritas_models.VeritasLRP) {
	say.Println(1, say.Green(lrp.ProcessGuid))
	if lrp.DesiredLRP.ProcessGuid != "" {
		privileged := ""
		if lrp.DesiredLRP.Privileged {
			privileged = say.Red(" PRIVILEGED")
		}

		routesString := routes(lrp.DesiredLRP.Routes)
		if routesString != "" {
			routesString = "\n" + say.Indent(1, routesString)
		}

		say.Println(
			2,
			"%s on %s%s (%d MB, %d MB, %d CPU)%s",
			say.Green("%d", lrp.DesiredLRP.Instances),
			say.Green(lrp.DesiredLRP.Stack),
			privileged,
			lrp.DesiredLRP.MemoryMB,
			lrp.DesiredLRP.DiskMB,
			lrp.DesiredLRP.CPUWeight,
			routesString,
		)
	} else {
		say.Println(2, say.Red("UNDESIRED"))
	}

	orderedActualIndices := lrp.OrderedActualLRPIndices()
	for _, index := range orderedActualIndices {
		actualLRPGroup := lrp.ActualLRPGroupsByIndex[index]
		if instance := actualLRPGroup.Instance; instance != nil {
			if instance.State == models.ActualLRPStateUnclaimed || instance.State == models.ActualLRPStateCrashed {
				say.Println(
					3,
					"%2s: [%s for %s]",
					index,
					actualState(instance),
					time.Since(time.Unix(0, instance.Since)),
				)
			} else {
				say.Println(
					3,
					"%2s: %s %s [%s for %s]",
					index,
					instance.InstanceGuid,
					say.Yellow(instance.CellID),
					actualState(instance),
					time.Since(time.Unix(0, instance.Since)),
				)
			}
		}
		if evacuating := actualLRPGroup.Evacuating; evacuating != nil {
			say.Println(
				3,
				"%s: %s %s [%s for %s] - %s",
				say.Red("%2s", index),
				say.Red(evacuating.InstanceGuid),
				say.Yellow(evacuating.CellID),
				actualState(evacuating),
				time.Since(time.Unix(0, evacuating.Since)),
				say.Red("EVACUATING"),
			)
		}
	}
}

func actualState(actual *models.ActualLRP) string {
	switch actual.State {
	case models.ActualLRPStateUnclaimed:
		if actual.PlacementError == "" {
			return say.LightGray("UNCLAIMED")
		} else {
			return say.Red("UNCLAIMED (%s)", actual.PlacementError)
		}
	case models.ActualLRPStateClaimed:
		return say.Yellow("CLAIMED")
	case models.ActualLRPStateRunning:
		return say.Green("RUNNING")
	case models.ActualLRPStateCrashed:
		return say.Red("CRASHED (%d - %s)", actual.CrashCount, strings.Replace(actual.CrashReason, "\n", " ", -1))
	default:
		return say.Red("INVALID")
	}
}

func routes(info receptor.RoutingInfo) string {
	if info == nil {
		return ""
	}

	routes, _ := cfroutes.CFRoutesFromRoutingInfo(info)

	if routes == nil {
		return ""
	}

	out := ""

	for _, route := range routes {
		out += fmt.Sprintf("%s => %s ", say.Yellow("%d", route.Port), say.Green(strings.Join(route.Hostnames, " ")))
	}

	return out
}
<|endoftext|>


<commit_before>// Copyright 2013 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
)

func apply(values []int, fn func(int)) {
	for _, v := range values {
		fn(v)
	}
}

func main() {
	values := []int{1, 2, 3}
	apply(values, func(i int) { fmt.Println(i) })
}
<commit_msg>basic/funcs: add multiple return functions and named results<commit_after>// Copyright 2013 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
)

func apply(values []int, fn func(int)) {
	for _, v := range values {
		fn(v)
	}
}

// count people in the database
func countPeople() (int, error) {
	n := 10
	return n, nil
}

func getInfo() (result int, err error) {
	result = 10
	return
}

func main() {
	values := []int{1, 2, 3}
	apply(values, func(i int) { fmt.Println(i) })
}
<|endoftext|>


<commit_before>// +build e2e

/*
Copyright 2018 The Knative 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 conformance

import (
	"reflect"
	"testing"

	"github.com/knative/pkg/test/logging"
	"github.com/knative/serving/pkg/apis/serving/v1alpha1"
	"github.com/knative/serving/test"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestUpdateConfigurationMetadata(t *testing.T) {
	clients := setup(t)

	logger := logging.GetContextLogger("TestUpdateConfigurationMetadata")

	var names test.ResourceNames
	names.Service = test.AppendRandomString("test-update-configuration-meta-", logger)
	names.Config = names.Service

	defer tearDown(clients, names)
	test.CleanupOnInterrupt(func() { tearDown(clients, names) }, logger)

	logger.Infof("Creating new configuration %s", names.Config)
	_, err := test.CreateConfiguration(logger, clients, names, test.ImagePath(pizzaPlanet1), &test.Options{})
	if err != nil {
		t.Fatalf("Failed to create configuration %s", names.Config)
	}

	var cfg *v1alpha1.Configuration

	logger.Info("The Configuration will be updated with the name of the Revision once it is created")
	names.Revision, err = waitForConfigurationLatestCreatedRevision(clients, names)
	if err != nil {
		t.Fatalf("Configuration %s was not updated with the new revision: %v", names.Config, err)
	}

	cfg = fetchConfiguration(names.Config, clients, t)

	logger.Infof("Updating labels of Configuration %s", names.Config)
	cfg.Labels = map[string]string{
		"labelX": "abc",
		"labelY": "def",
	}
	cfg, err = clients.ServingClient.Configs.Update(cfg)
	if err != nil {
		t.Fatalf("Failed to update labels for Configuration %s: %v", names.Config, err)
	}

	if err = waitForConfigurationLabelsUpdate(clients, names, cfg.Labels); err != nil {
		t.Fatalf("The labels for Configuration %s were not updated: %v", names.Config, err)
	}

	cfg = fetchConfiguration(names.Config, clients, t)
	expected := names.Revision
	actual := cfg.Status.LatestCreatedRevisionName
	if expected != actual {
		t.Errorf("Did not expect a new Revision after updating labels for Configuration %s - expected Revision: %s, actual Revision: %s",
			names.Config, expected, actual)
	}

	err = test.CheckRevisionState(clients.ServingClient, names.Revision, func(r *v1alpha1.Revision) (bool, error) {
		return checkMapKeysNotPresent(cfg.Labels, r.Labels), nil
	})
	if err != nil {
		t.Errorf("The labels for Revision %s of Configuration %s should not have been updated: %v", names.Revision, names.Config, err)
	}

	logger.Infof("Updating annotations of Configuration %s", names.Config)
	cfg.Annotations = map[string]string{
		"annotationA": "123",
		"annotationB": "456",
	}
	cfg, err = clients.ServingClient.Configs.Update(cfg)
	if err != nil {
		t.Fatalf("Failed to update annotations for Configuration %s: %v", names.Config, err)
	}

	if err = waitForConfigurationAnnotationsUpdate(clients, names, cfg.Annotations); err != nil {
		t.Fatalf("The annotations for Configuration %s were not updated: %v", names.Config, err)
	}

	cfg = fetchConfiguration(names.Config, clients, t)
	actual = cfg.Status.LatestCreatedRevisionName
	if expected != actual {
		t.Errorf("Did not expect a new Revision after updating annotations for Configuration %s - expected Revision: %s, actual Revision: %s",
			names.Config, expected, actual)
	}

	err = test.CheckRevisionState(clients.ServingClient, names.Revision, func(r *v1alpha1.Revision) (bool, error) {
		return checkMapKeysNotPresent(cfg.Annotations, r.Annotations), nil
	})
	if err != nil {
		t.Errorf("The annotations for Revision %s of Configuration %s should not have been updated: %v", names.Revision, names.Config, err)
	}
}

func fetchConfiguration(name string, clients *test.Clients, t *testing.T) *v1alpha1.Configuration {
	cfg, err := clients.ServingClient.Configs.Get(name, v1.GetOptions{})
	if err != nil {
		t.Fatalf("Failed to get configuration %s: %v", name, err)
	}
	return cfg
}

func waitForConfigurationLatestCreatedRevision(clients *test.Clients, names test.ResourceNames) (string, error) {
	var revisionName string
	err := test.WaitForConfigurationState(clients.ServingClient, names.Config, func(c *v1alpha1.Configuration) (bool, error) {
		if c.Status.LatestCreatedRevisionName != names.Revision {
			revisionName = c.Status.LatestCreatedRevisionName
			return true, nil
		}
		return false, nil
	}, "ConfigurationUpdatedWithRevision")
	return revisionName, err
}

func waitForConfigurationLabelsUpdate(clients *test.Clients, names test.ResourceNames, labels map[string]string) error {
	return test.WaitForConfigurationState(clients.ServingClient, names.Config, func(c *v1alpha1.Configuration) (bool, error) {
		return reflect.DeepEqual(c.Labels, labels) && c.Spec.Generation == c.Status.ObservedGeneration, nil
	}, "ConfigurationMetadataUpdatedWithLabels")
}

func waitForConfigurationAnnotationsUpdate(clients *test.Clients, names test.ResourceNames, annotations map[string]string) error {
	return test.WaitForConfigurationState(clients.ServingClient, names.Config, func(c *v1alpha1.Configuration) (bool, error) {
		return reflect.DeepEqual(c.Annotations, annotations) && c.Spec.Generation == c.Status.ObservedGeneration, nil
	}, "ConfigurationMetadataUpdatedWithAnnotations")
}

func checkMapKeysNotPresent(expected map[string]string, actual map[string]string) bool {
	for k := range expected {
		if _, ok := actual[k]; ok {
			return false
		}
	}
	return true
}
<commit_msg>Fix checkMapKeysNotPresent to checkNoKeysPresent and log the offending keys (#2875)<commit_after>// +build e2e

/*
Copyright 2018 The Knative 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 conformance

import (
	"reflect"
	"testing"

	"github.com/knative/pkg/test/logging"
	"github.com/knative/serving/pkg/apis/serving/v1alpha1"
	"github.com/knative/serving/test"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestUpdateConfigurationMetadata(t *testing.T) {
	clients := setup(t)

	logger := logging.GetContextLogger("TestUpdateConfigurationMetadata")

	var names test.ResourceNames
	names.Service = test.AppendRandomString("test-update-configuration-meta-", logger)
	names.Config = names.Service

	defer tearDown(clients, names)
	test.CleanupOnInterrupt(func() { tearDown(clients, names) }, logger)

	logger.Infof("Creating new configuration %s", names.Config)
	_, err := test.CreateConfiguration(logger, clients, names, test.ImagePath(pizzaPlanet1), &test.Options{})
	if err != nil {
		t.Fatalf("Failed to create configuration %s", names.Config)
	}

	var cfg *v1alpha1.Configuration

	logger.Info("The Configuration will be updated with the name of the Revision once it is created")
	names.Revision, err = waitForConfigurationLatestCreatedRevision(clients, names)
	if err != nil {
		t.Fatalf("Configuration %s was not updated with the new revision: %v", names.Config, err)
	}

	cfg = fetchConfiguration(names.Config, clients, t)

	logger.Infof("Updating labels of Configuration %s", names.Config)
	cfg.Labels = map[string]string{
		"labelX": "abc",
		"labelY": "def",
	}
	cfg, err = clients.ServingClient.Configs.Update(cfg)
	if err != nil {
		t.Fatalf("Failed to update labels for Configuration %s: %v", names.Config, err)
	}

	if err = waitForConfigurationLabelsUpdate(clients, names, cfg.Labels); err != nil {
		t.Fatalf("The labels for Configuration %s were not updated: %v", names.Config, err)
	}

	cfg = fetchConfiguration(names.Config, clients, t)
	expected := names.Revision
	actual := cfg.Status.LatestCreatedRevisionName
	if expected != actual {
		t.Errorf("Did not expect a new Revision after updating labels for Configuration %s - expected Revision: %s, actual Revision: %s",
			names.Config, expected, actual)
	}

	err = test.CheckRevisionState(clients.ServingClient, names.Revision, func(r *v1alpha1.Revision) (bool, error) {
		return checkNoKeysPresent(cfg.Labels, r.Labels, t), nil
	})
	if err != nil {
		t.Errorf("The labels for Revision %s of Configuration %s should not have been updated: %v", names.Revision, names.Config, err)
	}

	logger.Infof("Updating annotations of Configuration %s", names.Config)
	cfg.Annotations = map[string]string{
		"annotationA": "123",
		"annotationB": "456",
	}
	cfg, err = clients.ServingClient.Configs.Update(cfg)
	if err != nil {
		t.Fatalf("Failed to update annotations for Configuration %s: %v", names.Config, err)
	}

	if err = waitForConfigurationAnnotationsUpdate(clients, names, cfg.Annotations); err != nil {
		t.Fatalf("The annotations for Configuration %s were not updated: %v", names.Config, err)
	}

	cfg = fetchConfiguration(names.Config, clients, t)
	actual = cfg.Status.LatestCreatedRevisionName
	if expected != actual {
		t.Errorf("Did not expect a new Revision after updating annotations for Configuration %s - expected Revision: %s, actual Revision: %s",
			names.Config, expected, actual)
	}

	err = test.CheckRevisionState(clients.ServingClient, names.Revision, func(r *v1alpha1.Revision) (bool, error) {
		return checkNoKeysPresent(cfg.Annotations, r.Annotations, t), nil
	})
	if err != nil {
		t.Errorf("The annotations for Revision %s of Configuration %s should not have been updated: %v", names.Revision, names.Config, err)
	}
}

func fetchConfiguration(name string, clients *test.Clients, t *testing.T) *v1alpha1.Configuration {
	cfg, err := clients.ServingClient.Configs.Get(name, v1.GetOptions{})
	if err != nil {
		t.Fatalf("Failed to get configuration %s: %v", name, err)
	}
	return cfg
}

func waitForConfigurationLatestCreatedRevision(clients *test.Clients, names test.ResourceNames) (string, error) {
	var revisionName string
	err := test.WaitForConfigurationState(clients.ServingClient, names.Config, func(c *v1alpha1.Configuration) (bool, error) {
		if c.Status.LatestCreatedRevisionName != names.Revision {
			revisionName = c.Status.LatestCreatedRevisionName
			return true, nil
		}
		return false, nil
	}, "ConfigurationUpdatedWithRevision")
	return revisionName, err
}

func waitForConfigurationLabelsUpdate(clients *test.Clients, names test.ResourceNames, labels map[string]string) error {
	return test.WaitForConfigurationState(clients.ServingClient, names.Config, func(c *v1alpha1.Configuration) (bool, error) {
		return reflect.DeepEqual(c.Labels, labels) && c.Spec.Generation == c.Status.ObservedGeneration, nil
	}, "ConfigurationMetadataUpdatedWithLabels")
}

func waitForConfigurationAnnotationsUpdate(clients *test.Clients, names test.ResourceNames, annotations map[string]string) error {
	return test.WaitForConfigurationState(clients.ServingClient, names.Config, func(c *v1alpha1.Configuration) (bool, error) {
		return reflect.DeepEqual(c.Annotations, annotations) && c.Spec.Generation == c.Status.ObservedGeneration, nil
	}, "ConfigurationMetadataUpdatedWithAnnotations")
}

// checkNoKeysPresent returns true if _no_ keys from `expected`, are present in `actual`.
// checkNoKeysPresent will log the offending keys to t.Log.
func checkNoKeysPresent(expected map[string]string, actual map[string]string, t *testing.T) bool {
	t.Helper()
	present := []string{}
	for k := range expected {
		if _, ok := actual[k]; ok {
			present = append(present, k)
		}
	}
	t.Logf("Unexpected keys: %v", present)
	return len(present) == 0
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

package bees

import (
	"bytes"
	"log"
	"strings"
	"text/template"

	"github.com/muesli/beehive/filters"
)

// An element in a Chain
type ChainElement struct {
	Action Action
	Filter Filter
}

// A user defined Chain
type Chain struct {
	Name        string
	Description string
	Event       *Event
	Elements    []ChainElement
}

// Execute a filter. Returns whether the filter passed or not.
func execFilter(filter Filter, opts map[string]interface{}) bool {
	f := *filters.GetFilter(filter.Name)
	log.Println("\tExecuting filter:", f.Name(), "-", f.Description())

	for _, opt := range filter.Options {
		log.Println("\t\tOptions:", opt)
		origVal := opts[opt.Name]
		cleanVal := opt.Value
		if opt.Trimmed {
			switch v := origVal.(type) {
			case string:
				origVal = strings.TrimSpace(v)
			}
			switch v := cleanVal.(type) {
			case string:
				cleanVal = strings.TrimSpace(v)
			}
		}
		if opt.CaseInsensitive {
			switch v := origVal.(type) {
			case string:
				origVal = strings.ToLower(v)
			}
			switch v := cleanVal.(type) {
			case string:
				cleanVal = strings.ToLower(v)
			}
		}

		// if value is an array, iterate over it and pass if any of its values pass
		passes := false
		switch v := cleanVal.(type) {
			case []interface{}:
				for _, vi := range v {
					if f.Passes(origVal, vi) {
						passes = true
						break
					}
				}

			default:
				passes = f.Passes(origVal, cleanVal)
		}
		if passes == opt.Inverse {
			return false
		}
	}

	return true
}

// Execute an action and map its ins & outs.
func execAction(action Action, opts map[string]interface{}) bool {
	a := Action{
		Bee:  action.Bee,
		Name: action.Name,
	}

	for _, opt := range action.Options {
		ph := Placeholder{
			Name: opt.Name,
		}

		switch opt.Value.(type) {
		case string:
			var value bytes.Buffer

			funcMap := template.FuncMap{
				"Left": func(values ...interface{}) string {
					return values[0].(string)[:values[1].(int)]
				},
				"Mid": func(values ...interface{}) string {
					if len(values) > 2 {
						return values[0].(string)[values[1].(int):values[2].(int)]
					} else {
						return values[0].(string)[values[1].(int):]
					}
				},
				"Right": func(values ...interface{}) string {
					return values[0].(string)[len(values[0].(string))-values[1].(int):]
				},
			}

			tmpl, err := template.New(action.Bee + "_" + action.Name + "_" + opt.Name).Funcs(funcMap).Parse(opt.Value.(string))
			if err == nil {
				err = tmpl.Execute(&value, opts)
			}
			if err != nil {
				panic(err)
			}

			ph.Type = "string"
			ph.Value = value.String()

		default:
			ph.Type = opt.Type
			ph.Value = opt.Value
		}
		a.Options = append(a.Options, ph)
	}

	log.Println("\tExecuting action:", a.Bee, "/", a.Name, "-", GetActionDescriptor(&a).Description)
	for _, v := range a.Options {
		log.Println("\t\tOptions:", v)
	}
	(*GetBee(a.Bee)).Action(a)

	return true
}

// Execute chains for an event we received.
func execChains(event *Event) {
	for _, c := range chains {
		if c.Event.Name != event.Name || c.Event.Bee != event.Bee {
			continue
		}

		log.Println("Executing chain:", c.Name, "-", c.Description)
		for _, el := range c.Elements {
			m := make(map[string]interface{})
			for _, opt := range event.Options {
				m[opt.Name] = opt.Value
			}

			if el.Filter.Name != "" {
				if execFilter(el.Filter, m) {
					log.Println("\t\tPassed filter!")
				} else {
					log.Println("\t\tDid not pass filter!")
					break
				}
			}
			if el.Action.Name != "" {
				execAction(el.Action, m)
			}
		}
	}
}
<commit_msg>adds Split func to templates. go fmt<commit_after>/*
 *    Copyright (C) 2014 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

package bees

import (
	"bytes"
	"log"
	"strings"
	"text/template"

	"github.com/muesli/beehive/filters"
)

// An element in a Chain
type ChainElement struct {
	Action Action
	Filter Filter
}

// A user defined Chain
type Chain struct {
	Name        string
	Description string
	Event       *Event
	Elements    []ChainElement
}

// Execute a filter. Returns whether the filter passed or not.
func execFilter(filter Filter, opts map[string]interface{}) bool {
	f := *filters.GetFilter(filter.Name)
	log.Println("\tExecuting filter:", f.Name(), "-", f.Description())

	for _, opt := range filter.Options {
		log.Println("\t\tOptions:", opt)
		origVal := opts[opt.Name]
		cleanVal := opt.Value
		if opt.Trimmed {
			switch v := origVal.(type) {
			case string:
				origVal = strings.TrimSpace(v)
			}
			switch v := cleanVal.(type) {
			case string:
				cleanVal = strings.TrimSpace(v)
			}
		}
		if opt.CaseInsensitive {
			switch v := origVal.(type) {
			case string:
				origVal = strings.ToLower(v)
			}
			switch v := cleanVal.(type) {
			case string:
				cleanVal = strings.ToLower(v)
			}
		}

		// if value is an array, iterate over it and pass if any of its values pass
		passes := false
		switch v := cleanVal.(type) {
		case []interface{}:
			for _, vi := range v {
				if f.Passes(origVal, vi) {
					passes = true
					break
				}
			}

		default:
			passes = f.Passes(origVal, cleanVal)
		}
		if passes == opt.Inverse {
			return false
		}
	}

	return true
}

// Execute an action and map its ins & outs.
func execAction(action Action, opts map[string]interface{}) bool {
	a := Action{
		Bee:  action.Bee,
		Name: action.Name,
	}

	for _, opt := range action.Options {
		ph := Placeholder{
			Name: opt.Name,
		}

		switch opt.Value.(type) {
		case string:
			var value bytes.Buffer

			funcMap := template.FuncMap{
				"Left": func(values ...interface{}) string {
					return values[0].(string)[:values[1].(int)]
				},
				"Mid": func(values ...interface{}) string {
					if len(values) > 2 {
						return values[0].(string)[values[1].(int):values[2].(int)]
					} else {
						return values[0].(string)[values[1].(int):]
					}
				},
				"Right": func(values ...interface{}) string {
					return values[0].(string)[len(values[0].(string))-values[1].(int):]
				},
				"Split": strings.Split,
			}

			tmpl, err := template.New(action.Bee + "_" + action.Name + "_" + opt.Name).Funcs(funcMap).Parse(opt.Value.(string))
			if err == nil {
				err = tmpl.Execute(&value, opts)
			}
			if err != nil {
				panic(err)
			}

			ph.Type = "string"
			ph.Value = value.String()

		default:
			ph.Type = opt.Type
			ph.Value = opt.Value
		}
		a.Options = append(a.Options, ph)
	}

	log.Println("\tExecuting action:", a.Bee, "/", a.Name, "-", GetActionDescriptor(&a).Description)
	for _, v := range a.Options {
		log.Println("\t\tOptions:", v)
	}
	(*GetBee(a.Bee)).Action(a)

	return true
}

// Execute chains for an event we received.
func execChains(event *Event) {
	for _, c := range chains {
		if c.Event.Name != event.Name || c.Event.Bee != event.Bee {
			continue
		}

		log.Println("Executing chain:", c.Name, "-", c.Description)
		for _, el := range c.Elements {
			m := make(map[string]interface{})
			for _, opt := range event.Options {
				m[opt.Name] = opt.Value
			}

			if el.Filter.Name != "" {
				if execFilter(el.Filter, m) {
					log.Println("\t\tPassed filter!")
				} else {
					log.Println("\t\tDid not pass filter!")
					break
				}
			}
			if el.Action.Name != "" {
				execAction(el.Action, m)
			}
		}
	}
}
<|endoftext|>


<commit_before>package cache

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"sync"
)

// Reader is a generic interface for reading cache entries either from disk or
// directly attached to a downloader.
type Reader interface {
	io.ReadCloser
	GetEntry() (*Entry, error)
}

// Cache provides access to entries in the cache.
type Cache struct {
	mutex       sync.Mutex
	directory   string
	downloaders map[string]*downloader
	waitGroup   sync.WaitGroup
}

// NewCache creates a new cache in the specified directory.
func NewCache(directory string) (*Cache, error) {
	if err := os.MkdirAll(directory, 0775); err != nil {
		return nil, err
	}
	return &Cache{
		directory:   directory,
		downloaders: make(map[string]*downloader),
	}, nil
}

// GetReader obtains a Reader for the specified rawurl. If a downloader
// currently exists for the URL, a live reader is created and connected to it.
// If the URL exists in the cache, it is read using the standard file API. If
// not, a downloader and live reader are created.
func (c *Cache) GetReader(rawurl string) (Reader, error) {
	var (
		b            = md5.Sum([]byte(rawurl))
		hash         = hex.EncodeToString(b[:])
		jsonFilename = path.Join(c.directory, fmt.Sprintf("%s.json", hash))
		dataFilename = path.Join(c.directory, fmt.Sprintf("%s.data", hash))
	)
	c.mutex.Lock()
	defer c.mutex.Unlock()
	d, ok := c.downloaders[hash]
	if !ok {
		_, err := os.Stat(jsonFilename)
		if err != nil {
			if !os.IsNotExist(err) {
				return nil, err
			}
		} else {
			r, err := newDiskReader(jsonFilename, dataFilename)
			if err != nil {
				return nil, err
			}
			if e, _ := r.GetEntry(); e.Complete {
				log.Println("[HIT]", rawurl)
				return r, nil
			}
		}
		d = newDownloader(rawurl, jsonFilename, dataFilename)
		go func() {
			d.WaitForDone()
			c.mutex.Lock()
			defer c.mutex.Unlock()
			delete(c.downloaders, hash)
			c.waitGroup.Done()
		}()
		c.downloaders[hash] = d
		c.waitGroup.Add(1)
	}
	log.Println("[MISS]", rawurl)
	return newLiveReader(d, dataFilename)
}

// TODO: implement some form of "safe abort" for downloads so that the entire
// application doesn't end up spinning its tires waiting for downloads to end

// Close waits for all downloaders to complete before shutting down.
func (c *Cache) Close() {
	c.waitGroup.Wait()
}
<commit_msg>Added Insert() method to Cache (#1).<commit_after>package cache

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"mime"
	"net/http"
	"os"
	"path"
	"strconv"
	"sync"
	"time"
)

// Reader is a generic interface for reading cache entries either from disk or
// directly attached to a downloader.
type Reader interface {
	io.ReadCloser
	GetEntry() (*Entry, error)
}

// Cache provides access to entries in the cache.
type Cache struct {
	mutex       sync.Mutex
	directory   string
	downloaders map[string]*downloader
	waitGroup   sync.WaitGroup
}

// NewCache creates a new cache in the specified directory.
func NewCache(directory string) (*Cache, error) {
	if err := os.MkdirAll(directory, 0775); err != nil {
		return nil, err
	}
	return &Cache{
		directory:   directory,
		downloaders: make(map[string]*downloader),
	}, nil
}

// getFilenames returns the filenames for the JSON and data files from a URL.
func (c *Cache) getFilenames(rawurl string) (hash, jsonFilename, dataFilename string) {
	b := md5.Sum([]byte(rawurl))
	hash = hex.EncodeToString(b[:])
	jsonFilename = path.Join(c.directory, fmt.Sprintf("%s.json", hash))
	dataFilename = path.Join(c.directory, fmt.Sprintf("%s.data", hash))
	return
}

// GetReader obtains a Reader for the specified rawurl. If a downloader
// currently exists for the URL, a live reader is created and connected to it.
// If the URL exists in the cache, it is read using the standard file API. If
// not, a downloader and live reader are created.
func (c *Cache) GetReader(rawurl string) (Reader, error) {
	hash, jsonFilename, dataFilename := c.getFilenames(rawurl)
	c.mutex.Lock()
	defer c.mutex.Unlock()
	d, ok := c.downloaders[hash]
	if !ok {
		_, err := os.Stat(jsonFilename)
		if err != nil {
			if !os.IsNotExist(err) {
				return nil, err
			}
		} else {
			r, err := newDiskReader(jsonFilename, dataFilename)
			if err != nil {
				return nil, err
			}
			if e, _ := r.GetEntry(); e.Complete {
				log.Println("[HIT]", rawurl)
				return r, nil
			}
		}
		d = newDownloader(rawurl, jsonFilename, dataFilename)
		go func() {
			d.WaitForDone()
			c.mutex.Lock()
			defer c.mutex.Unlock()
			delete(c.downloaders, hash)
			c.waitGroup.Done()
		}()
		c.downloaders[hash] = d
		c.waitGroup.Add(1)
	}
	log.Println("[MISS]", rawurl)
	return newLiveReader(d, dataFilename)
}

// Insert adds an item into the cache.
func (c *Cache) Insert(rawurl string, r io.Reader) error {
	_, jsonFilename, dataFilename := c.getFilenames(rawurl)
	f, err := os.Open(dataFilename)
	if err != nil {
		return err
	}
	defer f.Close()
	n, err := io.Copy(f, r)
	if err != nil {
		return err
	}
	e := &Entry{
		URL:           rawurl,
		Complete:      true,
		ContentLength: strconv.FormatInt(n, 10),
		ContentType:   mime.TypeByExtension(rawurl),
		LastModified:  time.Now().Format(http.TimeFormat),
	}
	return e.Save(jsonFilename)
}

// TODO: implement some form of "safe abort" for downloads so that the entire
// application doesn't end up spinning its tires waiting for downloads to end.

// Close waits for all downloaders to complete before shutting down.
func (c *Cache) Close() {
	c.waitGroup.Wait()
}
<|endoftext|>


<commit_before>package cache

import (
	"bufio"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/dgageot/getme/files"
	"github.com/pkg/errors"
)

const (
	recentFile = ".recent"
)

// PathToUrl gives the path to the file on disk that caches a given url.
func PathToUrl(url string) (string, error) {
	return PathToFileInCache(sanitizeUrl(url))
}

// PathToCache gives the path of the cache.
func PathToCache() (string, error) {
	home := os.Getenv("HOME")
	if home == "" {
		return "", errors.New("HOME is not defined")
	}

	return filepath.Join(home, ".getme"), nil
}

// PathToFileInCache gives the path to the file in cache.
func PathToFileInCache(name string) (string, error) {
	folderCache, err := PathToCache()
	if err != nil {
		return "", err
	}

	return filepath.Join(folderCache, name), nil
}

// Download downloads an url to the cache if needed. Additional headers can be given.
// This is helpful to pass authentication tokens.
func Download(url string, headers []string) (path string, err error) {
	destination, err := PathToUrl(url)
	if err != nil {
		return "", err
	}

	if err := SaveAccessedUrl(url); err != nil {
		return "", err
	}

	if _, err := os.Stat(destination); err == nil {
		log.Println("Already in cache:", url)
		return destination, nil
	}

	log.Println("Download", url, "to", destination)

	return destination, files.Download(url, destination, headers)
}

func SaveAccessedUrl(url string) error {
	accessFile, err := PathToFileInCache(recentFile)
	if err != nil {
		return err
	}

	if err := files.MkdirAll(filepath.Dir(accessFile)); err != nil {
		return err
	}

	f, err := os.OpenFile(accessFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = f.WriteString(url + "\n")
	return err
}

// Prune removes any file from cache that were not accessed since last call to Prune.
func Prune() error {
	accessFile, err := PathToFileInCache(recentFile)
	if err != nil {
		return err
	}

	recentUrls := []string{}

	if _, err := os.Stat(accessFile); err == nil {
		// Read recently accessed urls
		file, err := os.Open(accessFile)
		if err != nil {
			return err
		}
		defer file.Close()

		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			recentUrl := scanner.Text()
			sanitizedUrl := sanitizeUrl(recentUrl)
			recentUrls = append(recentUrls, sanitizedUrl)
		}

		if err := scanner.Err(); err != nil {
			return err
		}
	}

	// Read urls in cache
	folderCache, err := PathToCache()
	if err != nil {
		return err
	}

	inCacheSanitizedUrls := []string{}
	if _, err := os.Stat(folderCache); err == nil {
		files, err := ioutil.ReadDir(folderCache)
		if err != nil {
			return err
		}

		for _, file := range files {
			name := file.Name()
			if !strings.HasPrefix(name, ".") {
				inCacheSanitizedUrls = append(inCacheSanitizedUrls, name)
			}
		}

		// Delete files not accessed recently
		for _, sanitizedUrl := range inCacheSanitizedUrls {
			if strings.HasPrefix(sanitizedUrl, ".") {
				continue
			}

			found := false
			for _, recent := range recentUrls {
				if sanitizedUrl == recent {
					found = true
					break
				}
			}

			if !found {
				log.Println("Delete", sanitizedUrl)

				if err := os.Remove(filepath.Join(folderCache, sanitizedUrl)); err != nil {
					return err
				}
			}
		}
	}

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

	return nil
}

func sanitizeUrl(url string) string {
	sanitizedUrl := url
	sanitizedUrl = strings.Replace(sanitizedUrl, "/", "-", -1)
	sanitizedUrl = strings.Replace(sanitizedUrl, ":", "-", -1)
	return sanitizedUrl
}
<commit_msg>Add comment<commit_after>package cache

import (
	"bufio"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/dgageot/getme/files"
	"github.com/pkg/errors"
)

const (
	recentFile = ".recent"
)

// PathToUrl gives the path to the file on disk that caches a given url.
func PathToUrl(url string) (string, error) {
	return PathToFileInCache(sanitizeUrl(url))
}

// PathToCache gives the path of the cache.
func PathToCache() (string, error) {
	home := os.Getenv("HOME")
	if home == "" {
		return "", errors.New("HOME is not defined")
	}

	return filepath.Join(home, ".getme"), nil
}

// PathToFileInCache gives the path to the file in cache.
func PathToFileInCache(name string) (string, error) {
	folderCache, err := PathToCache()
	if err != nil {
		return "", err
	}

	return filepath.Join(folderCache, name), nil
}

// Download downloads an url to the cache if needed. Additional headers can be given.
// This is helpful to pass authentication tokens.
func Download(url string, headers []string) (path string, err error) {
	destination, err := PathToUrl(url)
	if err != nil {
		return "", err
	}

	if err := SaveAccessedUrl(url); err != nil {
		return "", err
	}

	if _, err := os.Stat(destination); err == nil {
		log.Println("Already in cache:", url)
		return destination, nil
	}

	log.Println("Download", url, "to", destination)

	return destination, files.Download(url, destination, headers)
}

// SaveAccessedUrl appends a url to the file that lists recently accessed urls.
func SaveAccessedUrl(url string) error {
	accessFile, err := PathToFileInCache(recentFile)
	if err != nil {
		return err
	}

	if err := files.MkdirAll(filepath.Dir(accessFile)); err != nil {
		return err
	}

	f, err := os.OpenFile(accessFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = f.WriteString(url + "\n")
	return err
}

// Prune removes any file from cache that were not accessed since last call to Prune.
func Prune() error {
	accessFile, err := PathToFileInCache(recentFile)
	if err != nil {
		return err
	}

	recentUrls := []string{}

	if _, err := os.Stat(accessFile); err == nil {
		// Read recently accessed urls
		file, err := os.Open(accessFile)
		if err != nil {
			return err
		}
		defer file.Close()

		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			recentUrl := scanner.Text()
			sanitizedUrl := sanitizeUrl(recentUrl)
			recentUrls = append(recentUrls, sanitizedUrl)
		}

		if err := scanner.Err(); err != nil {
			return err
		}
	}

	// Read urls in cache
	folderCache, err := PathToCache()
	if err != nil {
		return err
	}

	inCacheSanitizedUrls := []string{}
	if _, err := os.Stat(folderCache); err == nil {
		files, err := ioutil.ReadDir(folderCache)
		if err != nil {
			return err
		}

		for _, file := range files {
			name := file.Name()
			if !strings.HasPrefix(name, ".") {
				inCacheSanitizedUrls = append(inCacheSanitizedUrls, name)
			}
		}

		// Delete files not accessed recently
		for _, sanitizedUrl := range inCacheSanitizedUrls {
			if strings.HasPrefix(sanitizedUrl, ".") {
				continue
			}

			found := false
			for _, recent := range recentUrls {
				if sanitizedUrl == recent {
					found = true
					break
				}
			}

			if !found {
				log.Println("Delete", sanitizedUrl)

				if err := os.Remove(filepath.Join(folderCache, sanitizedUrl)); err != nil {
					return err
				}
			}
		}
	}

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

	return nil
}

func sanitizeUrl(url string) string {
	sanitizedUrl := url
	sanitizedUrl = strings.Replace(sanitizedUrl, "/", "-", -1)
	sanitizedUrl = strings.Replace(sanitizedUrl, ":", "-", -1)
	return sanitizedUrl
}
<|endoftext|>


<commit_before>// Copyright 2011 Julian Phillips.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package py

// #include "utils.h"
// static inline void decref(PyObject *obj) { Py_DECREF(obj); }
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

type BaseObject struct {
	AbstractObject
	C.PyObject
}

var BaseType = (*Type)(unsafe.Pointer(&C.PyBaseObject_Type))

func newBaseObject(obj *C.PyObject) *BaseObject {
	return (*BaseObject)(unsafe.Pointer(obj))
}

// HasAttr returns true if "obj" has the attribute "name".  This is equivalent
// to the Python "hasattr(obj, name)".
func (obj *BaseObject) HasAttr(name Object) bool {
	ret := C.PyObject_HasAttr(c(obj), c(name))
	if ret == 1 {
		return true
	}
	return false
}

// HasAttrString returns true if "obj" has the attribute "name".  This is
// equivalent to the Python "hasattr(obj, name)".
func (obj *BaseObject) HasAttrString(name string) bool {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_HasAttrString(c(obj), s)
	if ret == 1 {
		return true
	}
	return false
}

// GetAttr returns the attribute of "obj" with the name "name".  This is
// equivalent to the Python "obj.name".
//
// Return value: New Reference.
func (obj *BaseObject) GetAttr(name Object) (Object, os.Error) {
	ret := C.PyObject_GetAttr(c(obj), c(name))
	return obj2ObjErr(ret)
}

// GetAttrString returns the attribute of "obj" with the name "name".  This is
// equivalent to the Python "obj.name".
//
// Return value: New Reference.
func (obj *BaseObject) GetAttrString(name string) (Object, os.Error) {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_GetAttrString(c(obj), s)
	return obj2ObjErr(ret)
}

// PyObject_GenericGetAttr : This is an internal helper function - we shouldn't
// need to expose it ...

// SetAttr sets the attribute of "obj" with the name "name" to "value".  This is
// equivalent to the Python "obj.name = value".
func (obj *BaseObject) SetAttr(name, value Object) os.Error {
	ret := C.PyObject_SetAttr(c(obj), c(name), c(value))
	return int2Err(ret)
}

// SetAttrString sets the attribute of "obj" with the name "name" to "value".
// This is equivalent to the Python "obj.name = value".
func (obj *BaseObject) SetAttrString(name string, value Object) os.Error {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_SetAttrString(c(obj), s, c(value))
	return int2Err(ret)
}

// PyObject_GenericSetAttr : This is an internal helper function - we shouldn't
// need to expose it ...

// DelAttr deletes the attribute with the name "name" from "obj".  This is
// equivalent to the Python "del obj.name".
func (obj *BaseObject) DelAttr(name Object) os.Error {
	ret := C.PyObject_SetAttr(c(obj), c(name), nil)
	return int2Err(ret)
}

// DelAttrString deletes the attribute with the name "name" from "obj".  This is
// equivalent to the Python "del obj.name".
func (obj *BaseObject) DelAttrString(name string) os.Error {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_SetAttrString(c(obj), s, nil)
	return int2Err(ret)
}

// RichCompare compares "obj" with "obj2" using the specified operation (LE, GE
// etc.), and returns the result.  The equivalent Python is "obj op obj2", where
// op is the corresponding Python operator for op.
//
// Return value: New Reference.
func (obj *BaseObject) RichCompare(obj2 Object, op Op) (Object, os.Error) {
	ret := C.PyObject_RichCompare(c(obj), c(obj2), C.int(op))
	return obj2ObjErr(ret)
}

// RichCompare compares "obj" with "obj2" using the specified operation (LE, GE
// etc.), and returns true or false.  The equivalent Python is "obj op obj2",
// where op is the corresponding Python operator for op.
func (obj *BaseObject) RichCompareBool(obj2 Object, op Op) (bool, os.Error) {
	ret := C.PyObject_RichCompareBool(c(obj), c(obj2), C.int(op))
	return int2BoolErr(ret)
}

// PyObject_Cmp : Thanks to multiple return values, we don't need this function
// to be available in Go.

// Compare returns the result of comparing "obj" and "obj2".  This is equivalent
// to the Python "cmp(obj, obj2)".
func (obj *BaseObject) Compare(obj2 Object) (int, os.Error) {
	ret := C.PyObject_Compare(c(obj), c(obj2))
	return int(ret), exception()
}

// Repr returns a String representation of "obj".  This is equivalent to the
// Python "repr(obj)".
//
// Return value: New Reference.
func (obj *BaseObject) Repr() (Object, os.Error) {
	ret := C.PyObject_Repr(c(obj))
	return obj2ObjErr(ret)
}

// Str returns a String representation of "obj".  This is equivalent to the
// Python "str(obj)".
//
// Return value: New Reference.
func (obj *BaseObject) Str() (Object, os.Error) {
	ret := C.PyObject_Str(c(obj))
	return obj2ObjErr(ret)
}

// Bytes returns a Bytes representation of "obj".  This is equivalent to the
// Python "bytes(obj)".  In Python 2.x this method is identical to Str().
//
// Return value: New Reference.
func (obj *BaseObject) Bytes() (Object, os.Error) {
	ret := C.PyObject_Bytes(c(obj))
	return obj2ObjErr(ret)
}

// PyObject_Unicode : TODO

// IsInstance returns true if "obj" is an instance of "cls", false otherwise.
// If "cls" is a Type instead of a class, then true will be return if "obj" is
// of that type.  If "cls" is a Tuple then true will be returned if "obj" is an
// instance of any of the Objects in the tuple.  This is equivalent to the
// Python "isinstance(obj, cls)".
func (obj *BaseObject) IsInstance(cls Object) (bool, os.Error) {
	ret := C.PyObject_IsInstance(c(obj), c(cls))
	return int2BoolErr(ret)
}

// IsSubclass retuns true if "obj" is a Subclass of "cls", false otherwise.  If
// "cls" is a Tuple, then true is returned if "obj" is a Subclass of any member
// of "cls".  This is equivalent to the Python "issubclass(obj, cls)".
func (obj *BaseObject) IsSubclass(cls Object) (bool, os.Error) {
	ret := C.PyObject_IsSubclass(c(obj), c(cls))
	return int2BoolErr(ret)
}

func (obj *BaseObject) Call(args *Tuple, kwds *Dict) (Object, os.Error) {
	ret := C.PyObject_Call(c(obj), c(args), c(kwds))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallObject(args *Tuple) (Object, os.Error) {
	var a *C.PyObject = nil
	if args != nil {
		a = c(args)
	}
	ret := C.PyObject_CallObject(c(obj), a)
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunction(format string, args ...interface{}) (Object, os.Error) {
	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethod(name string, format string, args ...interface{}) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunctionObjArgs(args ...Object) (Object, os.Error) {
	t, err := PackTuple(args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethodObjArgs(name string, args ...Object) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := PackTuple(args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

// PyObject_Hash : TODO

// PyObject_HashNotImplement : This is an internal function, that we probably
// don't need to export.

// PyObject_IsTrue : Implemented on AbstractObject

// PyObject_Not : Implemented on AbstractObject

// PyObject_Type : Implemented on AbstractObject

// PyObject_TypeCheck : TODO

// Length returns the length of the Object.  This is equivalent to the Python
// "len(obj)".
func (obj *BaseObject) Length() (int64, os.Error) {
	ret := C.PyObject_Length(c(obj))
	return int64(ret), exception()
}

// Size returns the length of the Object.  This is equivalent to the Python
// "len(obj)".
func (obj *BaseObject) Size() (int64, os.Error) {
	ret := C.PyObject_Size(c(obj))
	return int64(ret), exception()
}

// GetItem returns the element of "obj" corresponding to "key".  This is
// equivalent to the Python "obj[key]".
//
// Return value: New Reference.
func (obj *BaseObject) GetItem(key Object) (Object, os.Error) {
	ret := C.PyObject_GetItem(c(obj), c(key))
	return obj2ObjErr(ret)
}

// SetItem sets the element of "obj" corresponding to "key" to "value".  This is
// equivalent to the Python "obj[key] = value".
func (obj *BaseObject) SetItem(key, value Object) os.Error {
	ret := C.PyObject_SetItem(c(obj), c(key), c(value))
	return int2Err(ret)
}

// DelItem deletes the element from "obj" that corresponds to "key".  This is
// equivalent to the Python "del obj[key]".
func (obj *BaseObject) DelItem(key Object) os.Error {
	ret := C.PyObject_DelItem(c(obj), c(key))
	return int2Err(ret)
}

// PyObject_AsFileDescriptor : TODO

func (obj *BaseObject) Dir() (Object, os.Error) {
	ret := C.PyObject_Dir(c(obj))
	return obj2ObjErr(ret)
}

// PyObject_GetIter : TODO
<commit_msg>The internals of BaseObject aren't supposed to be public<commit_after>// Copyright 2011 Julian Phillips.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package py

// #include "utils.h"
// static inline void decref(PyObject *obj) { Py_DECREF(obj); }
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

type BaseObject struct {
	AbstractObject
	o C.PyObject
}

var BaseType = (*Type)(unsafe.Pointer(&C.PyBaseObject_Type))

func newBaseObject(obj *C.PyObject) *BaseObject {
	return (*BaseObject)(unsafe.Pointer(obj))
}

// HasAttr returns true if "obj" has the attribute "name".  This is equivalent
// to the Python "hasattr(obj, name)".
func (obj *BaseObject) HasAttr(name Object) bool {
	ret := C.PyObject_HasAttr(c(obj), c(name))
	if ret == 1 {
		return true
	}
	return false
}

// HasAttrString returns true if "obj" has the attribute "name".  This is
// equivalent to the Python "hasattr(obj, name)".
func (obj *BaseObject) HasAttrString(name string) bool {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_HasAttrString(c(obj), s)
	if ret == 1 {
		return true
	}
	return false
}

// GetAttr returns the attribute of "obj" with the name "name".  This is
// equivalent to the Python "obj.name".
//
// Return value: New Reference.
func (obj *BaseObject) GetAttr(name Object) (Object, os.Error) {
	ret := C.PyObject_GetAttr(c(obj), c(name))
	return obj2ObjErr(ret)
}

// GetAttrString returns the attribute of "obj" with the name "name".  This is
// equivalent to the Python "obj.name".
//
// Return value: New Reference.
func (obj *BaseObject) GetAttrString(name string) (Object, os.Error) {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_GetAttrString(c(obj), s)
	return obj2ObjErr(ret)
}

// PyObject_GenericGetAttr : This is an internal helper function - we shouldn't
// need to expose it ...

// SetAttr sets the attribute of "obj" with the name "name" to "value".  This is
// equivalent to the Python "obj.name = value".
func (obj *BaseObject) SetAttr(name, value Object) os.Error {
	ret := C.PyObject_SetAttr(c(obj), c(name), c(value))
	return int2Err(ret)
}

// SetAttrString sets the attribute of "obj" with the name "name" to "value".
// This is equivalent to the Python "obj.name = value".
func (obj *BaseObject) SetAttrString(name string, value Object) os.Error {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_SetAttrString(c(obj), s, c(value))
	return int2Err(ret)
}

// PyObject_GenericSetAttr : This is an internal helper function - we shouldn't
// need to expose it ...

// DelAttr deletes the attribute with the name "name" from "obj".  This is
// equivalent to the Python "del obj.name".
func (obj *BaseObject) DelAttr(name Object) os.Error {
	ret := C.PyObject_SetAttr(c(obj), c(name), nil)
	return int2Err(ret)
}

// DelAttrString deletes the attribute with the name "name" from "obj".  This is
// equivalent to the Python "del obj.name".
func (obj *BaseObject) DelAttrString(name string) os.Error {
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	ret := C.PyObject_SetAttrString(c(obj), s, nil)
	return int2Err(ret)
}

// RichCompare compares "obj" with "obj2" using the specified operation (LE, GE
// etc.), and returns the result.  The equivalent Python is "obj op obj2", where
// op is the corresponding Python operator for op.
//
// Return value: New Reference.
func (obj *BaseObject) RichCompare(obj2 Object, op Op) (Object, os.Error) {
	ret := C.PyObject_RichCompare(c(obj), c(obj2), C.int(op))
	return obj2ObjErr(ret)
}

// RichCompare compares "obj" with "obj2" using the specified operation (LE, GE
// etc.), and returns true or false.  The equivalent Python is "obj op obj2",
// where op is the corresponding Python operator for op.
func (obj *BaseObject) RichCompareBool(obj2 Object, op Op) (bool, os.Error) {
	ret := C.PyObject_RichCompareBool(c(obj), c(obj2), C.int(op))
	return int2BoolErr(ret)
}

// PyObject_Cmp : Thanks to multiple return values, we don't need this function
// to be available in Go.

// Compare returns the result of comparing "obj" and "obj2".  This is equivalent
// to the Python "cmp(obj, obj2)".
func (obj *BaseObject) Compare(obj2 Object) (int, os.Error) {
	ret := C.PyObject_Compare(c(obj), c(obj2))
	return int(ret), exception()
}

// Repr returns a String representation of "obj".  This is equivalent to the
// Python "repr(obj)".
//
// Return value: New Reference.
func (obj *BaseObject) Repr() (Object, os.Error) {
	ret := C.PyObject_Repr(c(obj))
	return obj2ObjErr(ret)
}

// Str returns a String representation of "obj".  This is equivalent to the
// Python "str(obj)".
//
// Return value: New Reference.
func (obj *BaseObject) Str() (Object, os.Error) {
	ret := C.PyObject_Str(c(obj))
	return obj2ObjErr(ret)
}

// Bytes returns a Bytes representation of "obj".  This is equivalent to the
// Python "bytes(obj)".  In Python 2.x this method is identical to Str().
//
// Return value: New Reference.
func (obj *BaseObject) Bytes() (Object, os.Error) {
	ret := C.PyObject_Bytes(c(obj))
	return obj2ObjErr(ret)
}

// PyObject_Unicode : TODO

// IsInstance returns true if "obj" is an instance of "cls", false otherwise.
// If "cls" is a Type instead of a class, then true will be return if "obj" is
// of that type.  If "cls" is a Tuple then true will be returned if "obj" is an
// instance of any of the Objects in the tuple.  This is equivalent to the
// Python "isinstance(obj, cls)".
func (obj *BaseObject) IsInstance(cls Object) (bool, os.Error) {
	ret := C.PyObject_IsInstance(c(obj), c(cls))
	return int2BoolErr(ret)
}

// IsSubclass retuns true if "obj" is a Subclass of "cls", false otherwise.  If
// "cls" is a Tuple, then true is returned if "obj" is a Subclass of any member
// of "cls".  This is equivalent to the Python "issubclass(obj, cls)".
func (obj *BaseObject) IsSubclass(cls Object) (bool, os.Error) {
	ret := C.PyObject_IsSubclass(c(obj), c(cls))
	return int2BoolErr(ret)
}

func (obj *BaseObject) Call(args *Tuple, kwds *Dict) (Object, os.Error) {
	ret := C.PyObject_Call(c(obj), c(args), c(kwds))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallObject(args *Tuple) (Object, os.Error) {
	var a *C.PyObject = nil
	if args != nil {
		a = c(args)
	}
	ret := C.PyObject_CallObject(c(obj), a)
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunction(format string, args ...interface{}) (Object, os.Error) {
	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethod(name string, format string, args ...interface{}) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunctionObjArgs(args ...Object) (Object, os.Error) {
	t, err := PackTuple(args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethodObjArgs(name string, args ...Object) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := PackTuple(args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

// PyObject_Hash : TODO

// PyObject_HashNotImplement : This is an internal function, that we probably
// don't need to export.

// PyObject_IsTrue : Implemented on AbstractObject

// PyObject_Not : Implemented on AbstractObject

// PyObject_Type : Implemented on AbstractObject

// PyObject_TypeCheck : TODO

// Length returns the length of the Object.  This is equivalent to the Python
// "len(obj)".
func (obj *BaseObject) Length() (int64, os.Error) {
	ret := C.PyObject_Length(c(obj))
	return int64(ret), exception()
}

// Size returns the length of the Object.  This is equivalent to the Python
// "len(obj)".
func (obj *BaseObject) Size() (int64, os.Error) {
	ret := C.PyObject_Size(c(obj))
	return int64(ret), exception()
}

// GetItem returns the element of "obj" corresponding to "key".  This is
// equivalent to the Python "obj[key]".
//
// Return value: New Reference.
func (obj *BaseObject) GetItem(key Object) (Object, os.Error) {
	ret := C.PyObject_GetItem(c(obj), c(key))
	return obj2ObjErr(ret)
}

// SetItem sets the element of "obj" corresponding to "key" to "value".  This is
// equivalent to the Python "obj[key] = value".
func (obj *BaseObject) SetItem(key, value Object) os.Error {
	ret := C.PyObject_SetItem(c(obj), c(key), c(value))
	return int2Err(ret)
}

// DelItem deletes the element from "obj" that corresponds to "key".  This is
// equivalent to the Python "del obj[key]".
func (obj *BaseObject) DelItem(key Object) os.Error {
	ret := C.PyObject_DelItem(c(obj), c(key))
	return int2Err(ret)
}

// PyObject_AsFileDescriptor : TODO

func (obj *BaseObject) Dir() (Object, os.Error) {
	ret := C.PyObject_Dir(c(obj))
	return obj2ObjErr(ret)
}

// PyObject_GetIter : TODO
<|endoftext|>