<commit_before>package rtm

import (
	"regexp"
	"strings"

	"github.com/firba1/slack"

	"github.com/gorilla/websocket"
)

type Conn struct {
	conn           *websocket.Conn
	messageCounter int
	userChanges    chan<- slack.User
	infoRequests   chan<- userInfoRequest
	cancel         chan struct{}
}

func (c *Conn) Close() error {
	close(c.cancel)
	return c.conn.Close()
}

type sendMessage struct {
	ID      int    `json:"id"`
	Type    string `json:"type"`
	Channel string `json:"channel"`
	Text    string `json:"text"`
}

func (c *Conn) SendMessage(text, channel string) error {
	c.messageCounter++
	msg := sendMessage{
		ID:      c.messageCounter,
		Type:    "message",
		Channel: channel,
		Text:    text,
	}
	return c.conn.WriteJSON(msg)
}

/*
NextEvent blocks until the next Event is sent and then returns it to the caller.
*/
func (c *Conn) NextEvent() Event {
	rawEvent := make(map[string]interface{})
	c.conn.ReadJSON(&rawEvent)
	return toEvent(rawEvent)
}

var escapeRegex = regexp.MustCompile("<(.*?)>")

var escapeTypePostprocessors = map[int]func(string) string{
	userEscape:    func(s string) string { return "@" + s },
	channelEscape: func(s string) string { return "#" + s },
}

/*
UnescapeMessage takes in the escape string text of a message and returns a new string that appears as it would to a user.

UnescapeMessage does so by parsing escape sequences according to <https://api.slack.com/docs/formatting> and substituting the appropriate user-facing junk (e.g. <@UABC123> would become @firba1, assuming there's a user named firba1 with the user ID UABC123).
*/
func (c Conn) UnescapeMessage(message string) string {
	message = escapeRegex.ReplaceAllStringFunc(message, func(match string) string {
		unescapedMatch, escapeType := replaceEscapeHelper(c, match)
		postprocess := escapeTypePostprocessors[escapeType]
		if postprocess != nil {
			unescapedMatch = postprocess(unescapedMatch)
		}
		return unescapedMatch
	})

	// finally replace all html entity escapes
	message = strings.Replace(message, "&", "&", -1)
	message = strings.Replace(message, "<", "<", -1)
	message = strings.Replace(message, ">", ">", -1)
	return message
}

func replaceEscapeHelper(c Conn, match string) (unescape string, escapeType int) {
	// remove < and > from each end
	fullEscape := match[1 : len(match)-1]

	// check for display string
	escapeParts := strings.Split(fullEscape, "|")

	// this is a case we don't recognize, just return the original match and treat it as a link (the default)
	if len(escapeParts) > 2 || len(escapeParts) <= 0 {
		unescape = match
		escapeType = linkEscape
		return
	}

	escape := escapeParts[0]
	escapeType = parseEscapeType(escape)

	// if we have an alias, just return that
	if len(escapeParts) == 2 {
		unescape = escapeParts[1]
		return
	}

	// since there's no alias, now it's time for idenitifier lookup
	escapeType = parseEscapeType(escape)

	switch escapeType {
	case userEscape:
		// user link
		user := c.UserInfo(escape[1:])
		// if user is zero value, this will just be empty string, which we handle later
		unescape = user.Name
	}

	// if we couldn't unescape properly, just return the original match text, make it a linkEscape type to prevent post processing
	if unescape == "" {
		escapeType = linkEscape
		unescape = match
	}
	return
}

const (
	linkEscape = iota
	userEscape
	channelEscape
	commandEscape
)

/*
parseEscapeType is a convience function for getting an easily comparable type from an escape sequence (e.g. "@U123A56BC" for users "#C789D10EF" for channels, etc)
*/
func parseEscapeType(escapeString string) int {
	switch {
	case escapeString[0:2] == "@U":
		return userEscape
	case escapeString[0:2] == "#C":
		return channelEscape
	case escapeString[0] == '!':
		return commandEscape
	default:
		// as per the docs, anything we can't recognize like this is a link
		return linkEscape
	}
}
<commit_msg>add UnescapeMessagePostprocess that allows for arbitrary postprocessing<commit_after>package rtm

import (
	"regexp"
	"strings"

	"github.com/firba1/slack"

	"github.com/gorilla/websocket"
)

type Conn struct {
	conn           *websocket.Conn
	messageCounter int
	userChanges    chan<- slack.User
	infoRequests   chan<- userInfoRequest
	cancel         chan struct{}
}

func (c *Conn) Close() error {
	close(c.cancel)
	return c.conn.Close()
}

type sendMessage struct {
	ID      int    `json:"id"`
	Type    string `json:"type"`
	Channel string `json:"channel"`
	Text    string `json:"text"`
}

func (c *Conn) SendMessage(text, channel string) error {
	c.messageCounter++
	msg := sendMessage{
		ID:      c.messageCounter,
		Type:    "message",
		Channel: channel,
		Text:    text,
	}
	return c.conn.WriteJSON(msg)
}

/*
NextEvent blocks until the next Event is sent and then returns it to the caller.
*/
func (c *Conn) NextEvent() Event {
	rawEvent := make(map[string]interface{})
	c.conn.ReadJSON(&rawEvent)
	return toEvent(rawEvent)
}

var escapeRegex = regexp.MustCompile("<(.*?)>")

var escapeTypePostprocessors = map[int]func(string) string{
	userEscape:    func(s string) string { return "@" + s },
	channelEscape: func(s string) string { return "#" + s },
}

/*
UnescapeMessage takes in the escape string text of a message and returns a new string that appears as it would to a user.

UnescapeMessage does so by parsing escape sequences according to <https://api.slack.com/docs/formatting> and substituting the appropriate user-facing junk (e.g. <@UABC123> would become @firba1, assuming there's a user named firba1 with the user ID UABC123).
*/
func (c Conn) UnescapeMessage(message string) string {
	return c.UnescapeMessagePostprocess(message, func(s string, i int) string { return s })
}

func (c Conn) UnescapeMessagePostprocess(
	message string,
	postprocessor func(userString string, escapeType int) string,
) string {
	message = escapeRegex.ReplaceAllStringFunc(message, func(match string) string {
		unescapedMatch, escapeType := replaceEscapeHelper(c, match)
		postprocess := escapeTypePostprocessors[escapeType]
		if postprocess != nil {
			unescapedMatch = postprocess(unescapedMatch)
		}
		return unescapedMatch
	})

	// finally replace all html entity escapes
	message = strings.Replace(message, "&", "&", -1)
	message = strings.Replace(message, "<", "<", -1)
	message = strings.Replace(message, ">", ">", -1)
	return message
}

func replaceEscapeHelper(c Conn, match string) (unescape string, escapeType int) {
	// remove < and > from each end
	fullEscape := match[1 : len(match)-1]

	// check for display string
	escapeParts := strings.Split(fullEscape, "|")

	// this is a case we don't recognize, just return the original match and treat it as a link (the default)
	if len(escapeParts) > 2 || len(escapeParts) <= 0 {
		unescape = match
		escapeType = linkEscape
		return
	}

	escape := escapeParts[0]
	escapeType = parseEscapeType(escape)

	// if we have an alias, just return that
	if len(escapeParts) == 2 {
		unescape = escapeParts[1]
		return
	}

	// since there's no alias, now it's time for idenitifier lookup
	escapeType = parseEscapeType(escape)

	switch escapeType {
	case userEscape:
		// user link
		user := c.UserInfo(escape[1:])
		// if user is zero value, this will just be empty string, which we handle later
		unescape = user.Name
	}

	// if we couldn't unescape properly, just return the original match text, make it a linkEscape type to prevent post processing
	if unescape == "" {
		escapeType = linkEscape
		unescape = match
	}
	return
}

const (
	linkEscape = iota
	userEscape
	channelEscape
	commandEscape
)

/*
parseEscapeType is a convience function for getting an easily comparable type from an escape sequence (e.g. "@U123A56BC" for users "#C789D10EF" for channels, etc)
*/
func parseEscapeType(escapeString string) int {
	switch {
	case escapeString[0:2] == "@U":
		return userEscape
	case escapeString[0:2] == "#C":
		return channelEscape
	case escapeString[0] == '!':
		return commandEscape
	default:
		// as per the docs, anything we can't recognize like this is a link
		return linkEscape
	}
}
<|endoftext|>


<commit_before>package psdock

