<commit_before>/*
	Execute shell commands via http server

	Install:
		go get github.com/msoap/shell2http
		ln -s $GOPATH/bin/shell2http ~/bin/shell2http

	Usage:
		shell2http /path "shell command" /path2 "shell command2" ...

	Examples:
		shell2http /top "top -l 1 | head -10"
		shell2http /date date /ps "ps aux"
		shell2http /env 'printenv | sort' /env/path 'echo $PATH' /env/gopath 'echo $GOPATH'
		shell2http /shell_vars_json 'perl -MJSON -E "say to_json(\%ENV)"'
		shell2http /cal_html 'echo "
Calendar
Date: $(date)

$(cal $(date +%Y))
"'

	Update:
		go get -u github.com/msoap/shell2http

*/
package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"os/exec"
)

const PORT = "8080"

// ------------------------------------------------------------------
const INDEX_HTML = `
<!DOCTYPE html>

	<title>Index shell commands</title>

Index shell commands

		%s

/exit

`

// ------------------------------------------------------------------
// one command type
type t_command struct {
	path string
	cmd  string
}

// ------------------------------------------------------------------
// parse argeuments
func get_handlers() ([]t_command, error) {
	// need >= 2 argeuments and count of it must be even
	if len(os.Args) < 3 || len(os.Args)%2 == 0 {
		return nil, errors.New(`Usage: shell2http /path "shell command" /path2 "shell command2" ...`)
	}

	cmd_handlers := []t_command{}

	args_i := 1
	for args_i < len(os.Args) {
		path, cmd := os.Args[args_i], os.Args[args_i+1]
		if path[0] != '/' {
			return nil, errors.New(fmt.Sprintf("Error: path %s dont starts with /", path))
		}
		cmd_handlers = append(cmd_handlers, t_command{path: path, cmd: cmd})
		args_i += 2
	}

	return cmd_handlers, nil
}

// ------------------------------------------------------------------
// setup http handlers
func setup_handlers(cmd_handlers []t_command, the_end chan interface{}) {
	index_li_html := ""
	for _, row := range cmd_handlers {
		path, cmd := row.path, row.cmd
		shell_handler := func(rw http.ResponseWriter, req *http.Request) {
			fmt.Println("GET", path)

			shell_out, err := exec.Command("sh", "-c", cmd).Output()
			if err != nil {
				fmt.Println("exec error: ", err)
				fmt.Fprint(rw, "exec error: ", err)
			} else {
				fmt.Fprint(rw, string(shell_out))
			}

			return
		}

		fmt.Printf("register: %s (%s)\n", path, cmd)
		http.HandleFunc(path, shell_handler)
		index_li_html += fmt.Sprintf(`<li><a href="%s">%s</a></li>`, path, path)
	}

	// --------------
	index_html := fmt.Sprintf(INDEX_HTML, index_li_html)
	http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
		fmt.Println("GET /")
		fmt.Fprint(rw, index_html)

		return
	})

	// --------------
	http.HandleFunc("/exit", func(rw http.ResponseWriter, req *http.Request) {
		fmt.Println("GET /exit")
		fmt.Fprint(rw, "Bye...")
		the_end <- nil

		return
	})
}

// ------------------------------------------------------------------
func main() {
	cmd_handlers, err := get_handlers()
	if err != nil {
		fmt.Println(err)
		return
	}
	the_end := make(chan interface{})
	setup_handlers(cmd_handlers, the_end)

	fmt.Println("listen http://localhost:" + PORT + "/")
	go http.ListenAndServe(":"+PORT, nil)
	<-the_end // wait for exit command
}
<commit_msg>Changes from golint<commit_after>/*
Execute shell commands via http server

Install:
	go get github.com/msoap/shell2http
	ln -s $GOPATH/bin/shell2http ~/bin/shell2http

Usage:
	shell2http /path "shell command" /path2 "shell command2" ...

Examples:
	shell2http /top "top -l 1 | head -10"
	shell2http /date date /ps "ps aux"
	shell2http /env 'printenv | sort' /env/path 'echo $PATH' /env/gopath 'echo $GOPATH'
	shell2http /shell_vars_json 'perl -MJSON -E "say to_json(\%ENV)"'
	shell2http /cal_html 'echo "
Calendar
Date: $(date)

$(cal $(date +%Y))
"'

Update:
	go get -u github.com/msoap/shell2http

*/
package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"os/exec"
)

// default port for http-server
const PORT = "8080"

// ------------------------------------------------------------------
const INDEX_HTML = `
<!DOCTYPE html>

	<title>Index shell commands</title>

Index shell commands

		%s

/exit

`

// ------------------------------------------------------------------
// one command type
type t_command struct {
	path string
	cmd  string
}

// ------------------------------------------------------------------
// parse argeuments
func get_handlers() ([]t_command, error) {
	// need >= 2 argeuments and count of it must be even
	if len(os.Args) < 3 || len(os.Args)%2 == 0 {
		return nil, errors.New(`Usage: shell2http /path "shell command" /path2 "shell command2" ...`)
	}

	cmd_handlers := []t_command{}

	args_i := 1
	for args_i < len(os.Args) {
		path, cmd := os.Args[args_i], os.Args[args_i+1]
		if path[0] != '/' {
			return nil, errors.New(fmt.Sprintf("Error: path %s dont starts with /", path))
		}
		cmd_handlers = append(cmd_handlers, t_command{path: path, cmd: cmd})
		args_i += 2
	}

	return cmd_handlers, nil
}

// ------------------------------------------------------------------
// setup http handlers
func setup_handlers(cmd_handlers []t_command, the_end chan interface{}) {
	index_li_html := ""
	for _, row := range cmd_handlers {
		path, cmd := row.path, row.cmd
		shell_handler := func(rw http.ResponseWriter, req *http.Request) {
			fmt.Println("GET", path)

			shell_out, err := exec.Command("sh", "-c", cmd).Output()
			if err != nil {
				fmt.Println("exec error: ", err)
				fmt.Fprint(rw, "exec error: ", err)
			} else {
				fmt.Fprint(rw, string(shell_out))
			}

			return
		}

		fmt.Printf("register: %s (%s)\n", path, cmd)
		http.HandleFunc(path, shell_handler)
		index_li_html += fmt.Sprintf(`<li><a href="%s">%s</a></li>`, path, path)
	}

	// --------------
	index_html := fmt.Sprintf(INDEX_HTML, index_li_html)
	http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
		fmt.Println("GET /")
		fmt.Fprint(rw, index_html)

		return
	})

	// --------------
	http.HandleFunc("/exit", func(rw http.ResponseWriter, req *http.Request) {
		fmt.Println("GET /exit")
		fmt.Fprint(rw, "Bye...")
		the_end <- nil

		return
	})
}

// ------------------------------------------------------------------
func main() {
	cmd_handlers, err := get_handlers()
	if err != nil {
		fmt.Println(err)
		return
	}
	the_end := make(chan interface{})
	setup_handlers(cmd_handlers, the_end)

	fmt.Println("listen http://localhost:" + PORT + "/")
	go http.ListenAndServe(":"+PORT, nil)
	<-the_end // wait for exit command
}
<|endoftext|>


<commit_before>package main

type bash int

var BASH bash

func (b bash) Hook() string {
	return `PROMPT_COMMAND="eval \"\$(direnv export bash) ;$PROMPT_COMMAND\""`
}

func (b bash) Escape(str string) string {
	return ShellEscape(str)
}

func (b bash) Export(key, value string) string {
	return "export " + b.Escape(key) + "=" + b.Escape(value) + ";"
}

func (b bash) Unset(key string) string {
	return "unset " + b.Escape(key) + ";"
}
<commit_msg>Fixes the bash hook<commit_after>package main

type bash int

var BASH bash

func (b bash) Hook() string {
	return `PROMPT_COMMAND="eval \"\$(direnv export bash)\";$PROMPT_COMMAND"`
}

func (b bash) Escape(str string) string {
	return ShellEscape(str)
}

func (b bash) Export(key, value string) string {
	return "export " + b.Escape(key) + "=" + b.Escape(value) + ";"
}

func (b bash) Unset(key string) string {
	return "unset " + b.Escape(key) + ";"
}
<|endoftext|>


<commit_before>package scipipe

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	t "testing"
)

