<commit_before>package gateway

import (
	"bytes"
	"fmt"
	"github.com/42wim/matterbridge/bridge"
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/sirupsen/logrus"
	//	"github.com/davecgh/go-spew/spew"
	"crypto/sha1"
	"github.com/hashicorp/golang-lru"
	"github.com/peterhellberg/emojilib"
	"net/http"
	"regexp"
	"strings"
	"time"
)

type Gateway struct {
	*config.Config
	Router         *Router
	MyConfig       *config.Gateway
	Bridges        map[string]*bridge.Bridge
	Channels       map[string]*config.ChannelInfo
	ChannelOptions map[string]config.ChannelOptions
	Message        chan config.Message
	Name           string
	Messages       *lru.Cache
}

type BrMsgID struct {
	br        *bridge.Bridge
	ID        string
	ChannelID string
}

var flog *log.Entry

func init() {
	flog = log.WithFields(log.Fields{"prefix": "gateway"})
}

func New(cfg config.Gateway, r *Router) *Gateway {
	gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message,
		Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config}
	cache, _ := lru.New(5000)
	gw.Messages = cache
	gw.AddConfig(&cfg)
	return gw
}

func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
	br := gw.Router.getBridge(cfg.Account)
	if br == nil {
		br = bridge.New(gw.Config, cfg, gw.Message)
	}
	gw.mapChannelsToBridge(br)
	gw.Bridges[cfg.Account] = br
	return nil
}

func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
	gw.Name = cfg.Name
	gw.MyConfig = cfg
	gw.mapChannels()
	for _, br := range append(gw.MyConfig.In, append(gw.MyConfig.InOut, gw.MyConfig.Out...)...) {
		err := gw.AddBridge(&br)
		if err != nil {
			return err
		}
	}
	return nil
}

func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge) {
	for ID, channel := range gw.Channels {
		if br.Account == channel.Account {
			br.Channels[ID] = *channel
		}
	}
}

func (gw *Gateway) reconnectBridge(br *bridge.Bridge) {
	br.Disconnect()
	time.Sleep(time.Second * 5)
RECONNECT:
	flog.Infof("Reconnecting %s", br.Account)
	err := br.Connect()
	if err != nil {
		flog.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err)
		time.Sleep(time.Second * 60)
		goto RECONNECT
	}
	br.Joined = make(map[string]bool)
	br.JoinChannels()
}

func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) {
	for _, br := range cfg {
		if isApi(br.Account) {
			br.Channel = "api"
		}
		// make sure to lowercase irc channels in config #348
		if strings.HasPrefix(br.Account, "irc.") {
			br.Channel = strings.ToLower(br.Channel)
		}
		ID := br.Channel + br.Account
		if _, ok := gw.Channels[ID]; !ok {
			channel := &config.ChannelInfo{Name: br.Channel, Direction: direction, ID: ID, Options: br.Options, Account: br.Account,
				SameChannel: make(map[string]bool)}
			channel.SameChannel[gw.Name] = br.SameChannel
			gw.Channels[channel.ID] = channel
		} else {
			// if we already have a key and it's not our current direction it means we have a bidirectional inout
			if gw.Channels[ID].Direction != direction {
				gw.Channels[ID].Direction = "inout"
			}
		}
		gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
	}
}

func (gw *Gateway) mapChannels() error {
	gw.mapChannelConfig(gw.MyConfig.In, "in")
	gw.mapChannelConfig(gw.MyConfig.Out, "out")
	gw.mapChannelConfig(gw.MyConfig.InOut, "inout")
	return nil
}

func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo {
	var channels []config.ChannelInfo

	// for messages received from the api check that the gateway is the specified one
	if msg.Protocol == "api" && gw.Name != msg.Gateway {
		return channels
	}

	// if source channel is in only, do nothing
	for _, channel := range gw.Channels {
		// lookup the channel from the message
		if channel.ID == getChannelID(*msg) {
			// we only have destinations if the original message is from an "in" (sending) channel
			if !strings.Contains(channel.Direction, "in") {
				return channels
			}
			continue
		}
	}
	for _, channel := range gw.Channels {
		if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
			continue
		}

		// do samechannelgateway flogic
		if channel.SameChannel[msg.Gateway] {
			if msg.Channel == channel.Name && msg.Account != dest.Account {
				channels = append(channels, *channel)
			}
			continue
		}
		if strings.Contains(channel.Direction, "out") && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
			channels = append(channels, *channel)
		}
	}
	return channels
}

func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrMsgID {
	var brMsgIDs []*BrMsgID

	// TODO refactor
	// only slack now, check will have to be done in the different bridges.
	// we need to check if we can't use fallback or text in other bridges
	if msg.Extra != nil {
		if dest.Protocol != "discord" &&
			dest.Protocol != "slack" &&
			dest.Protocol != "mattermost" &&
			dest.Protocol != "telegram" &&
			dest.Protocol != "matrix" &&
			dest.Protocol != "xmpp" &&
			len(msg.Extra[config.EVENT_FILE_FAILURE_SIZE]) == 0 {
			if msg.Text == "" {
				return brMsgIDs
			}
		}
	}

	// Avatar downloads are only relevant for telegram and mattermost for now
	if msg.Event == config.EVENT_AVATAR_DOWNLOAD {
		if dest.Protocol != "mattermost" &&
			dest.Protocol != "telegram" {
			return brMsgIDs
		}
	}
	// only relay join/part when configged
	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
		return brMsgIDs
	}
	if msg.Event == config.EVENT_TOPIC_CHANGE && !gw.Bridges[dest.Account].Config.ShowTopicChange {
		return brMsgIDs
	}

	// broadcast to every out channel (irc QUIT)
	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
		flog.Debug("empty channel")
		return brMsgIDs
	}
	originchannel := msg.Channel
	origmsg := msg
	channels := gw.getDestChannel(&msg, *dest)
	for _, channel := range channels {
		// Only send the avatar download event to ourselves.
		if msg.Event == config.EVENT_AVATAR_DOWNLOAD {
			if channel.ID != getChannelID(origmsg) {
				continue
			}
		} else {
			// do not send to ourself for any other event
			if channel.ID == getChannelID(origmsg) {
				continue
			}
		}
		flog.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
		msg.Channel = channel.Name
		msg.Avatar = gw.modifyAvatar(origmsg, dest)
		msg.Username = gw.modifyUsername(origmsg, dest)
		msg.ID = ""
		if res, ok := gw.Messages.Get(origmsg.ID); ok {
			IDs := res.([]*BrMsgID)
			for _, id := range IDs {
				// check protocol, bridge name and channelname
				// for people that reuse the same bridge multiple times. see #342
				if dest.Protocol == id.br.Protocol && dest.Name == id.br.Name && channel.ID == id.ChannelID {
					msg.ID = id.ID
				}
			}
		}
		// for api we need originchannel as channel
		if dest.Protocol == "api" {
			msg.Channel = originchannel
		}
		mID, err := dest.Send(msg)
		if err != nil {
			fmt.Println(err)
		}
		// append the message ID (mID) from this bridge (dest) to our brMsgIDs slice
		if mID != "" {
			brMsgIDs = append(brMsgIDs, &BrMsgID{dest, mID, channel.ID})
		}
	}
	return brMsgIDs
}

func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
	// if we don't have the bridge, ignore it
	if _, ok := gw.Bridges[msg.Account]; !ok {
		return true
	}
	if msg.Text == "" {
		// we have an attachment or actual bytes
		if msg.Extra != nil &&
			(msg.Extra["attachments"] != nil ||
				len(msg.Extra["file"]) > 0 ||
				len(msg.Extra[config.EVENT_FILE_FAILURE_SIZE]) > 0) {
			return false
		}
		flog.Debugf("ignoring empty message %#v from %s", msg, msg.Account)
		return true
	}
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreNicks) {
		if msg.Username == entry {
			flog.Debugf("ignoring %s from %s", msg.Username, msg.Account)
			return true
		}
	}
	// TODO do not compile regexps everytime
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreMessages) {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(msg.Text) {
				flog.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account)
				return true
			}
		}
	}
	return false
}

func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string {
	br := gw.Bridges[msg.Account]
	msg.Protocol = br.Protocol
	if gw.Config.General.StripNick || dest.Config.StripNick {
		re := regexp.MustCompile("[^a-zA-Z0-9]+")
		msg.Username = re.ReplaceAllString(msg.Username, "")
	}
	nick := dest.Config.RemoteNickFormat
	if nick == "" {
		nick = gw.Config.General.RemoteNickFormat
	}

	// loop to replace nicks
	for _, outer := range br.Config.ReplaceNicks {
		search := outer[0]
		replace := outer[1]
		// TODO move compile to bridge init somewhere
		re, err := regexp.Compile(search)
		if err != nil {
			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
			break
		}
		msg.Username = re.ReplaceAllString(msg.Username, replace)
	}

	if len(msg.Username) > 0 {
		// fix utf-8 issue #193
		i := 0
		for index := range msg.Username {
			if i == 1 {
				i = index
				break
			}
			i++
		}
		nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1)
	}
	nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
	nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
	nick = strings.Replace(nick, "{LABEL}", br.Config.Label, -1)
	nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
	return nick
}

func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string {
	iconurl := gw.Config.General.IconURL
	if iconurl == "" {
		iconurl = dest.Config.IconURL
	}
	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
	if msg.Avatar == "" {
		msg.Avatar = iconurl
	}
	return msg.Avatar
}

func (gw *Gateway) modifyMessage(msg *config.Message) {
	// replace :emoji: to unicode
	msg.Text = emojilib.Replace(msg.Text)
	br := gw.Bridges[msg.Account]
	// loop to replace messages
	for _, outer := range br.Config.ReplaceMessages {
		search := outer[0]
		replace := outer[1]
		// TODO move compile to bridge init somewhere
		re, err := regexp.Compile(search)
		if err != nil {
			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
			break
		}
		msg.Text = re.ReplaceAllString(msg.Text, replace)
	}

	// messages from api have Gateway specified, don't overwrite
	if msg.Protocol != "api" {
		msg.Gateway = gw.Name
	}
}

func (gw *Gateway) handleFiles(msg *config.Message) {
	if msg.Extra == nil || gw.Config.General.MediaServerUpload == "" {
		return
	}
	if len(msg.Extra["file"]) > 0 {
		client := &http.Client{
			Timeout: time.Second * 5,
		}
		for i, f := range msg.Extra["file"] {
			fi := f.(config.FileInfo)
			sha1sum := fmt.Sprintf("%x", sha1.Sum(*fi.Data))
			reader := bytes.NewReader(*fi.Data)
			url := gw.Config.General.MediaServerUpload + "/" + sha1sum + "/" + fi.Name
			durl := gw.Config.General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name
			extra := msg.Extra["file"][i].(config.FileInfo)
			extra.URL = durl
			req, _ := http.NewRequest("PUT", url, reader)
			req.Header.Set("Content-Type", "binary/octet-stream")
			_, err := client.Do(req)
			if err != nil {
				flog.Errorf("mediaserver upload failed: %#v", err)
				continue
			}
			flog.Debugf("mediaserver download URL = %s", durl)
			// we uploaded the file successfully. Add the SHA
			extra.SHA = sha1sum
			msg.Extra["file"][i] = extra
		}
	}
}

func getChannelID(msg config.Message) string {
	return msg.Channel + msg.Account
}

func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool {
	return msg.Gateway == gw.Name
}

func isApi(account string) bool {
	return strings.HasPrefix(account, "api.")
}
<commit_msg>Allow empty messages with file urls (irc)<commit_after>package gateway

import (
	"bytes"
	"fmt"
	"github.com/42wim/matterbridge/bridge"
	"github.com/42wim/matterbridge/bridge/config"
	log "github.com/sirupsen/logrus"
	//	"github.com/davecgh/go-spew/spew"
	"crypto/sha1"
	"github.com/hashicorp/golang-lru"
	"github.com/peterhellberg/emojilib"
	"net/http"
	"regexp"
	"strings"
	"time"
)