import (
	"bufio"
	"bytes"
	"github.com/kr/pty"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type Process struct {
	Cmd           *exec.Cmd
	Conf          *Config
	Notif         Notifier
	Pty           *os.File
	ioInfo        *ioStruct
	StatusChannel chan ProcessStatus
	eofChannel    chan bool
}

//NewProcess creates a new struct of type *Process and returns its address
func NewProcess(conf *Config) *Process {
	var cmd *exec.Cmd
	if len(conf.Args) > 0 {
		cmd = exec.Command(conf.Command, strings.Split(conf.Args, " ")...)
	} else {
		cmd = exec.Command(conf.Command)
	}
	newStatusChannel := make(chan ProcessStatus, 1)

	return &Process{Cmd: cmd, Conf: conf, StatusChannel: newStatusChannel, Notif: Notifier{webHook: conf.WebHook}}
}

//SetEnvVars sets the environment variables for the launched process
//If p.Conf.EnvVars is empty, we pass all the current env vars to the child
func (p *Process) SetEnvVars() {
	if len(p.Conf.EnvVars) == 0 {
		return
	}
	for _, envVar := range strings.Split(p.Conf.EnvVars, ",") {
		p.Cmd.Env = append(p.Cmd.Env, envVar)
	}
}

func (p *Process) Terminate(nbSec int) error {
	syscall.Kill(p.Cmd.Process.Pid, syscall.SIGTERM)
	time.Sleep(time.Duration(nbSec) * time.Second)
	if !p.isRunning() {
		return nil
	}
	return syscall.Kill(p.Cmd.Process.Pid, syscall.SIGKILL)
}

func (p *Process) isStarted() bool {
	return p.Cmd.Process != nil
}

func (p *Process) isRunning() bool {
	if p.Conf.BindPort == 0 {
		return p.isStarted()
	} else {
		return p.isStarted() && p.hasBoundPort()
	}
}

func (p *Process) hasBoundPort() bool {
	//We execute lsof -i :bindPort to find if bindPort is open
	//For the moment, we only verified that bindPort is used by some process
	lsofCmd := exec.Command("lsof", "-i", ":"+strconv.Itoa(p.Conf.BindPort))

	lsofBytes, _ := lsofCmd.Output()
	lsofScanner := bufio.NewScanner(bytes.NewBuffer(lsofBytes))
	lsofScanner.Scan()
	lsofScanner.Text()
	lsofScanner.Scan()
	lsofResult := lsofScanner.Text()
	if len(lsofResult) == 0 {
		return false
	}

	plsofResult := strings.Split(lsofResult, "    ")

	plsofResult = strings.Split(plsofResult[1], " ")
	ownerPid, _ := strconv.Atoi(plsofResult[0])
	ppids, _ := getPIDs(p.Cmd.Process.Pid)
	for _, v := range ppids {
		if v == ownerPid {
			return true
		}
	}
	return false
}

func (p *Process) Start() {
	initCompleteChannel := make(chan bool)
	p.eofChannel = make(chan bool, 1)

	go func() {
		var startErr error
		p.Pty, startErr = pty.Start(p.Cmd)
		if startErr != nil {
			log.Println(startErr)
		}
		initCompleteChannel <- true

		err := p.Cmd.Wait()
		if err != nil {
			log.Println(err)
			p.Notif.Notify(PROCESS_STOPPED)
			p.Terminate(5)
		}
		_ = <-p.eofChannel
		if err = p.Notif.Notify(PROCESS_STOPPED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STOPPED, Err: nil}
	}()

	go func() {
		var err error
		_ = <-initCompleteChannel

		p.ioInfo, err = newIOStruct(os.Stdin, p.Pty, p.Conf.Stdout, p.Conf.LogPrefix, p.Conf.LogRotation, p.Conf.LogColor,
			p.StatusChannel, p.eofChannel)
		if err != nil {
			p.StatusChannel <- ProcessStatus{Status: -1, Err: err}
		}
		defer p.ioInfo.restoreIO()

		for !p.isStarted() {
			time.Sleep(100 * time.Millisecond)
		}
		if err = p.Notif.Notify(PROCESS_STARTED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STARTED, Err: nil}

		for p.isRunning() == false {
			time.Sleep(100 * time.Millisecond)
		}
		if err = p.Notif.Notify(PROCESS_RUNNING); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_RUNNING, Err: nil}
	}()
}
<commit_msg>Fixed conflicts<commit_after>package psdock

import (
	"bufio"
	"bytes"
	"errors"
	"github.com/kr/pty"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type Process struct {
	Cmd           *exec.Cmd
	Conf          *Config
	Notif         Notifier
	Pty           *os.File
	ioInfo        *ioStruct
	StatusChannel chan ProcessStatus
	eofChannel    chan bool
}

//NewProcess creates a new struct of type *Process and returns its address
func NewProcess(conf *Config) *Process {
	var cmd *exec.Cmd
	if len(conf.Args) > 0 {
		cmd = exec.Command(conf.Command, strings.Split(conf.Args, " ")...)
	} else {
		cmd = exec.Command(conf.Command)
	}
	newStatusChannel := make(chan ProcessStatus, 1)

	return &Process{Cmd: cmd, Conf: conf, StatusChannel: newStatusChannel, Notif: Notifier{webHook: conf.WebHook}}
}

//SetEnvVars sets the environment variables for the launched process
//If p.Conf.EnvVars is empty, we pass all the current env vars to the child
func (p *Process) SetEnvVars() {
	if len(p.Conf.EnvVars) == 0 {
		return
	}
	for _, envVar := range strings.Split(p.Conf.EnvVars, ",") {
		p.Cmd.Env = append(p.Cmd.Env, envVar)
	}
}

func (p *Process) Terminate(nbSec int) error {
	syscall.Kill(p.Cmd.Process.Pid, syscall.SIGTERM)
	time.Sleep(time.Duration(nbSec) * time.Second)
	if !p.isRunning() {
		return nil
	}
	return syscall.Kill(p.Cmd.Process.Pid, syscall.SIGKILL)
}

func (p *Process) isStarted() bool {
	return p.Cmd.Process != nil
}

func (p *Process) isRunning() bool {
	if p.Conf.BindPort == 0 {
		return p.isStarted()
	} else {
		return p.isStarted() && p.hasBoundPort()
	}
}

func (p *Process) hasBoundPort() bool {
	//We execute lsof -i :bindPort to find if bindPort is open
	//For the moment, we only verified that bindPort is used by some process
	lsofCmd := exec.Command("lsof", "-i", ":"+strconv.Itoa(p.Conf.BindPort))

	lsofBytes, _ := lsofCmd.Output()
	lsofScanner := bufio.NewScanner(bytes.NewBuffer(lsofBytes))
	lsofScanner.Scan()
	lsofScanner.Text()
	lsofScanner.Scan()
	lsofResult := lsofScanner.Text()
	if len(lsofResult) == 0 {
		return false
	}

	plsofResult := strings.Split(lsofResult, "    ")

	plsofResult = strings.Split(plsofResult[1], " ")
	ownerPid, _ := strconv.Atoi(plsofResult[0])
	ppids, _ := getPIDs(p.Cmd.Process.Pid)
	for _, v := range ppids {
		if v == ownerPid {
			return true
		}
	}
	return false
}

func (p *Process) Start() {
	initCompleteChannel := make(chan bool)
	p.eofChannel = make(chan bool, 1)

	go func() {
		var startErr error
		p.Pty, startErr = pty.Start(p.Cmd)
		if startErr != nil {
			log.Println(startErr)
		}
		initCompleteChannel <- true

		err := p.Cmd.Wait()
		if err != nil {
			log.Println(err)
			p.Notif.Notify(PROCESS_STOPPED)
			p.Terminate(5)
		}
		_ = <-p.eofChannel
		if err = p.Notif.Notify(PROCESS_STOPPED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STOPPED, Err: nil}
	}()

	go func() {
		var err error
		_ = <-initCompleteChannel

		p.ioInfo, err = newIOStruct(os.Stdin, p.Pty, p.Conf.Stdout, p.Conf.LogPrefix, p.Conf.LogRotation, p.Conf.LogColor,
			p.StatusChannel, p.eofChannel)
		if err != nil {
			p.StatusChannel <- ProcessStatus{Status: -1, Err: err}
		}
		defer p.ioInfo.restoreIO()

		for !p.isStarted() {
			time.Sleep(100 * time.Millisecond)
		}
		if err = p.Notif.Notify(PROCESS_STARTED); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_STARTED, Err: nil}

		for p.isRunning() == false {
			time.Sleep(100 * time.Millisecond)
		}
		if err = p.Notif.Notify(PROCESS_RUNNING); err != nil {
			log.Println(err)
		}
		p.StatusChannel <- ProcessStatus{Status: PROCESS_RUNNING, Err: nil}
	}()
}
<|endoftext|>


<commit_before>package main

import (
  . "github.com/onsi/ginkgo"
  . "github.com/onsi/gomega"

  "path"
)

var _ = Describe("Run", func() {
  It("has a version number", func() {
    Expect(version).ToNot(BeNil())
  })

  Describe("callerDir", func() {
    It("should return the directory of this source code file in Run's implementation", func () {
      // TODO: Ensure that "run" is at the end of the string, instead of
      // anywhere.
      Expect(callerDir()).To(ContainSubstring("run"))
    })
  })

  Describe(".getLanguages", func() {
    It("should properly parse a JSON config file", func() {
      languages, err := getLanguages(path.Join(callerDir(), "mock_commands.json"))
      expectedLanguages := languageCollection {
        "uno": language{"one", "two"},
        "dos": language{"three", "four"},
      }
      Expect(languages).To(Equal(expectedLanguages));
      Expect(err).ToNot(HaveOccurred())
    })
  })

  PDescribe("runCommand", func() {
    PContext("when the binary exists", func() {
      PIt("should run the command, replacing the current process")
    })

    PContext("when the binary does not exist", func() {
      PIt("should return an error")
    })
  })
})
<commit_msg>Make the spec for callerDir more strict, requiring "run" to be at the end<commit_after>package main

import (
  . "github.com/onsi/ginkgo"
  . "github.com/onsi/gomega"

  "path"
)

var _ = Describe("Run", func() {
  It("has a version number", func() {
    Expect(version).ToNot(BeNil())
  })

  Describe("callerDir", func() {
    It("should return the directory of this source code file in Run's implementation", func () {
      Expect(callerDir()).To(MatchRegexp("run$"))
    })
  })

  Describe(".getLanguages", func() {
    It("should properly parse a JSON config file", func() {
      languages, err := getLanguages(path.Join(callerDir(), "mock_commands.json"))
      expectedLanguages := languageCollection {
        "uno": language{"one", "two"},
        "dos": language{"three", "four"},
      }
      Expect(languages).To(Equal(expectedLanguages));
      Expect(err).ToNot(HaveOccurred())
    })
  })

  PDescribe("runCommand", func() {
    PContext("when the binary exists", func() {
      PIt("should run the command, replacing the current process")
    })

    PContext("when the binary does not exist", func() {
      PIt("should return an error")
    })
  })
})
<|endoftext|>


