<commit_before>// 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/>.

package twitter

import (
	"github.com/ChimeraCoder/anaconda"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"net/url"
	"strconv"
	"strings"
)

type Module struct {
	api               *anaconda.TwitterApi
	ConsumerKey       string `json:"consumer_key"`
	ConsumerSecret    string `json:"consumer_secret"`
	AccessToken       string `json:"access_token"`
	AccessTokenSecret string `json:"access_token_secret"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "twitter"
}

func (m *Module) Help() string {
	return "USAGE: !tweet TEXT || !reply ID TEXT || !retweet ID || !favorite ID"
}

func (m *Module) Defaults() {
	return
}

func (m *Module) Load(client *irc.Client) error {
	anaconda.SetConsumerKey(m.ConsumerKey)
	anaconda.SetConsumerSecret(m.ConsumerSecret)
	m.api = anaconda.NewTwitterApi(m.AccessToken, m.AccessTokenSecret)

	client.CmdHook("privmsg", m.tweetCmd)
	client.CmdHook("privmsg", m.replyCmd)
	client.CmdHook("privmsg", m.retweetCmd)
	client.CmdHook("privmsg", m.favoriteCmd)

	values := url.Values{}
	values.Add("replies", "all")
	values.Add("with", "user")

	stream := m.api.UserStream(values)
	go func(c *irc.Client, s anaconda.Stream) {
		for i := range s.C {
			t, ok := i.(anaconda.Tweet)
			if ok {
				m.notify(c, t)
			}
		}
	}(client, stream)

	return nil
}

func (m *Module) tweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!tweet" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	status := strings.Join(splited[1:], " ")
	if _, err := m.api.PostTweet(status, url.Values{}); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) replyCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 3 || splited[0] != "!reply" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	values := url.Values{}
	values.Add("in_reply_to_status_id", splited[1])

	status := strings.Join(splited[2:], " ")
	if !strings.Contains(status, "@") {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, "A reply must contain a @mention")
	}

	if _, err := m.api.PostTweet(status, values); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) retweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!retweet" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	if _, err := m.api.Retweet(int64(id), false); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) favoriteCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!favorite" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	tweet, err := m.api.Favorite(int64(id))
	if err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return client.Write("NOTICE %s :Favorited tweet %d by %s: %q",
		msg.Receiver, tweet.Id, tweet.User.ScreenName, tweet.Text)
}

func (m *Module) notify(client *irc.Client, tweet anaconda.Tweet) {
	text := strings.Replace(tweet.Text, "\n", " ", -1)
	for _, ch := range client.Channels {
		client.Write("NOTICE %s :Tweet %d by %s: %s",
			ch, tweet.Id, tweet.User.ScreenName, text)
	}
}
<commit_msg>Don't qoute tweet text<commit_after>// 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/>.

package twitter

import (
	"github.com/ChimeraCoder/anaconda"
	"github.com/nmeum/marvin/irc"
	"github.com/nmeum/marvin/modules"
	"net/url"
	"strconv"
	"strings"
)

type Module struct {
	api               *anaconda.TwitterApi
	ConsumerKey       string `json:"consumer_key"`
	ConsumerSecret    string `json:"consumer_secret"`
	AccessToken       string `json:"access_token"`
	AccessTokenSecret string `json:"access_token_secret"`
}

func Init(moduleSet *modules.ModuleSet) {
	moduleSet.Register(new(Module))
}

func (m *Module) Name() string {
	return "twitter"
}

func (m *Module) Help() string {
	return "USAGE: !tweet TEXT || !reply ID TEXT || !retweet ID || !favorite ID"
}

func (m *Module) Defaults() {
	return
}

func (m *Module) Load(client *irc.Client) error {
	anaconda.SetConsumerKey(m.ConsumerKey)
	anaconda.SetConsumerSecret(m.ConsumerSecret)
	m.api = anaconda.NewTwitterApi(m.AccessToken, m.AccessTokenSecret)

	client.CmdHook("privmsg", m.tweetCmd)
	client.CmdHook("privmsg", m.replyCmd)
	client.CmdHook("privmsg", m.retweetCmd)
	client.CmdHook("privmsg", m.favoriteCmd)

	values := url.Values{}
	values.Add("replies", "all")
	values.Add("with", "user")

	stream := m.api.UserStream(values)
	go func(c *irc.Client, s anaconda.Stream) {
		for i := range s.C {
			t, ok := i.(anaconda.Tweet)
			if ok {
				m.notify(c, t)
			}
		}
	}(client, stream)

	return nil
}

func (m *Module) tweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!tweet" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	status := strings.Join(splited[1:], " ")
	if _, err := m.api.PostTweet(status, url.Values{}); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) replyCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 3 || splited[0] != "!reply" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	values := url.Values{}
	values.Add("in_reply_to_status_id", splited[1])

	status := strings.Join(splited[2:], " ")
	if !strings.Contains(status, "@") {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, "A reply must contain a @mention")
	}

	if _, err := m.api.PostTweet(status, values); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) retweetCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!retweet" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	if _, err := m.api.Retweet(int64(id), false); err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return nil
}

func (m *Module) favoriteCmd(client *irc.Client, msg irc.Message) error {
	splited := strings.Fields(msg.Data)
	if len(splited) < 2 || splited[0] != "!favorite" || !client.IsConnected(msg.Receiver) {
		return nil
	}

	id, err := strconv.Atoi(splited[1])
	if err != nil {
		return err
	}

	tweet, err := m.api.Favorite(int64(id))
	if err != nil {
		return client.Write("NOTICE %s :ERROR: %s",
			msg.Receiver, err.Error())
	}

	return client.Write("NOTICE %s :Favorited tweet %d by %s: %s",
		msg.Receiver, tweet.Id, tweet.User.ScreenName, tweet.Text)
}

func (m *Module) notify(client *irc.Client, tweet anaconda.Tweet) {
	text := strings.Replace(tweet.Text, "\n", " ", -1)
	for _, ch := range client.Channels {
		client.Write("NOTICE %s :Tweet %d by %s: %s",
			ch, tweet.Id, tweet.User.ScreenName, text)
	}
}
<|endoftext|>


<commit_before>package database

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"mud/utils"
)

type dbError struct {
	message string
}

func (self dbError) Error() string {
	return self.message
}

func newDbError(message string) dbError {
	var err dbError
	err.message = message
	return err
}

type collectionName string

func getCollection(session *mgo.Session, collection collectionName) *mgo.Collection {
	return session.DB("mud").C(string(collection))
}

// Collection names
const (
	cUsers      = collectionName("users")
	cCharacters = collectionName("characters")
	cRooms      = collectionName("rooms")
)

// Field names
const (
	fId          = "_id"
	fName        = "name"
	fCharacters  = "characters"
	fRoom        = "room"
	fLocation    = "location"
	fTitle       = "title"
	fDescription = "description"
	fNorth       = "exit_north"
	fEast        = "exit_east"
	fSouth       = "exit_south"
	fWest        = "exit_west"
	fUp          = "exit_up"
	fDown        = "exit_down"
	fDefault     = "default"
)

// DB commands
const (
	SET  = "$set"
	PUSH = "$push"
	PULL = "$pull"
)

func FindUser(session *mgo.Session, name string) (bool, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: name})

	count, err := q.Count()

	if err != nil {
		return false, err
	}

	return count > 0, nil
}

func NewUser(session *mgo.Session, name string) error {

	found, err := FindUser(session, name)

	if err != nil {
		return err
	}

	if found {
		return newDbError("That user already exists")
	}

	c := getCollection(session, cUsers)
	c.Insert(bson.M{fName: name})

	return nil
}

func GetCharacterRoom(session *mgo.Session, character Character) (Room, error) {
	return GetRoom(session, character.RoomId)
}

func FindObject(session *mgo.Session, collection collectionName, query interface{}, object interface{}) error {
	c := getCollection(session, collection)
	q := c.Find(query)

	count, err := q.Count()

	if err != nil {
		return err
	}

	if count == 0 {
		return newDbError(fmt.Sprintf("Query return no results: %v", query))
	}

	err = q.One(object)

	return err
}

func FindRoom(session *mgo.Session, query interface{}) (Room, error) {
	var room Room
	err := FindObject(session, cRooms, query, &room)
	return room, err
}

func FindCharacter(session *mgo.Session, query interface{}) (Character, error) {
	var character Character
	err := FindObject(session, cCharacters, query, &character)
	return character, err
}

func GetCharacter(session *mgo.Session, id bson.ObjectId) (Character, error) {
	return FindCharacter(session, bson.M{fId: id})
}

func GetCharacterByName(session *mgo.Session, name string) (Character, error) {
	return FindCharacter(session, bson.M{fName: name})
}

func GetRoom(session *mgo.Session, id bson.ObjectId) (Room, error) {
	return FindRoom(session, bson.M{fId: id})
}

func GetRoomByLocation(session *mgo.Session, location Coordinate) (Room, error) {
	return FindRoom(session, bson.M{fLocation: location})
}

func CreateRoom(session *mgo.Session, room Room) (Room, error) {
	c := getCollection(session, cRooms)
	err := c.Insert(room)

	if err != nil {
		fmt.Printf("Error creating room: %v\n", err)
		return room, err
	}

	room, err = GetRoomByLocation(session, room.Location)

	return room, err
}

func CreateCharacter(session *mgo.Session, userName string, characterName string) (Character, error) {
	character, err := GetCharacterByName(session, characterName)

	if err == nil {
		return character, newDbError("That character already exists")
	}

	character = newCharacter(characterName)

	characterCollection := getCollection(session, cCharacters)
	err = characterCollection.Insert(character)

	if err != nil {
		fmt.Printf("Error inserting new character object into database: %v\n", err)
		return character, err
	}

	character, err = GetCharacterByName(session, character.Name)

	startingRoom, err := StartingRoom(session)

	if err != nil {
		fmt.Printf("Error getting starting room: %v\n", err)
		return character, err
	}

	character.RoomId = startingRoom.Id
	err = CommitCharacter(session, character)

	if err != nil {
		fmt.Printf("Error committing character object: %v\n", err)
		return character, err
	}

	if err == nil {
		userCollection := getCollection(session, cUsers)
		err = userCollection.Update(bson.M{fName: userName}, bson.M{PUSH: bson.M{fCharacters: character.Id}})

		if err != nil {
			fmt.Printf("Error updating user with new character data: %v\n", err)
		}
	}

	return character, err
}

func SetCharacterRoom(session *mgo.Session, character string, roomId bson.ObjectId) error {
	c := getCollection(session, cCharacters)
	err := c.Update(bson.M{fName: character}, bson.M{SET: bson.M{fRoom: roomId}})

	if err != nil {
		fmt.Printf("Failed setting character room :%v\n", err)
	}

	return err
}

func GetUserCharacters(session *mgo.Session, userName string) ([]Character, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: userName})

	result := map[string][]bson.ObjectId{}
	err := q.One(&result)

	var characters []Character
	for _, charId := range result[fCharacters] {
		character, err := GetCharacter(session, charId)

		if err != nil {
			fmt.Printf("Failed to find character with id %s, belonging to user %s: %s\n", charId, userName, err)
		} else {
			characters = append(characters, character)
		}
	}

	return characters, err
}

func DeleteCharacter(session *mgo.Session, user string, character string) error {
	c := getCollection(session, cUsers)
	c.Update(bson.M{fName: user}, bson.M{PULL: bson.M{fCharacters: utils.Simplify(character)}})

	c = getCollection(session, cCharacters)
	c.Remove(bson.M{fName: character})

	return nil
}

func StartingRoom(session *mgo.Session) (Room, error) {
	c := getCollection(session, cRooms)
	q := c.Find(bson.M{fDefault: true})

	count, err := q.Count()

	var room Room
	if err != nil {
		return room, err
	}

	if count == 0 {
		return room, newDbError("No default room found")
	}

	if count > 1 {
		fmt.Printf("Warning: More than one default room found\n")
	}

	err = q.One(&room)

	return room, err
}

func GenerateDefaultMap(session *mgo.Session) {
	c := getCollection(session, cRooms)
	c.DropCollection()

	room := newRoom()
	room.Location = Coordinate{0, 0, 0}
	room.Default = true

	CreateRoom(session, room)
}

func SetRoomTitle(session *mgo.Session, room Room, title string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fTitle: title}})
}

func SetRoomDescription(session *mgo.Session, room Room, description string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fDescription: description}})
}

func directionToFieldName(direction ExitDirection) string {
	switch direction {
	case DirectionNorth:
		return fNorth
	case DirectionEast:
		return fEast
	case DirectionSouth:
		return fSouth
	case DirectionWest:
		return fWest
	case DirectionUp:
		return fUp
	case DirectionDown:
		return fDown
	}

	// Wouldn't ever expect DirectionNone to be passed here
	panic("Unexpected code path")
}

func CommitRoom(session *mgo.Session, room Room) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, room)
}

func CommitCharacter(session *mgo.Session, character Character) error {
	c := getCollection(session, cCharacters)
	return c.Update(bson.M{fId: character.Id}, character)
}

func MoveCharacter(session *mgo.Session, character *Character, direction ExitDirection) (Room, error) {
	room, err := GetRoom(session, character.RoomId)

	if err != nil {
		return room, err
	}

	newLocation := room.Location

	switch direction {
	case DirectionNorth:
		newLocation.Y -= 1
	case DirectionEast:
		newLocation.X += 1
	case DirectionSouth:
		newLocation.Y += 1
	case DirectionWest:
		newLocation.X -= 1
	case DirectionUp:
		newLocation.Z -= 1
	case DirectionDown:
		newLocation.Z += 1
	default:
		panic("Unexpected code path")
	}

	room, err = GetRoomByLocation(session, newLocation)

	if err != nil {
		fmt.Printf("No room found at location %v, creating a new one\n", newLocation)
		room = newRoom()

		switch direction {
		case DirectionNorth:
			room.ExitSouth = true
		case DirectionEast:
			room.ExitWest = true
		case DirectionSouth:
			room.ExitNorth = true
		case DirectionWest:
			room.ExitEast = true
		case DirectionUp:
			room.ExitDown = true
		case DirectionDown:
			room.ExitUp = true
		default:
			panic("Unexpected code path")
		}

		room.Location = newLocation
		room, err = CreateRoom(session, room)
	} else {
		character.RoomId = room.Id
		err = CommitCharacter(session, *character)
	}

	return room, err
}

// vim: nocindent
<commit_msg>Remove unused function<commit_after>package database

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"mud/utils"
)

type dbError struct {
	message string
}

func (self dbError) Error() string {
	return self.message
}

func newDbError(message string) dbError {
	var err dbError
	err.message = message
	return err
}

type collectionName string

func getCollection(session *mgo.Session, collection collectionName) *mgo.Collection {
	return session.DB("mud").C(string(collection))
}

// Collection names
const (
	cUsers      = collectionName("users")
	cCharacters = collectionName("characters")
	cRooms      = collectionName("rooms")
)

// Field names
const (
	fId          = "_id"
	fName        = "name"
	fCharacters  = "characters"
	fRoom        = "room"
	fLocation    = "location"
	fTitle       = "title"
	fDescription = "description"
	fNorth       = "exit_north"
	fEast        = "exit_east"
	fSouth       = "exit_south"
	fWest        = "exit_west"
	fUp          = "exit_up"
	fDown        = "exit_down"
	fDefault     = "default"
)

// DB commands
const (
	SET  = "$set"
	PUSH = "$push"
	PULL = "$pull"
)

func FindUser(session *mgo.Session, name string) (bool, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: name})

	count, err := q.Count()

	if err != nil {
		return false, err
	}

	return count > 0, nil
}

func NewUser(session *mgo.Session, name string) error {

	found, err := FindUser(session, name)

	if err != nil {
		return err
	}

	if found {
		return newDbError("That user already exists")
	}

	c := getCollection(session, cUsers)
	c.Insert(bson.M{fName: name})

	return nil
}

func GetCharacterRoom(session *mgo.Session, character Character) (Room, error) {
	return GetRoom(session, character.RoomId)
}

func FindObject(session *mgo.Session, collection collectionName, query interface{}, object interface{}) error {
	c := getCollection(session, collection)
	q := c.Find(query)

	count, err := q.Count()

	if err != nil {
		return err
	}

	if count == 0 {
		return newDbError(fmt.Sprintf("Query return no results: %v", query))
	}

	err = q.One(object)

	return err
}

func FindRoom(session *mgo.Session, query interface{}) (Room, error) {
	var room Room
	err := FindObject(session, cRooms, query, &room)
	return room, err
}

func FindCharacter(session *mgo.Session, query interface{}) (Character, error) {
	var character Character
	err := FindObject(session, cCharacters, query, &character)
	return character, err
}

func GetCharacter(session *mgo.Session, id bson.ObjectId) (Character, error) {
	return FindCharacter(session, bson.M{fId: id})
}

func GetCharacterByName(session *mgo.Session, name string) (Character, error) {
	return FindCharacter(session, bson.M{fName: name})
}

func GetRoom(session *mgo.Session, id bson.ObjectId) (Room, error) {
	return FindRoom(session, bson.M{fId: id})
}

func GetRoomByLocation(session *mgo.Session, location Coordinate) (Room, error) {
	return FindRoom(session, bson.M{fLocation: location})
}

func CreateRoom(session *mgo.Session, room Room) (Room, error) {
	c := getCollection(session, cRooms)
	err := c.Insert(room)

	if err != nil {
		fmt.Printf("Error creating room: %v\n", err)
		return room, err
	}

	room, err = GetRoomByLocation(session, room.Location)

	return room, err
}

func CreateCharacter(session *mgo.Session, userName string, characterName string) (Character, error) {
	character, err := GetCharacterByName(session, characterName)

	if err == nil {
		return character, newDbError("That character already exists")
	}

	character = newCharacter(characterName)

	characterCollection := getCollection(session, cCharacters)
	err = characterCollection.Insert(character)

	if err != nil {
		fmt.Printf("Error inserting new character object into database: %v\n", err)
		return character, err
	}

	character, err = GetCharacterByName(session, character.Name)

	startingRoom, err := StartingRoom(session)

	if err != nil {
		fmt.Printf("Error getting starting room: %v\n", err)
		return character, err
	}

	character.RoomId = startingRoom.Id
	err = CommitCharacter(session, character)

	if err != nil {
		fmt.Printf("Error committing character object: %v\n", err)
		return character, err
	}

	if err == nil {
		userCollection := getCollection(session, cUsers)
		err = userCollection.Update(bson.M{fName: userName}, bson.M{PUSH: bson.M{fCharacters: character.Id}})

		if err != nil {
			fmt.Printf("Error updating user with new character data: %v\n", err)
		}
	}

	return character, err
}

func GetUserCharacters(session *mgo.Session, userName string) ([]Character, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: userName})

	result := map[string][]bson.ObjectId{}
	err := q.One(&result)

	var characters []Character
	for _, charId := range result[fCharacters] {
		character, err := GetCharacter(session, charId)

		if err != nil {
			fmt.Printf("Failed to find character with id %s, belonging to user %s: %s\n", charId, userName, err)
		} else {
			characters = append(characters, character)
		}
	}

	return characters, err
}

func DeleteCharacter(session *mgo.Session, user string, character string) error {
	c := getCollection(session, cUsers)
	c.Update(bson.M{fName: user}, bson.M{PULL: bson.M{fCharacters: utils.Simplify(character)}})

	c = getCollection(session, cCharacters)
	c.Remove(bson.M{fName: character})

	return nil
}

func StartingRoom(session *mgo.Session) (Room, error) {
	c := getCollection(session, cRooms)
	q := c.Find(bson.M{fDefault: true})

	count, err := q.Count()

	var room Room
	if err != nil {
		return room, err
	}

	if count == 0 {
		return room, newDbError("No default room found")
	}

	if count > 1 {
		fmt.Printf("Warning: More than one default room found\n")
	}

	err = q.One(&room)

	return room, err
}

func GenerateDefaultMap(session *mgo.Session) {
	c := getCollection(session, cRooms)
	c.DropCollection()

	room := newRoom()
	room.Location = Coordinate{0, 0, 0}
	room.Default = true

	CreateRoom(session, room)
}

func SetRoomTitle(session *mgo.Session, room Room, title string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fTitle: title}})
}

func SetRoomDescription(session *mgo.Session, room Room, description string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fDescription: description}})
}

func directionToFieldName(direction ExitDirection) string {
	switch direction {
	case DirectionNorth:
		return fNorth
	case DirectionEast:
		return fEast
	case DirectionSouth:
		return fSouth
	case DirectionWest:
		return fWest
	case DirectionUp:
		return fUp
	case DirectionDown:
		return fDown
	}

	// Wouldn't ever expect DirectionNone to be passed here
	panic("Unexpected code path")
}

func CommitRoom(session *mgo.Session, room Room) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, room)
}

func CommitCharacter(session *mgo.Session, character Character) error {
	c := getCollection(session, cCharacters)
	return c.Update(bson.M{fId: character.Id}, character)
}

func MoveCharacter(session *mgo.Session, character *Character, direction ExitDirection) (Room, error) {
	room, err := GetRoom(session, character.RoomId)

	if err != nil {
		return room, err
	}

	newLocation := room.Location

	switch direction {
	case DirectionNorth:
		newLocation.Y -= 1
	case DirectionEast:
		newLocation.X += 1
	case DirectionSouth:
		newLocation.Y += 1
	case DirectionWest:
		newLocation.X -= 1
	case DirectionUp:
		newLocation.Z -= 1
	case DirectionDown:
		newLocation.Z += 1
	default:
		panic("Unexpected code path")
	}

	room, err = GetRoomByLocation(session, newLocation)

	if err != nil {
		fmt.Printf("No room found at location %v, creating a new one\n", newLocation)
		room = newRoom()

		switch direction {
		case DirectionNorth:
			room.ExitSouth = true
		case DirectionEast:
			room.ExitWest = true
		case DirectionSouth:
			room.ExitNorth = true
		case DirectionWest:
			room.ExitEast = true
		case DirectionUp:
			room.ExitDown = true
		case DirectionDown:
			room.ExitUp = true
		default:
			panic("Unexpected code path")
		}

		room.Location = newLocation
		room, err = CreateRoom(session, room)
	} else {
		character.RoomId = room.Id
		err = CommitCharacter(session, *character)
	}

	return room, err
}

// vim: nocindent
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"regexp"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "no pattern\n")
		return
	}

	re, err := regexp.Compile(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return
	}

	if len(os.Args) == 2 {
		doGrep(re, os.Stdin)
		return
	}

	for _, f := range os.Args[2:] {
		fp, err := os.Open(f)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v\n", err)
			return
		}
		defer fp.Close()

		if e := doGrep(re, fp); e != nil {
			fmt.Fprintf(os.Stderr, "%v\n", e)
			return
		}
	}
}

func doGrep(re *regexp.Regexp, fp *os.File) error {
	r := bufio.NewReader(fp)
	w := bufio.NewWriter(os.Stdout)

	for {
		line, err := r.ReadString('\n')
		if err == io.EOF {
			break
		}

		if re.MatchString(line) {
			if _, e := w.WriteString(line); e != nil {
				return e
			}

			if e := w.Flush(); e != nil {
				return e
			}
		}
	}

	return nil
}
<commit_msg>grep: add flags<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
)

func main() {
	var ins, inv bool
	flag.BoolVar(&ins, "i", false, "Perform case insensitive matching")
	flag.BoolVar(&inv, "v", false, "Selected lines are those NOT matching any of the specified patterns")
	flag.Parse()

	args := flag.Args()

	if len(args) == 0 {
		fmt.Fprintf(os.Stderr, "no pattern\n")
		return
	}

	expr := args[0]
	if ins {
		expr = "(?i)" + expr
	}

	re, err := regexp.Compile(expr)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		return
	}

	if len(args) == 1 {
		doGrep(re, os.Stdin, inv)
		return
	}

	for _, f := range args[1:] {
		fp, err := os.Open(f)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v\n", err)
			return
		}
		defer fp.Close()

		if e := doGrep(re, fp, inv); e != nil {
			fmt.Fprintf(os.Stderr, "%v\n", e)
			return
		}
	}
}

func doGrep(re *regexp.Regexp, fp *os.File, inv bool) error {
	r := bufio.NewReader(fp)
	w := bufio.NewWriter(os.Stdout)

	for {
		line, err := r.ReadString('\n')
		if err == io.EOF {
			break
		}

		disp := re.MatchString(line) == !inv
		if disp {
			if _, e := w.WriteString(line); e != nil {
				return e
			}

			if e := w.Flush(); e != nil {
				return e
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc. All Rights Reserved.
//
// 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.

// +build integration,go1.7

package testing

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"runtime"
	"testing"
	"text/template"
	"time"

	"github.com/GoogleCloudPlatform/google-cloud-go/profiler/proftest"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	compute "google.golang.org/api/compute/v1"
)

var (
	repo   = flag.String("repo", "https://github.com/GoogleCloudPlatform/cloud-profiler-nodejs.git", "git repo to test")
	branch = flag.String("branch", "", "git branch to test")
	commit = flag.String("commit", "", "git commit to test")
	pr     = flag.Int("pr", 0, "git pull request to test")
	runID  = time.Now().Unix()
)

const cloudScope = "https://www.googleapis.com/auth/cloud-platform"

const startupTemplate = `
#! /bin/bash

(
# Shut down the VM in 5 minutes after this script exits
# to stop accounting the VM for billing and cores quota.
trap "sleep 300 && poweroff" EXIT

# Fail on any error
set -eo pipefail

# Display commands being run
set -x
# Install git
apt-get update >/dev/null
apt-get -y -q install git build-essential  >/dev/null

# Install desired version of Node.js
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash >/dev/null
export NVM_DIR="$HOME/.nvm" >/dev/null
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" >/dev/null

# nvm install writes to stderr and stdout on successful install, so both are
# redirected.
nvm install {{.NodeVersion}} &>/dev/null
npm -v
node -v

# Install agent
git clone {{.Repo}}
cd cloud-profiler-nodejs
git fetch origin {{if .PR}}pull/{{.PR}}/head{{else}}{{.Branch}}{{end}}:pull_branch
git checkout pull_branch
git reset --hard {{.Commit}}
npm install >/dev/null
npm run compile
npm pack >/dev/null
VERSION=$(node -e "console.log(require('./package.json').version);")
PROFILER="$HOME/cloud-profiler-nodejs/google-cloud-profiler-$VERSION.tgz"

TESTDIR="$HOME/test"
mkdir -p "$TESTDIR"
cp "testing/busybench.js" "$TESTDIR"
cd "$TESTDIR"

npm install "$PROFILER" >/dev/null

# Run benchmark with agent
GCLOUD_PROFILER_LOGLEVEL=5 GAE_SERVICE={{.Service}} node --require @google-cloud/profiler busybench.js 600

# Indicate to test that script has finished running
echo "busybench finished profiling"

# Write output to serial port 2 with timestamp.
) 2>&1 | while read line; do echo "$(date): ${line}"; done >/dev/ttyS1
`

type profileSummary struct {
	profileType  string
	functionName string
}

type nodeGCETestCase struct {
	proftest.InstanceConfig
	name         string
	nodeVersion  string
	wantProfiles []profileSummary
}

func (tc *nodeGCETestCase) initializeStartUpScript(template *template.Template) error {
	var buf bytes.Buffer
	err := template.Execute(&buf,
		struct {
			Service     string
			NodeVersion string
			Repo        string
			PR          int
			Branch      string
			Commit      string
		}{
			Service:     tc.name,
			NodeVersion: tc.nodeVersion,
			Repo:        *repo,
			PR:          *pr,
			Branch:      *branch,
			Commit:      *commit,
		})
	if err != nil {
		return fmt.Errorf("failed to render startup script for %s: %v", tc.name, err)
	}
	tc.StartupScript = buf.String()
	return nil
}

func TestAgentIntegration(t *testing.T) {
	projectID := os.Getenv("GCLOUD_TESTS_NODEJS_PROJECT_ID")
	if projectID == "" {
		t.Fatalf("Getenv(GCLOUD_TESTS_NODEJS_PROJECT_ID) got empty string")
	}

	zone := os.Getenv("GCLOUD_TESTS_NODEJS_ZONE")
	if zone == "" {
		t.Fatalf("Getenv(GCLOUD_TESTS_NODEJS_ZONE) got empty string")
	}

	if *commit == "" {
		t.Fatal("commit flag is not set")
	}

	ctx := context.Background()

	client, err := google.DefaultClient(ctx, cloudScope)
	if err != nil {
		t.Fatalf("failed to get default client: %v", err)
	}

	computeService, err := compute.New(client)
	if err != nil {
		t.Fatalf("failed to initialize compute Service: %v", err)
	}

	template, err := template.New("startupScript").Parse(startupTemplate)
	if err != nil {
		t.Fatalf("failed to parse startup script template: %v", err)
	}

	gceTr := proftest.GCETestRunner{
		TestRunner: proftest.TestRunner{
			Client: client,
		},
		ComputeService: computeService,
	}

	testcases := []nodeGCETestCase{
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node6-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node6-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "6",
		},
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node8-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node8-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "8",
		},
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node9-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node9-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "9",
		},
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node10-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node10-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "10",
		},
	}

	// Allow test cases to run in parallel.
	runtime.GOMAXPROCS(len(testcases))

	for _, tc := range testcases {
		tc := tc // capture range variable
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			if err := tc.initializeStartUpScript(template); err != nil {
				t.Fatalf("failed to initialize startup script: %v", err)
			}

			gceTr.StartInstance(ctx, &tc.InstanceConfig)
			defer func() {
				if gceTr.DeleteInstance(ctx, &tc.InstanceConfig); err != nil {
					t.Fatal(err)
				}
			}()

			timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute*25)
			defer cancel()
			if err := gceTr.PollForSerialOutput(timeoutCtx, &tc.InstanceConfig, "busybench finished profiling"); err != nil {
				t.Fatal(err)
			}

			timeNow := time.Now()
			endTime := timeNow.Format(time.RFC3339)
			startTime := timeNow.Add(-1 * time.Hour).Format(time.RFC3339)
			for _, wantProfile := range tc.wantProfiles {
				pr, err := gceTr.TestRunner.QueryProfiles(tc.ProjectID, tc.name, startTime, endTime, wantProfile.profileType)
				if err != nil {
					t.Errorf("QueryProfiles(%s, %s, %s, %s, %s) got error: %v", tc.ProjectID, tc.name, startTime, endTime, wantProfile.profileType, err)
					continue
				}
				if err := pr.HasFunction(wantProfile.functionName); err != nil {
					t.Errorf("Function %s not found in profiles of type %s: %v", wantProfile.functionName, wantProfile.profileType, err)
				}
			}
		})
	}
}
<commit_msg>chore: retry flaky steps in e2e test (#208)<commit_after>// Copyright 2018 Google Inc. All Rights Reserved.
//
// 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.

// +build integration,go1.7

package testing

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"runtime"
	"testing"
	"text/template"
	"time"

	"github.com/GoogleCloudPlatform/google-cloud-go/profiler/proftest"
	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	compute "google.golang.org/api/compute/v1"
)

var (
	repo   = flag.String("repo", "https://github.com/GoogleCloudPlatform/cloud-profiler-nodejs.git", "git repo to test")
	branch = flag.String("branch", "", "git branch to test")
	commit = flag.String("commit", "", "git commit to test")
	pr     = flag.Int("pr", 0, "git pull request to test")
	runID  = time.Now().Unix()
)

const cloudScope = "https://www.googleapis.com/auth/cloud-platform"

const startupTemplate = `
#! /bin/bash

(
# Shut down the VM in 5 minutes after this script exits
# to stop accounting the VM for billing and cores quota.
trap "sleep 300 && poweroff" EXIT

retry() {
  for i in {1..3}; do
    "${@}" && return 0
  done
  return 1
}

# Fail on any error
set -eo pipefail

# Display commands being run
set -x
# Install git
retry apt-get update >/dev/null
retry apt-get -y -q install git build-essential >/dev/null

# Install desired version of Node.js
retry curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash >/dev/null
export NVM_DIR="$HOME/.nvm" >/dev/null
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" >/dev/null

# nvm install writes to stderr and stdout on successful install, so both are
# redirected.
retry nvm install {{.NodeVersion}} &>/dev/null
npm -v
node -v

# Install agent
retry git clone {{.Repo}}
cd cloud-profiler-nodejs
retry git fetch origin {{if .PR}}pull/{{.PR}}/head{{else}}{{.Branch}}{{end}}:pull_branch
git checkout pull_branch
git reset --hard {{.Commit}}
retry npm install >/dev/null
npm run compile
npm pack >/dev/null
VERSION=$(node -e "console.log(require('./package.json').version);")
PROFILER="$HOME/cloud-profiler-nodejs/google-cloud-profiler-$VERSION.tgz"

TESTDIR="$HOME/test"
mkdir -p "$TESTDIR"
cp "testing/busybench.js" "$TESTDIR"
cd "$TESTDIR"

npm install "$PROFILER" >/dev/null

# Run benchmark with agent
GCLOUD_PROFILER_LOGLEVEL=5 GAE_SERVICE={{.Service}} node --require @google-cloud/profiler busybench.js 600

# Indicate to test that script has finished running
echo "busybench finished profiling"

# Write output to serial port 2 with timestamp.
) 2>&1 | while read line; do echo "$(date): ${line}"; done >/dev/ttyS1
`

type profileSummary struct {
	profileType  string
	functionName string
}

type nodeGCETestCase struct {
	proftest.InstanceConfig
	name         string
	nodeVersion  string
	wantProfiles []profileSummary
}

func (tc *nodeGCETestCase) initializeStartUpScript(template *template.Template) error {
	var buf bytes.Buffer
	err := template.Execute(&buf,
		struct {
			Service     string
			NodeVersion string
			Repo        string
			PR          int
			Branch      string
			Commit      string
		}{
			Service:     tc.name,
			NodeVersion: tc.nodeVersion,
			Repo:        *repo,
			PR:          *pr,
			Branch:      *branch,
			Commit:      *commit,
		})
	if err != nil {
		return fmt.Errorf("failed to render startup script for %s: %v", tc.name, err)
	}
	tc.StartupScript = buf.String()
	return nil
}

func TestAgentIntegration(t *testing.T) {
	projectID := os.Getenv("GCLOUD_TESTS_NODEJS_PROJECT_ID")
	if projectID == "" {
		t.Fatalf("Getenv(GCLOUD_TESTS_NODEJS_PROJECT_ID) got empty string")
	}

	zone := os.Getenv("GCLOUD_TESTS_NODEJS_ZONE")
	if zone == "" {
		t.Fatalf("Getenv(GCLOUD_TESTS_NODEJS_ZONE) got empty string")
	}

	if *commit == "" {
		t.Fatal("commit flag is not set")
	}

	ctx := context.Background()

	client, err := google.DefaultClient(ctx, cloudScope)
	if err != nil {
		t.Fatalf("failed to get default client: %v", err)
	}

	computeService, err := compute.New(client)
	if err != nil {
		t.Fatalf("failed to initialize compute Service: %v", err)
	}

	template, err := template.New("startupScript").Parse(startupTemplate)
	if err != nil {
		t.Fatalf("failed to parse startup script template: %v", err)
	}

	gceTr := proftest.GCETestRunner{
		TestRunner: proftest.TestRunner{
			Client: client,
		},
		ComputeService: computeService,
	}

	testcases := []nodeGCETestCase{
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node6-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node6-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "6",
		},
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node8-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node8-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "8",
		},
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node9-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node9-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "9",
		},
		{
			InstanceConfig: proftest.InstanceConfig{
				ProjectID:   projectID,
				Zone:        zone,
				Name:        fmt.Sprintf("profiler-test-node10-%d", runID),
				MachineType: "n1-standard-1",
			},
			name:         fmt.Sprintf("profiler-test-node10-%d-gce", runID),
			wantProfiles: []profileSummary{{"WALL", "busyLoop"}, {"HEAP", "benchmark"}},
			nodeVersion:  "10",
		},
	}

	// Allow test cases to run in parallel.
	runtime.GOMAXPROCS(len(testcases))

	for _, tc := range testcases {
		tc := tc // capture range variable
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			if err := tc.initializeStartUpScript(template); err != nil {
				t.Fatalf("failed to initialize startup script: %v", err)
			}

			gceTr.StartInstance(ctx, &tc.InstanceConfig)
			defer func() {
				if gceTr.DeleteInstance(ctx, &tc.InstanceConfig); err != nil {
					t.Fatal(err)
				}
			}()

			timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute*25)
			defer cancel()
			if err := gceTr.PollForSerialOutput(timeoutCtx, &tc.InstanceConfig, "busybench finished profiling"); err != nil {
				t.Fatal(err)
			}

			timeNow := time.Now()
			endTime := timeNow.Format(time.RFC3339)
			startTime := timeNow.Add(-1 * time.Hour).Format(time.RFC3339)
			for _, wantProfile := range tc.wantProfiles {
				pr, err := gceTr.TestRunner.QueryProfiles(tc.ProjectID, tc.name, startTime, endTime, wantProfile.profileType)
				if err != nil {
					t.Errorf("QueryProfiles(%s, %s, %s, %s, %s) got error: %v", tc.ProjectID, tc.name, startTime, endTime, wantProfile.profileType, err)
					continue
				}
				if err := pr.HasFunction(wantProfile.functionName); err != nil {
					t.Errorf("Function %s not found in profiles of type %s: %v", wantProfile.functionName, wantProfile.profileType, err)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"sort"
	"strings"
	"syscall"

	weavenet "github.com/weaveworks/weave/net"
)

func main() {
	if len(os.Args) <= 1 {
		os.Exit(0)
	}

	var (
		args         = os.Args[1:]
		notInExec    = true
		rewriteHosts = true
	)

	if args[0] == "-s" {
		notInExec = false
		rewriteHosts = false
		args = args[1:]
	}

	if args[0] == "-h" {
		rewriteHosts = false
		args = args[1:]
	}

	if notInExec {
		usr2 := make(chan os.Signal)
		signal.Notify(usr2, syscall.SIGUSR2)
		<-usr2
	}

	iface, err := weavenet.EnsureInterface("ethwe", -1)
	checkErr(err)

	if rewriteHosts {
		updateHosts(iface)
	}

	binary, err := exec.LookPath(args[0])
	checkErr(err)

	checkErr(syscall.Exec(binary, args, os.Environ()))
}

func checkErr(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

// Prepend the addresses to /etc/hosts, removing the docker address
func updateHosts(iface *net.Interface) {
	addrs, err := iface.Addrs()
	checkErr(err)
	if len(addrs) == 0 {
		return
	}
	hostname, err := os.Hostname()
	checkErr(err)

	hosts := parseHosts()

	// Remove existing ips pointing to our hostname
	toRemove := []string{}
	for ip, addrs := range hosts {
		for _, addr := range addrs {
			if addr == hostname {
				toRemove = append(toRemove, ip)
				break
			}
		}
	}
	for _, ip := range toRemove {
		delete(hosts, ip)
	}

	// Add the weave ip(s)
	for _, addr := range addrs {
		if addr, ok := addr.(*net.IPNet); ok {
			ip := addr.IP.String()
			hosts[ip] = append(hosts[ip], hostname)
		}
	}

	writeHosts(hosts)
}

func parseHosts() map[string][]string {
	f, err := os.Open("/etc/hosts")
	checkErr(err)
	defer f.Close()
	ips := map[string][]string{}
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()

		// Remove any comments
		if i := strings.IndexByte(line, '#'); i != -1 {
			line = line[:i]
		}

		fields := strings.Fields(line)
		if len(fields) > 0 {
			ips[fields[0]] = fields[1:]
		}
	}
	checkErr(scanner.Err())
	return ips
}

func writeHosts(contents map[string][]string) {
	ips := []string{}
	for ip := range contents {
		ips = append(ips, ip)
	}
	sort.Strings(ips)

	buf := &bytes.Buffer{}
	for _, ip := range ips {
		if addrs := contents[ip]; len(addrs) > 0 {
			fmt.Fprintf(buf, "%s\t%s\n", ip, strings.Join(addrs, " "))
		}
	}
	checkErr(ioutil.WriteFile("/etc/hosts", buf.Bytes(), 644))
}
<commit_msg>Review feedback<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"sort"
	"strings"
	"syscall"

	weavenet "github.com/weaveworks/weave/net"
)

func main() {
	if len(os.Args) <= 1 {
		os.Exit(0)
	}

	var (
		args         = os.Args[1:]
		notInExec    = true
		rewriteHosts = true
	)

	if args[0] == "-s" {
		notInExec = false
		rewriteHosts = false
		args = args[1:]
	}

	if args[0] == "-h" {
		rewriteHosts = false
		args = args[1:]
	}

	if notInExec {
		usr2 := make(chan os.Signal)
		signal.Notify(usr2, syscall.SIGUSR2)
		<-usr2
	}

	iface, err := weavenet.EnsureInterface("ethwe", -1)
	checkErr(err)

	if rewriteHosts {
		updateHosts(iface)
	}

	binary, err := exec.LookPath(args[0])
	checkErr(err)

	checkErr(syscall.Exec(binary, args, os.Environ()))
}

func checkErr(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func updateHosts(iface *net.Interface) {
	addrs, err := iface.Addrs()
	checkErr(err)
	if len(addrs) == 0 {
		return
	}
	hostname, err := os.Hostname()
	checkErr(err)

	hosts := parseHosts()

	// Remove existing ips pointing to our hostname
	toRemove := []string{}
	for ip, addrs := range hosts {
		for _, addr := range addrs {
			if addr == hostname {
				toRemove = append(toRemove, ip)
				break
			}
		}
	}
	for _, ip := range toRemove {
		delete(hosts, ip)
	}

	// Add the weave ip(s)
	for _, addr := range addrs {
		if addr, ok := addr.(*net.IPNet); ok {
			ip := addr.IP.String()
			hosts[ip] = append(hosts[ip], hostname)
		}
	}

	writeHosts(hosts)
}

func parseHosts() map[string][]string {
	f, err := os.Open("/etc/hosts")
	checkErr(err)
	defer f.Close()
	ips := map[string][]string{}
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()

		// Remove any comments
		if i := strings.IndexByte(line, '#'); i != -1 {
			line = line[:i]
		}

		fields := strings.Fields(line)
		if len(fields) > 0 {
			ips[fields[0]] = append(ips[fields[0]], fields[1:]...)
		}
	}
	checkErr(scanner.Err())
	return ips
}

func writeHosts(contents map[string][]string) {
	ips := []string{}
	for ip := range contents {
		ips = append(ips, ip)
	}
	sort.Strings(ips)

	buf := &bytes.Buffer{}
	fmt.Fprintln(buf, "# modified by weave")
	for _, ip := range ips {
		if addrs := contents[ip]; len(addrs) > 0 {
			fmt.Fprintf(buf, "%s\t%s\n", ip, strings.Join(uniqueStrs(addrs), " "))
		}
	}
	checkErr(ioutil.WriteFile("/etc/hosts", buf.Bytes(), 644))
}

func uniqueStrs(s []string) []string {
	m := map[string]struct{}{}
	result := []string{}
	for _, str := range s {
		if _, ok := m[str]; !ok {
			m[str] = struct{}{}
			result = append(result, str)
		}
	}
	sort.Strings(result)
	return result
}
<|endoftext|>


<commit_before>/*
Copyright 2022 The Kubernetes Authors.

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

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

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

// Package init sets debug.DumpAllNamespaceInfo as implementation in the framework
// and enables log size verification and resource gathering.
package init

import (
	"sync"
	"time"

	"github.com/onsi/ginkgo/v2"
	"k8s.io/kubernetes/test/e2e/framework"
	e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"
)

var (
	// TODO: this variable used to be a field in framework.Framework. It is
	// not clear how it was ever set. https://grep.app/search?q=AddonResourceConstraints
	// returns only the default initialization with an empty map. Perhaps it can be removed?

	// Constraints that passed to a check which is executed after data is gathered to
	// see if 99% of results are within acceptable bounds. It has to be injected in the test,
	// as expectations vary greatly. Constraints are grouped by the container names.
	AddonResourceConstraints map[string]e2edebug.ResourceConstraint
)

func init() {
	framework.NewFrameworkExtensions = append(framework.NewFrameworkExtensions,
		func(f *framework.Framework) {
			f.DumpAllNamespaceInfo = func(f *framework.Framework, ns string) {
				e2edebug.DumpAllNamespaceInfo(f.ClientSet, ns)
			}

			if framework.TestContext.GatherLogsSizes {
				var (
					wg           sync.WaitGroup
					closeChannel chan bool
					verifier     *e2edebug.LogsSizeVerifier
				)

				ginkgo.BeforeEach(func() {
					wg.Add(1)
					closeChannel = make(chan bool)
					verifier = e2edebug.NewLogsVerifier(f.ClientSet, closeChannel)
					go func() {
						defer wg.Done()
						verifier.Run()
					}()
					ginkgo.DeferCleanup(func() {
						ginkgo.By("Gathering log sizes data", func() {
							close(closeChannel)
							wg.Wait()
							f.TestSummaries = append(f.TestSummaries, verifier.GetSummary())
						})
					})
				})
			}

			if framework.TestContext.GatherKubeSystemResourceUsageData != "false" &&
				framework.TestContext.GatherKubeSystemResourceUsageData != "none" {
				ginkgo.BeforeEach(func() {
					var nodeMode e2edebug.NodesSet
					switch framework.TestContext.GatherKubeSystemResourceUsageData {
					case "master":
						nodeMode = e2edebug.MasterNodes
					case "masteranddns":
						nodeMode = e2edebug.MasterAndDNSNodes
					default:
						nodeMode = e2edebug.AllNodes
					}

					gatherer, err := e2edebug.NewResourceUsageGatherer(f.ClientSet, e2edebug.ResourceGathererOptions{
						InKubemark:                  framework.ProviderIs("kubemark"),
						Nodes:                       nodeMode,
						ResourceDataGatheringPeriod: 60 * time.Second,
						ProbeDuration:               15 * time.Second,
						PrintVerboseLogs:            false,
					}, nil)
					if err != nil {
						framework.Logf("Error while creating NewResourceUsageGatherer: %v", err)
						return
					}

					go gatherer.StartGatheringData()
					ginkgo.DeferCleanup(func() {
						ginkgo.By("Collecting resource usage data", func() {
							summary, resourceViolationError := gatherer.StopAndSummarize([]int{90, 99, 100}, AddonResourceConstraints)
							// Always record the summary, even if there was an error.
							f.TestSummaries = append(f.TestSummaries, summary)
							// Now fail if there was an error.
							framework.ExpectNoError(resourceViolationError)
						})
					})
				})
			}
		},
	)
}
<commit_msg>e2e framework: remove AddonResourceConstraints<commit_after>/*
Copyright 2022 The Kubernetes Authors.

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

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

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

// Package init sets debug.DumpAllNamespaceInfo as implementation in the framework
// and enables log size verification and resource gathering.
package init

import (
	"sync"
	"time"

	"github.com/onsi/ginkgo/v2"
	"k8s.io/kubernetes/test/e2e/framework"
	e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"
)

func init() {
	framework.NewFrameworkExtensions = append(framework.NewFrameworkExtensions,
		func(f *framework.Framework) {
			f.DumpAllNamespaceInfo = func(f *framework.Framework, ns string) {
				e2edebug.DumpAllNamespaceInfo(f.ClientSet, ns)
			}

			if framework.TestContext.GatherLogsSizes {
				var (
					wg           sync.WaitGroup
					closeChannel chan bool
					verifier     *e2edebug.LogsSizeVerifier
				)

				ginkgo.BeforeEach(func() {
					wg.Add(1)
					closeChannel = make(chan bool)
					verifier = e2edebug.NewLogsVerifier(f.ClientSet, closeChannel)
					go func() {
						defer wg.Done()
						verifier.Run()
					}()
					ginkgo.DeferCleanup(func() {
						ginkgo.By("Gathering log sizes data", func() {
							close(closeChannel)
							wg.Wait()
							f.TestSummaries = append(f.TestSummaries, verifier.GetSummary())
						})
					})
				})
			}

			if framework.TestContext.GatherKubeSystemResourceUsageData != "false" &&
				framework.TestContext.GatherKubeSystemResourceUsageData != "none" {
				ginkgo.BeforeEach(func() {
					var nodeMode e2edebug.NodesSet
					switch framework.TestContext.GatherKubeSystemResourceUsageData {
					case "master":
						nodeMode = e2edebug.MasterNodes
					case "masteranddns":
						nodeMode = e2edebug.MasterAndDNSNodes
					default:
						nodeMode = e2edebug.AllNodes
					}

					gatherer, err := e2edebug.NewResourceUsageGatherer(f.ClientSet, e2edebug.ResourceGathererOptions{
						InKubemark:                  framework.ProviderIs("kubemark"),
						Nodes:                       nodeMode,
						ResourceDataGatheringPeriod: 60 * time.Second,
						ProbeDuration:               15 * time.Second,
						PrintVerboseLogs:            false,
					}, nil)
					if err != nil {
						framework.Logf("Error while creating NewResourceUsageGatherer: %v", err)
						return
					}

					go gatherer.StartGatheringData()
					ginkgo.DeferCleanup(func() {
						ginkgo.By("Collecting resource usage data", func() {
							summary, resourceViolationError := gatherer.StopAndSummarize([]int{90, 99, 100}, nil /* no constraints */)
							// Always record the summary, even if there was an error.
							f.TestSummaries = append(f.TestSummaries, summary)
							// Now fail if there was an error.
							framework.ExpectNoError(resourceViolationError)
						})
					})
				})
			}
		},
	)
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go 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 conf

import (
	"fmt"
	"strings"
	"unicode"
	"unicode/utf8"
)

// Pos represents a byte position in the original input text from which
// this template was parsed.
type Pos int

// item represents a token or text string returned from the scanner.
type item struct {
	typ itemType // The type of this item.
	pos Pos      // The starting position, in bytes, of this item in the input string.
	val string   // The value of this item.
}

func (i item) String() string {
	switch {
	case i.typ == itemEOF:
		return "EOF"
	case i.typ == itemError:
		return i.val
	case len(i.val) > 10:
		return fmt.Sprintf("%.10q...", i.val)
	}
	return fmt.Sprintf("%q", i.val)
}

// itemType identifies the type of lex items.
type itemType int

const (
	itemError itemType = iota // error occurred; value is text of error
	itemEOF
	itemNot       // '!'
	itemAnd       // '&&'
	itemOr        // '||'
	itemGreater   // '>'
	itemLess      // '<'
	itemGreaterEq // '>='
	itemLessEq    // '<='
	itemEq        // '=='
	itemNotEq     // '!='
	itemPlus      // '+'
	itemMinus     // '-'
	itemMult      // '*'
	itemDiv       // '/'
	itemNumber    // simple number
)

const eof = -1

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	name    string    // the name of the input; used only for error reports
	input   string    // the string being scanned
	state   stateFn   // the next lexing function to enter
	pos     Pos       // current position in the input
	start   Pos       // start position of this item
	width   Pos       // width of last rune read from input
	lastPos Pos       // position of most recent item returned by nextItem
	items   chan item // channel of scanned items
}

// next returns the next rune in the input.
func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

// accept consumes the next rune if it's from the valid set.
func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

// ignore skips over the pending input before this point.
func (l *lexer) ignore() {
	l.start = l.pos
}

// lineNumber reports which line we're on, based on the position of
// the previous item returned by nextItem. Doing it this way
// means we don't have to worry about peek double counting.
func (l *lexer) lineNumber() int {
	return 1 + strings.Count(l.input[:l.lastPos], "\n")
}

// errorf returns an error token and terminates the scan by passing
// back a nil pointer that will be the next state, terminating l.nextItem.
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
	return nil
}

// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = item.pos
	return item
}

// lex creates a new scanner for the input string.
func lex(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

// run runs the state machine for the lexer.
func (l *lexer) run() {
	for l.state = lexItem; l.state != nil; {
		l.state = l.state(l)
	}
}

// state functions

func lexItem(l *lexer) stateFn {
Loop:
	for {
		switch r := l.next(); {
		case isSymbol(r):
			l.backup()
			return lexSymbol
		case unicode.IsDigit(r) || r == '.':
			l.backup()
			return lexNumber
		case unicode.IsLetter(r):
			l.backup()
			return lexFunc
		case isSpace(r):
			l.ignore()
		case r == eof:
			l.emit(itemEOF)
			break Loop
		default:
			return l.errorf("invalid character")
		}
	}
	return nil
}

// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
// and "089" - but when it's wrong the input is invalid and the parser (via
// strconv) will notice.
func lexNumber(l *lexer) stateFn {
	if !l.scanNumber() {
		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
	}
	l.emit(itemNumber)
	return lexItem
}

func (l *lexer) scanNumber() bool {
	// Is it hex?
	digits := "0123456789"
	if l.accept("0") && l.accept("xX") {
		digits = "0123456789abcdefABCDEF"
	}
	l.acceptRun(digits)
	if l.accept(".") {
		l.acceptRun(digits)
	}
	if l.accept("eE") {
		l.accept("+-")
		l.acceptRun("0123456789")
	}
	return true
}

const symbols = "!<>=&|+-*/"

func lexSymbol(l *lexer) stateFn {
	l.acceptRun(symbols)
	s := l.input[l.start:l.pos]
	switch s {
	case "!":
		l.emit(itemNot)
	case "&&":
		l.emit(itemAnd)
	case "||":
		l.emit(itemOr)
	case ">":
		l.emit(itemGreater)
	case "<":
		l.emit(itemLess)
	case ">=":
		l.emit(itemGreaterEq)
	case "<=":
		l.emit(itemLessEq)
	case "==":
		l.emit(itemEq)
	case "!=":
		l.emit(itemNotEq)
	case "+":
		l.emit(itemPlus)
	case "-":
		l.emit(itemMinus)
	case "*":
		l.emit(itemMult)
	case "/":
		l.emit(itemDiv)
	default:
		l.emit(itemError)
	}
	return lexItem
}

func lexFunc(l *lexer) stateFn {
	l.emit(itemError)
	return lexItem
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t'
}

func isVarchar(r rune) bool {
	return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
}

func isSymbol(r rune) bool {
	return strings.IndexRune(symbols, r) != -1
}
<commit_msg>Func and query lexing<commit_after>// Copyright 2011 The Go 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 conf

import (
	"fmt"
	"strings"
	"unicode"
	"unicode/utf8"
)

// Pos represents a byte position in the original input text from which
// this template was parsed.
type Pos int

// item represents a token or text string returned from the scanner.
type item struct {
	typ itemType // The type of this item.
	pos Pos      // The starting position, in bytes, of this item in the input string.
	val string   // The value of this item.
}

func (i item) String() string {
	switch {
	case i.typ == itemEOF:
		return "EOF"
	case i.typ == itemError:
		return i.val
	case len(i.val) > 10:
		return fmt.Sprintf("%.10q...", i.val)
	}
	return fmt.Sprintf("%q", i.val)
}

// itemType identifies the type of lex items.
type itemType int

const (
	itemError itemType = iota // error occurred; value is text of error
	itemEOF
	itemNot       // '!'
	itemAnd       // '&&'
	itemOr        // '||'
	itemGreater   // '>'
	itemLess      // '<'
	itemGreaterEq // '>='
	itemLessEq    // '<='
	itemEq        // '=='
	itemNotEq     // '!='
	itemPlus      // '+'
	itemMinus     // '-'
	itemMult      // '*'
	itemDiv       // '/'
	itemNumber    // simple number
	itemComma
	itemLeftParen
	itemRightParen
	itemString
	itemQuery
	itemFunc
)

const eof = -1

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	name    string    // the name of the input; used only for error reports
	input   string    // the string being scanned
	state   stateFn   // the next lexing function to enter
	pos     Pos       // current position in the input
	start   Pos       // start position of this item
	width   Pos       // width of last rune read from input
	lastPos Pos       // position of most recent item returned by nextItem
	items   chan item // channel of scanned items
}

// next returns the next rune in the input.
func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

// accept consumes the next rune if it's from the valid set.
func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

// ignore skips over the pending input before this point.
func (l *lexer) ignore() {
	l.start = l.pos
}

// lineNumber reports which line we're on, based on the position of
// the previous item returned by nextItem. Doing it this way
// means we don't have to worry about peek double counting.
func (l *lexer) lineNumber() int {
	return 1 + strings.Count(l.input[:l.lastPos], "\n")
}

// errorf returns an error token and terminates the scan by passing
// back a nil pointer that will be the next state, terminating l.nextItem.
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
	return nil
}

// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = item.pos
	return item
}

// lex creates a new scanner for the input string.
func lex(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

// run runs the state machine for the lexer.
func (l *lexer) run() {
	for l.state = lexItem; l.state != nil; {
		l.state = l.state(l)
	}
}

// state functions

func lexItem(l *lexer) stateFn {
Loop:
	for {
		switch r := l.next(); {
		case isSymbol(r):
			return lexSymbol
		case isNumber(r):
			return lexNumber
		case unicode.IsLetter(r):
			return lexFunc
		case r == '(':
			l.emit(itemLeftParen)
		case r == ')':
			l.emit(itemRightParen)
		case r == '[':
			return lexQuery
		case r == '"':
			return lexString
		case r == ',':
			l.emit(itemComma)
		case isSpace(r):
			l.ignore()
		case r == eof:
			l.emit(itemEOF)
			break Loop
		default:
			return l.errorf("invalid character")
		}
	}
	return nil
}

// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
// and "089" - but when it's wrong the input is invalid and the parser (via
// strconv) will notice.
func lexNumber(l *lexer) stateFn {
	if !l.scanNumber() {
		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
	}
	l.emit(itemNumber)
	return lexItem
}

func (l *lexer) scanNumber() bool {
	// Is it hex?
	digits := "0123456789"
	if l.accept("0") && l.accept("xX") {
		digits = "0123456789abcdefABCDEF"
	}
	l.acceptRun(digits)
	if l.accept(".") {
		l.acceptRun(digits)
	}
	if l.accept("eE") {
		l.accept("+-")
		l.acceptRun("0123456789")
	}
	return true
}

const symbols = "!<>=&|+-*/"

func lexSymbol(l *lexer) stateFn {
	l.acceptRun(symbols)
	s := l.input[l.start:l.pos]
	switch s {
	case "!":
		l.emit(itemNot)
	case "&&":
		l.emit(itemAnd)
	case "||":
		l.emit(itemOr)
	case ">":
		l.emit(itemGreater)
	case "<":
		l.emit(itemLess)
	case ">=":
		l.emit(itemGreaterEq)
	case "<=":
		l.emit(itemLessEq)
	case "==":
		l.emit(itemEq)
	case "!=":
		l.emit(itemNotEq)
	case "+":
		l.emit(itemPlus)
	case "-":
		l.emit(itemMinus)
	case "*":
		l.emit(itemMult)
	case "/":
		l.emit(itemDiv)
	default:
		l.emit(itemError)
	}
	return lexItem
}

func lexFunc(l *lexer) stateFn {
	for {
		switch r := l.next(); {
		case unicode.IsLetter(r):
			// absorb
		default:
			l.backup()
			l.emit(itemFunc)
			return lexItem
		}
	}
}

func lexString(l *lexer) stateFn {
	for {
		switch l.next() {
		case '"':
			l.emit(itemString)
			return lexItem
		case eof:
			return l.errorf("expected \"")
		}
	}
}

func lexQuery(l *lexer) stateFn {
	for {
		switch l.next() {
		case ']':
			l.emit(itemQuery)
			return lexItem
		case eof:
			return l.errorf("expected ]")
		}
	}
}

// isSpace reports whether r is a space character.
func isSpace(r rune) bool {
	return r == ' ' || r == '\t'
}

func isVarchar(r rune) bool {
	return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
}

func isSymbol(r rune) bool {
	return strings.IndexRune(symbols, r) != -1
}

func isNumber(r rune) bool {
	return unicode.IsDigit(r) || r == '.'
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"

	cmds "github.com/jbenet/go-ipfs/commands"
	repo "github.com/jbenet/go-ipfs/repo"
	config "github.com/jbenet/go-ipfs/repo/config"
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
	u "github.com/jbenet/go-ipfs/util"
)

type ConfigField struct {
	Key   string
	Value interface{}
}

var ConfigCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "get and set IPFS config values",
		Synopsis: `
ipfs config <key>          - Get value of <key>
ipfs config <key> <value>  - Set value of <key> to <value>
ipfs config show           - Show config file
ipfs config edit           - Edit config file in $EDITOR
ipfs config replace <file> - Replaces the config file with <file>
`,
		ShortDescription: `
ipfs config controls configuration variables. It works like 'git config'.
The configuration values are stored in a config file inside your IPFS
repository.`,
		LongDescription: `
ipfs config controls configuration variables. It works
much like 'git config'. The configuration values are stored in a config
file inside your IPFS repository.

EXAMPLES:

Get the value of the 'datastore.path' key:

  ipfs config datastore.path

Set the value of the 'datastore.path' key:

  ipfs config datastore.path ~/.go-ipfs/datastore
`,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")"),
		cmds.StringArg("value", false, false, "The value to set the config entry to"),
	},
	Run: func(req cmds.Request, res cmds.Response) {
		args := req.Arguments()
		key := args[0]

		r := fsrepo.At(req.Context().ConfigRoot)
		if err := r.Open(); err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		defer r.Close()

		var value string
		if len(args) == 2 {
			value = args[1]
			output, err := setConfig(r, key, value)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			res.SetOutput(output)

		} else {
			output, err := getConfig(r, key)
			if err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
			res.SetOutput(output)
		}
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			if len(res.Request().Arguments()) == 2 {
				return nil, nil // dont output anything
			}

			v := res.Output()
			if v == nil {
				k := res.Request().Arguments()[0]
				return nil, fmt.Errorf("config does not contain key: %s", k)
			}
			vf, ok := v.(*ConfigField)
			if !ok {
				return nil, u.ErrCast()
			}

			buf, err := config.HumanOutput(vf.Value)
			if err != nil {
				return nil, err
			}
			buf = append(buf, byte('\n'))
			return bytes.NewReader(buf), nil
		},
	},
	Type: ConfigField{},
	Subcommands: map[string]*cmds.Command{
		"show":    configShowCmd,
		"edit":    configEditCmd,
		"replace": configReplaceCmd,
	},
}

var configShowCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Outputs the content of the config file",
		ShortDescription: `
WARNING: Your private key is stored in the config file, and it will be
included in the output of this command.
`,
	},

	Run: func(req cmds.Request, res cmds.Response) {
		filename, err := config.Filename(req.Context().ConfigRoot)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		output, err := showConfig(filename)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		res.SetOutput(output)
	},
}

var configEditCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Opens the config file for editing in $EDITOR",
		ShortDescription: `
To use 'ipfs config edit', you must have the $EDITOR environment
variable set to your preferred text editor.
`,
	},

	Run: func(req cmds.Request, res cmds.Response) {
		filename, err := config.Filename(req.Context().ConfigRoot)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = editConfig(filename)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
		}
	},
}

var configReplaceCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Replaces the config with `file>",
		ShortDescription: `
Make sure to back up the config file first if neccessary, this operation
can't be undone.
`,
	},

	Arguments: []cmds.Argument{
		cmds.FileArg("file", true, false, "The file to use as the new config"),
	},
	Run: func(req cmds.Request, res cmds.Response) {
		r := fsrepo.At(req.Context().ConfigRoot)
		if err := r.Open(); err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		defer r.Close()

		file, err := req.Files().NextFile()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		defer file.Close()

		err = replaceConfig(r, file)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
	},
}