func TestShellHasInOutPorts(t *t.T) {
	tt := Sh("echo {i:in1} {o:out1}")
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	go func() { tt.InPorts["in1"] <- NewFileTarget("foo.txt") }()
	go tt.Run()
	<-tt.OutPorts["out1"]

	assert.NotNil(t, tt.InPorts["in1"], "InPorts are nil!")
	assert.NotNil(t, tt.OutPorts["out1"], "OutPorts are nil!")

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestShellCloseOutPortOnInPortClose(t *t.T) {
	fooTask := Sh("echo foo > {o:out1}")
	fooTask.OutPathFuncs["out1"] = func() string {
		return "foo.txt"
	}

	barReplacer := Sh("sed 's/foo/bar/g' {i:foo} > {o:bar}")
	barReplacer.OutPathFuncs["bar"] = func() string {
		return barReplacer.GetInPath("foo") + ".bar"
	}

	barReplacer.InPorts["foo"] = fooTask.OutPorts["out1"]

	go fooTask.Run()
	go barReplacer.Run()
	<-barReplacer.OutPorts["bar"]

	// Assert no more content coming on channels
	assert.Nil(t, <-fooTask.OutPorts["out1"])
	assert.Nil(t, <-barReplacer.OutPorts["bar"])

	_, fooErr := os.Stat("foo.txt")
	assert.Nil(t, fooErr)
	_, barErr := os.Stat("foo.txt.bar")
	assert.Nil(t, barErr)

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestReplacePlaceholdersInCmd(t *t.T) {
	rawCmd := "echo {i:in1} > {o:out1}"
	tt := Sh(rawCmd)
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	ift := NewFileTarget("foo.txt")
	go func() {
		defer close(tt.InPorts["in1"])
		tt.InPorts["in1"] <- ift
	}()

	// Assert inport is still open after first read
	inPortsClosed := tt.receiveInputs()
	assert.Equal(t, false, inPortsClosed)

	// Assert inport is closed after second read
	inPortsClosed = tt.receiveInputs()
	assert.Equal(t, true, inPortsClosed)

	// Assert InPath is correct
	assert.Equal(t, "foo.txt", tt.InPaths["in1"], "foo.txt")

	// Assert placeholders are correctly replaced in command
	cmd := tt.replacePlaceholdersInCmd(rawCmd)
	assert.EqualValues(t, "echo foo.txt > foo.txt.bar", cmd)
}

func TestParameterCommand(t *t.T) {
	// An abc file printer
	abc := Sh("echo {p:a} {p:b} {p:c} > {o:out}")
	abc.OutPathFuncs["out"] = func() string {
		return fmt.Sprintf(
			"%s_%s_%s.txt",
			abc.Params["a"],
			abc.Params["b"],
			abc.Params["c"],
		)
	}

	// A printer task
	prt := Sh("cat {i:in} >> out.log")

	// Connection info
	prt.InPorts["in"] = abc.OutPorts["out"]

	// Feed the task with multiple combinations
	go func() {
		defer close(abc.ParamPorts["a"])
		defer close(abc.ParamPorts["b"])
		defer close(abc.ParamPorts["c"])

		for _, a := range SS("a1", "a2", "a3") {
			for _, b := range SS("b1", "b2", "b3") {
				for _, c := range SS("c1", "c2", "c3") {
					abc.ParamPorts["a"] <- a
					abc.ParamPorts["b"] <- b
					abc.ParamPorts["c"] <- c
				}
			}
		}
	}()

	go abc.Run()
	prt.Run()
}

func cleanFiles(fileNames ...string) {
	for _, fileName := range fileNames {
		os.Remove(fileName)
	}
}
<commit_msg>Add assertions and file clean-up in shell tests<commit_after>package scipipe

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	t "testing"
)

func TestShellHasInOutPorts(t *t.T) {
	tt := Sh("echo {i:in1} {o:out1}")
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	go func() { tt.InPorts["in1"] <- NewFileTarget("foo.txt") }()
	go tt.Run()
	<-tt.OutPorts["out1"]

	assert.NotNil(t, tt.InPorts["in1"], "InPorts are nil!")
	assert.NotNil(t, tt.OutPorts["out1"], "OutPorts are nil!")

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestShellCloseOutPortOnInPortClose(t *t.T) {
	fooTask := Sh("echo foo > {o:out1}")
	fooTask.OutPathFuncs["out1"] = func() string {
		return "foo.txt"
	}

	barReplacer := Sh("sed 's/foo/bar/g' {i:foo} > {o:bar}")
	barReplacer.OutPathFuncs["bar"] = func() string {
		return barReplacer.GetInPath("foo") + ".bar"
	}

	barReplacer.InPorts["foo"] = fooTask.OutPorts["out1"]

	go fooTask.Run()
	go barReplacer.Run()
	<-barReplacer.OutPorts["bar"]

	// Assert no more content coming on channels
	assert.Nil(t, <-fooTask.OutPorts["out1"])
	assert.Nil(t, <-barReplacer.OutPorts["bar"])

	_, fooErr := os.Stat("foo.txt")
	assert.Nil(t, fooErr)
	_, barErr := os.Stat("foo.txt.bar")
	assert.Nil(t, barErr)

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestReplacePlaceholdersInCmd(t *t.T) {
	rawCmd := "echo {i:in1} > {o:out1}"
	tt := Sh(rawCmd)
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	ift := NewFileTarget("foo.txt")
	go func() {
		defer close(tt.InPorts["in1"])
		tt.InPorts["in1"] <- ift
	}()

	// Assert inport is still open after first read
	inPortsClosed := tt.receiveInputs()
	assert.Equal(t, false, inPortsClosed)

	// Assert inport is closed after second read
	inPortsClosed = tt.receiveInputs()
	assert.Equal(t, true, inPortsClosed)

	// Assert InPath is correct
	assert.Equal(t, "foo.txt", tt.InPaths["in1"], "foo.txt")

	// Assert placeholders are correctly replaced in command
	cmd := tt.replacePlaceholdersInCmd(rawCmd)
	assert.EqualValues(t, "echo foo.txt > foo.txt.bar", cmd)
}

func TestParameterCommand(t *t.T) {
	// An abc file printer
	abc := Sh("echo {p:a} {p:b} {p:c} > {o:out}")
	abc.OutPathFuncs["out"] = func() string {
		return fmt.Sprintf(
			"%s_%s_%s.txt",
			abc.Params["a"],
			abc.Params["b"],
			abc.Params["c"],
		)
	}

	// A printer task
	prt := Sh("cat {i:in} >> /tmp/log.txt; rm {i:in}")

	// Connection info
	prt.InPorts["in"] = abc.OutPorts["out"]

	// Feed the task with multiple combinations
	go func() {
		defer close(abc.ParamPorts["a"])
		defer close(abc.ParamPorts["b"])
		defer close(abc.ParamPorts["c"])

		for _, a := range SS("a1", "a2", "a3") {
			for _, b := range SS("b1", "b2", "b3") {
				for _, c := range SS("c1", "c2", "c3") {
					abc.ParamPorts["a"] <- a
					abc.ParamPorts["b"] <- b
					abc.ParamPorts["c"] <- c
				}
			}
		}
	}()

	go abc.Run()
	prt.Run()
	fmt.Println("Finished TestParameterCommand")

	_, err := os.Stat("/tmp/log.txt")
	assert.Nil(t, err)

	cleanFiles("/tmp/log.txt")
}

func cleanFiles(fileNames ...string) {
	for _, fileName := range fileNames {
		if _, err := os.Stat(fileName); err == nil {
			fmt.Println("Removing file", fileName)
			os.Remove(fileName)
			fmt.Println("Successfully removed file", fileName)
		}
	}
}
<|endoftext|>


<commit_before>package disgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/slf4go/logger"
)

type shard struct {
	// Parent session
	session *Session

	// Websocket information used for identification and reconnection
	webSocket *websocket.Conn
	shard     int
	sessionID string
	sequence  uint64
	heartbeat int

	// Mutex locks, reconnect to make sure there is only 1 process reconnecting and concurrent read/write accesses on the socket
	readLock, writeLock sync.Mutex

	// Channels used to synchronize shutdown of this shards goroutines
	isShuttingDown    bool
	closeMainLoop     chan bool
	closeConfirmation chan bool
}

// Shard constructor, automatically connects with the given shardNum
func newShard(session *Session, shardNum int) (*shard, error) {
	s := &shard{
		session:           session,
		shard:             shardNum,
		closeMainLoop:     make(chan bool),
		closeConfirmation: make(chan bool),
	}

	// These will be unlocked once a connection is made.
	s.readLock.Lock()
	s.writeLock.Lock()

	if err := s.connect(); err != nil {
		return nil, err
	}

	return s, nil
}

// Builds a new connection with Discord, waits for the "hello" frame and then proceeds to identify itself to the Discord service
func (s *shard) connect() error {
	// Open the websocket
	conn, _, err := websocket.DefaultDialer.Dial(s.session.wsUrl, http.Header{})
	if err != nil {
		return err
	}

	s.webSocket = conn
	s.webSocket.SetCloseHandler(s.onClose)

	// At the end of this function, clean up the socket if we didn't identify correctly.
	defer func() {
		if err != nil {
			conn.Close()
			s.webSocket = nil
		}
	}()

	// Discord always sends a hello frame upon opening the connection
	var helloFrame *receivedFrame
	helloFrame, err = s.readFrame(true)
	if err != nil {
		return err
	} else if helloFrame.Op != opHello {
		return errors.New("First frame sent from the Discord Gateway is not hello")
	}

	hello := helloPayload{}
	if err = json.Unmarshal(helloFrame.Data, &hello); err != nil {
		return err
	}

	// We've succesfully connected.
	logger.Debugf("Connected to Discord servers: %s", strings.Join(hello.Servers, ", "))
	logger.Debugf("Setting up a heartbeat interval of %d ms", hello.HeartbeatInterval)
	s.heartbeat = hello.HeartbeatInterval

	// Now identify
	if err = s.identify(); err != nil {
		return err
	}

	// Identification succesful, unlock reading/writing and start the goroutines
	s.readLock.Unlock()
	s.writeLock.Unlock()
	go s.mainLoop()

	return nil
}

// identify takes care of the identification using the bot token on the discord server
func (s *shard) identify() error {
	if s.sessionID != "" {
		logger.Debugf("Resuming connection starting at sequence %d.", s.sequence)
		s.sendFrame(&gatewayFrame{opResume, resumePayload{
			Token:     s.session.token,
			SessionID: s.sessionID,
			Sequence:  s.sequence,
		}}, true)
	} else {
		logger.Debugf("Identifying to websocket")
		s.sendFrame(&gatewayFrame{opIdentify, identifyPayload{
			Token:          s.session.token,
			Compress:       true,
			LargeThreshold: 250,
			Shard:          [2]int{s.shard, cap(s.session.shards)},
			Properties: propertiesPayload{
				OS:      runtime.GOOS,
				Browser: "DisGo",
				Device:  "DisGo",
			},
		}}, true)
	}

	for {
		frame, err := s.readFrame(true)
		if err != nil {
			return err
		}

		switch frame.Op {
		case opDispatch:
			switch frame.EventName {
			case "READY":
				ready := ReadyEvent{}
				if err := json.Unmarshal(frame.Data, &ready); err != nil {
					return err
				}

				s.sessionID = ready.SessionID

				fallthrough
			case "RESUMED":
				s.session.dispatchEvent(frame)
				return nil // Break out of the loop, we have what we want
			default:
				s.session.dispatchEvent(frame) // Nope, resume action, let's wait for more frames
			}
		case opInvalidSession:
			s.sessionID = "" // Invalidate session and retry
			return s.identify()
		default:
			return fmt.Errorf("Unexpected opCode received from Discord: %d", frame.Op)
		}
	}
}

// Main loop of the shard connection, also responsible for starting the read loop.
// This goroutine will pass around all the messages through the rest of the library.
func (s *shard) mainLoop() {
	logger.Debugf("Starting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	heartbeat := time.NewTicker(time.Duration(s.heartbeat) * time.Millisecond)
	defer heartbeat.Stop()
	sentHeartBeat := false

	reader := make(chan *receivedFrame, 1)
	go s.readWebSocket(reader)

	for {
		select {
		case <-heartbeat.C:
			if !sentHeartBeat {
				go s.sendFrame(&gatewayFrame{opHeartbeat, s.sequence}, false)
				sentHeartBeat = true
			} else {
				go s.disconnect(websocket.ClosePolicyViolation, "Did not respond to previous heartbeat")
			}
		case <-s.closeMainLoop:
			return
		case frame := <-reader:
			switch frame.Op {
			case opHeartbeat:
				s.sendFrame(&gatewayFrame{Op: opHeartbeatAck}, false)
			case opHeartbeatAck:
				sentHeartBeat = false
			case opReconnect:
				go s.disconnect(websocket.CloseNormalClosure, "op Reconnect")
			case opInvalidSession:
				s.sessionID = ""
				s.identify()
			case opDispatch:
				s.session.dispatchEvent(frame)
			default:
				logger.Errorf("Unexpected opCode received: %d", frame.Op)
			}
		}
	}
}

// The secondary goroutine of each shard, responsible for reading frames and putting them in the channel.
func (s *shard) readWebSocket(reader chan *receivedFrame) {
	logger.Debugf("Starting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	for {
		frame, err := s.readFrame(false)
		if err != nil {
			if !s.isShuttingDown {
				s.onClose(websocket.CloseAbnormalClosure, err.Error())
			}
			return
		}

		reader <- frame
	}

}

// Reads 1 frame from the websocket.
func (s *shard) readFrame(isConnecting bool) (*receivedFrame, error) {
	if !isConnecting {
		s.readLock.Lock()
		defer s.readLock.Unlock()
	}

	logger.Tracef("Shard.readFrame() called")
	msgType, msg, err := s.webSocket.ReadMessage()
	if err != nil {
		return nil, err
	}

	var reader io.Reader
	reader = bytes.NewBuffer(msg)

	if msgType == websocket.BinaryMessage {
		zReader, err := zlib.NewReader(reader)
		if err != nil {
			return nil, err
		}

		defer zReader.Close()

		reader = zReader
	}

	frame := receivedFrame{Sequence: -1}
	err = json.NewDecoder(reader).Decode(&frame)
	if err != nil {
		return nil, err
	}

	logger.Debugf("Received frame with opCode: %d", frame.Op)

	if frame.Sequence > s.sequence {
		logger.Tracef("Last sequence received set to %d.", frame.Sequence)
		s.sequence = frame.Sequence
	}
	return &frame, nil
}

// Sends 1 frame to the websocket
func (s *shard) sendFrame(frame *gatewayFrame, isConnecting bool) {
	if !isConnecting {
		s.writeLock.Lock()
		defer s.writeLock.Unlock()
	}

	logger.Debugf("Sending frame with opCode: %d", frame.Op)
	s.webSocket.WriteJSON(frame)
}

// Called when we have received a closing intention that we have not initiated (ws close message, recv error)
func (s *shard) onClose(code int, text string) error {
	go func() {
		logger.Warnf("Received Close Frame from Discord. Code: %d. Text: %s", code, text)

		s.isShuttingDown = true
		s.stopRoutines()
		s.readLock.Lock()
		s.writeLock.Lock()

		if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
			logger.Error("Could not confirm close message.")
			logger.ErrorE(err)
		}

		s.cleanupWebSocket()
	}()

	return nil
}

// Called by us to disconnect the websocket (shutdown, protocol errors, missed heartbeats)
func (s *shard) disconnect(code int, text string) {
	s.isShuttingDown = true
	s.writeLock.Lock()

	closeMessage := make(chan int)
	s.webSocket.SetCloseHandler(func(code int, _ string) error {
		closeMessage <- code
		return nil
	})

	if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
		logger.Error("Could not write close message to Discord, connection already dead?")
		logger.ErrorE(err)
	} else {
		select {
		case code := <-closeMessage:
			logger.Debugf("Discord connection closed with code %d", code)
		case <-time.After(1 * time.Second):
			logger.Warn("Discord did not reply to the close message, force-closing connection.")
		}
	}

	s.stopRoutines()
	s.readLock.Lock()
	s.cleanupWebSocket()
}

// Stops the two shard goroutines
func (s *shard) stopRoutines() {
	s.webSocket.SetReadDeadline(time.Now()) // Stop the read loop, in case it hasn't already due to an error
	<-s.closeConfirmation                   // Wait for the read loop
	s.closeMainLoop <- true                 // Stop the main loop
	<-s.closeConfirmation                   // Wait for the main loop
}

// Cleans up the current websocket and tries to reconnect it if needed
func (s *shard) cleanupWebSocket() {
	s.webSocket.Close()
	s.webSocket = nil

	for !s.session.isShuttingDown() {
		if err := s.connect(); err != nil {
			logger.Error("Could not reconnect to Discord.")
			logger.ErrorE(err)

			time.Sleep(500 * time.Millisecond)
		} else {
			break
		}
	}
}
<commit_msg>Fixed unsigned overflow<commit_after>package disgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/slf4go/logger"
)

type shard struct {
	// Parent session
	session *Session

	// Websocket information used for identification and reconnection
	webSocket *websocket.Conn
	shard     int
	sessionID string
	sequence  uint64
	heartbeat int

	// Mutex locks, reconnect to make sure there is only 1 process reconnecting and concurrent read/write accesses on the socket
	readLock, writeLock sync.Mutex

	// Channels used to synchronize shutdown of this shards goroutines
	isShuttingDown    bool
	closeMainLoop     chan bool
	closeConfirmation chan bool
}