<commit_before>// Package adt provides read access to ADT database files
package adt

<commit_msg>gofmt fix<commit_after>// Package adt provides read access to ADT database files
package adt
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"errors"
	"fmt"
	"io"
)

type Decryptor io.ReadCloser

type Encryptor io.WriteCloser

type AesDecryptor struct {
	Reader io.Reader
	Key    [aes.BlockSize]byte
	IV     [aes.BlockSize]byte
	Mode   cipher.BlockMode
	Buffer bytes.Buffer
}

type AesEncryptor struct {
	Writer io.Writer
	Key    [aes.BlockSize]byte
	IV     [aes.BlockSize]byte
	Mode   cipher.BlockMode
	Buffer bytes.Buffer
	IvDone bool
}

func NewAesDecryptor(key []byte, reader io.Reader) (Decryptor, error) {
	dec := &AesDecryptor{}
	dec.Reader = reader
	if len(key) > aes.BlockSize {
		return nil, errors.New(fmt.Sprintf("key size must not larger than %d", aes.BlockSize))
	}
	copy(dec.Key[:], key)

	block, err := aes.NewCipher(dec.Key[:])
	if err != nil {
		return nil, err
	}

	i := 0
	for {
		if i >= aes.BlockSize {
			break
		}
		bs, err := dec.Reader.Read(dec.IV[i:])
		if err != nil {
			if err == io.EOF {
				err = errors.New("not enought bytes for IV")
			}
			return nil, err
		}
		i += bs
	}
	if i != aes.BlockSize {
		panic("reader error")
	}
	dec.Mode = cipher.NewCBCDecrypter(block, dec.IV[:])

	return dec, nil
}

func NewAesEncryptor(key []byte, writer io.Writer) (Encryptor, error) {
	enc := &AesEncryptor{}
	enc.Writer = writer
	if len(key) > aes.BlockSize {
		return nil, errors.New(fmt.Sprintf("key size must not larger than %d", aes.BlockSize))
	}
	copy(enc.Key[:], key)

	block, err := aes.NewCipher(enc.Key[:])
	if err != nil {
		return nil, err
	}

	copy(enc.IV[:], RandStringBytes(aes.BlockSize))
	enc.Mode = cipher.NewCBCEncrypter(block, enc.IV[:])
	return enc, nil
}

func (dec *AesDecryptor) Read(output []byte) (int, error) {

	readSize := (len(output) / aes.BlockSize * aes.BlockSize) - dec.Buffer.Len()
	readBuff := make([]byte, readSize)

	var errRet error
	i := 0
	for {
		if i >= readSize {
			break
		}
		bs, err := dec.Reader.Read(readBuff[i:])
		if err != nil {
			if err == io.EOF {
				errRet = err
				break
			}
			// return any error other than io.EOF
			return 0, err
		}
		if bs == 0 {
			// if currently there is no available byte, return without blocking the process
			break
		}
		i += bs
	}

	if i > readSize {
		panic("reader error")
	}

	// ignore error as the error returned bytes.Buffer is always nil
	dec.Buffer.Write(readBuff[:i])

	decSize := dec.Buffer.Len() / aes.BlockSize * aes.BlockSize
	decBuff := make([]byte, decSize)
	dec.Buffer.Read(decBuff)

	dec.Mode.CryptBlocks(output[:decSize], decBuff)
	if decSize != 0 {
		return decSize, nil
	} else {
		return 0, errRet
	}
}

func (dec *AesDecryptor) Close() (err error) {
	if dec.Buffer.Len() != 0 {
		err = errors.New("There is unread bytes in buffer")
	}
	return
}

func (enc *AesEncryptor) write(input []byte) (int, error) {
	size := len(input)
	i := 0
	for {
		if i >= size {
			break
		}
		bs, err := enc.Writer.Write(input[i:])
		if err != nil {
			return 0, err
		}
		i += bs
	}

	if i > size {
		panic("writer error")
	}
	return i, nil
}

func (enc *AesEncryptor) Write(input []byte) (int, error) {

	enc.Buffer.Write(input)
	encSize := enc.Buffer.Len() / aes.BlockSize * aes.BlockSize
	encBuff := make([]byte, encSize)
	readBuff := make([]byte, encSize)

	enc.Buffer.Read(readBuff)

	enc.Mode.CryptBlocks(encBuff, readBuff)

	if !enc.IvDone {
		_, err := enc.write(enc.IV[:])
		if err != nil {
			return 0, err
		}
		enc.IvDone = true
	}

	return enc.write(encBuff)
}

func (enc *AesEncryptor) Close() (err error) {
	if enc.Buffer.Len() >= aes.BlockSize {
		panic("there is too much unwritten bytes")
	} else {
		buff := make([]byte, aes.BlockSize-enc.Buffer.Len())
		_, err = enc.Write(buff)
	}
	return
}

func MakeEncryptor(config EncryptConfig, writer io.Writer) Encryptor {
	if config.Type == "aes" {
		if aes, err := NewAesEncryptor([]byte(config.Key), writer); err != nil {
			Fatal(err.Error())
		} else {
			return aes
		}
	} else {
		Fatal(fmt.Sprintf("encryptor type '%s' is not implemented", config.Type))
	}
	return nil
}

func MakeDecryptor(config EncryptConfig, reader io.Reader) Decryptor {
	if config.Type == "aes" {
		if aes, err := NewAesDecryptor([]byte(config.Key), reader); err != nil {
			Fatal(err.Error())
		} else {
			return aes
		}
	} else {
		Fatal(fmt.Sprintf("decryptor type '%s' is not implemented", config.Type))
	}
	return nil
}
<commit_msg>fix crash due to data is not filled<commit_after>package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"errors"
	"fmt"
	"io"
)

type Decryptor io.ReadCloser

type Encryptor io.WriteCloser

type AesDecryptor struct {
	Reader io.Reader
	Key    [aes.BlockSize]byte
	IV     [aes.BlockSize]byte
	Mode   cipher.BlockMode
	Buffer bytes.Buffer
}

type AesEncryptor struct {
	Writer io.Writer
	Key    [aes.BlockSize]byte
	IV     [aes.BlockSize]byte
	Mode   cipher.BlockMode
	Buffer bytes.Buffer
	IvDone bool
}

func NewAesDecryptor(key []byte, reader io.Reader) (Decryptor, error) {
	dec := &AesDecryptor{}
	dec.Reader = reader
	if len(key) > aes.BlockSize {
		return nil, errors.New(fmt.Sprintf("key size must not larger than %d", aes.BlockSize))
	}
	copy(dec.Key[:], key)

	block, err := aes.NewCipher(dec.Key[:])
	if err != nil {
		return nil, err
	}

	i := 0
	for {
		if i >= aes.BlockSize {
			break
		}
		bs, err := dec.Reader.Read(dec.IV[i:])
		if err != nil {
			if err == io.EOF {
				err = errors.New("not enought bytes for IV")
			}
			return nil, err
		}
		i += bs
	}
	if i != aes.BlockSize {
		panic("reader error")
	}
	dec.Mode = cipher.NewCBCDecrypter(block, dec.IV[:])

	return dec, nil
}

func NewAesEncryptor(key []byte, writer io.Writer) (Encryptor, error) {
	enc := &AesEncryptor{}
	enc.Writer = writer
	if len(key) > aes.BlockSize {
		return nil, errors.New(fmt.Sprintf("key size must not larger than %d", aes.BlockSize))
	}
	copy(enc.Key[:], key)

	block, err := aes.NewCipher(enc.Key[:])
	if err != nil {
		return nil, err
	}

	copy(enc.IV[:], RandStringBytes(aes.BlockSize))
	enc.Mode = cipher.NewCBCEncrypter(block, enc.IV[:])
	return enc, nil
}

func (dec *AesDecryptor) Read(output []byte) (i int, errRet error) {

	readSize := (len(output) / aes.BlockSize * aes.BlockSize) - dec.Buffer.Len()
	readBuff := make([]byte, readSize)

	for {
		if i >= readSize {
			break
		}
		bs, err := dec.Reader.Read(readBuff[i:])
		errRet = err
		i += bs
		if err != nil {
			if err == io.EOF {
				break
			}
			// return any error other than io.EOF
			return
		}
		if bs == 0 {
			// if currently there is no available byte, return without blocking the process
			break
		}
	}

	if i > readSize {
		panic("reader error")
	}

	// ignore error as the error returned bytes.Buffer is always nil
	dec.Buffer.Write(readBuff[:i])

	decSize := dec.Buffer.Len() / aes.BlockSize * aes.BlockSize
	decBuff := make([]byte, decSize)
	dec.Buffer.Read(decBuff)

	dec.Mode.CryptBlocks(output[:decSize], decBuff)
	return
}

func (dec *AesDecryptor) Close() (err error) {
	if dec.Buffer.Len() != 0 {
		err = errors.New("There is unread bytes in buffer")
	}
	return
}

func (enc *AesEncryptor) write(input []byte) (int, error) {
	size := len(input)
	i := 0
	for {
		if i >= size {
			break
		}
		bs, err := enc.Writer.Write(input[i:])
		if err != nil {
			return 0, err
		}
		i += bs
	}

	if i > size {
		panic("writer error")
	}
	return i, nil
}

func (enc *AesEncryptor) Write(input []byte) (int, error) {

	enc.Buffer.Write(input)
	encSize := enc.Buffer.Len() / aes.BlockSize * aes.BlockSize
	encBuff := make([]byte, encSize)
	readBuff := make([]byte, encSize)

	enc.Buffer.Read(readBuff)

	enc.Mode.CryptBlocks(encBuff, readBuff)

	if !enc.IvDone {
		_, err := enc.write(enc.IV[:])
		if err != nil {
			return 0, err
		}
		enc.IvDone = true
	}

	return enc.write(encBuff)
}