type Gateway struct {
	*config.Config
	Router         *Router
	MyConfig       *config.Gateway
	Bridges        map[string]*bridge.Bridge
	Channels       map[string]*config.ChannelInfo
	ChannelOptions map[string]config.ChannelOptions
	Message        chan config.Message
	Name           string
	Messages       *lru.Cache
}

type BrMsgID struct {
	br        *bridge.Bridge
	ID        string
	ChannelID string
}

var flog *log.Entry

func init() {
	flog = log.WithFields(log.Fields{"prefix": "gateway"})
}

func New(cfg config.Gateway, r *Router) *Gateway {
	gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message,
		Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config}
	cache, _ := lru.New(5000)
	gw.Messages = cache
	gw.AddConfig(&cfg)
	return gw
}

func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
	br := gw.Router.getBridge(cfg.Account)
	if br == nil {
		br = bridge.New(gw.Config, cfg, gw.Message)
	}
	gw.mapChannelsToBridge(br)
	gw.Bridges[cfg.Account] = br
	return nil
}

func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
	gw.Name = cfg.Name
	gw.MyConfig = cfg
	gw.mapChannels()
	for _, br := range append(gw.MyConfig.In, append(gw.MyConfig.InOut, gw.MyConfig.Out...)...) {
		err := gw.AddBridge(&br)
		if err != nil {
			return err
		}
	}
	return nil
}

func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge) {
	for ID, channel := range gw.Channels {
		if br.Account == channel.Account {
			br.Channels[ID] = *channel
		}
	}
}

func (gw *Gateway) reconnectBridge(br *bridge.Bridge) {
	br.Disconnect()
	time.Sleep(time.Second * 5)
RECONNECT:
	flog.Infof("Reconnecting %s", br.Account)
	err := br.Connect()
	if err != nil {
		flog.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err)
		time.Sleep(time.Second * 60)
		goto RECONNECT
	}
	br.Joined = make(map[string]bool)
	br.JoinChannels()
}

func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) {
	for _, br := range cfg {
		if isApi(br.Account) {
			br.Channel = "api"
		}
		// make sure to lowercase irc channels in config #348
		if strings.HasPrefix(br.Account, "irc.") {
			br.Channel = strings.ToLower(br.Channel)
		}
		ID := br.Channel + br.Account
		if _, ok := gw.Channels[ID]; !ok {
			channel := &config.ChannelInfo{Name: br.Channel, Direction: direction, ID: ID, Options: br.Options, Account: br.Account,
				SameChannel: make(map[string]bool)}
			channel.SameChannel[gw.Name] = br.SameChannel
			gw.Channels[channel.ID] = channel
		} else {
			// if we already have a key and it's not our current direction it means we have a bidirectional inout
			if gw.Channels[ID].Direction != direction {
				gw.Channels[ID].Direction = "inout"
			}
		}
		gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
	}
}

func (gw *Gateway) mapChannels() error {
	gw.mapChannelConfig(gw.MyConfig.In, "in")
	gw.mapChannelConfig(gw.MyConfig.Out, "out")
	gw.mapChannelConfig(gw.MyConfig.InOut, "inout")
	return nil
}

func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo {
	var channels []config.ChannelInfo

	// for messages received from the api check that the gateway is the specified one
	if msg.Protocol == "api" && gw.Name != msg.Gateway {
		return channels
	}

	// if source channel is in only, do nothing
	for _, channel := range gw.Channels {
		// lookup the channel from the message
		if channel.ID == getChannelID(*msg) {
			// we only have destinations if the original message is from an "in" (sending) channel
			if !strings.Contains(channel.Direction, "in") {
				return channels
			}
			continue
		}
	}
	for _, channel := range gw.Channels {
		if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
			continue
		}

		// do samechannelgateway flogic
		if channel.SameChannel[msg.Gateway] {
			if msg.Channel == channel.Name && msg.Account != dest.Account {
				channels = append(channels, *channel)
			}
			continue
		}
		if strings.Contains(channel.Direction, "out") && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
			channels = append(channels, *channel)
		}
	}
	return channels
}

func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrMsgID {
	var brMsgIDs []*BrMsgID

	// TODO refactor
	// only slack now, check will have to be done in the different bridges.
	// we need to check if we can't use fallback or text in other bridges
	if msg.Extra != nil {
		if dest.Protocol != "discord" &&
			dest.Protocol != "slack" &&
			dest.Protocol != "mattermost" &&
			dest.Protocol != "telegram" &&
			dest.Protocol != "matrix" &&
			dest.Protocol != "xmpp" &&
			dest.Protocol != "irc" &&
			len(msg.Extra[config.EVENT_FILE_FAILURE_SIZE]) == 0 {
			if msg.Text == "" {
				return brMsgIDs
			}
		}
	}

	// Avatar downloads are only relevant for telegram and mattermost for now
	if msg.Event == config.EVENT_AVATAR_DOWNLOAD {
		if dest.Protocol != "mattermost" &&
			dest.Protocol != "telegram" {
			return brMsgIDs
		}
	}
	// only relay join/part when configged
	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
		return brMsgIDs
	}
	if msg.Event == config.EVENT_TOPIC_CHANGE && !gw.Bridges[dest.Account].Config.ShowTopicChange {
		return brMsgIDs
	}

	// broadcast to every out channel (irc QUIT)
	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
		flog.Debug("empty channel")
		return brMsgIDs
	}
	originchannel := msg.Channel
	origmsg := msg
	channels := gw.getDestChannel(&msg, *dest)
	for _, channel := range channels {
		// Only send the avatar download event to ourselves.
		if msg.Event == config.EVENT_AVATAR_DOWNLOAD {
			if channel.ID != getChannelID(origmsg) {
				continue
			}
		} else {
			// do not send to ourself for any other event
			if channel.ID == getChannelID(origmsg) {
				continue
			}
		}
		flog.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
		msg.Channel = channel.Name
		msg.Avatar = gw.modifyAvatar(origmsg, dest)
		msg.Username = gw.modifyUsername(origmsg, dest)
		msg.ID = ""
		if res, ok := gw.Messages.Get(origmsg.ID); ok {
			IDs := res.([]*BrMsgID)
			for _, id := range IDs {
				// check protocol, bridge name and channelname
				// for people that reuse the same bridge multiple times. see #342
				if dest.Protocol == id.br.Protocol && dest.Name == id.br.Name && channel.ID == id.ChannelID {
					msg.ID = id.ID
				}
			}
		}
		// for api we need originchannel as channel
		if dest.Protocol == "api" {
			msg.Channel = originchannel
		}
		mID, err := dest.Send(msg)
		if err != nil {
			flog.Error(err)
		}
		// append the message ID (mID) from this bridge (dest) to our brMsgIDs slice
		if mID != "" {
			brMsgIDs = append(brMsgIDs, &BrMsgID{dest, mID, channel.ID})
		}
	}
	return brMsgIDs
}

func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
	// if we don't have the bridge, ignore it
	if _, ok := gw.Bridges[msg.Account]; !ok {
		return true
	}
	if msg.Text == "" {
		// we have an attachment or actual bytes
		if msg.Extra != nil &&
			(msg.Extra["attachments"] != nil ||
				len(msg.Extra["file"]) > 0 ||
				len(msg.Extra[config.EVENT_FILE_FAILURE_SIZE]) > 0) {
			return false
		}
		flog.Debugf("ignoring empty message %#v from %s", msg, msg.Account)
		return true
	}
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreNicks) {
		if msg.Username == entry {
			flog.Debugf("ignoring %s from %s", msg.Username, msg.Account)
			return true
		}
	}
	// TODO do not compile regexps everytime
	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreMessages) {
		if entry != "" {
			re, err := regexp.Compile(entry)
			if err != nil {
				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account)
				continue
			}
			if re.MatchString(msg.Text) {
				flog.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account)
				return true
			}
		}
	}
	return false
}

func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string {
	br := gw.Bridges[msg.Account]
	msg.Protocol = br.Protocol
	if gw.Config.General.StripNick || dest.Config.StripNick {
		re := regexp.MustCompile("[^a-zA-Z0-9]+")
		msg.Username = re.ReplaceAllString(msg.Username, "")
	}
	nick := dest.Config.RemoteNickFormat
	if nick == "" {
		nick = gw.Config.General.RemoteNickFormat
	}

	// loop to replace nicks
	for _, outer := range br.Config.ReplaceNicks {
		search := outer[0]
		replace := outer[1]
		// TODO move compile to bridge init somewhere
		re, err := regexp.Compile(search)
		if err != nil {
			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
			break
		}
		msg.Username = re.ReplaceAllString(msg.Username, replace)
	}

	if len(msg.Username) > 0 {
		// fix utf-8 issue #193
		i := 0
		for index := range msg.Username {
			if i == 1 {
				i = index
				break
			}
			i++
		}
		nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1)
	}
	nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
	nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
	nick = strings.Replace(nick, "{LABEL}", br.Config.Label, -1)
	nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
	return nick
}

func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string {
	iconurl := gw.Config.General.IconURL
	if iconurl == "" {
		iconurl = dest.Config.IconURL
	}
	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
	if msg.Avatar == "" {
		msg.Avatar = iconurl
	}
	return msg.Avatar
}

func (gw *Gateway) modifyMessage(msg *config.Message) {
	// replace :emoji: to unicode
	msg.Text = emojilib.Replace(msg.Text)
	br := gw.Bridges[msg.Account]
	// loop to replace messages
	for _, outer := range br.Config.ReplaceMessages {
		search := outer[0]
		replace := outer[1]
		// TODO move compile to bridge init somewhere
		re, err := regexp.Compile(search)
		if err != nil {
			flog.Errorf("regexp in %s failed: %s", msg.Account, err)
			break
		}
		msg.Text = re.ReplaceAllString(msg.Text, replace)
	}

	// messages from api have Gateway specified, don't overwrite
	if msg.Protocol != "api" {
		msg.Gateway = gw.Name
	}
}

func (gw *Gateway) handleFiles(msg *config.Message) {
	if msg.Extra == nil || gw.Config.General.MediaServerUpload == "" {
		return
	}
	if len(msg.Extra["file"]) > 0 {
		client := &http.Client{
			Timeout: time.Second * 5,
		}
		for i, f := range msg.Extra["file"] {
			fi := f.(config.FileInfo)
			sha1sum := fmt.Sprintf("%x", sha1.Sum(*fi.Data))
			reader := bytes.NewReader(*fi.Data)
			url := gw.Config.General.MediaServerUpload + "/" + sha1sum + "/" + fi.Name
			durl := gw.Config.General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name
			extra := msg.Extra["file"][i].(config.FileInfo)
			extra.URL = durl
			req, _ := http.NewRequest("PUT", url, reader)
			req.Header.Set("Content-Type", "binary/octet-stream")
			_, err := client.Do(req)
			if err != nil {
				flog.Errorf("mediaserver upload failed: %#v", err)
				continue
			}
			flog.Debugf("mediaserver download URL = %s", durl)
			// we uploaded the file successfully. Add the SHA
			extra.SHA = sha1sum
			msg.Extra["file"][i] = extra
		}
	}
}

func getChannelID(msg config.Message) string {
	return msg.Channel + msg.Account
}

func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool {
	return msg.Gateway == gw.Name
}

func isApi(account string) bool {
	return strings.HasPrefix(account, "api.")
}
<|endoftext|>


<commit_before>package geos

/*
#cgo LDFLAGS: -lgeos_c
#include "geos_c.h"
#include <stdlib.h>
#include <stdint.h>

extern void IndexQueryCallback(void *, void *);
extern void goIndexSendQueryResult(size_t, void *);
extern uint32_t *IndexQuery(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, uint32_t *);
extern void IndexAdd(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, size_t);

*/
import "C"
import (
	"sync"
	"unsafe"
)

// IndexGeom is a struct for indexed geometries used by Index
// and returned by IndexQuery. Access to Prepared requires acquiring .Lock()
type IndexGeom struct {
	*sync.Mutex // Mutex for Prepared
	Geom        *Geom
	Prepared    *PreparedGeom
}
type Index struct {
	v     *C.GEOSSTRtree
	geoms []IndexGeom
}