func getConfig(r repo.Repo, key string) (*ConfigField, error) {
	value, err := r.GetConfigKey(key)
	if err != nil {
		return nil, fmt.Errorf("Failed to get config value: %s", err)
	}
	return &ConfigField{
		Key:   key,
		Value: value,
	}, nil
}

func setConfig(r repo.Repo, key, value string) (*ConfigField, error) {
	err := r.SetConfigKey(key, value)
	if err != nil {
		return nil, fmt.Errorf("Failed to set config value: %s", err)
	}
	return getConfig(r, key)
}

func showConfig(filename string) (io.Reader, error) {
	// TODO maybe we should omit privkey so we don't accidentally leak it?

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	return bytes.NewReader(data), nil
}

func editConfig(filename string) error {
	editor := os.Getenv("EDITOR")
	if editor == "" {
		return errors.New("ENV variable $EDITOR not set")
	}

	cmd := exec.Command("sh", "-c", editor+" "+filename)
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	return cmd.Run()
}

func replaceConfig(r repo.Repo, file io.Reader) error {
	var cfg config.Config
	if err := json.NewDecoder(file).Decode(&cfg); err != nil {
		return errors.New("Failed to decode file as config")
	}

	return r.SetConfig(&cfg)
}
<commit_msg>core/commands: config: Simplified some syntax<commit_after>package commands

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"

	cmds "github.com/jbenet/go-ipfs/commands"
	repo "github.com/jbenet/go-ipfs/repo"
	config "github.com/jbenet/go-ipfs/repo/config"
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
	u "github.com/jbenet/go-ipfs/util"
)