// Shard constructor, automatically connects with the given shardNum
func newShard(session *Session, shardNum int) (*shard, error) {
	s := &shard{
		session:           session,
		shard:             shardNum,
		closeMainLoop:     make(chan bool),
		closeConfirmation: make(chan bool),
	}

	// These will be unlocked once a connection is made.
	s.readLock.Lock()
	s.writeLock.Lock()

	if err := s.connect(); err != nil {
		return nil, err
	}

	return s, nil
}

// Builds a new connection with Discord, waits for the "hello" frame and then proceeds to identify itself to the Discord service
func (s *shard) connect() error {
	// Open the websocket
	conn, _, err := websocket.DefaultDialer.Dial(s.session.wsUrl, http.Header{})
	if err != nil {
		return err
	}

	s.webSocket = conn
	s.webSocket.SetCloseHandler(s.onClose)

	// At the end of this function, clean up the socket if we didn't identify correctly.
	defer func() {
		if err != nil {
			conn.Close()
			s.webSocket = nil
		}
	}()

	// Discord always sends a hello frame upon opening the connection
	var helloFrame *receivedFrame
	helloFrame, err = s.readFrame(true)
	if err != nil {
		return err
	} else if helloFrame.Op != opHello {
		return errors.New("First frame sent from the Discord Gateway is not hello")
	}

	hello := helloPayload{}
	if err = json.Unmarshal(helloFrame.Data, &hello); err != nil {
		return err
	}

	// We've succesfully connected.
	logger.Debugf("Connected to Discord servers: %s", strings.Join(hello.Servers, ", "))
	logger.Debugf("Setting up a heartbeat interval of %d ms", hello.HeartbeatInterval)
	s.heartbeat = hello.HeartbeatInterval

	// Now identify
	if err = s.identify(); err != nil {
		return err
	}

	// Identification succesful, unlock reading/writing and start the goroutines
	s.readLock.Unlock()
	s.writeLock.Unlock()
	go s.mainLoop()

	return nil
}

// identify takes care of the identification using the bot token on the discord server
func (s *shard) identify() error {
	if s.sessionID != "" {
		logger.Debugf("Resuming connection starting at sequence %d.", s.sequence)
		s.sendFrame(&gatewayFrame{opResume, resumePayload{
			Token:     s.session.token,
			SessionID: s.sessionID,
			Sequence:  s.sequence,
		}}, true)
	} else {
		logger.Debugf("Identifying to websocket")
		s.sendFrame(&gatewayFrame{opIdentify, identifyPayload{
			Token:          s.session.token,
			Compress:       true,
			LargeThreshold: 250,
			Shard:          [2]int{s.shard, cap(s.session.shards)},
			Properties: propertiesPayload{
				OS:      runtime.GOOS,
				Browser: "DisGo",
				Device:  "DisGo",
			},
		}}, true)
	}

	for {
		frame, err := s.readFrame(true)
		if err != nil {
			return err
		}

		switch frame.Op {
		case opDispatch:
			switch frame.EventName {
			case "READY":
				ready := ReadyEvent{}
				if err := json.Unmarshal(frame.Data, &ready); err != nil {
					return err
				}

				s.sessionID = ready.SessionID

				fallthrough
			case "RESUMED":
				s.session.dispatchEvent(frame)
				return nil // Break out of the loop, we have what we want
			default:
				s.session.dispatchEvent(frame) // Nope, resume action, let's wait for more frames
			}
		case opInvalidSession:
			s.sessionID = "" // Invalidate session and retry
			return s.identify()
		default:
			return fmt.Errorf("Unexpected opCode received from Discord: %d", frame.Op)
		}
	}
}

// Main loop of the shard connection, also responsible for starting the read loop.
// This goroutine will pass around all the messages through the rest of the library.
func (s *shard) mainLoop() {
	logger.Debugf("Starting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting main loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	heartbeat := time.NewTicker(time.Duration(s.heartbeat) * time.Millisecond)
	defer heartbeat.Stop()
	sentHeartBeat := false

	reader := make(chan *receivedFrame, 1)
	go s.readWebSocket(reader)

	for {
		select {
		case <-heartbeat.C:
			if !sentHeartBeat {
				go s.sendFrame(&gatewayFrame{opHeartbeat, s.sequence}, false)
				sentHeartBeat = true
			} else {
				go s.disconnect(websocket.ClosePolicyViolation, "Did not respond to previous heartbeat")
			}
		case <-s.closeMainLoop:
			return
		case frame := <-reader:
			switch frame.Op {
			case opHeartbeat:
				s.sendFrame(&gatewayFrame{Op: opHeartbeatAck}, false)
			case opHeartbeatAck:
				sentHeartBeat = false
			case opReconnect:
				go s.disconnect(websocket.CloseNormalClosure, "op Reconnect")
			case opInvalidSession:
				s.sessionID = ""
				s.identify()
			case opDispatch:
				s.session.dispatchEvent(frame)
			default:
				logger.Errorf("Unexpected opCode received: %d", frame.Op)
			}
		}
	}
}

// The secondary goroutine of each shard, responsible for reading frames and putting them in the channel.
func (s *shard) readWebSocket(reader chan *receivedFrame) {
	logger.Debugf("Starting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer logger.Debugf("Exiting read loop for shard [%d/%d]", s.shard+1, cap(s.session.shards))
	defer func() { s.closeConfirmation <- true }()

	for {
		frame, err := s.readFrame(false)
		if err != nil {
			if !s.isShuttingDown {
				s.onClose(websocket.CloseAbnormalClosure, err.Error())
			}
			return
		}

		reader <- frame
	}

}

// Reads 1 frame from the websocket.
func (s *shard) readFrame(isConnecting bool) (*receivedFrame, error) {
	if !isConnecting {
		s.readLock.Lock()
		defer s.readLock.Unlock()
	}

	logger.Tracef("Shard.readFrame() called")
	msgType, msg, err := s.webSocket.ReadMessage()
	if err != nil {
		return nil, err
	}

	var reader io.Reader
	reader = bytes.NewBuffer(msg)

	if msgType == websocket.BinaryMessage {
		zReader, err := zlib.NewReader(reader)
		if err != nil {
			return nil, err
		}

		defer zReader.Close()

		reader = zReader
	}

	frame := receivedFrame{Sequence: 0}
	err = json.NewDecoder(reader).Decode(&frame)
	if err != nil {
		return nil, err
	}

	logger.Debugf("Received frame with opCode: %d", frame.Op)

	if frame.Sequence > s.sequence {
		logger.Tracef("Last sequence received set to %d.", frame.Sequence)
		s.sequence = frame.Sequence
	}
	return &frame, nil
}

// Sends 1 frame to the websocket
func (s *shard) sendFrame(frame *gatewayFrame, isConnecting bool) {
	if !isConnecting {
		s.writeLock.Lock()
		defer s.writeLock.Unlock()
	}

	logger.Debugf("Sending frame with opCode: %d", frame.Op)
	s.webSocket.WriteJSON(frame)
}

// Called when we have received a closing intention that we have not initiated (ws close message, recv error)
func (s *shard) onClose(code int, text string) error {
	go func() {
		logger.Warnf("Received Close Frame from Discord. Code: %d. Text: %s", code, text)

		s.isShuttingDown = true
		s.stopRoutines()
		s.readLock.Lock()
		s.writeLock.Lock()

		if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
			logger.Error("Could not confirm close message.")
			logger.ErrorE(err)
		}

		s.cleanupWebSocket()
	}()

	return nil
}

// Called by us to disconnect the websocket (shutdown, protocol errors, missed heartbeats)
func (s *shard) disconnect(code int, text string) {
	s.isShuttingDown = true
	s.writeLock.Lock()

	closeMessage := make(chan int)
	s.webSocket.SetCloseHandler(func(code int, _ string) error {
		closeMessage <- code
		return nil
	})

	if err := s.webSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(code, text)); err != nil {
		logger.Error("Could not write close message to Discord, connection already dead?")
		logger.ErrorE(err)
	} else {
		select {
		case code := <-closeMessage:
			logger.Debugf("Discord connection closed with code %d", code)
		case <-time.After(1 * time.Second):
			logger.Warn("Discord did not reply to the close message, force-closing connection.")
		}
	}

	s.stopRoutines()
	s.readLock.Lock()
	s.cleanupWebSocket()
}

// Stops the two shard goroutines
func (s *shard) stopRoutines() {
	s.webSocket.SetReadDeadline(time.Now()) // Stop the read loop, in case it hasn't already due to an error
	<-s.closeConfirmation                   // Wait for the read loop
	s.closeMainLoop <- true                 // Stop the main loop
	<-s.closeConfirmation                   // Wait for the main loop
}

// Cleans up the current websocket and tries to reconnect it if needed
func (s *shard) cleanupWebSocket() {
	s.webSocket.Close()
	s.webSocket = nil

	for !s.session.isShuttingDown() {
		if err := s.connect(); err != nil {
			logger.Error("Could not reconnect to Discord.")
			logger.ErrorE(err)

			time.Sleep(500 * time.Millisecond)
		} else {
			break
		}
	}
}
<|endoftext|>


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

package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"os"
)

const (
	// This salt is not meant to be kept secret (it’s checked in after all). It’s
	// a tiny bit of paranoia to avoid whatever problems a collision may cause.
	salt = "Go playground salt\n"

	maxSnippetSize = 64 * 1024
)

type snippet struct {
	Body []byte
}

func (s *snippet) ID() string {
	h := sha256.New()
	io.WriteString(h, salt)
	h.Write(s.Body)
	sum := h.Sum(nil)
	b := make([]byte, base64.URLEncoding.EncodedLen(len(sum)))
	base64.URLEncoding.Encode(b, sum)
	// Web sites don’t always linkify a trailing underscore, making it seem like
	// the link is broken. If there is an underscore at the end of the substring,
	// extend it until there is not.
	hashLen := 11
	for hashLen <= len(b) && b[hashLen-1] == '_' {
		hashLen++
	}
	return string(b)[:hashLen]
}