func (this *Geos) CreateIndex() *Index {
	tree := C.GEOSSTRtree_create_r(this.v, 10)
	if tree == nil {
		panic("unable to create tree")
	}
	return &Index{tree, []IndexGeom{}}
}

// IndexQuery adds a geom to the index with the id.
func (this *Geos) IndexAdd(index *Index, geom *Geom) {
	id := len(index.geoms)
	C.IndexAdd(this.v, index.v, geom.v, C.size_t(id))
	prep := this.Prepare(geom)
	index.geoms = append(index.geoms, IndexGeom{&sync.Mutex{}, geom, prep})
}

// IndexQuery queries the index for intersections with geom.
func (this *Geos) IndexQuery(index *Index, geom *Geom) []IndexGeom {
	var num C.uint32_t
	r := C.IndexQuery(this.v, index.v, geom.v, &num)
	if r == nil {
		return nil
	}
	hits := (*[2 << 16]C.uint32_t)(unsafe.Pointer(r))[:num]
	defer C.free(unsafe.Pointer(r))

	var geoms []IndexGeom
	for idx := range hits {
		geoms = append(geoms, index.geoms[idx])
	}
	return geoms
}
<commit_msg>use mutex for IndexQuery<commit_after>package geos

/*
#cgo LDFLAGS: -lgeos_c
#include "geos_c.h"
#include <stdlib.h>
#include <stdint.h>

extern void IndexQueryCallback(void *, void *);
extern void goIndexSendQueryResult(size_t, void *);
extern uint32_t *IndexQuery(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, uint32_t *);
extern void IndexAdd(GEOSContextHandle_t, GEOSSTRtree *, const GEOSGeometry *, size_t);

*/
import "C"
import (
	"sync"
	"unsafe"
)

// IndexGeom is a struct for indexed geometries used by Index
// and returned by IndexQuery. Access to Prepared requires acquiring .Lock()
type IndexGeom struct {
	*sync.Mutex // Mutex for Prepared
	Geom        *Geom
	Prepared    *PreparedGeom
}
type Index struct {
	v     *C.GEOSSTRtree
	mu    *sync.Mutex
	geoms []IndexGeom
}

func (this *Geos) CreateIndex() *Index {
	tree := C.GEOSSTRtree_create_r(this.v, 10)
	if tree == nil {
		panic("unable to create tree")
	}
	return &Index{tree, &sync.Mutex{}, []IndexGeom{}}
}

// IndexQuery adds a geom to the index with the id.
func (this *Geos) IndexAdd(index *Index, geom *Geom) {
	index.mu.Lock()
	defer index.mu.Unlock()
	id := len(index.geoms)
	C.IndexAdd(this.v, index.v, geom.v, C.size_t(id))
	prep := this.Prepare(geom)
	index.geoms = append(index.geoms, IndexGeom{&sync.Mutex{}, geom, prep})
}

// IndexQuery queries the index for intersections with geom.
func (this *Geos) IndexQuery(index *Index, geom *Geom) []IndexGeom {
	index.mu.Lock()
	defer index.mu.Unlock()
	var num C.uint32_t
	r := C.IndexQuery(this.v, index.v, geom.v, &num)
	if r == nil {
		return nil
	}
	hits := (*[2 << 16]C.uint32_t)(unsafe.Pointer(r))[:num]
	defer C.free(unsafe.Pointer(r))

	var geoms []IndexGeom
	for idx := range hits {
		geoms = append(geoms, index.geoms[idx])
	}
	return geoms
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"io/ioutil"
	"os"
)

var colors []string

type InputNode struct {
	Id      string   `json:"id"`
	Parents []string `json:"parents"`
}

// Type:
// 0: |
// 1: ┘
// 2: ┐
// 3: ┌
type Point struct {
	X    int `json:"x"`
	Y    int `json:"y"`
	Type int `json:"type"`
}

type Path struct {
	Id    string  `json:"id"`
	Path  []Point `json:"path"`
	Color string  `json:"color"`
}

type OutputNode struct {
	Id                string          `json:"id"`
	Parents           []string        `json:"parents"`
	Column            int             `json:"column"`
	ParentsPaths      map[string]Path `json:"-"`
	FinalParentsPaths []Path          `json:"parents_paths"`
	Idx               int             `json:"idx"`
	Children          []string        `json:"-"`
	Color             string          `json:"color"`
	FirstInRow        bool            `json:"-"`
}

func (node *OutputNode) Append(parentId string, point Point) {
	tmp := node.ParentsPaths[parentId]
	tmp.Path = append(tmp.Path, point)
	node.ParentsPaths[parentId] = tmp
}

func (node *OutputNode) Remove(parentId string, idx int) {
	tmp := node.ParentsPaths[parentId]
	tmp.Path = append(tmp.Path[:idx], tmp.Path[idx+1:]...)
	node.ParentsPaths[parentId] = tmp
}

func (node *OutputNode) Insert(parentId string, idx int, point Point) {
	tmp := node.ParentsPaths[parentId]
	tmp.Path = append(tmp.Path, Point{})
	copy(tmp.Path[idx+1:], tmp.Path[idx:])
	tmp.Path[idx] = point
	node.ParentsPaths[parentId] = tmp
}

func (node *OutputNode) SetPathColor(parentId, color string) {
	tmp := node.ParentsPaths[parentId]
	tmp.Color = color
	node.ParentsPaths[parentId] = tmp
}

func serializeOutput(out []*OutputNode) ([]byte, error) {
	for _, node := range out {
		for parentId, path := range node.ParentsPaths {
			node.FinalParentsPaths = append(node.FinalParentsPaths, Path{parentId, path.Path, path.Color})
		}
	}
	treeBytes, err := json.Marshal(&out)
	return treeBytes, err
}

func getInputNodesFromJson(inputJson string) (nodes []InputNode, err error) {
	if err = json.Unmarshal([]byte(inputJson), &nodes); err != nil {
		return
	}
	return
}

func initNodes(inputNodes []InputNode) []*OutputNode {
	out := make([]*OutputNode, 0)
	for idx, node := range inputNodes {
		newNode := OutputNode{}
		newNode.Id = node.Id
		newNode.Parents = node.Parents
		newNode.Column = -1
		newNode.ParentsPaths = make(map[string]Path)
		newNode.FinalParentsPaths = make([]Path, 0)
		newNode.Idx = idx
		newNode.Children = make([]string, 0)
		out = append(out, &newNode)
	}
	return out
}

func initIndex(nodes []*OutputNode) map[string]*OutputNode {
	index := make(map[string]*OutputNode)
	for _, node := range nodes {
		index[node.Id] = node
	}
	return index
}

func initChildren(nodes []*OutputNode, index map[string]*OutputNode) {
	for _, node := range nodes {
		for _, parentId := range node.Parents {
			index[parentId].Children = append(index[parentId].Children, node.Id)
		}
	}
}

func setColumns(nodes []*OutputNode, index map[string]*OutputNode) {
	nextColumn := 0
	for _, node := range nodes {
		if node.Column == -1 {
			node.Column = nextColumn
			node.Color, colors = colors[0], colors[1:]
			nextColumn++
		}

		for _, childId := range node.Children {
			child := index[childId]
			if node.Column < child.Column {
				nextColumn--

				if child.Parents[0] != node.Id || len(child.Parents) <= 1 {
					if !child.FirstInRow {
						child.SetPathColor(node.Id, child.Color)
					}
					colors = append(colors[:1], append([]string{child.Color}, colors[1:]...)...)

					// Insert before the last element
					pos := len(child.ParentsPaths[node.Id].Path) - 1
					point := Point{child.ParentsPaths[node.Id].Path[pos-1].X, node.Idx, 1}
					child.Insert(node.Id, pos, point)

					for followingNodeIdx, followingNode := range nodes {
						if followingNodeIdx > node.Idx {
							if followingNode.Column > child.Column {

								for _, followingNodeChildId := range followingNode.Children {
									followingNodeChild := index[followingNodeChildId]

									idxRemove := len(followingNodeChild.ParentsPaths[followingNode.Id].Path) - 1
									followingNodeChild.Remove(followingNode.Id, idxRemove)

									pos := len(followingNodeChild.ParentsPaths[followingNode.Id].Path) - 1
									followingNodeChild.Append(followingNode.Id, Point{followingNodeChild.ParentsPaths[followingNode.Id].Path[pos].X, node.Idx, 1})
									followingNodeChild.Append(followingNode.Id, Point{followingNode.Column - 1, node.Idx, 0})
									followingNodeChild.Append(followingNode.Id, Point{followingNode.Column - 1, followingNode.Idx, 0})
								}

								followingNode.Column--
							}
						}
					}
				}
			}
		}

		for parentIdx, parentId := range node.Parents {
			parent := index[parentId]

			node.Append(parent.Id, Point{node.Column, node.Idx, 0})

			if parent.Column == -1 {
				if parentIdx == 0 || (parentIdx == 1 && index[node.Parents[0]].Column < node.Column) {
					parent.Column = node.Column
				} else {
					parent.Column = nextColumn
					parent.Color, colors = colors[0], colors[1:]
					node.Append(parent.Id, Point{parent.Column, node.Idx, 2})
					node.SetPathColor(parent.Id, parent.Color)
					node.FirstInRow = true
					nextColumn++
				}
			} else {
				if node.Column < parent.Column && parentIdx == 0 {
					for _, childId := range parent.Children {
						child := index[childId]
						idxRemove := len(child.ParentsPaths[parent.Id].Path) - 1
						if idxRemove > 0 {
							if child.ParentsPaths[parent.Id].Path[idxRemove].Type != 2 {
								child.Remove(parent.Id, idxRemove)
							}
							child.Append(parent.Id, Point{node.Column, parent.Idx, 0})
						}
					}
					parent.Column = node.Column
					parent.Color = node.Color
				} else if node.Column > parent.Column {
					if node.Parents[0] == parent.Id && len(node.Parents) > 1 {
						node.Append(parent.Id, Point{parent.Column, node.Idx, 3})
					}
				}
			}

			node.Append(parent.Id, Point{parent.Column, parent.Idx, 0})

		}
	}
}

func buildTree(inputNodes []InputNode, myColors []string) ([]*OutputNode, error) {
	colors = myColors
	var nodes []*OutputNode = initNodes(inputNodes)
	var index map[string]*OutputNode = initIndex(nodes)

	initChildren(nodes, index)
	setColumns(nodes, index)

	return nodes, nil
}

func BuildTreeJson(inputJson string, myColors []string) (tree string, err error) {
	nodes, err := getInputNodesFromJson(inputJson)
	if err != nil {
		return
	}

	out, err := buildTree(nodes, myColors)
	if err != nil {
		return
	}

	treeBytes, err := serializeOutput(out)
	if err != nil {
		return
	}
	tree = string(treeBytes)
	return
}

func bootstrap(c *cli.Context) {
	var inputJson string
	jsonFlag := c.String("json")
	fileFlag := c.String("file")
	if jsonFlag != "" {
		inputJson = jsonFlag
	} else if fileFlag != "" {
		bytes, err := ioutil.ReadFile(fileFlag)
		if err != nil {
			fmt.Println(err)
			return
		}
		inputJson = string(bytes)
	} else {
		cli.ShowAppHelp(c)
		return
	}

	myColors := []string{"#5aa1be", "#c065b8", "#c0ab5f", "#59bc95", "#c0615b", "#7a63be", "#73bb5e", "#6ee585", "#7088e8", "#eb77a3"}

	out, err := BuildTreeJson(inputJson, myColors)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(out)
}

func main() {
	var authors []cli.Author
	// Collaborators, add your name here :)
	authors = append(authors, cli.Author{"Alain Gilbert", "alain.gilbert.15@gmail.com"})

	app := cli.NewApp()
	app.Authors = authors
	app.Version = "0.0.0"
	app.Name = "git2graph"
	app.Usage = "Take a git tree, make a graph structure"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "f, file",
			Usage: "File",
		},
		cli.StringFlag{
			Name:  "j, json",
			Usage: "Json input",
		},
	}
	app.Action = bootstrap
	app.Run(os.Args)
}
<commit_msg>Fix some other bugs<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"io/ioutil"
	"os"
)

var colors []string