func (enc *AesEncryptor) Close() (err error) {
	if enc.Buffer.Len() >= aes.BlockSize {
		panic("there is too much unwritten bytes")
	} else {
		buff := make([]byte, aes.BlockSize-enc.Buffer.Len())
		_, err = enc.Write(buff)
	}
	return
}

func MakeEncryptor(config EncryptConfig, writer io.Writer) Encryptor {
	if config.Type == "aes" {
		if aes, err := NewAesEncryptor([]byte(config.Key), writer); err != nil {
			Fatal(err.Error())
		} else {
			return aes
		}
	} else {
		Fatal(fmt.Sprintf("encryptor type '%s' is not implemented", config.Type))
	}
	return nil
}

func MakeDecryptor(config EncryptConfig, reader io.Reader) Decryptor {
	if config.Type == "aes" {
		if aes, err := NewAesDecryptor([]byte(config.Key), reader); err != nil {
			Fatal(err.Error())
		} else {
			return aes
		}
	} else {
		Fatal(fmt.Sprintf("decryptor type '%s' is not implemented", config.Type))
	}
	return nil
}
<|endoftext|>


<commit_before>// Package juggler implements a websocket-based, redis-backed RPC and
// pub-sub server. RPC (remote procedure call) requests are routed
// to a URI, and the response is asynchronous and is only sent to
// the calling client. Pub-sub events are also asynchronous but
// are routed to every client subscribed to the channel on which the
// event is published. Only active clients receive the event - this is
// not to be confused with a reliable message queue.
//
// All messages sent by the client receive an acknowledge message
// (ACK) when processed successfully or a negative acknowledge (NACK)
// if the request was rejected. See the juggler/message package documentation
// for all details regarding the supported messages.
//
// Server
//
// The Server struct defines a juggler server. In its simplest form, the
// following initializes a ready-to-use server:
//
//     broker := &redisbroker.Broker{...} // initialize a broker
//     server := &juggler.Server{
//       PubSubBroker: broker,
//       CallerBroker: broker,
//     }
//
// That is, only the pub-sub and caller brokers must be set for the server
// to start serving connections. The broker is typically a redisbroker.Broker,
// although it can be any value that implements the broker.PubSubBroker and
// broker.CallerBroker interfaces, respectively.
//
// Additional fields allow for more advanced configuration, such as
// read and write timeouts and limits, and custom message handling,
// via the Handler. Metrics can be collected by setting the Vars field
// to an *expvar.Map. See the Server type documentation for all details.
//
// The ServeConn method serves a connection using a configured Server.
// The Upgrade function creates an http.Handler that upgrades the
// HTTP connection to a websocket connection, and serves it using the
// provided Server.
//
// Because HTTP/2 does not support websockets, the HTTP server used
// to run the juggler server must not use HTTP/2. Since Go1.6, HTTP/2
// is automatically enabled over HTTPS. See https://golang.org/doc/go1.6#http2
// for details on how to explicitly disable it.
//
// One or many callees must be registered to listen for RPC requests.
// The callees are decoupled from the server, with redis acting as the
// broker. The pub-sub part is handled natively by redis. See the
// callee package for details.
//
// Conn
//
// The Conn struct represents a websocket connection to a juggler
// server. To be accepted by the server, the connection must accept
// one of the subprotocols supported by the server (the Subprotocols
// package variable). The negociated subprotocol is available via
// the Subprotocol connection method.
//
// A connection listens for its RPC call results, pub-sub events and
// requests from the client end, and ensures the messages flow from client to
// server and back as needed.
//
// Some client connections may know ahead of time that they won't make
// any RPC calls, or won't subscribe to any pub-sub channel, etc. In that
// case, the Juggler-Allowed-Messages header can be set on the HTTP
// request that initiates the connection with a restricted list of allowed
// messages, e.g.:
//
//     http.Header{"Juggler-Allowed-Messages": {"call, pub"}}
//
// The value is a comma-separated list of allowed messages. When that header
// is non-empty and not *, only the specified messages are allowed. This
// leads to a more efficient server-side connection and ensures the
// connection behaves as advertised, otherwise the connection is closed.
//
// Handler
//
// By default, when Server.Handler is nil, each message sent or received
// by the Server goes through the ProcessMsg function, which implements
// the standard behaviour for each message type.
//
// A custom handler can be set to implement middleware-style behaviour,
// similar to the stdlib's net/http server. When Handler is not nil, it is
// the responsibility of the handler to eventually call ProcessMsg so
// that the messages produce the expected results.
//
// Typical use of handlers can be:
//
//     - to implement logging of requests/responses
//     - to recover in case of panics
//     - to implement authentication for some requests
//     - to implement authorization checks for some requests
//     - etc.
//
// If a handler detects that the message cannot be executed as requested,
// e.g. because the caller is not authenticated or doesn't have access
// to the requested RPC URI, ProcessMsg must not be called. The message
// must be "intercepted" before the call to ProcessMsg, and a NACK reply
// must be returned to the client to let it know that the request will
// not be processed.
//
// To do so, the Conn offers the Send method, for example:
//
//     func CheckAccessHandler(ctx context.Context, c *juggler.Conn, m message.Msg) {
//       // assume we detected that the caller doesn't have access, in the ok variable
//       if !ok {
//         nack := message.NewNack(m, 403, errors.New("caller doesn't have access"))
//         c.Send(nack)
//         return
//       }
//     }
//
// The Send method makes sure the provided message goes through the handler
// too, so typically a handler would implement conditional checks depending
// on the type of the message. Authentication and authorization, for example,
// only make sense on request messages (messages coming from the client),
// which have their Type.IsRead method return true. Responses (messages
// sent by the server) have their Type.IsWrite method return true.
//
// A new context.Context is passed for each message processed to maintain
// values for the duration of a specific message.
//
package juggler
<commit_msg>juggler: small doc fix<commit_after>// Package juggler implements a websocket-based, redis-backed RPC and
// pub-sub server. RPC (remote procedure call) requests are routed
// to a URI, and the response is asynchronous and is only sent to
// the calling client. Pub-sub events are also asynchronous but
// are routed to every client subscribed to the channel on which the
// event is published. Only active clients receive the event - this is
// not to be confused with a reliable message queue.
//
// All messages sent by the client receive an acknowledge message
// (ACK) when processed successfully or a negative acknowledge (NACK)
// if the request was rejected. See the message package documentation
// for all details regarding the supported messages.
//
// Server
//
// The Server struct defines a juggler server. In its simplest form, the
// following initializes a ready-to-use server:
//
//     broker := &redisbroker.Broker{...} // initialize a broker
//     server := &juggler.Server{
//       PubSubBroker: broker,
//       CallerBroker: broker,
//     }
//
// That is, only the pub-sub and caller brokers must be set for the server
// to start serving connections. The broker is typically a redisbroker.Broker,
// although it can be any value that implements the broker.PubSubBroker and
// broker.CallerBroker interfaces, respectively.
//
// Additional fields allow for more advanced configuration, such as
// read and write timeouts and limits, and custom message handling,
// via the Handler. Metrics can be collected by setting the Vars field
// to an *expvar.Map. See the Server type documentation for all details.
//
// The ServeConn method serves a connection using a configured Server.
// The Upgrade function creates an http.Handler that upgrades the
// HTTP connection to a websocket connection, and serves it using the
// provided Server.
//
// Because HTTP/2 does not support websockets, the HTTP server used
// to run the juggler server must not use HTTP/2. Since Go1.6, HTTP/2
// is automatically enabled over HTTPS. See https://golang.org/doc/go1.6#http2
// for details on how to explicitly disable it.
//
// One or many callees must be registered to listen for RPC requests.
// The callees are decoupled from the server, with redis acting as the
// broker. The pub-sub part is handled natively by redis. See the
// callee package for details.
//
// Conn
//
// The Conn struct represents a websocket connection to a juggler
// server. To be accepted by the server, the connection must accept
// one of the subprotocols supported by the server (the Subprotocols
// package variable). The negociated subprotocol is available via
// the Subprotocol connection method.
//
// A connection listens for its RPC call results, pub-sub events and
// requests from the client end, and ensures the messages flow from client to
// server and back as needed.
//
// Some client connections may know ahead of time that they won't make
// any RPC calls, or won't subscribe to any pub-sub channel, etc. In that
// case, the Juggler-Allowed-Messages header can be set on the HTTP
// request that initiates the connection with a restricted list of allowed
// messages, e.g.:
//
//     http.Header{"Juggler-Allowed-Messages": {"call, pub"}}
//
// The value is a comma-separated list of allowed messages. When that header
// is non-empty and not *, only the specified messages are allowed. This
// leads to a more efficient server-side connection and ensures the
// connection behaves as advertised, otherwise the connection is closed.
//
// Handler
//
// By default, when Server.Handler is nil, each message sent or received
// by the Server goes through the ProcessMsg function, which implements
// the standard behaviour for each message type.
//
// A custom handler can be set to implement middleware-style behaviour,
// similar to the stdlib's net/http server. When Handler is not nil, it is
// the responsibility of the handler to eventually call ProcessMsg so
// that the messages produce the expected results.
//
// Typical use of handlers can be:
//
//     - to implement logging of requests/responses
//     - to recover in case of panics
//     - to implement authentication for some requests
//     - to implement authorization checks for some requests
//     - etc.
//
// If a handler detects that the message cannot be executed as requested,
// e.g. because the caller is not authenticated or doesn't have access
// to the requested RPC URI, ProcessMsg must not be called. The message
// must be "intercepted" before the call to ProcessMsg, and a NACK reply
// must be returned to the client to let it know that the request will
// not be processed.
//
// To do so, the Conn offers the Send method, for example:
//
//     func CheckAccessHandler(ctx context.Context, c *juggler.Conn, m message.Msg) {
//       // assume we detected that the caller doesn't have access, in the ok variable
//       if !ok {
//         nack := message.NewNack(m, 403, errors.New("caller doesn't have access"))
//         c.Send(nack)
//         return
//       }
//     }
//
// The Send method makes sure the provided message goes through the handler
// too, so typically a handler would implement conditional checks depending
// on the type of the message. Authentication and authorization, for example,
// only make sense on request messages (messages coming from the client),
// which have their Type.IsRead method return true. Responses (messages
// sent by the server) have their Type.IsWrite method return true.
//
// A new context.Context is passed for each message processed to maintain
// values for the duration of a specific message.
//
package juggler
<|endoftext|>