func (s *server) handleShare(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	if r.Method == "OPTIONS" {
		// This is likely a pre-flight CORS request.
		return
	}
	if r.Method != "POST" {
		http.Error(w, "Requires POST", http.StatusMethodNotAllowed)
		return
	}
	if !allowShare(r) {
		http.Error(w, "Either this isn't available in your country due to legal reasons, or our IP geolocation is wrong.",
			http.StatusUnavailableForLegalReasons)
		return
	}

	var body bytes.Buffer
	_, err := io.Copy(&body, io.LimitReader(r.Body, maxSnippetSize+1))
	r.Body.Close()
	if err != nil {
		s.log.Errorf("reading Body: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}
	if body.Len() > maxSnippetSize {
		http.Error(w, "Snippet is too large", http.StatusRequestEntityTooLarge)
		return
	}

	snip := &snippet{Body: body.Bytes()}
	id := snip.ID()
	if err := s.db.PutSnippet(r.Context(), id, snip); err != nil {
		s.log.Errorf("putting Snippet: %v", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, id)
}

func allowShare(r *http.Request) bool {
	if os.Getenv("GAE_INSTANCE") == "" {
		return true
	}
	switch r.Header.Get("X-AppEngine-Country") {
	case "", "ZZ", "CN":
		return false
	}
	return true
}
<commit_msg>playground: ensure that any inserted snippets do not index the Body property<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"os"
)

const (
	// This salt is not meant to be kept secret (it’s checked in after all). It’s
	// a tiny bit of paranoia to avoid whatever problems a collision may cause.
	salt = "Go playground salt\n"

	maxSnippetSize = 64 * 1024
)

type snippet struct {
	Body []byte `datastore:",noindex"` // golang.org/issues/23253
}

func (s *snippet) ID() string {
	h := sha256.New()
	io.WriteString(h, salt)
	h.Write(s.Body)
	sum := h.Sum(nil)
	b := make([]byte, base64.URLEncoding.EncodedLen(len(sum)))
	base64.URLEncoding.Encode(b, sum)
	// Web sites don’t always linkify a trailing underscore, making it seem like
	// the link is broken. If there is an underscore at the end of the substring,
	// extend it until there is not.
	hashLen := 11
	for hashLen <= len(b) && b[hashLen-1] == '_' {
		hashLen++
	}
	return string(b)[:hashLen]
}

func (s *server) handleShare(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	if r.Method == "OPTIONS" {
		// This is likely a pre-flight CORS request.
		return
	}
	if r.Method != "POST" {
		http.Error(w, "Requires POST", http.StatusMethodNotAllowed)
		return
	}
	if !allowShare(r) {
		http.Error(w, "Either this isn't available in your country due to legal reasons, or our IP geolocation is wrong.",
			http.StatusUnavailableForLegalReasons)
		return
	}

	var body bytes.Buffer
	_, err := io.Copy(&body, io.LimitReader(r.Body, maxSnippetSize+1))
	r.Body.Close()
	if err != nil {
		s.log.Errorf("reading Body: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}
	if body.Len() > maxSnippetSize {
		http.Error(w, "Snippet is too large", http.StatusRequestEntityTooLarge)
		return
	}

	snip := &snippet{Body: body.Bytes()}
	id := snip.ID()
	if err := s.db.PutSnippet(r.Context(), id, snip); err != nil {
		s.log.Errorf("putting Snippet: %v", err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, id)
}

func allowShare(r *http.Request) bool {
	if os.Getenv("GAE_INSTANCE") == "" {
		return true
	}
	switch r.Header.Get("X-AppEngine-Country") {
	case "", "ZZ", "CN":
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/abiosoft/ishell"
	"github.com/docker/libkv/store"
)

func buildShell(client store.Store) (*ishell.Shell, error) {
	shell := ishell.NewShell()

	shell.Println("kvshell starting...")

	shell.Register("ls", func(args ...string) (string, error) {
		pairs, err := client.List(args[0])
		if err != nil {
			panic(err)
		}

		result := ""
		for _, pair := range pairs {
			result += fmt.Sprintf("%s => %s", pair.Key, string(pair.Value))
		}

		return result, nil
	})

	shell.Register("get", func(args ...string) (string, error) {
		pair, err := client.Get(args[0])
		if err != nil {
			panic(err)
		}
		result := fmt.Sprintf("%s => %v", pair.Key, string(pair.Value))
		return result, nil
	})

	shell.Register("set", func(args ...string) (string, error) {
		err := client.Put(args[0], []byte(args[1]), nil)
		if err != nil {
			panic(err)
		}
		result := fmt.Sprintf("%s => %v", args[0], args[1])
		return result, nil
	})

	return shell, nil
}
<commit_msg>use ishell's error logging<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/abiosoft/ishell"
	"github.com/docker/libkv/store"
)

func buildShell(client store.Store) (*ishell.Shell, error) {
	shell := ishell.NewShell()

	shell.Println("kvshell starting...")

	shell.Register("ls", func(args ...string) (string, error) {
		if len(args) != 1 {
			err := errors.New("Invalid number of args. >> ls path")
			return "", err
		}
		pairs, err := client.List(args[0])
		if err != nil {
			return "", err
		} else {
			result := ""
			for _, pair := range pairs {
				result += fmt.Sprintf("%s => %s", pair.Key, string(pair.Value))
			}

			return result, nil
		}
	})

	shell.Register("get", func(args ...string) (string, error) {
		pair, err := client.Get(args[0])
		if err != nil {
			return "", err
		}
		result := fmt.Sprintf("%s => %v", pair.Key, string(pair.Value))
		return result, nil
	})

	shell.Register("set", func(args ...string) (string, error) {
		if len(args) != 2 {
			return "", errors.New("Invalid number of args. >> set path value")
		}

		err := client.Put(args[0], []byte(args[1]), nil)
		if err != nil {
			return "", err
		}
		result := fmt.Sprintf("%s => %v", args[0], args[1])
		return result, nil
	})

	return shell, nil
}
<|endoftext|>


<commit_before>package main

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

	"github.com/codegangsta/cli"

	"launchpad.net/goyaml"

	"github.com/vito/spiff/compare"
	"github.com/vito/spiff/flow"
	"github.com/vito/spiff/yaml"
)

func main() {
	app := cli.NewApp()
	app.Name = "spiff"
	app.Usage = "BOSH deployment manifest toolkit"

	app.Commands = []cli.Command{
		{
			Name:      "merge",
			ShortName: "m",
			Usage:     "merge merge stub files into a manifest template",
			Action: func(c *cli.Context) {
				if len(c.Args()) < 2 {
					cli.ShowCommandHelp(c, "merge")
					os.Exit(1)
				}

				merge(c.Args()[0], c.Args()[1:])
			},
		},
		{
			Name:      "diff",
			ShortName: "d",
			Usage:     "structurally compare two YAML files",
			Action: func(c *cli.Context) {
				if len(c.Args()) < 2 {
					cli.ShowCommandHelp(c, "diff")
					os.Exit(1)
				}

				diff(c.Args()[0], c.Args()[1])
			},
		},
	}

	app.Run(os.Args)
}

func merge(templateFilePath string, stubFilePaths []string) {
	templateFile, err := ioutil.ReadFile(templateFilePath)
	if err != nil {
		log.Fatalln("error reading template:", err)
	}

	templateYAML, err := yaml.Parse(templateFile)
	if err != nil {
		log.Fatalln("error parsing template:", err)
	}

	stubs := []yaml.Node{}

	for _, stubFilePath := range stubFilePaths {
		stubFile, err := ioutil.ReadFile(stubFilePath)
		if err != nil {
			log.Fatalln("error reading stub:", err)
		}

		stubYAML, err := yaml.Parse(stubFile)
		if err != nil {
			log.Fatalln("error parsing stub:", err)
		}

		stubs = append(stubs, stubYAML)
	}

	flowed, err := flow.Flow(templateYAML, stubs...)
	if err != nil {
		log.Fatalln("error generating manifest:", err)
	}

	yaml, err := goyaml.Marshal(flowed)
	if err != nil {
		log.Fatalln("error marshalling manifest:", err)
	}

	fmt.Println(string(yaml))
}

func diff(aFilePath, bFilePath string) {
	aFile, err := ioutil.ReadFile(aFilePath)
	if err != nil {
		log.Fatalln("error reading a:", err)
	}

	aYAML, err := yaml.Parse(aFile)
	if err != nil {
		log.Fatalln("error parsing a:", err)
	}

	bFile, err := ioutil.ReadFile(bFilePath)
	if err != nil {
		log.Fatalln("error reading b:", err)
	}

	bYAML, err := yaml.Parse(bFile)
	if err != nil {
		log.Fatalln("error parsing b:", err)
	}

	diffs := compare.Compare(aYAML, bYAML)

	if len(diffs) == 0 {
		fmt.Println("no differences!")
		return
	}

	for _, diff := range diffs {
		fmt.Println("Difference in", strings.Join(diff.Path, "."))

		if diff.A != nil {
			ayaml, err := goyaml.Marshal(diff.A)
			if err != nil {
				panic(err)
			}

			fmt.Printf("  %s has:\n    %s\n", aFilePath, strings.Replace(string(ayaml), "\n", "\n    ", -1))
		}

		if diff.B != nil {
			byaml, err := goyaml.Marshal(diff.B)
			if err != nil {
				panic(err)
			}

			fmt.Printf("  %s has:\n    %s\n", bFilePath, strings.Replace(string(byaml), "\n", "\n    ", -1))
		}
	}
}
<commit_msg>diff: colorized output<commit_after>package main

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

	"github.com/codegangsta/cli"

	"launchpad.net/goyaml"

	"github.com/vito/spiff/compare"
	"github.com/vito/spiff/flow"
	"github.com/vito/spiff/yaml"
)

func main() {
	app := cli.NewApp()
	app.Name = "spiff"
	app.Usage = "BOSH deployment manifest toolkit"

	app.Commands = []cli.Command{
		{
			Name:      "merge",
			ShortName: "m",
			Usage:     "merge merge stub files into a manifest template",
			Action: func(c *cli.Context) {
				if len(c.Args()) < 2 {
					cli.ShowCommandHelp(c, "merge")
					os.Exit(1)
				}

				merge(c.Args()[0], c.Args()[1:])
			},
		},
		{
			Name:      "diff",
			ShortName: "d",
			Usage:     "structurally compare two YAML files",
			Action: func(c *cli.Context) {
				if len(c.Args()) < 2 {
					cli.ShowCommandHelp(c, "diff")
					os.Exit(1)
				}

				diff(c.Args()[0], c.Args()[1])
			},
		},
	}

	app.Run(os.Args)
}

func merge(templateFilePath string, stubFilePaths []string) {
	templateFile, err := ioutil.ReadFile(templateFilePath)
	if err != nil {
		log.Fatalln("error reading template:", err)
	}

	templateYAML, err := yaml.Parse(templateFile)
	if err != nil {
		log.Fatalln("error parsing template:", err)
	}

	stubs := []yaml.Node{}

	for _, stubFilePath := range stubFilePaths {
		stubFile, err := ioutil.ReadFile(stubFilePath)
		if err != nil {
			log.Fatalln("error reading stub:", err)
		}

		stubYAML, err := yaml.Parse(stubFile)
		if err != nil {
			log.Fatalln("error parsing stub:", err)
		}

		stubs = append(stubs, stubYAML)
	}

	flowed, err := flow.Flow(templateYAML, stubs...)
	if err != nil {
		log.Fatalln("error generating manifest:", err)
	}

	yaml, err := goyaml.Marshal(flowed)
	if err != nil {
		log.Fatalln("error marshalling manifest:", err)
	}

	fmt.Println(string(yaml))
}

func diff(aFilePath, bFilePath string) {
	aFile, err := ioutil.ReadFile(aFilePath)
	if err != nil {
		log.Fatalln("error reading a:", err)
	}

	aYAML, err := yaml.Parse(aFile)
	if err != nil {
		log.Fatalln("error parsing a:", err)
	}

	bFile, err := ioutil.ReadFile(bFilePath)
	if err != nil {
		log.Fatalln("error reading b:", err)
	}

	bYAML, err := yaml.Parse(bFile)
	if err != nil {
		log.Fatalln("error parsing b:", err)
	}

	diffs := compare.Compare(aYAML, bYAML)

	if len(diffs) == 0 {
		fmt.Println("no differences!")
		return
	}

	for _, diff := range diffs {
		fmt.Println("Difference in", strings.Join(diff.Path, "."))

		if diff.A != nil {
			ayaml, err := goyaml.Marshal(diff.A)
			if err != nil {
				panic(err)
			}

			fmt.Printf("  %s has:\n    \x1b[32m%s\x1b[0m\n", aFilePath, strings.Replace(string(ayaml), "\n", "\n    ", -1))
		}

		if diff.B != nil {
			byaml, err := goyaml.Marshal(diff.B)
			if err != nil {
				panic(err)
			}

			fmt.Printf("  %s has:\n    \x1b[31m%s\x1b[0m\n", bFilePath, strings.Replace(string(byaml), "\n", "\n    ", -1))
		}
	}
}
<|endoftext|>


<commit_before>// Package stack provides utilities to capture and pass around stack traces.
//
// This is useful for building errors that know where they originated from, to
// track where a certain log event occured and so on.
//
// The package provides stack.Multi which represents a sequence of stack
// traces. Since in Go we return errors they don't necessarily end up with a
// single useful stack trace. For example an error may be going thru a channel
// across goroutines, in which case we may want to capture a stack trace in
// both (or many) goroutines. stack.Multi in turn is made up of stack.Stack,
// which is a set of stack.Frames. Each stack.Frame contains the File/Line/Name
// (function name). All these types implement a pretty human readable String()
// function.
//
// The GOPATH is stripped from the File location. Look at the StripGOPATH
// function on instructions for how to embed to GOPATH into the binary for when
// deploying to production and the GOPATH environment variable may not be set.
// The package name is stripped from the Name of the function since it included
// in the File location.
package stack

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const maxStackSize = 32

// Frame identifies a file, line & function name in the stack.
type Frame struct {
	File string
	Line int
	Name string
}

// String provides the standard file:line representation.
func (f Frame) String() string {
	return fmt.Sprintf("%s:%d %s", f.File, f.Line, f.Name)
}

// Stack represents an ordered set of Frames.
type Stack []Frame

// String provides the standard multi-line stack trace.
func (s Stack) String() string {
	var b bytes.Buffer
	writeStack(&b, s)
	return b.String()
}

// Multi represents a number of Stacks. This is useful to allow tracking a
// value as it travels thru code.
type Multi struct {
	stacks []Stack
}

// Stacks returns the tracked Stacks.
func (m *Multi) Stacks() []Stack {
	return m.stacks
}

// Add the given Stack to this Multi.
func (m *Multi) Add(s Stack) {
	m.stacks = append(m.stacks, s)
}

// AddCallers adds the Callers Stack to this Multi. The argument skip is
// the number of stack frames to ascend, with 0 identifying the caller of
// Callers.
func (m *Multi) AddCallers(skip int) {
	m.Add(Callers(skip + 1))
}

// String provides a human readable multi-line stack trace.
func (m *Multi) String() string {
	var b bytes.Buffer
	for i, s := range m.stacks {
		if i != 0 {
			fmt.Fprintf(&b, "\n(Stack %d)\n", i+1)
		}
		writeStack(&b, s)
	}
	return b.String()
}

// Copy makes a copy of the stack which is safe to modify.
func (m *Multi) Copy() *Multi {
	m2 := &Multi{
		stacks: make([]Stack, len(m.stacks)),
	}
	copy(m2.stacks, m.stacks)
	return m2
}

// Caller returns a single Frame for the caller. The argument skip is the
// number of stack frames to ascend, with 0 identifying the caller of Callers.
func Caller(skip int) Frame {
	pc, file, line, _ := runtime.Caller(skip + 1)
	fun := runtime.FuncForPC(pc)
	return Frame{
		File: StripGOPATH(file),
		Line: line,
		Name: StripPackage(fun.Name()),
	}
}

// Callers returns a Stack of Frames for the callers. The argument skip is the
// number of stack frames to ascend, with 0 identifying the caller of Callers.
func Callers(skip int) Stack {
	pcs := make([]uintptr, maxStackSize)
	num := runtime.Callers(skip+2, pcs)
	stack := make(Stack, num)
	for i, pc := range pcs[:num] {
		fun := runtime.FuncForPC(pc)
		file, line := fun.FileLine(pc - 1)
		stack[i].File = StripGOPATH(file)
		stack[i].Line = line
		stack[i].Name = StripPackage(fun.Name())
	}
	return stack
}

// CallersMulti returns a Multi which includes one Stack for the
// current callers. The argument skip is the number of stack frames to ascend,
// with 0 identifying the caller of CallersMulti.
func CallersMulti(skip int) *Multi {
	m := new(Multi)
	m.AddCallers(skip + 1)
	return m
}

func writeStack(b *bytes.Buffer, s Stack) {
	var width int
	for _, f := range s {
		if l := len(f.File) + numDigits(f.Line) + 1; l > width {
			width = l
		}
	}
	last := len(s) - 1
	for i, f := range s {
		b.WriteString(f.File)
		b.WriteRune(rune(':'))
		n, _ := fmt.Fprintf(b, "%d", f.Line)
		for i := width - len(f.File) - n; i != 0; i-- {
			b.WriteRune(rune(' '))
		}
		b.WriteString(f.Name)
		if i != last {
			b.WriteRune(rune('\n'))
		}
	}
}

func numDigits(i int) int {
	var n int
	for {
		n++
		i = i / 10
		if i == 0 {
			return n
		}
	}
}

// This can be set by a build script. It will be the colon separated equivalent
// of the environment variable.
var gopath string

// This is the processed version based on either the above variable set by the
// build or from the GOPATH environment variable.
var gopaths []string

func init() {
	// prefer the variable set at build time, otherwise fallback to the
	// environment variable.
	if gopath == "" {
		gopath = os.Getenv("GOPATH")
	}

	for _, p := range strings.Split(gopath, ":") {
		if p != "" {
			gopaths = append(gopaths, filepath.Join(p, "src")+"/")
		}
	}

	// Also strip GOROOT for maximum cleanliness
	gopaths = append(gopaths, filepath.Join(runtime.GOROOT(), "src", "pkg")+"/")
}

// StripGOPATH strips the GOPATH prefix from the file path f.
// In development, this will be done using the GOPATH environment variable.
// For production builds, where the GOPATH environment will not be set, the
// GOPATH can be included in the binary by passing ldflags, for example:
//
//     GO_LDFLAGS="$GO_LDFLAGS -X github.com/facebookgo/stack.gopath $GOPATH"
//     go install "-ldflags=$GO_LDFLAGS" my/pkg
func StripGOPATH(f string) string {
	for _, p := range gopaths {
		if strings.HasPrefix(f, p) {
			return f[len(p):]
		}
	}
	return f
}

// StripPackage strips the package name from the given Func.Name.
func StripPackage(n string) string {
	slashI := strings.LastIndex(n, "/")
	if slashI == -1 {
		slashI = 0 // for built-in packages
	}
	dotI := strings.Index(n[slashI:], ".")
	if dotI == -1 {
		return n
	}
	return n[slashI+dotI+1:]
}
<commit_msg>SetGOPATH function to be able to configure the GOPATH at runtime<commit_after>// Package stack provides utilities to capture and pass around stack traces.
//
// This is useful for building errors that know where they originated from, to
// track where a certain log event occured and so on.
//
// The package provides stack.Multi which represents a sequence of stack
// traces. Since in Go we return errors they don't necessarily end up with a
// single useful stack trace. For example an error may be going thru a channel
// across goroutines, in which case we may want to capture a stack trace in
// both (or many) goroutines. stack.Multi in turn is made up of stack.Stack,
// which is a set of stack.Frames. Each stack.Frame contains the File/Line/Name
// (function name). All these types implement a pretty human readable String()
// function.
//
// The GOPATH is stripped from the File location. Look at the StripGOPATH
// function on instructions for how to embed to GOPATH into the binary for when
// deploying to production and the GOPATH environment variable may not be set.
// The package name is stripped from the Name of the function since it included
// in the File location.
package stack

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const maxStackSize = 32

// Frame identifies a file, line & function name in the stack.
type Frame struct {
	File string
	Line int
	Name string
}

// String provides the standard file:line representation.
func (f Frame) String() string {
	return fmt.Sprintf("%s:%d %s", f.File, f.Line, f.Name)
}

// Stack represents an ordered set of Frames.
type Stack []Frame

// String provides the standard multi-line stack trace.
func (s Stack) String() string {
	var b bytes.Buffer
	writeStack(&b, s)
	return b.String()
}

// Multi represents a number of Stacks. This is useful to allow tracking a
// value as it travels thru code.
type Multi struct {
	stacks []Stack
}

// Stacks returns the tracked Stacks.
func (m *Multi) Stacks() []Stack {
	return m.stacks
}

// Add the given Stack to this Multi.
func (m *Multi) Add(s Stack) {
	m.stacks = append(m.stacks, s)
}

// AddCallers adds the Callers Stack to this Multi. The argument skip is
// the number of stack frames to ascend, with 0 identifying the caller of
// Callers.
func (m *Multi) AddCallers(skip int) {
	m.Add(Callers(skip + 1))
}

// String provides a human readable multi-line stack trace.
func (m *Multi) String() string {
	var b bytes.Buffer
	for i, s := range m.stacks {
		if i != 0 {
			fmt.Fprintf(&b, "\n(Stack %d)\n", i+1)
		}
		writeStack(&b, s)
	}
	return b.String()
}

// Copy makes a copy of the stack which is safe to modify.
func (m *Multi) Copy() *Multi {
	m2 := &Multi{
		stacks: make([]Stack, len(m.stacks)),
	}
	copy(m2.stacks, m.stacks)
	return m2
}

// Caller returns a single Frame for the caller. The argument skip is the
// number of stack frames to ascend, with 0 identifying the caller of Callers.
func Caller(skip int) Frame {
	pc, file, line, _ := runtime.Caller(skip + 1)
	fun := runtime.FuncForPC(pc)
	return Frame{
		File: StripGOPATH(file),
		Line: line,
		Name: StripPackage(fun.Name()),
	}
}

// Callers returns a Stack of Frames for the callers. The argument skip is the
// number of stack frames to ascend, with 0 identifying the caller of Callers.
func Callers(skip int) Stack {
	pcs := make([]uintptr, maxStackSize)
	num := runtime.Callers(skip+2, pcs)
	stack := make(Stack, num)
	for i, pc := range pcs[:num] {
		fun := runtime.FuncForPC(pc)
		file, line := fun.FileLine(pc - 1)
		stack[i].File = StripGOPATH(file)
		stack[i].Line = line
		stack[i].Name = StripPackage(fun.Name())
	}
	return stack
}

// CallersMulti returns a Multi which includes one Stack for the
// current callers. The argument skip is the number of stack frames to ascend,
// with 0 identifying the caller of CallersMulti.
func CallersMulti(skip int) *Multi {
	m := new(Multi)
	m.AddCallers(skip + 1)
	return m
}

func writeStack(b *bytes.Buffer, s Stack) {
	var width int
	for _, f := range s {
		if l := len(f.File) + numDigits(f.Line) + 1; l > width {
			width = l
		}
	}
	last := len(s) - 1
	for i, f := range s {
		b.WriteString(f.File)
		b.WriteRune(rune(':'))
		n, _ := fmt.Fprintf(b, "%d", f.Line)
		for i := width - len(f.File) - n; i != 0; i-- {
			b.WriteRune(rune(' '))
		}
		b.WriteString(f.Name)
		if i != last {
			b.WriteRune(rune('\n'))
		}
	}
}

func numDigits(i int) int {
	var n int
	for {
		n++
		i = i / 10
		if i == 0 {
			return n
		}
	}
}

var (
	// This can be set by a build script. It will be the colon separated equivalent
	// of the environment variable.
	gopath string

	// This is the processed version based on either the above variable set by the
	// build or from the GOPATH environment variable.
	gopaths []string
)

func init() {
	// prefer the variable set at build time, otherwise fallback to the
	// environment variable.
	if gopath == "" {
		gopath = os.Getenv("GOPATH")
	}
	SetGOPATH(gopath)
}

// StripGOPATH strips the GOPATH prefix from the file path f.
// In development, this will be done using the GOPATH environment variable.
// For production builds, where the GOPATH environment will not be set, the
// GOPATH can be included in the binary by passing ldflags, for example:
//
//     GO_LDFLAGS="$GO_LDFLAGS -X github.com/facebookgo/stack.gopath $GOPATH"
//     go install "-ldflags=$GO_LDFLAGS" my/pkg
func StripGOPATH(f string) string {
	for _, p := range gopaths {
		if strings.HasPrefix(f, p) {
			return f[len(p):]
		}
	}
	return f
}

// SetGOPATH configures the GOPATH to enable relative paths in stack traces.
func SetGOPATH(gp string) {
	gopath = gp
	gopaths = nil

	for _, p := range strings.Split(gopath, ":") {
		if p != "" {
			gopaths = append(gopaths, filepath.Join(p, "src")+"/")
		}
	}

	// Also strip GOROOT for maximum cleanliness
	gopaths = append(gopaths, filepath.Join(runtime.GOROOT(), "src", "pkg")+"/")
}

// StripPackage strips the package name from the given Func.Name.
func StripPackage(n string) string {
	slashI := strings.LastIndex(n, "/")
	if slashI == -1 {
		slashI = 0 // for built-in packages
	}
	dotI := strings.Index(n[slashI:], ".")
	if dotI == -1 {
		return n
	}
	return n[slashI+dotI+1:]
}
<|endoftext|>


<commit_before>package driver

import (
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"time"
)

// HTTP のキャッシュみたいなことができるように。
// 取得操作の場合、対象の更新日時がキャッシュの日時以降、または、ダイジェストがキャッシュと異なる場合のみ、現在の対象が返る。
//
// 対象が            返り値 返りスタンプ
// 無い              nil    nil
// キャッシュと同じ  nil    あり
// キャッシュと違う  あり   あり
//
// 更新操作の場合、対象がキャッシュと等しい場合のみ操作が行われ、新しいスタンプが返る。

// キャッシュの情報。
type Stamp struct {
	Date     time.Time `json:"date"                      bson:"date"`                      // 元データの更新日時。
	ExpiDate time.Time `json:"expiration_date,omitempty" bson:"expiration_date,omitempty"` // 有効期限。
	Digest   string    `json:"digest"                    bson:"digest"`                    // ハッシュ値とか。
}

func WriteStampToRequestHeader(stmp *Stamp, h http.Header) {
	h.Set("If-Modified-Since", stmp.Date.Format(time.RFC1123))
	h.Set("If-None-Match", stmp.Digest)
}
func ParseStampFromRequestHeader(h http.Header) (*Stamp, error) {
	dateStr, dig := h.Get("If-Modified-Since"), h.Get("If-None-Match")
	if dig == "" && dateStr == "" {
		return nil, nil
	}

	stmp := &Stamp{Digest: dig}
	if dateStr != "" {
		var err error
		stmp.Date, err = time.Parse(time.RFC1123, dateStr)
		if err != nil {
			return nil, erro.Wrap(err)
		}
	}

	return stmp, nil
}
func WriteStampToResponseHeader(stmp *Stamp, h http.Header) {
	h.Set("Last-Modified", stmp.Date.Format(time.RFC1123))
	h.Set("Expires", stmp.ExpiDate.Format(time.RFC1123))
	h.Set("ETag", stmp.Digest)
}
func ParseStampFromResponseHeader(h http.Header) (*Stamp, error) {
	dateStr, expiDateStr, dig := h.Get("Last-Modified"), h.Get("Expires"), h.Get("ETag")
	if dig == "" && dateStr == "" {
		return nil, nil
	}

	stmp := &Stamp{Digest: dig}
	if dateStr != "" {
		var err error
		stmp.Date, err = time.Parse(time.RFC1123, dateStr)
		if err != nil {
			return nil, erro.Wrap(err)
		}
	}
	if expiDateStr != "" {
		var err error
		stmp.ExpiDate, err = time.Parse(time.RFC1123, expiDateStr)
		if err != nil {
			return nil, erro.Wrap(err)
		}
	}

	return stmp, nil
}
<commit_msg>HTTP の時刻表記に http.TimeFormat を使うように修正<commit_after>package driver

import (
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"time"
)

// HTTP のキャッシュみたいなことができるように。
// 取得操作の場合、対象の更新日時がキャッシュの日時以降、または、ダイジェストがキャッシュと異なる場合のみ、現在の対象が返る。
//
// 対象が            返り値 返りスタンプ
// 無い              nil    nil
// キャッシュと同じ  nil    あり
// キャッシュと違う  あり   あり
//
// 更新操作の場合、対象がキャッシュと等しい場合のみ操作が行われ、新しいスタンプが返る。

// キャッシュの情報。
type Stamp struct {
	Date     time.Time `json:"date"                      bson:"date"`                      // 元データの更新日時。
	ExpiDate time.Time `json:"expiration_date,omitempty" bson:"expiration_date,omitempty"` // 有効期限。
	Digest   string    `json:"digest"                    bson:"digest"`                    // ハッシュ値とか。
}

func WriteStampToRequestHeader(stmp *Stamp, h http.Header) {
	h.Set("If-Modified-Since", stmp.Date.Format(http.TimeFormat))
	h.Set("If-None-Match", stmp.Digest)
}
func ParseStampFromRequestHeader(h http.Header) (*Stamp, error) {
	dateStr, dig := h.Get("If-Modified-Since"), h.Get("If-None-Match")
	if dig == "" && dateStr == "" {
		return nil, nil
	}

	stmp := &Stamp{Digest: dig}
	if dateStr != "" {
		var err error
		stmp.Date, err = time.Parse(http.TimeFormat, dateStr)
		if err != nil {
			return nil, erro.Wrap(err)
		}
	}

	return stmp, nil
}
func WriteStampToResponseHeader(stmp *Stamp, h http.Header) {
	h.Set("Last-Modified", stmp.Date.Format(http.TimeFormat))
	h.Set("Expires", stmp.ExpiDate.Format(http.TimeFormat))
	h.Set("ETag", stmp.Digest)
}
func ParseStampFromResponseHeader(h http.Header) (*Stamp, error) {
	dateStr, expiDateStr, dig := h.Get("Last-Modified"), h.Get("Expires"), h.Get("ETag")
	if dig == "" && dateStr == "" {
		return nil, nil
	}

	stmp := &Stamp{Digest: dig}
	if dateStr != "" {
		var err error
		stmp.Date, err = time.Parse(http.TimeFormat, dateStr)
		if err != nil {
			return nil, erro.Wrap(err)
		}
	}
	if expiDateStr != "" {
		var err error
		stmp.ExpiDate, err = time.Parse(http.TimeFormat, expiDateStr)
		if err != nil {
			return nil, erro.Wrap(err)
		}
	}

	return stmp, nil
}
<|endoftext|>


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

package cryptica

import (
	"bytes"
	"fmt"
)

type Wall interface {
	Contains(pos Position) bool
}

type HorizontalWall struct {
	Y, Start, End int
}

func (wall HorizontalWall) Contains(pos Position) bool {
	return pos.Y == wall.Y && pos.X >= wall.Start && pos.X <= wall.End
}

type VerticalWall struct {
	X, Start, End int
}

func (wall VerticalWall) Contains(pos Position) bool {
	return pos.X == wall.X && pos.Y >= wall.Start && pos.Y <= wall.End
}

type Board struct {
	W, H  int
	Walls []Wall
}

func (board Board) Encode(state State) (n uint64) {
	n = 0
	power, s := uint64(1), uint64(board.W)*uint64(board.H)+1
	for _, tile := range state.Tiles {
		n += (uint64(tile.Y)*uint64(board.W) + uint64(tile.X) + 1) * power
		power *= s
	}
	return
}

func (board *Board) Decode(n uint64) (state State) {
	s := uint64(board.W)*uint64(board.H) + 1
	state = State{board, make([]Position, 0)}
	for n > 0 {
		m := n%s - 1
		x, y := int(m%uint64(board.W)), int(m/uint64(board.W))
		state.Tiles = append(state.Tiles, Position{x, y})
		n /= s
	}
	return
}

type State struct {
	Board *Board
	Tiles []Position
}

func (state State) ItemAt(pos Position) interface{} {
	if pos.X < 0 || pos.X >= state.Board.W {
		return false
	}
	if pos.Y < 0 || pos.Y >= state.Board.H {
		return false
	}
	for _, wall := range state.Board.Walls {
		if wall.Contains(pos) {
			return false
		}
	}
	for i, tile := range state.Tiles {
		if tile.Equal(pos) {
			return i
		}
	}
	return true
}

func (state State) String() string {
	var buffer bytes.Buffer
	for y := 0; y < state.Board.H; y++ {
		for x := 0; x < state.Board.W; x++ {
			item := state.ItemAt(Position{x, y})
			if tile, ok := item.(int); ok {
				buffer.WriteString(fmt.Sprintf("%X", tile))
			} else if empty := item.(bool); empty {
				buffer.WriteString(".")
			} else {
				buffer.WriteString("#")
			}

		}
		buffer.WriteString("\n")
	}
	return buffer.String()
}

func (state State) move(pos Position, dir Direction) (Position, bool) {
	newpos := pos.Move(dir)
	if newpos.X < 0 || newpos.X > state.Board.W ||
		newpos.Y < 0 || newpos.Y > state.Board.H {
		return pos, false
	}
	item := state.ItemAt(newpos)
	if tile, ok := item.(int); ok {
		if _, changed := state.move(state.Tiles[tile], dir); changed {
			return newpos, true
		} else {
			return pos, false
		}
	} else if empty := item.(bool); empty {
		return newpos, true
	} else {
		return pos, false
	}
}

func (state State) Move(dir Direction) (State, bool) {
	changed := false
	tiles := make([]Position, len(state.Tiles))
	for tile, pos := range state.Tiles {
		newpos, poschanged := state.move(pos, dir)
		changed = changed || poschanged
		tiles[tile] = newpos
	}
	return State{state.Board, tiles}, changed
}

type Goal []Position

func (state State) Match(goal Goal) bool {
	for i, pos := range goal {
		if !pos.Equal(state.Tiles[i]) {
			return false
		}
	}
	return true
}
<commit_msg>cleanup<commit_after>// Copyright 2017 Roberto Virga. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cryptica

import (
	"bytes"
	"fmt"
)

type Wall interface {
	Contains(pos Position) bool
}

type HorizontalWall struct {
	Y, Start, End int
}

func (wall HorizontalWall) Contains(pos Position) bool {
	return pos.Y == wall.Y && pos.X >= wall.Start && pos.X <= wall.End
}

type VerticalWall struct {
	X, Start, End int
}

func (wall VerticalWall) Contains(pos Position) bool {
	return pos.X == wall.X && pos.Y >= wall.Start && pos.Y <= wall.End
}

type Board struct {
	W, H  int
	Walls []Wall
}

func (board Board) Encode(state State) (n uint64) {
	n = 0
	power, s := uint64(1), uint64(board.W)*uint64(board.H)+1
	for _, tile := range state.Tiles {
		n += (uint64(tile.Y)*uint64(board.W) + uint64(tile.X) + 1) * power
		power *= s
	}
	return
}

func (board *Board) Decode(n uint64) (state State) {
	s := uint64(board.W)*uint64(board.H) + 1
	state = State{board, make([]Position, 0)}
	for n > 0 {
		m := n%s - 1
		x, y := int(m%uint64(board.W)), int(m/uint64(board.W))
		state.Tiles = append(state.Tiles, Position{x, y})
		n /= s
	}
	return
}

type State struct {
	Board *Board
	Tiles []Position
}

func (state State) ItemAt(pos Position) interface{} {
	if pos.X < 0 || pos.X >= state.Board.W {
		return false
	}
	if pos.Y < 0 || pos.Y >= state.Board.H {
		return false
	}
	for _, wall := range state.Board.Walls {
		if wall.Contains(pos) {
			return false
		}
	}
	for i, tile := range state.Tiles {
		if tile.Equal(pos) {
			return i
		}
	}
	return true
}

func (state State) String() string {
	var buffer bytes.Buffer
	for y := 0; y < state.Board.H; y++ {
		for x := 0; x < state.Board.W; x++ {
			item := state.ItemAt(Position{x, y})
			if tile, ok := item.(int); ok {
				buffer.WriteString(fmt.Sprintf("%X", tile))
			} else if empty := item.(bool); empty {
				buffer.WriteRune('.')
			} else {
				buffer.WriteRune('#')
			}

		}
		buffer.WriteRune('\n')
	}
	return buffer.String()
}

func (state State) move(pos Position, dir Direction) (Position, bool) {
	newpos := pos.Move(dir)
	if newpos.X < 0 || newpos.X > state.Board.W ||
		newpos.Y < 0 || newpos.Y > state.Board.H {
		return pos, false
	}
	item := state.ItemAt(newpos)
	if tile, ok := item.(int); ok {
		if _, changed := state.move(state.Tiles[tile], dir); changed {
			return newpos, true
		} else {
			return pos, false
		}
	} else if empty := item.(bool); empty {
		return newpos, true
	} else {
		return pos, false
	}
}

func (state State) Move(dir Direction) (State, bool) {
	changed := false
	tiles := make([]Position, len(state.Tiles))
	for tile, pos := range state.Tiles {
		newpos, poschanged := state.move(pos, dir)
		changed = changed || poschanged
		tiles[tile] = newpos
	}
	return State{state.Board, tiles}, changed
}

type Goal []Position

func (state State) Match(goal Goal) bool {
	for i, pos := range goal {
		if !pos.Equal(state.Tiles[i]) {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2014 Square Inc.
//
// 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 squalor

import (
	"bytes"
	"database/sql"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"text/tabwriter"
)

// Column models a database column.
type Column struct {
	Name     string
	AutoIncr bool
	Nullable bool
	sqlType  string
}

func (c *Column) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%s\t%s", c.Name, c.sqlType)
	if c.Nullable {
		fmt.Fprintf(&buf, "\tNULL")
	} else {
		fmt.Fprintf(&buf, "\tNOT NULL")
	}
	if c.AutoIncr {
		fmt.Fprintf(&buf, " AUTO INCREMENT")
	}
	return buf.String()
}

type byName []*Column

func (n byName) Len() int {
	return len(n)
}

func (n byName) Less(i, j int) bool {
	return n[i].Name < n[j].Name
}

func (n byName) Swap(i, j int) {
	n[i], n[j] = n[j], n[i]
}

type keyColumn struct {
	seq  int
	name string
}

type bySeq []keyColumn

func (s bySeq) Len() int {
	return len(s)
}

func (s bySeq) Less(i, j int) bool {
	return s[i].seq < s[j].seq
}

func (s bySeq) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

// Key models a key (index) for a database table. A key is composed of
// one or more columns.
type Key struct {
	Name    string
	Primary bool
	Unique  bool
	Columns []*Column
}

func (k *Key) String() string {
	var buf bytes.Buffer
	if k.Primary {
		fmt.Fprintf(&buf, "PRIMARY ")
	} else if k.Unique {
		fmt.Fprintf(&buf, "UNIQUE ")
	}
	fmt.Fprintf(&buf, "KEY")
	if !k.Primary {
		fmt.Fprintf(&buf, " %s", k.Name)
	}
	fmt.Fprintf(&buf, "\t(")
	var sep string
	for _, col := range k.Columns {
		fmt.Fprintf(&buf, "%s%s", sep, col.Name)
		sep = ","
	}
	fmt.Fprintf(&buf, ")")
	return buf.String()
}

func (k *Key) matches(cols ...string) bool {
	if len(k.Columns) != len(cols) {
		return false
	}
	for i := range cols {
		if k.Columns[i].Name != cols[i] {
			return false
		}
	}
	return true
}

// Table models a database table containing column and key definitions.
type Table struct {
	Name       string
	Alias      string
	Columns    []*Column
	ColumnMap  map[string]*Column
	PrimaryKey *Key
	Keys       []*Key
	KeyMap     map[string]*Key
}

func makeTable(name string) *Table {
	return &Table{
		Name:      name,
		ColumnMap: make(map[string]*Column),
		KeyMap:    make(map[string]*Key),
	}
}

// NewTable constructs a table from a model struct. The resulting
// table is less detailed than one created from LoadTable due to the
// lack of keys of type info.
func NewTable(name string, model interface{}) *Table {
	t := makeTable(name)
	m := getDBFields(reflect.TypeOf(model))
	for k := range m {
		col := &Column{Name: k}
		t.Columns = append(t.Columns, col)
		t.ColumnMap[k] = col
	}
	sort.Sort(byName(t.Columns))
	return t
}

// NewAliasedTable constructs a table with an alias from a model struct. The
// alias will be used in column names and in joins. The resulting
// table is less detailed than one created from LoadTable due to the
// lack of keys of type info.
func NewAliasedTable(name, alias string, model interface{}) *Table {
	t := NewTable(name, model)
	t.Alias = alias
	return t
}

// LoadTable loads a table's definition from a database.
func LoadTable(db *sql.DB, name string) (*Table, error) {
	t := makeTable(name)
	err := t.loadColumns(db)
	if err != nil {
		return nil, err
	}
	err = t.loadKeys(db)
	if err != nil {
		return nil, err
	}
	return t, nil
}

func (t *Table) String() string {
	var buf bytes.Buffer
	tab := tabwriter.NewWriter(&buf, 0, 4, 2, ' ', 0)
	fmt.Fprintf(tab, "%s:\n", t.Name)
	fmt.Fprintf(tab, "  columns:\n")
	for _, col := range t.Columns {
		fmt.Fprintf(tab, "    %s\n", col)
	}
	fmt.Fprintf(tab, "  keys:\n")
	for _, key := range t.Keys {
		fmt.Fprintf(tab, "    %s\n", key)
	}
	tab.Flush()
	return buf.String()
}

// GetKey retrieves a key from the table definition.
func (t *Table) GetKey(cols ...string) *Key {
	for _, key := range t.Keys {
		if key.matches(cols...) {
			return key
		}
	}
	return nil
}

// C returns an expression for the specified list of columns. An error
// expression is created if any of the columns do not exist in the table. An
// error expression is created if no columns are specified.
func (t *Table) C(cols ...string) ValExprBuilder {
	if len(cols) == 0 {
		return ValExprBuilder{makeErrVal("no columns specified")}
	}

	if len(cols) == 1 {
		name := cols[0]
		if _, ok := t.ColumnMap[name]; !ok {
			return ValExprBuilder{makeErrVal("unknown column: %s", name)}
		}
		return ValExprBuilder{&ColName{Name: name, Qualifier: t.aliasOrName()}}
	}
	list := make([]interface{}, len(cols))
	for i, name := range cols {
		if _, ok := t.ColumnMap[name]; !ok {
			list[i] = makeErrVal("unknown column: %s", name)
		} else {
			list[i] = &ColName{Name: name, Qualifier: t.aliasOrName()}
		}
	}
	return ValExprBuilder{makeValTuple(list)}
}

// All returns an expression for all of the columns in the table in
// the order in which they are defined in the table (the order of
// Table.Columns). Note that returned expression is a tuple of
// columns, not a star expression.
func (t *Table) All() ValExprBuilder {
	list := make([]interface{}, len(t.Columns))
	for i, col := range t.Columns {
		list[i] = &ColName{Name: col.Name, Qualifier: t.aliasOrName()}
	}
	return ValExprBuilder{makeValTuple(list)}
}

// InnerJoin creates an INNER JOIN statement builder. Note that inner
// join and join are synonymous in MySQL. Inner join is used here for
// clarity.
func (t *Table) InnerJoin(other *Table) *JoinBuilder {
	return makeJoinBuilder("INNER JOIN", t, other)
}

// LeftJoin creates a LEFT JOIN statement builder.
func (t *Table) LeftJoin(other *Table) *JoinBuilder {
	return makeJoinBuilder("LEFT JOIN", t, other)
}

// RightJoin creates a RIGHT JOIN statement builder.
func (t *Table) RightJoin(other *Table) *JoinBuilder {
	return makeJoinBuilder("RIGHT JOIN", t, other)
}

// Delete creates a DELETE statement builder.
func (t *Table) Delete() *DeleteBuilder {
	return makeDeleteBuilder(t.Name)
}

// Insert creates an INSERT statement builder.
func (t *Table) Insert(cols ...interface{}) *InsertBuilder {
	return makeInsertBuilder(t, cols...)
}

// Replace creates a REPLACE statement builder.
func (t *Table) Replace(cols ...interface{}) *ReplaceBuilder {
	return makeReplaceBuilder(t, cols...)
}

// Select creates a SELECT statement builder.
func (t *Table) Select(exprs ...interface{}) *SelectBuilder {
	return makeSelectBuilder(t, exprs...)
}

// Update creates an UPDATE statement builder.
func (t *Table) Update() *UpdateBuilder {
	return makeUpdateBuilder(t)
}

func (t *Table) validateFields(m fieldMap) error {
	// Verify all of the model columns exist in the table.
	for name, field := range m {
		c1 := t.ColumnMap[name]
		if c1 == nil {
			return fmt.Errorf("%s: model column '%s' not found in table", t.Name, name)
		}
		if err := validateModelType(c1.sqlType, field.Type); err != nil {
			return fmt.Errorf("%s: '%s': %s", t.Name, name, err)
		}
	}
	// Verify all of the table columns exist in the model.
	for name := range t.ColumnMap {
		if _, ok := m[name]; !ok {
			return fmt.Errorf("%s: table column '%s' not found in model", t.Name, name)
		}
	}
	return nil
}

// ValidateModel validates that the model is compatible for the
// table's schema. It checks that every column in the database is
// mapped to a field in the model and every field in the model has a
// corresponding column in the table schema.
func (t *Table) ValidateModel(model interface{}) error {
	m := getDBFields(reflect.TypeOf(model))
	return t.validateFields(m)
}

// aliasOrName will return table's alias if its not blank
// Otherwise it will use the table's name.
func (t *Table) aliasOrName() string {
	if t.Alias != "" {
		return t.Alias
	}
	return t.Name
}

// loadColumns loads a table's columns from a database. MySQL
// specific.
func (t *Table) loadColumns(db *sql.DB) error {
	rows, err := db.Query("SHOW FULL COLUMNS FROM " + t.Name)
	if err != nil {
		return err
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	var (
		col      string
		sqlType  string
		nullable string
		extra    string
	)
	m := map[string]interface{}{
		"Field": &col,
		"Type":  &sqlType,
		"Null":  &nullable,
		"Extra": &extra,
	}

	vals := make([]interface{}, len(cols))
	for i, n := range cols {
		if v, ok := m[n]; ok {
			vals[i] = v
		} else {
			vals[i] = &sql.RawBytes{}
		}
	}

	for rows.Next() {
		err := rows.Scan(vals...)
		if err != nil {
			return err
		}
		c := &Column{
			Name:     col,
			Nullable: strings.EqualFold(nullable, "YES"),
			AutoIncr: strings.Contains(extra, "auto_increment"),
			sqlType:  sqlType,
		}
		t.Columns = append(t.Columns, c)
		t.ColumnMap[c.Name] = c
	}
	return nil
}

func (t *Table) tableExpr() TableExpr {
	ate := &AliasedTableExpr{
		Expr: &TableName{Name: t.Name},
	}
	if t.Alias != "" {
		ate.As = t.Alias
	}

	return ate
}

func (t *Table) tableExists(name string) bool {
	return t.Name == name
}

func (t *Table) column(name string) *ColName {
	parts := strings.Split(name, ".")
	if len(parts) == 2 {
		if parts[0] != t.Name {
			return nil
		}
		name = parts[1]
	}
	if _, ok := t.ColumnMap[name]; !ok {
		return nil
	}
	return &ColName{Name: name, Qualifier: t.Name}
}

func (t *Table) columnCount(name string) int {
	if _, ok := t.ColumnMap[name]; !ok {
		return 0
	}
	return 1
}

// loadKeys loads a table's keys (indexes) from a database. MySQL
// specific.
func (t *Table) loadKeys(db *sql.DB) error {
	rows, err := db.Query("SHOW INDEX FROM " + t.Name)
	if err != nil {
		return err
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	var (
		nonUnique bool
		keyName   string
		seq       int
		colName   string
	)
	m := map[string]interface{}{
		"Non_unique":   &nonUnique,
		"Key_name":     &keyName,
		"Seq_in_index": &seq,
		"Column_name":  &colName,
	}

	vals := make([]interface{}, len(cols))
	for i, n := range cols {
		if v, ok := m[n]; ok {
			vals[i] = v
		} else {
			vals[i] = &sql.RawBytes{}
		}
	}

	keys := map[string][]keyColumn{}
	for rows.Next() {
		err := rows.Scan(vals...)
		if err != nil {
			return err
		}
		keys[keyName] = append(keys[keyName], keyColumn{
			seq:  seq,
			name: colName,
		})

		if _, ok := t.KeyMap[keyName]; !ok {
			k := &Key{
				Name:   keyName,
				Unique: !nonUnique,
			}
			t.Keys = append(t.Keys, k)
			t.KeyMap[keyName] = k
		}
	}

	for n, k := range keys {
		sort.Sort(bySeq(k))
		var cols []*Column
		for _, c := range k {
			cols = append(cols, t.ColumnMap[c.name])
		}
		t.KeyMap[n].Columns = cols
	}

	t.PrimaryKey = t.KeyMap["PRIMARY"]
	if t.PrimaryKey != nil {
		t.PrimaryKey.Primary = true
	}

	return nil
}
<commit_msg>addressing comments<commit_after>// Copyright 2014 Square Inc.
//
// 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 squalor

import (
	"bytes"
	"database/sql"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"text/tabwriter"
)

// Column models a database column.
type Column struct {
	Name     string
	AutoIncr bool
	Nullable bool
	sqlType  string
}

func (c *Column) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%s\t%s", c.Name, c.sqlType)
	if c.Nullable {
		fmt.Fprintf(&buf, "\tNULL")
	} else {
		fmt.Fprintf(&buf, "\tNOT NULL")
	}
	if c.AutoIncr {
		fmt.Fprintf(&buf, " AUTO INCREMENT")
	}
	return buf.String()
}

type byName []*Column

func (n byName) Len() int {
	return len(n)
}

func (n byName) Less(i, j int) bool {
	return n[i].Name < n[j].Name
}

func (n byName) Swap(i, j int) {
	n[i], n[j] = n[j], n[i]
}

type keyColumn struct {
	seq  int
	name string
}

type bySeq []keyColumn

func (s bySeq) Len() int {
	return len(s)
}

func (s bySeq) Less(i, j int) bool {
	return s[i].seq < s[j].seq
}

func (s bySeq) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

// Key models a key (index) for a database table. A key is composed of
// one or more columns.
type Key struct {
	Name    string
	Primary bool
	Unique  bool
	Columns []*Column
}

func (k *Key) String() string {
	var buf bytes.Buffer
	if k.Primary {
		fmt.Fprintf(&buf, "PRIMARY ")
	} else if k.Unique {
		fmt.Fprintf(&buf, "UNIQUE ")
	}
	fmt.Fprintf(&buf, "KEY")
	if !k.Primary {
		fmt.Fprintf(&buf, " %s", k.Name)
	}
	fmt.Fprintf(&buf, "\t(")
	var sep string
	for _, col := range k.Columns {
		fmt.Fprintf(&buf, "%s%s", sep, col.Name)
		sep = ","
	}
	fmt.Fprintf(&buf, ")")
	return buf.String()
}

func (k *Key) matches(cols ...string) bool {
	if len(k.Columns) != len(cols) {
		return false
	}
	for i := range cols {
		if k.Columns[i].Name != cols[i] {
			return false
		}
	}
	return true
}

// Table models a database table containing column and key definitions.
type Table struct {
	Name       string
	Alias      string
	Columns    []*Column
	ColumnMap  map[string]*Column
	PrimaryKey *Key
	Keys       []*Key
	KeyMap     map[string]*Key
}

func makeTable(name string) *Table {
	return &Table{
		Name:      name,
		ColumnMap: make(map[string]*Column),
		KeyMap:    make(map[string]*Key),
	}
}

// NewTable constructs a table from a model struct. The resulting
// table is less detailed than one created from LoadTable due to the
// lack of keys of type info.
func NewTable(name string, model interface{}) *Table {
	t := makeTable(name)
	m := getDBFields(reflect.TypeOf(model))
	for k := range m {
		col := &Column{Name: k}
		t.Columns = append(t.Columns, col)
		t.ColumnMap[k] = col
	}
	sort.Sort(byName(t.Columns))
	return t
}

// NewAliasedTable constructs a table with an alias from a model struct. The
// alias will be used in column names and in joins. The resulting
// table is less detailed than one created from LoadTable due to the
// lack of keys of type info.
func NewAliasedTable(name, alias string, model interface{}) *Table {
	t := NewTable(name, model)
	t.Alias = alias
	return t
}

// LoadTable loads a table's definition from a database.
func LoadTable(db *sql.DB, name string) (*Table, error) {
	t := makeTable(name)
	err := t.loadColumns(db)
	if err != nil {
		return nil, err
	}
	err = t.loadKeys(db)
	if err != nil {
		return nil, err
	}
	return t, nil
}

func (t *Table) String() string {
	var buf bytes.Buffer
	tab := tabwriter.NewWriter(&buf, 0, 4, 2, ' ', 0)
	fmt.Fprintf(tab, "%s:\n", t.Name)
	fmt.Fprintf(tab, "  columns:\n")
	for _, col := range t.Columns {
		fmt.Fprintf(tab, "    %s\n", col)
	}
	fmt.Fprintf(tab, "  keys:\n")
	for _, key := range t.Keys {
		fmt.Fprintf(tab, "    %s\n", key)
	}
	tab.Flush()
	return buf.String()
}

// GetKey retrieves a key from the table definition.
func (t *Table) GetKey(cols ...string) *Key {
	for _, key := range t.Keys {
		if key.matches(cols...) {
			return key
		}
	}
	return nil
}

// C returns an expression for the specified list of columns. An error
// expression is created if any of the columns do not exist in the table. An
// error expression is created if no columns are specified.
func (t *Table) C(cols ...string) ValExprBuilder {
	if len(cols) == 0 {
		return ValExprBuilder{makeErrVal("no columns specified")}
	}

	if len(cols) == 1 {
		name := cols[0]
		if _, ok := t.ColumnMap[name]; !ok {
			return ValExprBuilder{makeErrVal("unknown column: %s", name)}
		}
		return ValExprBuilder{&ColName{Name: name, Qualifier: t.aliasOrName()}}
	}
	list := make([]interface{}, len(cols))
	for i, name := range cols {
		if _, ok := t.ColumnMap[name]; !ok {
			list[i] = makeErrVal("unknown column: %s", name)
		} else {
			list[i] = &ColName{Name: name, Qualifier: t.aliasOrName()}
		}
	}
	return ValExprBuilder{makeValTuple(list)}
}

// All returns an expression for all of the columns in the table in
// the order in which they are defined in the table (the order of
// Table.Columns). Note that returned expression is a tuple of
// columns, not a star expression.
func (t *Table) All() ValExprBuilder {
	list := make([]interface{}, len(t.Columns))
	for i, col := range t.Columns {
		list[i] = &ColName{Name: col.Name, Qualifier: t.aliasOrName()}
	}
	return ValExprBuilder{makeValTuple(list)}
}

// InnerJoin creates an INNER JOIN statement builder. Note that inner
// join and join are synonymous in MySQL. Inner join is used here for
// clarity.
func (t *Table) InnerJoin(other *Table) *JoinBuilder {
	return makeJoinBuilder("INNER JOIN", t, other)
}

// LeftJoin creates a LEFT JOIN statement builder.
func (t *Table) LeftJoin(other *Table) *JoinBuilder {
	return makeJoinBuilder("LEFT JOIN", t, other)
}

// RightJoin creates a RIGHT JOIN statement builder.
func (t *Table) RightJoin(other *Table) *JoinBuilder {
	return makeJoinBuilder("RIGHT JOIN", t, other)
}

// Delete creates a DELETE statement builder.
func (t *Table) Delete() *DeleteBuilder {
	return makeDeleteBuilder(t.Name)
}

// Insert creates an INSERT statement builder.
func (t *Table) Insert(cols ...interface{}) *InsertBuilder {
	return makeInsertBuilder(t, cols...)
}

// Replace creates a REPLACE statement builder.
func (t *Table) Replace(cols ...interface{}) *ReplaceBuilder {
	return makeReplaceBuilder(t, cols...)
}

// Select creates a SELECT statement builder.
func (t *Table) Select(exprs ...interface{}) *SelectBuilder {
	return makeSelectBuilder(t, exprs...)
}

// Update creates an UPDATE statement builder.
func (t *Table) Update() *UpdateBuilder {
	return makeUpdateBuilder(t)
}

func (t *Table) validateFields(m fieldMap) error {
	// Verify all of the model columns exist in the table.
	for name, field := range m {
		c1 := t.ColumnMap[name]
		if c1 == nil {
			return fmt.Errorf("%s: model column '%s' not found in table", t.Name, name)
		}
		if err := validateModelType(c1.sqlType, field.Type); err != nil {
			return fmt.Errorf("%s: '%s': %s", t.Name, name, err)
		}
	}
	// Verify all of the table columns exist in the model.
	for name := range t.ColumnMap {
		if _, ok := m[name]; !ok {
			return fmt.Errorf("%s: table column '%s' not found in model", t.Name, name)
		}
	}
	return nil
}

// ValidateModel validates that the model is compatible for the
// table's schema. It checks that every column in the database is
// mapped to a field in the model and every field in the model has a
// corresponding column in the table schema.
func (t *Table) ValidateModel(model interface{}) error {
	m := getDBFields(reflect.TypeOf(model))
	return t.validateFields(m)
}

// aliasOrName will return table's alias if it is not blank,
// otherwise it will return the table's name.
func (t *Table) aliasOrName() string {
	if t.Alias != "" {
		return t.Alias
	}
	return t.Name
}

// loadColumns loads a table's columns from a database. MySQL
// specific.
func (t *Table) loadColumns(db *sql.DB) error {
	rows, err := db.Query("SHOW FULL COLUMNS FROM " + t.Name)
	if err != nil {
		return err
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	var (
		col      string
		sqlType  string
		nullable string
		extra    string
	)
	m := map[string]interface{}{
		"Field": &col,
		"Type":  &sqlType,
		"Null":  &nullable,
		"Extra": &extra,
	}

	vals := make([]interface{}, len(cols))
	for i, n := range cols {
		if v, ok := m[n]; ok {
			vals[i] = v
		} else {
			vals[i] = &sql.RawBytes{}
		}
	}

	for rows.Next() {
		err := rows.Scan(vals...)
		if err != nil {
			return err
		}
		c := &Column{
			Name:     col,
			Nullable: strings.EqualFold(nullable, "YES"),
			AutoIncr: strings.Contains(extra, "auto_increment"),
			sqlType:  sqlType,
		}
		t.Columns = append(t.Columns, c)
		t.ColumnMap[c.Name] = c
	}
	return nil
}

func (t *Table) tableExpr() TableExpr {
	ate := &AliasedTableExpr{
		Expr: &TableName{Name: t.Name},
	}
	if t.Alias != "" {
		ate.As = t.Alias
	}

	return ate
}

func (t *Table) tableExists(name string) bool {
	return t.Name == name
}

func (t *Table) column(name string) *ColName {
	parts := strings.Split(name, ".")
	if len(parts) == 2 {
		if parts[0] != t.Name {
			return nil
		}
		name = parts[1]
	}
	if _, ok := t.ColumnMap[name]; !ok {
		return nil
	}
	return &ColName{Name: name, Qualifier: t.Name}
}

func (t *Table) columnCount(name string) int {
	if _, ok := t.ColumnMap[name]; !ok {
		return 0
	}
	return 1
}

// loadKeys loads a table's keys (indexes) from a database. MySQL
// specific.
func (t *Table) loadKeys(db *sql.DB) error {
	rows, err := db.Query("SHOW INDEX FROM " + t.Name)
	if err != nil {
		return err
	}
	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	var (
		nonUnique bool
		keyName   string
		seq       int
		colName   string
	)
	m := map[string]interface{}{
		"Non_unique":   &nonUnique,
		"Key_name":     &keyName,
		"Seq_in_index": &seq,
		"Column_name":  &colName,
	}

	vals := make([]interface{}, len(cols))
	for i, n := range cols {
		if v, ok := m[n]; ok {
			vals[i] = v
		} else {
			vals[i] = &sql.RawBytes{}
		}
	}

	keys := map[string][]keyColumn{}
	for rows.Next() {
		err := rows.Scan(vals...)
		if err != nil {
			return err
		}
		keys[keyName] = append(keys[keyName], keyColumn{
			seq:  seq,
			name: colName,
		})

		if _, ok := t.KeyMap[keyName]; !ok {
			k := &Key{
				Name:   keyName,
				Unique: !nonUnique,
			}
			t.Keys = append(t.Keys, k)
			t.KeyMap[keyName] = k
		}
	}

	for n, k := range keys {
		sort.Sort(bySeq(k))
		var cols []*Column
		for _, c := range k {
			cols = append(cols, t.ColumnMap[c.name])
		}
		t.KeyMap[n].Columns = cols
	}

	t.PrimaryKey = t.KeyMap["PRIMARY"]
	if t.PrimaryKey != nil {
		t.PrimaryKey.Primary = true
	}

	return nil
}
<|endoftext|>


<commit_before>package xql

// Table ...
// Struct defined for a table object.
type Table struct {
    columns      []*Column
    constraints  []*Constraint
    indexes      []*Index
    primary_keys []*Column
    m_columns    map[string]*Column
    x_columns    map[string]*Column
    j_columns    map[string]*Column
    entity       TableIdentified
    schema       string
}

// TableIdentified which make sure struct have a method TableName()
// This is mandatory for a struct can use as Table structure.
type TableIdentified interface {
    TableName() string
}

// TableIgnored
// Which allow struct to define a method Ignore() to tell ignore elements for table columns
type TableIgnored interface {
    Ignore() []string
}

// TableConstrainted
// Which allow struct to define a method Constraints() to cunstomize table constraints
// type, fields, statement
type TableConstrainted interface {
    Constraints() [][3]string
}

// TableIndexed
// Which allow struct to define a method Indexes() to define table indexes
// type, fields, statement
type TableIndexed interface {
    Indexes() [][2]string
}

// TablePreInsert
// Which entity implemented will be called when xql create a new struct instance.
type TablePreInsert interface {
    PreInsert(*Table, *Session)
}

type TabelPreUpdate interface {
    PreUpdate(*Table, *Session)
}

type TablePreDelete interface {
    PreDelete(*Table, *Session)
}

type TablePostInsert interface {
    PostInsert(*Table, *Session)
}

type TablePostUpdate interface {
    PostUpdate(*Table, *Session)
}

type TablePostDelete interface {
    PostDelete(*Table, *Session)
}

func (t *Table) TableName() string {
    if t.schema != "" {
        return t.schema + "." + t.entity.TableName()
    }
    return t.entity.TableName()
}

func (t *Table) BaseTableName() string {
    return t.entity.TableName()
}

func (t *Table) GetColumns() []*Column {
    return t.columns
}

func (t *Table) GetConstraints() []*Constraint {
    return t.constraints
}

func (t *Table) GetIndexes() []*Index {
    return t.indexes
}

func (t *Table) GetPrimaryKeys() []*Column {
    return t.primary_keys
}

func (t *Table) SetSchema(s string) {
    t.schema = s
}

func (t *Table) Schema() string {
    return t.schema
}

func (t *Table) GetColumn(name string) (*Column, bool) {
    if c, ok := t.m_columns[name]; ok {
        return c, true
    }
    if c, ok := t.x_columns[name]; ok {
        return c, true
    }
    if c, ok := t.j_columns[name]; ok {
        return c, true
    }
    return nil, false
}
<commit_msg>Fixed typo.<commit_after>package xql

// Table ...
// Struct defined for a table object.
type Table struct {
    columns      []*Column
    constraints  []*Constraint
    indexes      []*Index
    primary_keys []*Column
    m_columns    map[string]*Column
    x_columns    map[string]*Column
    j_columns    map[string]*Column
    entity       TableIdentified
    schema       string
}

// TableIdentified which make sure struct have a method TableName()
// This is mandatory for a struct can use as Table structure.
type TableIdentified interface {
    TableName() string
}

// TableIgnored
// Which allow struct to define a method Ignore() to tell ignore elements for table columns
type TableIgnored interface {
    Ignore() []string
}

// TableConstrainted
// Which allow struct to define a method Constraints() to cunstomize table constraints
// type, fields, statement
type TableConstrainted interface {
    Constraints() [][3]string
}

// TableIndexed
// Which allow struct to define a method Indexes() to define table indexes
// type, fields, statement
type TableIndexed interface {
    Indexes() [][2]string
}

// TablePreInsert
// Which entity implemented will be called when xql create a new struct instance.
type TablePreInsert interface {
    PreInsert(*Table, *Session)
}

type TablePreUpdate interface {
    PreUpdate(*Table, *Session)
}

type TablePreDelete interface {
    PreDelete(*Table, *Session)
}

type TablePostInsert interface {
    PostInsert(*Table, *Session)
}

type TablePostUpdate interface {
    PostUpdate(*Table, *Session)
}

type TablePostDelete interface {
    PostDelete(*Table, *Session)
}

func (t *Table) TableName() string {
    if t.schema != "" {
        return t.schema + "." + t.entity.TableName()
    }
    return t.entity.TableName()
}

func (t *Table) BaseTableName() string {
    return t.entity.TableName()
}

func (t *Table) GetColumns() []*Column {
    return t.columns
}

func (t *Table) GetConstraints() []*Constraint {
    return t.constraints
}

func (t *Table) GetIndexes() []*Index {
    return t.indexes
}

func (t *Table) GetPrimaryKeys() []*Column {
    return t.primary_keys
}

func (t *Table) SetSchema(s string) {
    t.schema = s
}

func (t *Table) Schema() string {
    return t.schema
}

func (t *Table) GetColumn(name string) (*Column, bool) {
    if c, ok := t.m_columns[name]; ok {
        return c, true
    }
    if c, ok := t.x_columns[name]; ok {
        return c, true
    }
    if c, ok := t.j_columns[name]; ok {
        return c, true
    }
    return nil, false
}
<|endoftext|>