type InputNode struct {
	Id      string   `json:"id"`
	Parents []string `json:"parents"`
}

// Type:
// 0: |
// 1: ┘
// 2: ┐
// 3: ┌
type Point struct {
	X    int `json:"x"`
	Y    int `json:"y"`
	Type int `json:"type"`
}

type Path struct {
	Id    string  `json:"id"`
	Path  []Point `json:"path"`
	Color string  `json:"color"`
}

type OutputNode struct {
	Id                string          `json:"id"`
	Parents           []string        `json:"parents"`
	Column            int             `json:"column"`
	ParentsPaths      map[string]Path `json:"-"`
	FinalParentsPaths []Path          `json:"parents_paths"`
	Idx               int             `json:"idx"`
	Children          []string        `json:"-"`
	Color             string          `json:"color"`
	FirstInRow        bool            `json:"-"`
}

func (node *OutputNode) Append(parentId string, point Point) {
	tmp := node.ParentsPaths[parentId]
	tmp.Path = append(tmp.Path, point)
	node.ParentsPaths[parentId] = tmp
}

func (node *OutputNode) Remove(parentId string, idx int) {
	tmp := node.ParentsPaths[parentId]
	tmp.Path = append(tmp.Path[:idx], tmp.Path[idx+1:]...)
	node.ParentsPaths[parentId] = tmp
}

func (node *OutputNode) Insert(parentId string, idx int, point Point) {
	tmp := node.ParentsPaths[parentId]
	tmp.Path = append(tmp.Path, Point{})
	copy(tmp.Path[idx+1:], tmp.Path[idx:])
	tmp.Path[idx] = point
	node.ParentsPaths[parentId] = tmp
}

func (node *OutputNode) SetPathColor(parentId, color string) {
	tmp := node.ParentsPaths[parentId]
	tmp.Color = color
	node.ParentsPaths[parentId] = tmp
}

func serializeOutput(out []*OutputNode) ([]byte, error) {
	for _, node := range out {
		for parentId, path := range node.ParentsPaths {
			node.FinalParentsPaths = append(node.FinalParentsPaths, Path{parentId, path.Path, path.Color})
		}
	}
	treeBytes, err := json.Marshal(&out)
	return treeBytes, err
}

func getInputNodesFromJson(inputJson string) (nodes []InputNode, err error) {
	if err = json.Unmarshal([]byte(inputJson), &nodes); err != nil {
		return
	}
	return
}

func initNodes(inputNodes []InputNode) []*OutputNode {
	out := make([]*OutputNode, 0)
	for idx, node := range inputNodes {
		newNode := OutputNode{}
		newNode.Id = node.Id
		newNode.Parents = node.Parents
		newNode.Column = -1
		newNode.ParentsPaths = make(map[string]Path)
		newNode.FinalParentsPaths = make([]Path, 0)
		newNode.Idx = idx
		newNode.Children = make([]string, 0)
		out = append(out, &newNode)
	}
	return out
}

func initIndex(nodes []*OutputNode) map[string]*OutputNode {
	index := make(map[string]*OutputNode)
	for _, node := range nodes {
		index[node.Id] = node
	}
	return index
}

func initChildren(nodes []*OutputNode, index map[string]*OutputNode) {
	for _, node := range nodes {
		for _, parentId := range node.Parents {
			index[parentId].Children = append(index[parentId].Children, node.Id)
		}
	}
}

func setColumns(nodes []*OutputNode, index map[string]*OutputNode) {
	nextColumn := 0
	for _, node := range nodes {
		if node.Column == -1 {
			node.Column = nextColumn
			node.Color, colors = colors[0], colors[1:]
			nextColumn++
		}

		for _, childId := range node.Children {
			child := index[childId]
			if node.Column < child.Column {
				nextColumn--

				if child.Parents[0] != node.Id || len(child.Parents) <= 1 {
					if !child.FirstInRow {
						child.SetPathColor(node.Id, child.Color)
					}
					colors = append(colors[:1], append([]string{child.Color}, colors[1:]...)...)

					// Insert before the last element
					pos := len(child.ParentsPaths[node.Id].Path) - 1
					point := Point{child.ParentsPaths[node.Id].Path[pos-1].X, node.Idx, 1}
					child.Insert(node.Id, pos, point)

					for followingNodeIdx, followingNode := range nodes {
						if followingNodeIdx > node.Idx {
							if followingNode.Column > child.Column {

								for _, followingNodeChildId := range followingNode.Children {
									followingNodeChild := index[followingNodeChildId]

									idxRemove := len(followingNodeChild.ParentsPaths[followingNode.Id].Path) - 1
									followingNodeChild.Remove(followingNode.Id, idxRemove)

									pos := len(followingNodeChild.ParentsPaths[followingNode.Id].Path) - 1
									followingNodeChild.Append(followingNode.Id, Point{followingNodeChild.ParentsPaths[followingNode.Id].Path[pos].X, node.Idx, 1})
									followingNodeChild.Append(followingNode.Id, Point{followingNode.Column - 1, node.Idx, 0})
									followingNodeChild.Append(followingNode.Id, Point{followingNode.Column - 1, followingNode.Idx, 0})
								}

								followingNode.Column--
							}
						}
					}
				}
			}
		}

		for parentIdx, parentId := range node.Parents {
			parent := index[parentId]

			node.Append(parent.Id, Point{node.Column, node.Idx, 0})

			if parent.Column == -1 {
				if parentIdx == 0 || (parentIdx == 1 && index[node.Parents[0]].Column < node.Column) {
					parent.Column = node.Column
					parent.Color = node.Color
					node.SetPathColor(parent.Id, parent.Color)
				} else {
					parent.Column = nextColumn
					parent.Color, colors = colors[0], colors[1:]
					node.Append(parent.Id, Point{parent.Column, node.Idx, 2})
					node.SetPathColor(parent.Id, parent.Color)
					node.FirstInRow = true
					nextColumn++
				}
			} else {
				if node.Column < parent.Column && parentIdx == 0 {
					for _, childId := range parent.Children {
						child := index[childId]
						idxRemove := len(child.ParentsPaths[parent.Id].Path) - 1
						if idxRemove > 0 {
							if child.ParentsPaths[parent.Id].Path[idxRemove].Type != 2 {
								child.Remove(parent.Id, idxRemove)
							}
							child.Append(parent.Id, Point{node.Column, parent.Idx, 0})
						}
					}
					parent.Column = node.Column
					parent.Color = node.Color
					node.SetPathColor(parent.Id, node.Color)
				} else if node.Column > parent.Column {
					if node.Parents[0] == parent.Id && len(node.Parents) > 1 {
						node.Append(parent.Id, Point{parent.Column, node.Idx, 3})
						node.SetPathColor(parent.Id, parent.Color)
					}
				}
			}

			node.Append(parent.Id, Point{parent.Column, parent.Idx, 0})

		}
	}
}

func buildTree(inputNodes []InputNode, myColors []string) ([]*OutputNode, error) {
	colors = myColors
	var nodes []*OutputNode = initNodes(inputNodes)
	var index map[string]*OutputNode = initIndex(nodes)

	initChildren(nodes, index)
	setColumns(nodes, index)

	return nodes, nil
}

func BuildTreeJson(inputJson string, myColors []string) (tree string, err error) {
	nodes, err := getInputNodesFromJson(inputJson)
	if err != nil {
		return
	}

	out, err := buildTree(nodes, myColors)
	if err != nil {
		return
	}

	treeBytes, err := serializeOutput(out)
	if err != nil {
		return
	}
	tree = string(treeBytes)
	return
}

func bootstrap(c *cli.Context) {
	var inputJson string
	jsonFlag := c.String("json")
	fileFlag := c.String("file")
	if jsonFlag != "" {
		inputJson = jsonFlag
	} else if fileFlag != "" {
		bytes, err := ioutil.ReadFile(fileFlag)
		if err != nil {
			fmt.Println(err)
			return
		}
		inputJson = string(bytes)
	} else {
		cli.ShowAppHelp(c)
		return
	}

	myColors := []string{"#5aa1be", "#c065b8", "#c0ab5f", "#59bc95", "#c0615b", "#7a63be", "#73bb5e", "#6ee585", "#7088e8", "#eb77a3"}

	out, err := BuildTreeJson(inputJson, myColors)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(out)
}

func main() {
	var authors []cli.Author
	// Collaborators, add your name here :)
	authors = append(authors, cli.Author{"Alain Gilbert", "alain.gilbert.15@gmail.com"})

	app := cli.NewApp()
	app.Authors = authors
	app.Version = "0.0.0"
	app.Name = "git2graph"
	app.Usage = "Take a git tree, make a graph structure"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "f, file",
			Usage: "File",
		},
		cli.StringFlag{
			Name:  "j, json",
			Usage: "Json input",
		},
	}
	app.Action = bootstrap
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package github

import (
	"fmt"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/crosbymichael/octokat"
)

func (g GitHub) addDCOUnsignedComment(repo octokat.Repo, pr *octokat.PullRequest, content *pullRequestContent) error {
	comment := `Can you please sign your commits following these rules:
https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work
The easiest way to do this is to amend the last commit:
~~~console
`
	comment += fmt.Sprintf("$ git clone -b %q %s %s\n", pr.Head.Ref, pr.Head.Repo.SSHURL, "somewhere")
	comment += "$ cd somewhere\n"

	if pr.Commits > 1 {
		comment += fmt.Sprintf("$ git rebase -i HEAD~%d\n", pr.Commits)
		comment += "editor opens\nchange each 'pick' to 'edit'\nsave the file and quit\n"
	}

	comment += "$ git commit --amend -s --no-edit\n"
	if pr.Commits > 1 {
		comment += "$ git rebase --continue # and repeat the amend for each commit\n"
	}

	comment += "$ git push -f\n"
	comment += `~~~
This will update the existing PR, so you do not need to open a new one.
`

	return g.addUniqueComment(repo, strconv.Itoa(pr.Number), comment, "sign your commits", content)
}

func (g GitHub) removeComment(repo octokat.Repo, pr *octokat.PullRequest, commentType string, content *pullRequestContent) error {
	if c := content.FindComment(commentType, g.User); c != nil {
		return g.Client().RemoveComment(repo, c.Id)
	}

	return nil
}

func (g GitHub) addUniqueComment(repo octokat.Repo, prNum, comment, commentType string, content *pullRequestContent) error {
	// check if we already made the comment
	if content.AlreadyCommented(commentType, g.User) {
		return nil
	}

	// add the comment because we must not have already made it
	if _, err := g.Client().AddComment(repo, prNum, comment); err != nil {
		return err
	}

	log.Infof("Would have added comment about %q PR %s", commentType, prNum)
	return nil
}
<commit_msg>listen here naow<commit_after>package github

import (
	"fmt"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/crosbymichael/octokat"
)

func (g GitHub) addDCOUnsignedComment(repo octokat.Repo, pr *octokat.PullRequest, content *pullRequestContent) error {
	comment := `Can you please sign your commits following these rules:
https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work
The easiest way to do this is to amend the last commit:
~~~console
`
	comment += fmt.Sprintf("$ git clone -b %q %s %s\n", pr.Head.Ref, pr.Head.Repo.SSHURL, "somewhere")
	comment += "$ cd somewhere\n"

	if pr.Commits > 1 {
		comment += fmt.Sprintf("$ git rebase -i HEAD~%d\n", pr.Commits)
		comment += "editor opens\nchange each 'pick' to 'edit'\nsave the file and quit\n"
	}

	comment += "$ git commit --amend -s --no-edit\n"
	if pr.Commits > 1 {
		comment += "$ git rebase --continue # and repeat the amend for each commit\n"
	}

	comment += "$ git push -f\n"
	comment += `~~~

This will update the existing PR, so **DO NOT** open a new one.
`

	return g.addUniqueComment(repo, strconv.Itoa(pr.Number), comment, "sign your commits", content)
}

func (g GitHub) removeComment(repo octokat.Repo, pr *octokat.PullRequest, commentType string, content *pullRequestContent) error {
	if c := content.FindComment(commentType, g.User); c != nil {
		return g.Client().RemoveComment(repo, c.Id)
	}

	return nil
}