<commit_before>/*

Watchdog is an in-process task scheduler and simple execution monitor.
Watchdog accepts a workload and runs it at the specified interval.

Watchdog exposes two channels for monitoring its workload: Executions
and Stalls. Executions are sent for every invocation of a workload
Task, and stalls are only sent if a Task invocation takes longer than
a specified timeout.

A Watchdog is created with the Watch method, and starts running its
workload immediately. Its execution semantics are very close to those
of time.Ticker: a single tick may be "queued up" at any time if the
command takes longer to execute than the scheduling period.

A Watchdog may be stopped with the Stop command. If a task is
currently executing, that task will complete before Stop returns, and
information about its execution and stall (if any) will be sent on the
standard channels.

Here is a simple but functioning example:

	import (
		"fmt"
		"github.com/deafbybeheading/watchdog"
		"time"
	)

	func main() {
		w := watchdog.Watch(&Task{
			Schedule: 1 * time.Second,
			Command: func(t time.Time) error {
				return fmt.Printf("the time is %v\n", t)
			},
			Timeout: 10 * time.Milliseconds,
		})
		loop: for {
			executions := 0
			stalls := 0
			select {
			case exec := <- w.Executions():
				executions += 1
				fmt.Printf("invoked at %v; ran %v times\n",
					exec.StartedAt, executions)
				if err := exec.Error; err != nil {
					fmt.Printf("encountered error: %v\n", err)
				}
			case stall := <- w.Stalls():
				fmt.Printf("execution %v stalled at %v\n",
					executions + 1, stall.StalledAt)
			case <- time.After(10 * time.Second):
				w.Stop()
				fmt.Println("done!")
				break loop
			}
		}
	}

*/
<commit_msg>Fix docs generation by including package in doc.go<commit_after>/*

Watchdog is an in-process task scheduler and simple execution monitor.
Watchdog accepts a workload and runs it at the specified interval.

Watchdog exposes two channels for monitoring its workload: Executions
and Stalls. Executions are sent for every invocation of a workload
Task, and stalls are only sent if a Task invocation takes longer than
a specified timeout.

A Watchdog is created with the Watch method, and starts running its
workload immediately. Its execution semantics are very close to those
of time.Ticker: a single tick may be "queued up" at any time if the
command takes longer to execute than the scheduling period.

A Watchdog may be stopped with the Stop command. If a task is
currently executing, that task will complete before Stop returns, and
information about its execution and stall (if any) will be sent on the
standard channels.

Here is a simple but functioning example:

	import (
		"fmt"
		"github.com/deafbybeheading/watchdog"
		"time"
	)

	func main() {
		w := watchdog.Watch(&Task{
			Schedule: 1 * time.Second,
			Command: func(t time.Time) error {
				return fmt.Printf("the time is %v\n", t)
			},
			Timeout: 10 * time.Milliseconds,
		})
		loop: for {
			executions := 0
			stalls := 0
			select {
			case exec := <- w.Executions():
				executions += 1
				fmt.Printf("invoked at %v; ran %v times\n",
					exec.StartedAt, executions)
				if err := exec.Error; err != nil {
					fmt.Printf("encountered error: %v\n", err)
				}
			case stall := <- w.Stalls():
				fmt.Printf("execution %v stalled at %v\n",
					executions + 1, stall.StalledAt)
			case <- time.After(10 * time.Second):
				w.Stop()
				fmt.Println("done!")
				break loop
			}
		}
	}

*/
package watchdog
<|endoftext|>


<commit_before>package core

import (
	"sync"
)

var pool *sync.Pool

const BufSize = 2 * 1024

var defaultBufferPool = &sync.Pool{
	New: func() interface{} {
		return make([]byte, BufSize)
	},
}

func SetBufferPool(p *sync.Pool) {
	pool = p
}

func NewBytes(size int) []byte {
	if size <= BufSize {
		return pool.Get().([]byte)
	} else {
		return make([]byte, size)
	}
}

func FreeBytes(b []byte) {
	if len(b) <= BufSize {
		pool.Put(b)
	}
}

func init() {
	SetBufferPool(defaultBufferPool)
}
<commit_msg>bugfix<commit_after>package core

import (
	"sync"
)

var pool *sync.Pool

const BufSize = 2 * 1024

func SetBufferPool(p *sync.Pool) {
	pool = p
}

func NewBytes(size int) []byte {
	if size <= BufSize {
		return pool.Get().([]byte)
	} else {
		return make([]byte, size)
	}
}

func FreeBytes(b []byte) {
	if len(b) <= BufSize {
		pool.Put(b)
	}
}

func init() {
	SetBufferPool(&sync.Pool{
		New: func() interface{} {
			return make([]byte, BufSize)
		},
	})
}
<|endoftext|>


<commit_before>/*
Package core provides a pure handlers (or middlewares) stack so you can perform actions downstream, then filter and manipulate the response upstream.

The handlers stack

A handler is a function that receives a context.
It can be registered with Use and has the possibility to break the stream or to continue with the next handler in the stack.

Example of a logger, followed by a security headers setter, followed by a response writer:

	// Log
	core.Use(func(c *core.Context) {
		// Before the response.
		start := time.Now()

		// Execute the next handler in the stack.
		c.Next()

		// After the response.
		log.Printf(" %s  %s  %s", c.Request.Method, c.Request.URL, time.Since(start))
	})

	// Secure
	core.Use(func(c *core.Context) {
		c.ResponseWriter.Header().Set("X-Frame-Options", "SAMEORIGIN")
		c.ResponseWriter.Header().Set("X-Content-Type-Options", "nosniff")
		c.ResponseWriter.Header().Set("X-XSS-Protection", "1; mode=block")

		// Execute the next handler in the stack.
		c.Next()
	})

	// Response
	core.Use(func(c *core.Context) {
		fmt.Fprint(c.ResponseWriter, "Hello, World!")
	})

	// Run server
	core.Run()

A clearer visualization of this serving flow:

	request open
	  |— log start
	  |——— secure start
	  |————— response write
	  |——— secure end
	  |— log end
	request close

When using Run, your app is reachable at http://localhost:8080 by default.

If you need more flexibility, you can make a new handlers stack, which is fully compatible with the net/http.Handler interface:

	hs := core.NewHandlersStack()

	hs.Use(func(c *core.Context) {
		fmt.Fprint(c.ResponseWriter, "Hello, World!")
	})

	http.ListenAndServe(":8080", hs)

Flags

These flags are predefined:

	-address
		The address to listen and serving on.
		Value is saved in Address.
	-production
		Run the server in production environment.
		Some third-party handlers may have different behaviors
		depending on the environment.
		Value is saved in Production.

It's up to you to call
	flag.Parse()
in your main function if you want to use them.

Panic recovering

When using Run, your server always recovers from panics, logs the error with stack, and sends a 500 Internal Server Error.
If you want to use a custom handler on panic, give one to HandlePanic.

Handlers and helpers

No handlers or helpers are bundled in the core: it does one thing and does it well.
That's why you have to import all and only the handlers or helpers you need:

	compress
		Clever response compressing
		https://godoc.org/github.com/volatile/compress
	cors
		Cross-Origin Resource Sharing support
		https://godoc.org/github.com/volatile/cors
	i18n
		Simple internationalization
		https://godoc.org/github.com/volatile/i18n
	log
		Requests logging
		https://godoc.org/github.com/volatile/log
	response
		Readable response helper
		https://godoc.org/github.com/volatile/response
	route
		Flexible routing helper
		https://godoc.org/github.com/volatile/route
	secure
		Quick security wins
		https://godoc.org/github.com/volatile/secure
	static
		Simple assets serving
		https://godoc.org/github.com/volatile/static
*/
package core
<commit_msg>Update doc<commit_after>/*
Package core provides a pure handlers (or middlewares) stack so you can perform actions downstream, then filter and manipulate the response upstream.

The handlers stack

A handler is a function that receives a Context (which contains the response writer and the request).
It can be registered with Use and has the possibility to break the stream or to continue with the next handler of the stack.

Example of a logger, followed by a security headers setter, followed by a response writer:

	// Log
	core.Use(func(c *core.Context) {
		// Before the response.
		start := time.Now()

		// Execute the next handler in the stack.
		c.Next()

		// After the response.
		log.Printf(" %s  %s  %s", c.Request.Method, c.Request.URL, time.Since(start))
	})

	// Secure
	core.Use(func(c *core.Context) {
		c.ResponseWriter.Header().Set("X-Frame-Options", "SAMEORIGIN")
		c.ResponseWriter.Header().Set("X-Content-Type-Options", "nosniff")
		c.ResponseWriter.Header().Set("X-XSS-Protection", "1; mode=block")

		// Execute the next handler in the stack.
		c.Next()
	})

	// Response
	core.Use(func(c *core.Context) {
		fmt.Fprint(c.ResponseWriter, "Hello, World!")
	})

	// Run server
	core.Run()

A clearer visualization of this serving flow:

	request open
	  |— log start
	  |——— secure start
	  |————— response write
	  |——— secure end
	  |— log end
	request close

When using Run, your app is reachable at http://localhost:8080 by default.

If you need more flexibility, you can make a new handlers stack, which is fully compatible with the net/http.Handler interface:

	hs := core.NewHandlersStack()

	hs.Use(func(c *core.Context) {
		fmt.Fprint(c.ResponseWriter, "Hello, World!")
	})

	http.ListenAndServe(":8080", hs)

Flags

These flags are predefined:

	-address
		The address to listen and serving on.
		Value is saved in Address.
	-production
		Run the server in production environment.
		Some third-party handlers may have different behaviors
		depending on the environment.
		Value is saved in Production.

It's up to you to call
	flag.Parse()
in your main function if you want to use them.

Panic recovering

When using Run, your server always recovers from panics, logs the error with stack, and sends a 500 Internal Server Error.
If you want to use a custom handler on panic, give one to HandlePanic.

Handlers and helpers

No handlers or helpers are bundled in the core: it does one thing and does it well.
That's why you have to import all and only the handlers or helpers you need:

	compress
		Clever response compressing
		https://godoc.org/github.com/volatile/compress
	cors
		Cross-Origin Resource Sharing support
		https://godoc.org/github.com/volatile/cors
	i18n
		Simple internationalization
		https://godoc.org/github.com/volatile/i18n
	log
		Requests logging
		https://godoc.org/github.com/volatile/log
	response
		Readable response helper
		https://godoc.org/github.com/volatile/response
	route
		Flexible routing helper
		https://godoc.org/github.com/volatile/route
	secure
		Quick security wins
		https://godoc.org/github.com/volatile/secure
	static
		Simple assets serving
		https://godoc.org/github.com/volatile/static
*/
package core
<|endoftext|>