type ConfigField struct {
	Key   string
	Value interface{}
}

var ConfigCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "get and set IPFS config values",
		Synopsis: `
ipfs config <key>          - Get value of <key>
ipfs config <key> <value>  - Set value of <key> to <value>
ipfs config show           - Show config file
ipfs config edit           - Edit config file in $EDITOR
ipfs config replace <file> - Replaces the config file with <file>
`,
		ShortDescription: `
ipfs config controls configuration variables. It works like 'git config'.
The configuration values are stored in a config file inside your IPFS
repository.`,
		LongDescription: `
ipfs config controls configuration variables. It works
much like 'git config'. The configuration values are stored in a config
file inside your IPFS repository.

EXAMPLES:

Get the value of the 'datastore.path' key:

  ipfs config datastore.path

Set the value of the 'datastore.path' key:

  ipfs config datastore.path ~/.go-ipfs/datastore
`,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")"),
		cmds.StringArg("value", false, false, "The value to set the config entry to"),
	},
	Run: func(req cmds.Request, res cmds.Response) {
		args := req.Arguments()
		key := args[0]

		r := fsrepo.At(req.Context().ConfigRoot)
		if err := r.Open(); err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		defer r.Close()

		var err error
		var output *ConfigField
		if len(args) == 2 {
			value := args[1]
			output, err = setConfig(r, key, value)
		} else {
			output, err = getConfig(r, key)
		}
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		res.SetOutput(output)
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			if len(res.Request().Arguments()) == 2 {
				return nil, nil // dont output anything
			}

			v := res.Output()
			if v == nil {
				k := res.Request().Arguments()[0]
				return nil, fmt.Errorf("config does not contain key: %s", k)
			}
			vf, ok := v.(*ConfigField)
			if !ok {
				return nil, u.ErrCast()
			}

			buf, err := config.HumanOutput(vf.Value)
			if err != nil {
				return nil, err
			}
			buf = append(buf, byte('\n'))
			return bytes.NewReader(buf), nil
		},
	},
	Type: ConfigField{},
	Subcommands: map[string]*cmds.Command{
		"show":    configShowCmd,
		"edit":    configEditCmd,
		"replace": configReplaceCmd,
	},
}

var configShowCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Outputs the content of the config file",
		ShortDescription: `
WARNING: Your private key is stored in the config file, and it will be
included in the output of this command.
`,
	},

	Run: func(req cmds.Request, res cmds.Response) {
		filename, err := config.Filename(req.Context().ConfigRoot)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		output, err := showConfig(filename)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		res.SetOutput(output)
	},
}

var configEditCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Opens the config file for editing in $EDITOR",
		ShortDescription: `
To use 'ipfs config edit', you must have the $EDITOR environment
variable set to your preferred text editor.
`,
	},

	Run: func(req cmds.Request, res cmds.Response) {
		filename, err := config.Filename(req.Context().ConfigRoot)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = editConfig(filename)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
		}
	},
}

var configReplaceCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Replaces the config with `file>",
		ShortDescription: `
Make sure to back up the config file first if neccessary, this operation
can't be undone.
`,
	},

	Arguments: []cmds.Argument{
		cmds.FileArg("file", true, false, "The file to use as the new config"),
	},
	Run: func(req cmds.Request, res cmds.Response) {
		r := fsrepo.At(req.Context().ConfigRoot)
		if err := r.Open(); err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		defer r.Close()

		file, err := req.Files().NextFile()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		defer file.Close()

		err = replaceConfig(r, file)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
	},
}

func getConfig(r repo.Repo, key string) (*ConfigField, error) {
	value, err := r.GetConfigKey(key)
	if err != nil {
		return nil, fmt.Errorf("Failed to get config value: %s", err)
	}
	return &ConfigField{
		Key:   key,
		Value: value,
	}, nil
}

func setConfig(r repo.Repo, key, value string) (*ConfigField, error) {
	err := r.SetConfigKey(key, value)
	if err != nil {
		return nil, fmt.Errorf("Failed to set config value: %s", err)
	}
	return getConfig(r, key)
}

func showConfig(filename string) (io.Reader, error) {
	// TODO maybe we should omit privkey so we don't accidentally leak it?

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	return bytes.NewReader(data), nil
}

func editConfig(filename string) error {
	editor := os.Getenv("EDITOR")
	if editor == "" {
		return errors.New("ENV variable $EDITOR not set")
	}

	cmd := exec.Command("sh", "-c", editor+" "+filename)
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	return cmd.Run()
}

func replaceConfig(r repo.Repo, file io.Reader) error {
	var cfg config.Config
	if err := json.NewDecoder(file).Decode(&cfg); err != nil {
		return errors.New("Failed to decode file as config")
	}

	return r.SetConfig(&cfg)
}
<|endoftext|>