func (g GitHub) addUniqueComment(repo octokat.Repo, prNum, comment, commentType string, content *pullRequestContent) error {
	// check if we already made the comment
	if content.AlreadyCommented(commentType, g.User) {
		return nil
	}

	// add the comment because we must not have already made it
	if _, err := g.Client().AddComment(repo, prNum, comment); err != nil {
		return err
	}

	log.Infof("Would have added comment about %q PR %s", commentType, prNum)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The go-github 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 github

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strings"
)

// Reference represents a GitHub reference.
type Reference struct {
	Ref    *string    `json:"ref"`
	URL    *string    `json:"url"`
	Object *GitObject `json:"object"`
	NodeID *string    `json:"node_id,omitempty"`
}

func (r Reference) String() string {
	return Stringify(r)
}

// GitObject represents a Git object.
type GitObject struct {
	Type *string `json:"type"`
	SHA  *string `json:"sha"`
	URL  *string `json:"url"`
}

func (o GitObject) String() string {
	return Stringify(o)
}

// createRefRequest represents the payload for creating a reference.
type createRefRequest struct {
	Ref *string `json:"ref"`
	SHA *string `json:"sha"`
}

// updateRefRequest represents the payload for updating a reference.
type updateRefRequest struct {
	SHA   *string `json:"sha"`
	Force *bool   `json:"force"`
}

// GetRef fetches a single Reference object for a given Git ref.
// If there is no exact match, GetRef will return an error.
//
// Note: The GitHub API can return multiple matches.
// If you wish to use this functionality please use the GetRefs() method.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) {
	ref = strings.TrimPrefix(ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	r := new(Reference)
	resp, err := s.client.Do(ctx, req, r)
	if _, ok := err.(*json.UnmarshalTypeError); ok {
		// Multiple refs, means there wasn't an exact match.
		return nil, resp, errors.New("multiple matches found for this ref")
	} else if resp.StatusCode == 404 {
		// No ref, there was no match for the ref
		return nil, resp, errors.New("no match found for this ref")
	} else if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

// GetRefs fetches a slice of Reference objects for a given Git ref.
// If there is an exact match, only that ref is returned.
// If there is no exact match, GitHub returns all refs that start with ref.
// If returned error is nil, there will be at least 1 ref returned.
// For example:
//
// 	"heads/featureA" -> ["refs/heads/featureA"]                         // Exact match, single ref is returned.
// 	"heads/feature"  -> ["refs/heads/featureA", "refs/heads/featureB"]  // All refs that start with ref.
// 	"heads/notexist" -> []                                              // Returns an error.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref string) ([]*Reference, *Response, error) {
	ref = strings.TrimPrefix(ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var rawJSON json.RawMessage
	resp, err := s.client.Do(ctx, req, &rawJSON)
	if err != nil {
		return nil, resp, err
	}

	// Prioritize the most common case: a single returned ref.
	r := new(Reference)
	singleUnmarshalError := json.Unmarshal(rawJSON, r)
	if singleUnmarshalError == nil {
		return []*Reference{r}, resp, nil
	}

	// Attempt to unmarshal multiple refs.
	var rs []*Reference
	multipleUnmarshalError := json.Unmarshal(rawJSON, &rs)
	if multipleUnmarshalError == nil {
		if len(rs) == 0 {
			return nil, resp, fmt.Errorf("unexpected response from GitHub API: an array of refs with length 0")
		}
		return rs, resp, nil
	}

	return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", singleUnmarshalError, multipleUnmarshalError)
}

// ReferenceListOptions specifies optional parameters to the
// GitService.ListRefs method.
type ReferenceListOptions struct {
	Type string `url:"-"`

	ListOptions
}

// ListRefs lists all refs in a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references
func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) {
	var u string
	if opt != nil && opt.Type != "" {
		u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type)
	} else {
		u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
	}
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var rs []*Reference
	resp, err := s.client.Do(ctx, req, &rs)
	if err != nil {
		return nil, resp, err
	}

	return rs, resp, nil
}

// CreateRef creates a new ref in a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference
func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
	req, err := s.client.NewRequest("POST", u, &createRefRequest{
		// back-compat with previous behavior that didn't require 'refs/' prefix
		Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")),
		SHA: ref.Object.SHA,
	})
	if err != nil {
		return nil, nil, err
	}

	r := new(Reference)
	resp, err := s.client.Do(ctx, req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

// UpdateRef updates an existing ref in a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference
func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) {
	refPath := strings.TrimPrefix(*ref.Ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath)
	req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{
		SHA:   ref.Object.SHA,
		Force: &force,
	})
	if err != nil {
		return nil, nil, err
	}

	r := new(Reference)
	resp, err := s.client.Do(ctx, req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

// DeleteRef deletes a ref from a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference
func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) {
	ref = strings.TrimPrefix(ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	return s.client.Do(ctx, req, nil)
}
<commit_msg>Update git_refs.go (#1240)<commit_after>// Copyright 2013 The go-github 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 github

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strings"
)

// Reference represents a GitHub reference.
type Reference struct {
	Ref    *string    `json:"ref"`
	URL    *string    `json:"url"`
	Object *GitObject `json:"object"`
	NodeID *string    `json:"node_id,omitempty"`
}

func (r Reference) String() string {
	return Stringify(r)
}

// GitObject represents a Git object.
type GitObject struct {
	Type *string `json:"type"`
	SHA  *string `json:"sha"`
	URL  *string `json:"url"`
}

func (o GitObject) String() string {
	return Stringify(o)
}

// createRefRequest represents the payload for creating a reference.
type createRefRequest struct {
	Ref *string `json:"ref"`
	SHA *string `json:"sha"`
}

// updateRefRequest represents the payload for updating a reference.
type updateRefRequest struct {
	SHA   *string `json:"sha"`
	Force *bool   `json:"force"`
}

// GetRef fetches a single Reference object for a given Git ref.
// If there is no exact match, GetRef will return an error.
//
// Note: The GitHub API can return multiple matches.
// If you wish to use this functionality please use the GetRefs() method.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) {
	ref = strings.TrimPrefix(ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	r := new(Reference)
	resp, err := s.client.Do(ctx, req, r)
	if _, ok := err.(*json.UnmarshalTypeError); ok {
		// Multiple refs, means there wasn't an exact match.
		return nil, resp, errors.New("multiple matches found for this ref")
	} else if _, ok := err.(*ErrorResponse); ok && resp.StatusCode == 404 {
		// No ref, there was no match for the ref
		return nil, resp, errors.New("no match found for this ref")
	} else if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

// GetRefs fetches a slice of Reference objects for a given Git ref.
// If there is an exact match, only that ref is returned.
// If there is no exact match, GitHub returns all refs that start with ref.
// If returned error is nil, there will be at least 1 ref returned.
// For example:
//
// 	"heads/featureA" -> ["refs/heads/featureA"]                         // Exact match, single ref is returned.
// 	"heads/feature"  -> ["refs/heads/featureA", "refs/heads/featureB"]  // All refs that start with ref.
// 	"heads/notexist" -> []                                              // Returns an error.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref string) ([]*Reference, *Response, error) {
	ref = strings.TrimPrefix(ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var rawJSON json.RawMessage
	resp, err := s.client.Do(ctx, req, &rawJSON)
	if err != nil {
		return nil, resp, err
	}

	// Prioritize the most common case: a single returned ref.
	r := new(Reference)
	singleUnmarshalError := json.Unmarshal(rawJSON, r)
	if singleUnmarshalError == nil {
		return []*Reference{r}, resp, nil
	}

	// Attempt to unmarshal multiple refs.
	var rs []*Reference
	multipleUnmarshalError := json.Unmarshal(rawJSON, &rs)
	if multipleUnmarshalError == nil {
		if len(rs) == 0 {
			return nil, resp, fmt.Errorf("unexpected response from GitHub API: an array of refs with length 0")
		}
		return rs, resp, nil
	}

	return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", singleUnmarshalError, multipleUnmarshalError)
}

// ReferenceListOptions specifies optional parameters to the
// GitService.ListRefs method.
type ReferenceListOptions struct {
	Type string `url:"-"`

	ListOptions
}

// ListRefs lists all refs in a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references
func (s *GitService) ListRefs(ctx context.Context, owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) {
	var u string
	if opt != nil && opt.Type != "" {
		u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type)
	} else {
		u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
	}
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	var rs []*Reference
	resp, err := s.client.Do(ctx, req, &rs)
	if err != nil {
		return nil, resp, err
	}

	return rs, resp, nil
}

// CreateRef creates a new ref in a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference
func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo)
	req, err := s.client.NewRequest("POST", u, &createRefRequest{
		// back-compat with previous behavior that didn't require 'refs/' prefix
		Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")),
		SHA: ref.Object.SHA,
	})
	if err != nil {
		return nil, nil, err
	}

	r := new(Reference)
	resp, err := s.client.Do(ctx, req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

// UpdateRef updates an existing ref in a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference
func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) {
	refPath := strings.TrimPrefix(*ref.Ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath)
	req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{
		SHA:   ref.Object.SHA,
		Force: &force,
	})
	if err != nil {
		return nil, nil, err
	}

	r := new(Reference)
	resp, err := s.client.Do(ctx, req, r)
	if err != nil {
		return nil, resp, err
	}

	return r, resp, nil
}

// DeleteRef deletes a ref from a repository.
//
// GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference
func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) {
	ref = strings.TrimPrefix(ref, "refs/")
	u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, url.QueryEscape(ref))
	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	return s.client.Do(ctx, req, nil)
}
<|endoftext|>


<commit_before>// Copyright 2013 The Author - Unknown. 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 (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"strings"
)

func main() {
	targetFilePath := "test.tar.gz"
	srcDirPath := "test"
	TarGz(srcDirPath, targetFilePath)
	fmt.Println("Finish!")
}

// Gzip and tar from source directory to destination file
// you need check file exist before you call this function
func TarGz(srcDirPath string, destFilePath string) {
	fmt.Println("Cerating tar.gz...")
	fw, err := os.Create(destFilePath)
	handleError(err)
	defer fw.Close()

	// Gzip writer
	gw := gzip.NewWriter(fw)
	defer gw.Close()

	// Tar writer
	tw := tar.NewWriter(gw)
	defer tw.Close()

	// handle source directory
	TarGzDir(srcDirPath, path.Base(srcDirPath), tw)
}

// Deal with directories
// if find files, handle them with HandleFile
// Every recurrence append the base path to the recPath
// recPath is the path inside of tar.gz
func TarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
	// Open source diretory
	dir, err := os.Open(srcDirPath)
	handleError(err)
	defer dir.Close()

	// Get file info slice
	fis, err := dir.Readdir(0)
	handleError(err)
	for _, fi := range fis {
		// Append path
		curPath := srcDirPath + "/" + fi.Name()
		// Check it is directory or file
		if fi.IsDir() {
			// Directory
			// (Directory won't add unitl all subfiles are added)
			fmt.Printf("Adding path...%s\n", curPath)
			TarGzDir(curPath, recPath+"/"+fi.Name(), tw)
		} else {
			// File
			fmt.Printf("Adding file...%s\n", curPath)
		}

		TarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
	}
}

// Deal with files
func TarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
	if fi.IsDir() {
		// Create tar header
		hdr := new(tar.Header)
		hdr.Name = recPath + "/"

		// Write hander
		err := tw.WriteHeader(hdr)
		handleError(err)
	} else {
		// File reader
		fr, err := os.Open(srcFile)
		handleError(err)
		defer fr.Close()

		// Create tar header
		hdr := new(tar.Header)
		hdr.Name = recPath
		hdr.Size = fi.Size()
		hdr.Mode = int64(fi.Mode())
		hdr.ModTime = fi.ModTime()

		// Write hander
		err = tw.WriteHeader(hdr)
		handleError(err)

		// Write file data
		_, err = io.Copy(tw, fr)
		handleError(err)
	}
}