<commit_before>// BUG(telyn): Unsure of the default hwprofile
// BUG(telyn): Needs more create-vm flags. Also boot-script isn't here yet.
// BUG(telyn): Flesh out the list of commands
/*
BigV API Client

Basic Usage:

	bigv [flags] <command> [command-flags] [command args]

	Common Flags:

		Common flags may be placed anywhere

		--force        - Runs without prompting, except purges.
		--purge        - Runs purges without prompting.
		--yubikey      - Will prompt for a yubikey one-time pass.
		--no-yubikey   - Will not use BIGV_YUBIKEY. See below for more information on environment variables.
		--yubikey-otp  - Your yubikey one-time pass. Defaults to nothing.
		--endpoint     - The API endpoint of the BigV service you're trying to access. Without a URL scheme, assumes https. Defaults to uk0.bigv.io.
		--user         - Your BigV username.
		--help         - Show this hel

	Both the `--flag=value` and `--flag value` forms are supported.

	The BigV command will generally prompt you for your username and password.
	Set the BIGV_USER and BIGV_PASS (and optionally BIGV_YUBIKEY) environment variables,
	or the --user and --yubikey-otp flags in order to not receive prompting for these.

	If BIGV_YUBIKEY or --yubikey-otp is set, it will be used unless --no-yubikey is specified.

	Command flags trump environment variables, so if BIGV_USER and --user are specified, the value passed in --user will be used.

	Where a VM, group or account name can be entered, you may enter the entire domain name of the machine, for example:
	bigv.is.awesome.uk0.bigv.io for the VM "bigv" in group "is" of account "awesome". If a VM is in the default group of your
	primary account, you may specify just the VM name, for example for a user with the default account "example", specifying
	"awesomevm" is the same as specifying awesomevm.default.example or awesomevm.default.example.uk0.bigv.io
	(if you haven't provided an --endpoint)

	Dashes in commands may be replaced with spaces, for example: create vm is an alias for create-vm.

	New is always an alias for create, for example: new-vm is an alias for create-vm.

Commands available:

	create-vm [flags] <name> [image] [disc-specs]
	create [flags] <name> [image] [disc-specs]
	new-vm [flags] <name> [image] [disc-specs]
	new [flags] <name> [image] [disc-specs]

		Creates a VM with the provided name, image and disc-specs.

		If image and disc-specs are not provided, will interactively prompt for them, or default to "wheezy" and a 25GiB SATA SSD.

		Flags available:

			--boot-script - A filename of a boot-script to upload from the local machine. This script will be run the first time the virtual machine starts up.
			--hwprofile   - Sets the hardware profile. Defaults to virtio2013 probably.
			--lock        - Locks the hardware profile, preventing automatic upgrades. Not set by default

*/
package main
<commit_msg>More usage documentation: disks<commit_after>// BUG(telyn): Needs more create-vm flags. Also boot-script isn't here yet.
// BUG(telyn): Flesh out the list of commands
// BUG(telyn): Can you remove a disk from a running VM?
// BUG(telyn): Not default to "wheezy" and 25GiB, default to whatever the API says are the defaults? https://projects.bytemark.co.uk/issues/9378
/*
BigV API Client

Basic Usage:

	bigv [flags] <command> [command-flags] [command args]

	Common Flags:

		Common flags may be placed anywhere

		--force        - Runs without prompting, except purges.
		--purge        - Runs purges without prompting.
		--yubikey      - Will prompt for a yubikey one-time pass.
		--no-yubikey   - Will not use BIGV_YUBIKEY. See below for more information on environment variables.
		--yubikey-otp  - Your yubikey one-time pass. Defaults to nothing.
		--endpoint     - The API endpoint of the BigV service you're trying to access. Without a URL scheme, assumes https. Defaults to uk0.bigv.io.
		--user         - Your BigV username.
		--help         - Show this hel

	Both the `--flag=value` and `--flag value` forms are supported.

	The BigV command will generally prompt you for your username and password.
	Set the BIGV_USER and BIGV_PASS (and optionally BIGV_YUBIKEY) environment variables,
	or the --user and --yubikey-otp flags in order to not receive prompting for these.

	If BIGV_YUBIKEY or --yubikey-otp is set, it will be used unless --no-yubikey is specified.

	Command flags trump environment variables, so if BIGV_USER and --user are specified, the value passed in --user will be used.

	Where a VM, group or account name can be entered, you may enter the entire domain name of the machine, for example:
	bigv.is.awesome.uk0.bigv.io for the VM "bigv" in group "is" of account "awesome". If a VM is in the default group of your
	primary account, you may specify just the VM name, for example for a user with the default account "example", specifying
	"awesomevm" is the same as specifying awesomevm.default.example or awesomevm.default.example.uk0.bigv.io
	(if you haven't provided an --endpoint)

	Dashes in commands may be replaced with spaces, for example: create vm is an alias for create-vm.

	New is always an alias for create, for example: new-vm is an alias for create-vm.
	You may also misspell disk as disc, at no penalty ;-)

Commands available:

	create-vm [flags] <name> [image] [disk-specs]
	new-vm [flags] <name> [image] [disk-specs]

		Creates a VM with the provided name, image and disk-specs.

		Disk specs must match the following format: [storage-grade:]size[MgGtT] and are comma or space separated. The available storage grades can be listed with the list-storage-grades command. See the create-disk documentation below for the size suffixes.

		If image and disk-specs are not provided, will interactively prompt for them, or default to "wheezy" and a 25GiB SATA SSD if the --force flag is present.

		The VM's full specification will be given and you will be prompted to confirm it unless the --force flag is present.

		Flags available:

			--boot-script - A filename of a boot-script to upload from the local machine. This script will be run the first time the virtual machine starts up.
			--hwprofile   - Sets the hardware profile. See the output of list-hwprofiles.
			--lock        - Locks the hardware profile, preventing automatic upgrades. Not set by default

	create-disk [flags] <vm> <disk spec> [name]
	new-disk [flags] <vm> <disk spec> [name]

		Creates a disk attached to the VM provided, with the given spec

		Disk specs must match the following format: [storage-grade:]size[MgGtT]. The available storage grades can be listed with the list-storage-grades command.

		Size must be a positive integer, and the suffixes are as follows:
			M - Megabytes - default
			g - GB  (1000 megabytes)
			G - GiB (1024 megabytes)
			t - TB  (1000 GB)
			T - TiB (1024 GiB)

		The disk's specification will be given and you will be prompted to confirm it unless the --force flag is present.

		Flags available:

			--grade - Specifies what storage grade to use. Overridden if the storage-grade is part of the disk-spec.

	resize-disk <vm> <disk> [size]

		Resizes the disk named <disk> attached to the specified VM.
		If size begins with a +, will increase the disk's size by the amount specified.

		You'll be prompted to confirm the new size unless the --force flag is given.

		Disks cannot be resized to a lower size than they currently have.

	delete-disk <vm> <disk>
	remove-disk <vm> <disk>

		Removes the named disk from the specified VM.
		This operation can probably only be performed on stopped VMs.

		You will be prompted for confirmation unless the --force flag is given.

*/
package main
<|endoftext|>