// Ungzip and untar from source file to destination directory
// you need check file exist before you call this function
func UnTarGz(srcFilePath string, destDirPath string) {
	fmt.Println("UnTarGzing tar.gz...")
	fr, err := os.Open(srcFilePath)
	handleError(err)
	defer fr.Close()

	// Set current directory path
	curDirPath := destDirPath
	// Tar reader
	tr := tar.NewReader(fr)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// End of tar archive
			break
		}
		handleError(err)

		// Get files from archive
		if strings.Contains(hdr.Name, "/") {
			// This is a path
			curDirPath = destDirPath + "/" + hdr.Name
			_, err := os.Create(curDirPath)
			handleError(err)
		} else {
			// This is a file
			fw, err := os.Create(curDirPath + "/" + hdr.Name)
			handleError(err)
			// Write data to file
			_, err = io.Copy(fw, tr)
			handleError(err)
		}
	}
}

func handleError(e error) {
	if e != nil {
		log.Fatal(e)
	}

}
<commit_msg>finish tar.gz<commit_after>// Copyright 2013 The Author - Unknown. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Help linls:
// https://codereview.appspot.com/7305072
package main

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"log"
	"os"
	"path"
)

// Copy from http://golang.org/misc/dist/bindist.go
// Mode constants from the tar spec.
const (
	c_ISDIR  = 040000
	c_ISFIFO = 010000
	c_ISREG  = 0100000
	c_ISLNK  = 0120000
	c_ISBLK  = 060000
	c_ISCHR  = 020000
	c_ISSOCK = 0140000
)

func main() {
	targetFilePath := "test.tar.gz"
	srcDirPath := "test"
	TarGz(srcDirPath, targetFilePath)
	UnTarGz(targetFilePath, srcDirPath+"_temp")
	fmt.Println("Finish!")
}

// Gzip and tar from source directory to destination file
// you need check file exist before you call this function
func TarGz(srcDirPath string, destFilePath string) {
	fmt.Println("Cerating tar.gz...")
	fw, err := os.Create(destFilePath)
	handleError(err)
	defer fw.Close()

	// Gzip writer
	gw := gzip.NewWriter(fw)
	defer gw.Close()

	// Tar writer
	tw := tar.NewWriter(gw)
	defer tw.Close()

	// handle source directory
	TarGzDir(srcDirPath, path.Base(srcDirPath), tw)
}

// Deal with directories
// if find files, handle them with HandleFile
// Every recurrence append the base path to the recPath
// recPath is the path inside of tar.gz
func TarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
	// Open source diretory
	dir, err := os.Open(srcDirPath)
	handleError(err)
	defer dir.Close()

	// Get file info slice
	fis, err := dir.Readdir(0)
	handleError(err)
	for _, fi := range fis {
		// Append path
		curPath := srcDirPath + "/" + fi.Name()
		// Check it is directory or file
		if fi.IsDir() {
			// Directory
			// (Directory won't add unitl all subfiles are added)
			fmt.Printf("Adding path...%s\n", curPath)
			TarGzDir(curPath, recPath+"/"+fi.Name(), tw)
		} else {
			// File
			fmt.Printf("Adding file...%s\n", curPath)
		}

		TarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
	}
}

// Deal with files
func TarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
	if fi.IsDir() {
		// Create tar header
		hdr := new(tar.Header)
		hdr.Name = recPath + "/"
		hdr.Typeflag = tar.TypeDir
		hdr.Size = 0
		hdr.Mode = 0755 | c_ISDIR
		hdr.ModTime = fi.ModTime()
		// if last character of header name is '/' it also can be directory

		// Write hander
		err := tw.WriteHeader(hdr)
		handleError(err)
	} else {
		// File reader
		fr, err := os.Open(srcFile)
		handleError(err)
		defer fr.Close()

		// Create tar header
		hdr := new(tar.Header)
		hdr.Name = recPath
		hdr.Size = fi.Size()
		hdr.Mode = int64(fi.Mode())
		hdr.ModTime = fi.ModTime()

		// Write hander
		err = tw.WriteHeader(hdr)
		handleError(err)

		// Write file data
		_, err = io.Copy(tw, fr)
		handleError(err)
	}
}

// Ungzip and untar from source file to destination directory
// you need check file exist before you call this function
func UnTarGz(srcFilePath string, destDirPath string) {
	fmt.Println("UnTarGzing " + srcFilePath + "...")
	// Create destination directory
	os.Mkdir(destDirPath, os.ModePerm)

	fr, err := os.Open(srcFilePath)
	handleError(err)
	defer fr.Close()

	// Gzip reader
	gr, err := gzip.NewReader(fr)

	// Tar reader
	tr := tar.NewReader(gr)

	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// End of tar archive
			break
		}
		//handleError(err)
		fmt.Println("UnTarGzing file..." + hdr.Name)

		// If header name ends with '/' means it is directory ,
		// and doesn't need extract
		c := []byte(hdr.Name)
		if c[len(hdr.Name)-1] != '/' {
			// Get files from archive
			os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
			// Write data to file
			fw, _ := os.Create(destDirPath + "/" + hdr.Name)
			handleError(err)
			_, err = io.Copy(fw, tr)
			handleError(err)
		}
	}
}

func handleError(e error) {
	if e != nil {
		log.Fatal(e)
	}

}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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 fn

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"

	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/kio"
)

// AsMain reads the resourceList in yaml format from stdin, evaluates the
// function and write the updated resourceList in yaml to stdout. Errors if any
// will be printed to stderr.
func AsMain(p ResourceListProcessor) error {
	err := func() error {
		in, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return fmt.Errorf("unable to read from stdin: %v", err)
		}
		out, err := Run(p, in)
		// If there is an error, we don't return the error immediately.
		// We write out to stdout before returning any error.
		_, outErr := os.Stdout.Write(out)
		if outErr != nil {
			return outErr
		}
		return err
	}()
	return err
}

// Run evaluates the function. input must be a resourceList in yaml format. An
// updated resourceList will be returned.
func Run(p ResourceListProcessor, input []byte) (out []byte, err error) {
	rl, err := ParseResourceList(input)
	if err != nil {
		return nil, err
	}
	defer func() {
		// if we run into a panic, we still need to log the error to Results,
		// and return the ResourceList and error.
		v := recover()
		if v != nil {
			switch t := v.(type) {
			case *ErrKubeObjectFields:
				err = t
			case *ErrSubObjectFields:
				err = t
			default:
				panic(v)
			}
			rl.LogResult(err)
			out, _ = rl.ToYAML()
		}
	}()
	success, fnErr := p.Process(rl)
	out, yamlErr := rl.ToYAML()
	if yamlErr != nil {
		return out, yamlErr
	}
	if fnErr != nil {
		return out, fnErr
	}
	if !success {
		return out, fmt.Errorf("error: function failure")
	}
	return out, nil
}

func Execute(p ResourceListProcessor, r io.Reader, w io.Writer) error {
	rw := &byteReadWriter{
		kio.ByteReadWriter{
			Reader:                r,
			Writer:                w,
			KeepReaderAnnotations: true,
		},
	}
	return execute(p, rw)
}

func execute(p ResourceListProcessor, rw *byteReadWriter) error {
	// Read the input
	rl, err := rw.Read()
	if err != nil {
		return errors.WrapPrefixf(err, "failed to read ResourceList input")
	}
	success, fnErr := p.Process(rl)
	// Write the output
	if err := rw.Write(rl); err != nil {
		return errors.WrapPrefixf(err, "failed to write ResourceList output")
	}
	if fnErr != nil {
		return fnErr
	}
	if !success {
		return fmt.Errorf("error: function failure")
	}
	return nil
}
<commit_msg>fn sdk should not try to set id annotations (#565)<commit_after>// Copyright 2022 Google LLC
//
// 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 fn

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"

	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/kio"
)

// AsMain reads the resourceList in yaml format from stdin, evaluates the
// function and write the updated resourceList in yaml to stdout. Errors if any
// will be printed to stderr.
func AsMain(p ResourceListProcessor) error {
	err := func() error {
		in, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return fmt.Errorf("unable to read from stdin: %v", err)
		}
		out, err := Run(p, in)
		// If there is an error, we don't return the error immediately.
		// We write out to stdout before returning any error.
		_, outErr := os.Stdout.Write(out)
		if outErr != nil {
			return outErr
		}
		return err
	}()
	return err
}

// Run evaluates the function. input must be a resourceList in yaml format. An
// updated resourceList will be returned.
func Run(p ResourceListProcessor, input []byte) (out []byte, err error) {
	rl, err := ParseResourceList(input)
	if err != nil {
		return nil, err
	}
	defer func() {
		// if we run into a panic, we still need to log the error to Results,
		// and return the ResourceList and error.
		v := recover()
		if v != nil {
			switch t := v.(type) {
			case *ErrKubeObjectFields:
				err = t
			case *ErrSubObjectFields:
				err = t
			default:
				panic(v)
			}
			rl.LogResult(err)
			out, _ = rl.ToYAML()
		}
	}()
	success, fnErr := p.Process(rl)
	out, yamlErr := rl.ToYAML()
	if yamlErr != nil {
		return out, yamlErr
	}
	if fnErr != nil {
		return out, fnErr
	}
	if !success {
		return out, fmt.Errorf("error: function failure")
	}
	return out, nil
}

func Execute(p ResourceListProcessor, r io.Reader, w io.Writer) error {
	rw := &byteReadWriter{
		kio.ByteReadWriter{
			Reader: r,
			Writer: w,
			// We should not set the id annotation in the function, since we should not
			// overwrite what the orchestrator set.
			OmitReaderAnnotations: true,
			// We should not remove the id annotations in the function, since the
			// orchestrator (e.g. kpt) may need them.
			KeepReaderAnnotations: true,
		},
	}
	return execute(p, rw)
}

func execute(p ResourceListProcessor, rw *byteReadWriter) error {
	// Read the input
	rl, err := rw.Read()
	if err != nil {
		return errors.WrapPrefixf(err, "failed to read ResourceList input")
	}
	success, fnErr := p.Process(rl)
	// Write the output
	if err := rw.Write(rl); err != nil {
		return errors.WrapPrefixf(err, "failed to write ResourceList output")
	}
	if fnErr != nil {
		return fnErr
	}
	if !success {
		return fmt.Errorf("error: function failure")
	}
	return nil
}
<|endoftext|>


<commit_before>package goenocean

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	//"github.com/tarm/goserial"
)

func Decode(data []byte) (p *Packet, err error) {
	if data[0] != 0x55 {
		return nil, errors.New("goenocean.Decode: must start with 0x55")
	}

	p = NewPacket()
	p.syncByte = data[0]
	p.header.setFromBytes(data[1:5])
	p.headerCrc = data[5]

	p.data = data[6 : 6+p.header.dataLength]
	p.optData = data[6+p.header.dataLength : 6+int(p.header.dataLength)+int(p.header.optDataLength)]
	p.dataCrc = data[len(data)-1]

	err = p.ValidateCrc()

	return
}

func Read(rd io.Reader, f func([]byte)) {
	//TODO use this example receivePacket when reading from serial https://github.com/kleckse/enocean/blob/master/esp3.py

	buf := make([]byte, 1)
	var rawPacket []byte
	state := 0
	var length int

	for {
		readLen, err := rd.Read(buf)
		if err != nil {
			fmt.Println("ERROR reading:", err)
			continue
		}
		//f(buf)
		//continue

		if readLen > 0 && buf[0] == 0x55 {
			rawPacket = []byte{}
			state = 1
		}

		rawPacket = append(rawPacket, buf...)
		//fmt.Println("State", state)
		//fmt.Println("readLen", readLen)
		//fmt.Println(buf)
		switch state {
		case 1: //header
			if len(rawPacket) > 5 {
				state = 2
			}

		case 2: // data
			length = int(binary.BigEndian.Uint16(rawPacket[1:3]))
			//fmt.Println("length", length)
			if len(rawPacket) > 5+length {
				state = 3
			}

		case 3: //opt data
			if len(rawPacket) > 5+length+int(rawPacket[3]) {
				state = 4
			}

		case 4: //data crc
			state = 5
			f(rawPacket)
		}

	}

}

func PrintHex(a []byte) { // {{{
	fmt.Println(ToHex(a))
} // }}}

func ToHex(a []byte) string { // {{{
	b := fmt.Sprintf("% x", a)
	return b
} // }}}
<commit_msg>simplified packet read from serial<commit_after>package goenocean

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	//"github.com/tarm/goserial"
)

func Decode(data []byte) (p *Packet, err error) {
	if data[0] != 0x55 {
		return nil, errors.New("goenocean.Decode: must start with 0x55")
	}

	p = NewPacket()
	p.syncByte = data[0]
	p.header.setFromBytes(data[1:5])
	p.headerCrc = data[5]

	p.data = data[6 : 6+p.header.dataLength]
	p.optData = data[6+p.header.dataLength : 6+int(p.header.dataLength)+int(p.header.optDataLength)]
	p.dataCrc = data[len(data)-1]

	err = p.ValidateCrc()

	return
}

func Read(rd io.Reader, f func([]byte)) {
	//TODO use this example receivePacket when reading from serial https://github.com/kleckse/enocean/blob/master/esp3.py

	buf := make([]byte, 1)
	var rawPacket []byte
	state := 0
	var length int

	for {
		readLen, err := rd.Read(buf)
		if err != nil {
			fmt.Println("ERROR reading:", err)
			continue
		}

		if readLen > 0 && buf[0] == 0x55 {
			rawPacket = []byte{}
			state = 1
		}

		rawPacket = append(rawPacket, buf...)

		switch state {
		case 1: //header
			if len(rawPacket) > 5 {
				length = int(binary.BigEndian.Uint16(rawPacket[1:3]))
				state = 2
			}

		case 2: // the rest!
			if len(rawPacket) > 5+length+int(rawPacket[3]) {
				state = 3
			}

		case 3: //data crc
			state = 0
			f(rawPacket)
		}

	}

}

func PrintHex(a []byte) { // {{{
	fmt.Println(ToHex(a))
} // }}}

func ToHex(a []byte) string { // {{{
	b := fmt.Sprintf("% x", a)
	return b
} // }}}
<|endoftext|>


<commit_before>// Copyright 2015 Peter Goetz
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"go/ast"
	"go/token"
	"reflect"
	"strings"

	"github.com/petergtz/goextract/util"
)

type Selection struct {
	Begin, End Position
}

type Position struct {
	Line, Column int
}

type visitorContext struct {
	fset           *token.FileSet
	posParent      ast.Node
	endParent      ast.Node
	nodesToExtract []ast.Node
	shouldRecord   bool

	selection Selection
}

type astNodeVisitor struct {
	parentNode ast.Node
	context    *visitorContext
}

func (visitor *astNodeVisitor) Visit(node ast.Node) (w ast.Visitor) {
	if node != nil {
		if visitor.context.fset.Position(node.Pos()).Line == visitor.context.selection.Begin.Line &&
			visitor.context.fset.Position(node.Pos()).Column == visitor.context.selection.Begin.Column {
			fmt.Print("The node: ")
			ast.Print(visitor.context.fset, node)
			fmt.Print("The pos: ", visitor.context.fset.Position(node.Pos()), "\n")
			visitor.context.posParent = visitor.parentNode
			visitor.context.shouldRecord = true
		}
		if visitor.context.shouldRecord {
			visitor.context.nodesToExtract = append(visitor.context.nodesToExtract, node)
		}
		if visitor.context.fset.Position(node.End()).Line == visitor.context.selection.End.Line &&
			visitor.context.fset.Position(node.End()).Column == visitor.context.selection.End.Column {
			fmt.Print("The node: ")
			ast.Print(visitor.context.fset, node)
			fmt.Print("The end: ", visitor.context.fset.Position(node.End()), "\n")
			visitor.context.endParent = visitor.parentNode
			visitor.context.shouldRecord = false
			return nil
		}
	}
	return &astNodeVisitor{
		parentNode: node,
		context:    visitor.context,
	}
}

// 3 cases:
// 1. Pure expression
// 2. Pure procedural (implies side effects) -> list of statemtents -> no return value
// 3. Final assignment to local variable -> list of statements where final is an assignment

// fmt.Println(
// 	fileSet.Position(astFile.Decls[1].Pos()),
// 	fileSet.Position(astFile.Decls[1].End()),
// )

func ExtractFileToFile(inputFileName string, selection Selection, extractedFuncName string, outputFilename string) {
	fileSet, astFile := astFromFile(inputFileName)
	createAstFileDump(inputFileName+".ast", fileSet, astFile)
	doExtraction(fileSet, astFile, selection, extractedFuncName)
	util.WriteFileAsStringOrPanic(outputFilename, stringFrom(fileSet, astFile))
}

func ExtractFileToString(inputFileName string, selection Selection, extractedFuncName string) string {
	fileSet, astFile := astFromFile(inputFileName)
	createAstFileDump(inputFileName+".ast", fileSet, astFile)
	doExtraction(fileSet, astFile, selection, extractedFuncName)
	return stringFrom(fileSet, astFile)
}

func ExtractStringToString(input string, selection Selection, extractedFuncName string) string {
	fileSet, astFile := astFromInput(input)
	doExtraction(fileSet, astFile, selection, extractedFuncName)
	return stringFrom(fileSet, astFile)
}

func doExtraction(fileSet *token.FileSet, astFile *ast.File, selection Selection, extractedFuncName string) {

	visitor := &astNodeVisitor{parentNode: nil, context: &visitorContext{fset: fileSet, selection: selection}}
	ast.Walk(visitor, astFile)
	if visitor.context.posParent != visitor.context.endParent {
		panic(fmt.Sprintf("Selection is not valid. posParent: %v; endParent: %v",
			visitor.context.posParent, visitor.context.endParent))
	}
	// if posParent == endParent {
	// 	fmt.Println("parent: ")
	// 	ast.Print(fileSet, posParent)
	// 	fmt.Println("to extract: ")
	// 	for _, node := range nodesToExtract {
	// 		ast.Print(fileSet, node)
	// 	}
	//
	// }

	// assume len(nodes) == 1 ==> simple expression:
	if len(visitor.context.nodesToExtract) == 1 {
		extractExpression(astFile, visitor.context, extractedFuncName)
	} else {
		panic("Only expression extractions are supported so far.")
	}

}