<commit_before>// Package cc is a very flexible library for configuration management,
// which is easy to use and support YAML and JSON only.
//
// Usage:
//
//		c, _ := cc.NewConfigFromFile("./example/example.yaml")  // file must has extension
//		_ := c.MergeFromFile("./example/example.json") // do not ignore the errors
//
//		c.Must("name")  // panic if not found
//		c.String("name")
//
//		cc := c.Config("map")
//		cc.Bool("key_one")
//
//		list := c.Value("list").List()
//		list[1].Int()
//
//		// environment variables
//		os.Setenv("float_env", "11.11")
//		c.Float("float_env")
//
//
// Default configs
//
// We may write the code like this:
//
//		name := "default"
//		if c.Has("name") {
//			name = c.String("name")  // or panic
//		}
//
// Now, we can write code like this:
//
//		name := c.StringOr("name", "cc")  // or c.Must("name")
//		b := c.BoolOr("bool", true)
//		f := c.FloatOr("float", 3.14)
//		i := c.IntOr("int", 33)
//
//
// Pattern && Validation
//
// If you want to check string value whether it is matched by regexp:
//
//		s, ok := c.StringAnd("name", "^c")
//
// Or, the make the string value as a pattern:
//
//		p := c.Pattern("pattern_key_name")
//		ok := p.ValidateString("a string")
//
// For int and float, cc use if-like condition to do similar work.
// Assume we have `threhold: "N>=30&&N<=80"` in config file, we can use it like this:
//
//		p := c.Pattern("threhold")
//		ok := p.ValidateInt(40)  // or ValidateFloat
//
// Or, using a pattern to validate the number:
//
//		ni, ok := c.IntAnd("int_key", "N>50")
//		nf, ok := c.FloatAnd("float_key", "N/100>=0.3")
//
// NOTE: bit operation is not supported.
package cc
<commit_msg>Fix style<commit_after>// Package cc is a very flexible library for configuration management,
// which is easy to use and support YAML and JSON only.
//
//
// Usage
//
//		c, _ := cc.NewConfigFromFile("./example/example.yaml")  // file must has extension
//		_ := c.MergeFromFile("./example/example.json") // do not ignore the errors
//
//		c.Must("name")  // panic if not found
//		c.String("name")
//
//		cc := c.Config("map")
//		cc.Bool("key_one")
//
//		list := c.Value("list").List()
//		list[1].Int()
//
//		// environment variables
//		os.Setenv("float_env", "11.11")
//		c.Float("float_env")
//
//
// Default Configs
//
// We may write the code like this:
//
//		name := "default"
//		if c.Has("name") {
//			name = c.String("name")  // or panic
//		}
//
// Now, we can write code like this:
//
//		name := c.StringOr("name", "cc")  // or c.Must("name")
//		b := c.BoolOr("bool", true)
//		f := c.FloatOr("float", 3.14)
//		i := c.IntOr("int", 33)
//
//
// Pattern and Validation
//
// If you want to check string value whether it is matched by regexp:
//
//		s, ok := c.StringAnd("name", "^c")
//
// Or, the make the string value as a pattern:
//
//		p := c.Pattern("pattern_key_name")
//		ok := p.ValidateString("a string")
//
// For int and float, cc use if-like condition to do similar work.
// Assume we have `threhold: "N>=30&&N<=80"` in config file, we can use it like this:
//
//		p := c.Pattern("threhold")
//		ok := p.ValidateInt(40)  // or ValidateFloat
//
// Or, using a pattern to validate the number:
//
//		ni, ok := c.IntAnd("int_key", "N>50")
//		nf, ok := c.FloatAnd("float_key", "N/100>=0.3")
//
// NOTE: bit operation is not supported.
package cc
<|endoftext|>


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

/*
Compatibility

The gohg client library is created with Go1 (v1.0.3). It is tested against
Mercurial 2.5.2, both on Windows 7 and Ubuntu 12.04.

Currently there is no mechanism to handle differences in possibilities between
different Mercurial versions. The errors returned by Mercurial are your only
help here.

Dependencies

Only Go and it's standard library. Though I'm using gocov for checking test
coverage (see https://github.com/axw/gocov).

Installation

At the commandline type:
  go get [-u] bitbucket.org/gohg/gohg
  go test -v bitbucket.org/gohg/gohg

Import the package

Start with importing the gohg package:
  import . "bitbucket.org/gohg/gohg"

Connecting the Mercurial Command Server

All interaction with the Mercurial Command Server (Hg CS from now on) happens
through the HgClient type, of which you have to create an instance:

  hc :=  NewHgClient()

Then you can connect the Hg CS:

  err := hc.Connect("hg", "~/myrepo", nil)
   4                 1        2        3

1. The Hg executable:

The first parameter is the Mercurial command to use (which 'hg'). You can leave
it blanc to let the gohg tool use the default Mercurial command on the system.
Having a parameter for the Hg command allows for using a different Hg version,
for testing purposes for instance.

2. The repository path:

The second parameter is the path to the repository you want to work on. You can
leave it blanc to have gohg use the repository it can find for the current path
(searching upward in the folder tree eventually).

3. The config for the session:

The third parameter allows to provide extra configuration for the session.
Though this is currently not implemented yet.

4. The returnvalue:

The HgClient.Connect() method eventually returns an error, so you can check if
the connection succeeded, and if it is safe to go on or not.

Once the work is done, you can disconnect the Hg CS. We advise to use a typical
Go idiom for this:

  err := hc.Connect("hg", "~/myrepo", nil)
  if err != nil {
      log.Fatal(err)
  }
  defer hc.Disconnect()
  // do the real work here

Config

The gohg tool sets some environment variables for the Hg CS session, to ensure
it's good working:
  // ensure Hg works in english
  HGPLAIN=True
  // Use only the .hg/hgrc from the repo itself.
  HGRCPATH=''
  HGENCODING=UTF-8

Commands

Once we have a connection to a Hg CS we can do some work with the repository.
This is done with commands, and gohg offers 3 ways for issuing them.

1. The command methods of the HgClient type.

2. The HgCmd type.

3. The ExecCmd() method of the HgClient type.

Each of which has its own reason of existance.

Commands return a byte slice containing the resulting data, and eventually an
error. But there are a few exceptions (see api docs).

  log, err := hc.Log(nil, nil)       // log is a byte slice
  err := hc.Init(nil, "~/mynewrepo") // only returns an error eventually
  vers, err:= hc.Version()           // vers is a string of the form '2.4'

If a command fails, the returned error contains 3 elements: 1) the returncode
by Mercurial, 2) the full command that was passed to the Hg CS, and 3) the
eventual error message returned by Mercurial.

So the command

  idinfo, err := hc.Identify([]Option{Verbose(true)}, []string{"C:\\DEV\\myrepo"})

could return something like the following in the err variable when it fails:

  runcommand: Identify(): returncode=-1
  cmd: identify -v C:\DEV\myrepo
  hgerr:

The command aliases are not implemented. But there are examples of how
you can easily implement them in identify.go and showconfig.go.

Commands - HgClient command methods

This is the easiest way, a kind of convenience. And the most readable too.
A con is that as a user you cannot know the exact command that was passed to Hg,
without some extra mechanics.

Each command has the same name as the corresponding Hg command, except it starts
with a capital letter of course.

An example:

  log, err := hc.Log([]Option{Limit(2)}, []string("my-file"))
  if err != nil {
      fmt.Printf(err)
      ...
  }
  fmt.Printf("%s", log)

Note that these methods all use the HgCmd type internally. As such they are
convenience wrappers around that type. You could also call them a kind of
syntactic sugar. If you just want to simply issue a command, nothing more, they
are the way to go.

The only way to obtain the commandstring sent to Hg when using these command
methods, is by calling the HgClient.ShowLastCmd() method:

  log, err := hc.Log([]Option{Limit(2)}, []string("my-file"))
  fmt.Printf("%s", hc.ShowLastCmd()) // prints: log --limit 2 -v my-file

But you have to do this before issuing any other command, as the name of the
method already suggests.

Commands - the HgCmd type

Using the HgCmd type is kind of the standard way. It is a struct that you can
instantiate for any new command, and for which you can set elements Name,
Options and Params (see the api docs hereafter for more details). It allows for
building the command step by step, and also to query the exact command that will
be sent to the Hg CS.

A pro of this method is that it allows you to obtain the exact command string
that will be passed to Mercurial, as you would type it on the commandline. This
could be handy for logging, or for showing feedback to the user in a GUI program.

An example (also see examples/example2.go):

  opts := make([]Option, 2)
  var lim Limit = 2
  opts[0] = lim
  var verb Verbose = true
  opts[1] = verb
  hc.SetOptions(opts)
  hc, _ := NewHgCmd("log", opts, nil, new(logOpts))
  cmdline, _ := hc.CmdLine(hgcl)
  fmt.Printf("%s\n", cmdline) // output: log --limit 2 -v
  hc.Exec(hgcl)

As you can see, this way requires some more coding.

The api docs will also show you the HgCmd type has a convenient constructor for
each command, allowing for easy and correct initialization of the new command
type.

Commands - ExecCmd

The HgClient type has an extra method ExecCmd(), allowing you to pass a fully
custom build command to Hg. It accepts a string slice that is supposed to
contain the complete command, as you would type it at the command line.

It could be a convenient way for issuing commands that are not yet implemented
in gohg, or to make use of extensions to Hg (for which gohg offers no support).

An example:

  // hgcl is a HgClient instance that has a connection to the Hg CS
  hgcmd := []string{"log", "--limit", "2"}
  result, err := hgcl.ExecCmd(hgcmd)

Options and Parameters

Just like on the commandline, options come before parameters.

  opts := []Option{Verbose(true), Limit(2)}
  params := []string{"mytool.go"}
  log, err := hc.Log(opts, params)

Options to commands use the same name as the long form of the Mercurial option
they represent, but start with a capital letter (as do all exported symbols in
Go). An options value can be of type bool, int or string. You just pass the
value as the parameter to the option (= type conversion of the value to the
option type). You can pass any number of options, as the elements of a slice.
Options can occur more than once if appropriate (see the ones marked with '[+]'
in the Mercurial help).

  log, err := hc.Log([]Option{Verbose(true)}, nil)
  log, err := hc.Log([]Option{Limit(2)}, nil)
  log, err := hc.Log([]Option{User("John Doe"), User("me")}, nil)

Parameters are used to provide any arguments for a command that are not options.
They are passed in as a string or a string slice, depending on the command.
These parameters typically contain revisions, paths or filenames and so.

  log, err := hc.Log(nil, []string{"myfile"})
  heads, err := hc.Heads(nil, []string{"foobranch"})

The gohg tool only checks if the options the caller gives are valid for that
command. It does not check if the values are valid for the combination of that
command and that option, as that is done by Mercurial. No need to implement that
again. If an option is not valid for a command, it is silently ignored, so it is
not passed to the Hg CS.

Some options are not implemented, as they seemed not relevant for use with this
tool (for instance: the global --color option, or the --print0 option for
status).

Error handling

The gohg tool only returns errors, with an as clear as possible message, and
never uses log.Fatal() nor panics, even if those may seem appropriate. It leaves
it up to the caller to do that eventually. It's not up to this library to decide
whether to do a retry or to abort the complete application.

Limitations

* The following config settings are fixated in the code (at least for now):
  encoding=utf-8
  ui.interactive=False
  extensions.color=!

* As mentioned earlier, passing config info is not implemented yet.

* Currently there is no support for any extensions to Mercurial.

* If multiple Hg CSers are used against the same repo, it is up to Mercurial
to handle this correctly.

* Mercurial is always run in english. No internationalization yet.

Issues

If you experience any problems using the gohg tool, please register an issue
using the Bitbucket issue tracker at https://bitbucket.org/gohg/gohg/issues.

You can also register any enhancement requests or suggestions for improvement
there.

License

Copyright 2012, The gohg Authors. All rights reserved.

Use of this source code is governed by a BSD style license that can be found in
the LICENSE.md file.

*/
package gohg
<commit_msg>doc: referenced the example code<commit_after>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE file.