func extractExpression(astFile *ast.File, context *visitorContext, extractedFuncName string) {
	extractedExpressionNode := context.nodesToExtract[0].(ast.Expr)
	var returnTypeString string
	switch context.posParent.(type) {
	case *ast.AssignStmt:
		assignStmt := context.posParent.(*ast.AssignStmt)
		for i, rhs := range assignStmt.Rhs {
			if rhs == extractedExpressionNode {
				assignStmt.Rhs[i] =
					&ast.CallExpr{Fun: &ast.Ident{Name: extractedFuncName}}
			}
		}
		returnTypeString = strings.ToLower(extractedExpressionNode.(*ast.BasicLit).Kind.String())
	case *ast.CallExpr:
		callExpr := context.posParent.(*ast.CallExpr)
		for i, arg := range callExpr.Args {
			if arg == extractedExpressionNode {
				callExpr.Args[i] = &ast.CallExpr{Fun: &ast.Ident{Name: extractedFuncName}}

			}
		}
		returnTypeString = extractedExpressionNode.(*ast.CallExpr).Fun.(*ast.Ident).Obj.Decl.(*ast.FuncDecl).Type.Results.List[0].Type.(*ast.Ident).Name

	// TODO:
	// Add more cases here, e.g. for CallExpr

	default:
		panic(fmt.Sprintf("Type %v not supported yet", reflect.TypeOf(context.posParent)))
	}
	astFile.Decls = append(astFile.Decls, &ast.FuncDecl{
		Name: &ast.Ident{Name: extractedFuncName},
		Type: &ast.FuncType{
			Results: &ast.FieldList{
				List: []*ast.Field{
					&ast.Field{
						Type: &ast.Ident{Name: returnTypeString},
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.ReturnStmt{
					Results: []ast.Expr{
						extractedExpressionNode,
					},
				},
			},
		},
	})

}
<commit_msg>Fix existing test cases<commit_after>// Copyright 2015 Peter Goetz
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"go/ast"
	"go/token"
	"os/exec"
	"reflect"
	"strings"

	"github.com/petergtz/goextract/util"
)

type Selection struct {
	Begin, End Position
}

type Position struct {
	Line, Column int
}

type visitorContext struct {
	fset           *token.FileSet
	posParent      ast.Node
	endParent      ast.Node
	nodesToExtract []ast.Node
	shouldRecord   bool

	selection Selection
}

type astNodeVisitorForExpressions struct {
	parentNode ast.Node
	context    *visitorContext
}

func (visitor *astNodeVisitorForExpressions) Visit(node ast.Node) (w ast.Visitor) {
	if node != nil {
		if visitor.context.fset.Position(node.Pos()).Line == visitor.context.selection.Begin.Line &&
			visitor.context.fset.Position(node.Pos()).Column == visitor.context.selection.Begin.Column &&
			visitor.context.fset.Position(node.End()).Line == visitor.context.selection.End.Line &&
			visitor.context.fset.Position(node.End()).Column == visitor.context.selection.End.Column {
			// fmt.Println("Starting with node at pos", visitor.context.fset.Position(node.Pos()), "and end", visitor.context.fset.Position(node.End()))
			// ast.Print(visitor.context.fset, node)
			// fmt.Println(node.Pos(), node)
			visitor.context.posParent = visitor.parentNode
			visitor.context.endParent = visitor.parentNode
			visitor.context.nodesToExtract = append(visitor.context.nodesToExtract, node)
			return nil
		}
	}
	return &astNodeVisitorForExpressions{
		parentNode: node,
		context:    visitor.context,
	}
}

// func (visitor *astNodeVisitorForMultipleStatements) Visit(node ast.Node) (w ast.Visitor) {
// 	if node != nil {
// 		if visitor.context.fset.Position(node.Pos()).Line == visitor.context.selection.Begin.Line &&
// 			visitor.context.fset.Position(node.Pos()).Column == visitor.context.selection.Begin.Column {
// 			fmt.Println("Starting with node at pos", visitor.context.fset.Position(node.Pos()), "and end", visitor.context.fset.Position(node.End()))
// 			ast.Print(visitor.context.fset, node)
// 			fmt.Println(node.Pos(), node)
// 			visitor.context.posParent = visitor.parentNode
// 			visitor.context.shouldRecord = true
// 		}
// 		if visitor.context.shouldRecord {
// 			visitor.context.nodesToExtract = append(visitor.context.nodesToExtract, node)
// 		}
// 		if visitor.context.fset.Position(node.End()).Line == visitor.context.selection.End.Line &&
// 			visitor.context.fset.Position(node.End()).Column == visitor.context.selection.End.Column {
// 			fmt.Println("Ending with node at pos", visitor.context.fset.Position(node.Pos()), "and end", visitor.context.fset.Position(node.End()))
// 			ast.Print(visitor.context.fset, node)
// 			visitor.context.endParent = visitor.parentNode
// 			visitor.context.shouldRecord = false
// 			return nil
// 		}
// 	}
// 	return &astNodeVisitor{
// 		parentNode: node,
// 		context:    visitor.context,
// 	}
// }

// 3 cases:
// 1. Pure expression
// 2. Pure procedural (implies side effects) -> list of statemtents -> no return value
// 3. Final assignment to local variable -> list of statements where final is an assignment

// fmt.Println(
// 	fileSet.Position(astFile.Decls[1].Pos()),
// 	fileSet.Position(astFile.Decls[1].End()),
// )

func ExtractFileToFile(inputFileName string, selection Selection, extractedFuncName string, outputFilename string) {
	fileSet, astFile := astFromFile(inputFileName)
	createAstFileDump(inputFileName+".ast", fileSet, astFile)
	doExtraction(fileSet, astFile, selection, extractedFuncName)
	util.WriteFileAsStringOrPanic(outputFilename, stringFrom(fileSet, astFile))
	err := exec.Command("gofmt", "-w", outputFilename).Run()
	util.PanicOnError(err)
}

func ExtractFileToString(inputFileName string, selection Selection, extractedFuncName string) string {
	fileSet, astFile := astFromFile(inputFileName)
	createAstFileDump(inputFileName+".ast", fileSet, astFile)
	doExtraction(fileSet, astFile, selection, extractedFuncName)
	return stringFrom(fileSet, astFile)
}

func ExtractStringToString(input string, selection Selection, extractedFuncName string) string {
	fileSet, astFile := astFromInput(input)
	doExtraction(fileSet, astFile, selection, extractedFuncName)
	return stringFrom(fileSet, astFile)
}

func doExtraction(fileSet *token.FileSet, astFile *ast.File, selection Selection, extractedFuncName string) {

	visitor := &astNodeVisitorForExpressions{parentNode: nil, context: &visitorContext{fset: fileSet, selection: selection}}
	ast.Walk(visitor, astFile)
	if visitor.context.posParent != visitor.context.endParent {
		panic(fmt.Sprintf("Selection is not valid. posParent: %v; endParent: %v",
			visitor.context.posParent, visitor.context.endParent))
	}
	if len(visitor.context.nodesToExtract) == 1 {
		extractExpression(astFile, visitor.context, extractedFuncName)
	} else {
		panic("Only expression extractions are supported so far.")
	}

}

func extractExpression(astFile *ast.File, context *visitorContext, extractedFuncName string) {
	extractedExpressionNode := context.nodesToExtract[0].(ast.Expr)
	var returnTypeString string
	switch context.posParent.(type) {
	case *ast.AssignStmt:
		assignStmt := context.posParent.(*ast.AssignStmt)
		for i, rhs := range assignStmt.Rhs {
			if rhs == extractedExpressionNode {
				assignStmt.Rhs[i] =
					&ast.CallExpr{Fun: &ast.Ident{Name: extractedFuncName}}
			}
		}
		returnTypeString = strings.ToLower(extractedExpressionNode.(*ast.BasicLit).Kind.String())
	case *ast.CallExpr:
		callExpr := context.posParent.(*ast.CallExpr)
		for i, arg := range callExpr.Args {
			if arg == extractedExpressionNode {
				callExpr.Args[i] = &ast.CallExpr{Fun: &ast.Ident{Name: extractedFuncName}}

			}
		}
		returnTypeString = extractedExpressionNode.(*ast.CallExpr).Fun.(*ast.Ident).Obj.Decl.(*ast.FuncDecl).Type.Results.List[0].Type.(*ast.Ident).Name

	// TODO:
	// Add more cases here, e.g. for CallExpr

	default:
		panic(fmt.Sprintf("Type %v not supported yet", reflect.TypeOf(context.posParent)))
	}
	astFile.Decls = append(astFile.Decls, &ast.FuncDecl{
		Name: &ast.Ident{Name: extractedFuncName},
		Type: &ast.FuncType{
			Results: &ast.FieldList{
				List: []*ast.Field{
					&ast.Field{
						Type: &ast.Ident{Name: returnTypeString},
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.ReturnStmt{
					Results: []ast.Expr{
						extractedExpressionNode,
					},
				},
			},
		},
	})

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func convert(t int) interface{} {
	stats := map[int]int{}
	n := t
	c := 0
	for {
		if n == 0 {
			break
		}

		stats[c] = n % 10
		n = n / 10
		c++
	}

	return stats
}

func main() {

	ones := []string{
		"zero",
		"one",
		"two",
		"three",
		"four",
		"five",
		"six",
		"seven",
		"eight",
		"nine",
		"ten",
		"eleven",
		"twelve",
		"thirteen",
		"fourteen",
		"fifteen",
		"sixteen",
		"seventeen",
		"eighteen",
		"nineteen",
	}

	tens := []string{
		"twenty",
		"thirty",
		"fourty",
		"fifty",
		"sixty",
		"seventy",
		"eighty",
		"ninety",
	}

	fmt.Println(stat)
	fmt.Println(convert(422))
	s := convert(422)

	for i:=2; i>=0 ; i-- {
		fmt.Println(
	}
}
<commit_msg>update<commit_after>package main

import (
	"fmt"
)

func convert(n int) string {
	//func convert(n int) interface{} {

	ones := []string{
		"",
		"one",
		"two",
		"three",
		"four",
		"five",
		"six",
		"seven",
		"eight",
		"nine",
		"ten",
		"eleven",
		"twelve",
		"thirteen",
		"fourteen",
		"fifteen",
		"sixteen",
		"seventeen",
		"eighteen",
		"nineteen",
	}

	tens := []string{
		"",
		"",
		"twenty",
		"thirty",
		"fourty",
		"fifty",
		"sixty",
		"seventy",
		"eighty",
		"ninety",
	}

	stats := make([]int, 4, 5)
	//	n := t
	c := 0
	for {
		if n == 0 {
			break
		}

		stats[c] = n % 10
		n = n / 10
		c++
	}

	//t := s.([]int)

	t := stats
	res := ""

	//fmt.Println(res)
	return res
}

func convert2(n int) []int {
	a := []int{1, 2, 3}
	return a
}

func main() {

	//	fmt.Println(stat)
	//	fmt.Println(convert(422))
	arr := make([]string, 1001, 1050)
	sum := 0
	for i := 1; i < 1001; i++ {
		arr[i-1] = convert(i)
		sum += len(arr[i-1])

		fmt.Println(arr[i-1])
		//fmt.Println(i)
		//sum += len(convert(i))
	}

	fmt.Println(sum)

}
<|endoftext|>


<commit_before>package gosseract

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

type AnywayArgs struct {
	SourcePath  string
	Destination string
}

// TODO?: Support windows? :(
var (
	TMPFILEPREFIX = "gosseract"
	OUTEXT        = ".txt"
	COMMAND       = "tesseract"
	VERSION       = "0.0.1"
)

func Greeting() string {
	return "Hello,Gosseract!"
}

// `Anyway` provide the way to execute OCR instantly and directly.
func Anyway(args AnywayArgs) string {
	out := ""
	// TODO: DO NOT USE tmp files, using stdin is better
	//	   @see https://code.google.com/p/tesseract-ocr/issues/detail?id=813
	// TODO: Check tesseract-ocr's version?
	if args.Destination == "" {
		args.Destination = genTmpFilePath()
	}
	// Execute the command
	command := exec.Command(COMMAND, args.SourcePath, args.Destination)
	e := command.Run()
	if e != nil {
		panic(e)
	}

	// TODO: DRY
	// Reading output
	// (outputs of `tesseract` automatically be `{second-args}.txt` format)
	fn := args.Destination + OUTEXT
	f, _ := os.OpenFile(fn, 1, 1)
	buf, _ := ioutil.ReadFile(f.Name())
	out = string(buf)

	_ = os.Remove(f.Name())

	return out
}

func getTesseractVersion() string {
	command := exec.Command(COMMAND, "--version")
	var stderr bytes.Buffer
	command.Stderr = &stderr // XXX: Why it's stderr X(
	e := command.Run()
	if e != nil {
		panic(e)
	}
	// ugly
	tesseractInfo := strings.Split(stderr.String(), " ")[1]
	return strings.TrimRight(tesseractInfo, "\n")
}

// Get all available language able to use from `tesseract`
func getAvailableLanguages() []string {
	command := exec.Command(COMMAND, "--list-langs")
	var stderr bytes.Buffer
	command.Stderr = &stderr // XXX: Why it's stderr X(
	e := command.Run()
	if e != nil {
		panic(e)
	}
	langs := strings.Split(stderr.String(), "\n")
	return langs[1 : len(langs)-1]
}

// Capsulize files management.
// Takes path to source file.
// Returns result string.
func execute(source string, args []string) string {
	_args := []string{}
	_args = append(_args, source)

	dest := genTmpFilePath()

	_args = append(_args, dest)
	for _, a := range args {
		_args = append(_args, a)
	}
	_ = _exec(COMMAND, _args)

	// TODO: DRY
	// Reading output
	// (outputs of `tesseract` automatically be `{second-args}.txt` format)
	fn := dest + OUTEXT

	f, _ := os.OpenFile(fn, 1, 1)
	buf, _ := ioutil.ReadFile(f.Name())
	out := string(buf)

	_ = os.Remove(fn)

	return out
}

func tesseractInstalled() bool {
	found := _exec("which", []string{"tesseract"})

	return found != ""
}

// the very general command execution wrapper
func _exec(command string, args []string) string {
	cmd := exec.Command(command, args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	_ = cmd.Run()
	if stdout.String() != "" {
		return stdout.String()
	}
	return stderr.String()
}

// Generates tmp filepath
func genTmpFilePath() string {
	myTmpDir := "" // TODO: enable to choose optionally
	f, e := ioutil.TempFile(myTmpDir, TMPFILEPREFIX)
	if e != nil {
		panic(e)
	}
	return f.Name()
}
<commit_msg>Mark TODO<commit_after>package gosseract

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

type AnywayArgs struct {
	SourcePath  string
	Destination string
}

// TODO?: Support windows? :(
// <- may be solved by 403cb0ff41bfa65a2e2882ed1329803ce27f4f26
// TODO: check in windows
var (
	TMPFILEPREFIX = "gosseract"
	OUTEXT        = ".txt"
	COMMAND       = "tesseract"
	VERSION       = "0.0.1"
)

func Greeting() string {
	return "Hello,Gosseract!"
}

// `Anyway` provide the way to execute OCR instantly and directly.
func Anyway(args AnywayArgs) string {
	out := ""
	// TODO: DO NOT USE tmp files, using stdin is better
	//	   @see https://code.google.com/p/tesseract-ocr/issues/detail?id=813
	// TODO: Check tesseract-ocr's version?
	if args.Destination == "" {
		args.Destination = genTmpFilePath()
	}
	// Execute the command
	command := exec.Command(COMMAND, args.SourcePath, args.Destination)
	e := command.Run()
	if e != nil {
		panic(e)
	}

	// TODO: DRY
	// Reading output
	// (outputs of `tesseract` automatically be `{second-args}.txt` format)
	fn := args.Destination + OUTEXT
	f, _ := os.OpenFile(fn, 1, 1)
	buf, _ := ioutil.ReadFile(f.Name())
	out = string(buf)

	_ = os.Remove(f.Name())

	return out
}

func getTesseractVersion() string {
	command := exec.Command(COMMAND, "--version")
	var stderr bytes.Buffer
	command.Stderr = &stderr // XXX: Why it's stderr X(
	e := command.Run()
	if e != nil {
		panic(e)
	}
	// ugly
	tesseractInfo := strings.Split(stderr.String(), " ")[1]
	return strings.TrimRight(tesseractInfo, "\n")
}

// Get all available language able to use from `tesseract`
func getAvailableLanguages() []string {
	command := exec.Command(COMMAND, "--list-langs")
	var stderr bytes.Buffer
	command.Stderr = &stderr // XXX: Why it's stderr X(
	e := command.Run()
	if e != nil {
		panic(e)
	}
	langs := strings.Split(stderr.String(), "\n")
	return langs[1 : len(langs)-1]
}

// Capsulize files management.
// Takes path to source file.
// Returns result string.
func execute(source string, args []string) string {
	_args := []string{}
	_args = append(_args, source)

	dest := genTmpFilePath()

	_args = append(_args, dest)
	for _, a := range args {
		_args = append(_args, a)
	}
	_ = _exec(COMMAND, _args)

	// TODO: DRY
	// Reading output
	// (outputs of `tesseract` automatically be `{second-args}.txt` format)
	fn := dest + OUTEXT

	f, _ := os.OpenFile(fn, 1, 1)
	buf, _ := ioutil.ReadFile(f.Name())
	out := string(buf)

	_ = os.Remove(fn)

	return out
}

func tesseractInstalled() bool {
	found := _exec("which", []string{"tesseract"})

	return found != ""
}

// the very general command execution wrapper
func _exec(command string, args []string) string {
	cmd := exec.Command(command, args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	_ = cmd.Run()
	if stdout.String() != "" {
		return stdout.String()
	}
	return stderr.String()
}

// Generates tmp filepath
func genTmpFilePath() string {
	myTmpDir := "" // TODO: enable to choose optionally
	f, e := ioutil.TempFile(myTmpDir, TMPFILEPREFIX)
	if e != nil {
		panic(e)
	}
	return f.Name()
}
<|endoftext|>