/*
Compatibility

The gohg client library is created with Go1 (v1.0.3). It is tested against
Mercurial 2.5.2, both on Windows 7 and Ubuntu 12.04.

Currently there is no mechanism to handle differences in possibilities between
different Mercurial versions. The errors returned by Mercurial are your only
help here.

Dependencies

Only Go and it's standard library. Though I'm using gocov for checking test
coverage (see https://github.com/axw/gocov).

Installation

At the commandline type:
  go get [-u] bitbucket.org/gohg/gohg
  go test -v bitbucket.org/gohg/gohg

Import the package

Start with importing the gohg package:
  import . "bitbucket.org/gohg/gohg"

Connecting the Mercurial Command Server

All interaction with the Mercurial Command Server (Hg CS from now on) happens
through the HgClient type, of which you have to create an instance:

  hc :=  NewHgClient()

Then you can connect the Hg CS:

  err := hc.Connect("hg", "~/myrepo", nil)
   4                 1        2        3

1. The Hg executable:

The first parameter is the Mercurial command to use (which 'hg'). You can leave
it blanc to let the gohg tool use the default Mercurial command on the system.
Having a parameter for the Hg command allows for using a different Hg version,
for testing purposes for instance.

2. The repository path:

The second parameter is the path to the repository you want to work on. You can
leave it blanc to have gohg use the repository it can find for the current path
(searching upward in the folder tree eventually).

3. The config for the session:

The third parameter allows to provide extra configuration for the session.
Though this is currently not implemented yet.

4. The returnvalue:

The HgClient.Connect() method eventually returns an error, so you can check if
the connection succeeded, and if it is safe to go on or not.

Once the work is done, you can disconnect the Hg CS. We advise to use a typical
Go idiom for this:

  err := hc.Connect("hg", "~/myrepo", nil)
  if err != nil {
      log.Fatal(err)
  }
  defer hc.Disconnect()
  // do the real work here

Config

The gohg tool sets some environment variables for the Hg CS session, to ensure
it's good working:
  // ensure Hg works in english
  HGPLAIN=True
  // Use only the .hg/hgrc from the repo itself.
  HGRCPATH=''
  HGENCODING=UTF-8

Commands

Once we have a connection to a Hg CS we can do some work with the repository.
This is done with commands, and gohg offers 3 ways for issuing them.

1. The command methods of the HgClient type.

2. The HgCmd type.

3. The ExecCmd() method of the HgClient type.

Each of which has its own reason of existance.

Commands return a byte slice containing the resulting data, and eventually an
error. But there are a few exceptions (see api docs).

  log, err := hc.Log(nil, nil)       // log is a byte slice
  err := hc.Init(nil, "~/mynewrepo") // only returns an error eventually
  vers, err:= hc.Version()           // vers is a string of the form '2.4'

If a command fails, the returned error contains 3 elements: 1) the returncode
by Mercurial, 2) the full command that was passed to the Hg CS, and 3) the
eventual error message returned by Mercurial.

So the command

  idinfo, err := hc.Identify([]Option{Verbose(true)}, []string{"C:\\DEV\\myrepo"})

could return something like the following in the err variable when it fails:

  runcommand: Identify(): returncode=-1
  cmd: identify -v C:\DEV\myrepo
  hgerr:

The command aliases are not implemented. But there are examples of how
you can easily implement them in identify.go and showconfig.go.

Commands - HgClient command methods

This is the easiest way, a kind of convenience. And the most readable too.
A con is that as a user you cannot know the exact command that was passed to Hg,
without some extra mechanics.

Each command has the same name as the corresponding Hg command, except it starts
with a capital letter of course.

An example (also see examples/example1.go):

  log, err := hc.Log([]Option{Limit(2)}, []string("my-file"))
  if err != nil {
      fmt.Printf(err)
      ...
  }
  fmt.Printf("%s", log)

Note that these methods all use the HgCmd type internally. As such they are
convenience wrappers around that type. You could also call them a kind of
syntactic sugar. If you just want to simply issue a command, nothing more, they
are the way to go.

The only way to obtain the commandstring sent to Hg when using these command
methods, is by calling the HgClient.ShowLastCmd() method:

  log, err := hc.Log([]Option{Limit(2)}, []string("my-file"))
  fmt.Printf("%s", hc.ShowLastCmd()) // prints: log --limit 2 -v my-file

But you have to do this before issuing any other command, as the name of the
method already suggests.

Commands - the HgCmd type

Using the HgCmd type is kind of the standard way. It is a struct that you can
instantiate for any new command, and for which you can set elements Name,
Options and Params (see the api docs hereafter for more details). It allows for
building the command step by step, and also to query the exact command that will
be sent to the Hg CS.

A pro of this method is that it allows you to obtain the exact command string
that will be passed to Mercurial, as you would type it on the commandline. This
could be handy for logging, or for showing feedback to the user in a GUI program.

An example (also see examples/example2.go):

  opts := make([]Option, 2)
  var lim Limit = 2
  opts[0] = lim
  var verb Verbose = true
  opts[1] = verb
  hc.SetOptions(opts)
  hc, _ := NewHgCmd("log", opts, nil, new(logOpts))
  cmdline, _ := hc.CmdLine(hgcl)
  fmt.Printf("%s\n", cmdline) // output: log --limit 2 -v
  hc.Exec(hgcl)

As you can see, this way requires some more coding.

The api docs will also show you the HgCmd type has a convenient constructor for
each command, allowing for easy and correct initialization of the new command
type.

Commands - ExecCmd

The HgClient type has an extra method ExecCmd(), allowing you to pass a fully
custom build command to Hg. It accepts a string slice that is supposed to
contain the complete command, as you would type it at the command line.

It could be a convenient way for issuing commands that are not yet implemented
in gohg, or to make use of extensions to Hg (for which gohg offers no support).

An example (also see examples/example3.go):

  // hgcl is a HgClient instance that has a connection to the Hg CS
  hgcmd := []string{"log", "--limit", "2"}
  result, err := hgcl.ExecCmd(hgcmd)

Options and Parameters

Just like on the commandline, options come before parameters.

  opts := []Option{Verbose(true), Limit(2)}
  params := []string{"mytool.go"}
  log, err := hc.Log(opts, params)

Options to commands use the same name as the long form of the Mercurial option
they represent, but start with a capital letter (as do all exported symbols in
Go). An options value can be of type bool, int or string. You just pass the
value as the parameter to the option (= type conversion of the value to the
option type). You can pass any number of options, as the elements of a slice.
Options can occur more than once if appropriate (see the ones marked with '[+]'
in the Mercurial help).

  log, err := hc.Log([]Option{Verbose(true)}, nil)
  log, err := hc.Log([]Option{Limit(2)}, nil)
  log, err := hc.Log([]Option{User("John Doe"), User("me")}, nil)

Parameters are used to provide any arguments for a command that are not options.
They are passed in as a string or a string slice, depending on the command.
These parameters typically contain revisions, paths or filenames and so.

  log, err := hc.Log(nil, []string{"myfile"})
  heads, err := hc.Heads(nil, []string{"foobranch"})

The gohg tool only checks if the options the caller gives are valid for that
command. It does not check if the values are valid for the combination of that
command and that option, as that is done by Mercurial. No need to implement that
again. If an option is not valid for a command, it is silently ignored, so it is
not passed to the Hg CS.

Some options are not implemented, as they seemed not relevant for use with this
tool (for instance: the global --color option, or the --print0 option for
status).

Error handling

The gohg tool only returns errors, with an as clear as possible message, and
never uses log.Fatal() nor panics, even if those may seem appropriate. It leaves
it up to the caller to do that eventually. It's not up to this library to decide
whether to do a retry or to abort the complete application.

Limitations

* The following config settings are fixated in the code (at least for now):
  encoding=utf-8
  ui.interactive=False
  extensions.color=!

* As mentioned earlier, passing config info is not implemented yet.

* Currently there is no support for any extensions to Mercurial.

* If multiple Hg CSers are used against the same repo, it is up to Mercurial
to handle this correctly.

* Mercurial is always run in english. No internationalization yet.

Issues

If you experience any problems using the gohg tool, please register an issue
using the Bitbucket issue tracker at https://bitbucket.org/gohg/gohg/issues.

You can also register any enhancement requests or suggestions for improvement
there.

License

Copyright 2012, The gohg Authors. All rights reserved.

Use of this source code is governed by a BSD style license that can be found in
the LICENSE.md file.

*/
package gohg
<|endoftext|>