<commit_before>// Copyright 2014 gandalf 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 api

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/tsuru/gandalf/db"
	"github.com/tsuru/gandalf/hook"
	"github.com/tsuru/gandalf/repository"
	"github.com/tsuru/gandalf/user"
	"io"
	"io/ioutil"
	"net/http"
	"reflect"
)

func accessParameters(body io.ReadCloser) (repositories, users []string, err error) {
	var params map[string][]string
	if err := parseBody(body, &params); err != nil {
		return []string{}, []string{}, err
	}
	users, ok := params["users"]
	if !ok {
		return []string{}, []string{}, errors.New("It is need a user list")
	}
	repositories, ok = params["repositories"]
	if !ok {
		return []string{}, []string{}, errors.New("It is need a repository list")
	}
	return repositories, users, nil
}

func GrantAccess(w http.ResponseWriter, r *http.Request) {
	// TODO: update README
	repositories, users, err := accessParameters(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if err := repository.GrantAccess(repositories, users); err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	fmt.Fprintf(w, "Successfully granted access to users \"%s\" into repository \"%s\"", users, repositories)
}

func RevokeAccess(w http.ResponseWriter, r *http.Request) {
	repositories, users, err := accessParameters(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if err := repository.RevokeAccess(repositories, users); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Successfully revoked access to users \"%s\" into repositories \"%s\"", users, repositories)
}

func AddKey(w http.ResponseWriter, r *http.Request) {
	keys := map[string]string{}
	if err := parseBody(r.Body, &keys); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if len(keys) == 0 {
		http.Error(w, "A key is needed", http.StatusBadRequest)
		return
	}
	uName := r.URL.Query().Get(":name")
	if err := user.AddKey(uName, keys); err != nil {
		switch err {
		case user.ErrInvalidKey:
			http.Error(w, err.Error(), http.StatusBadRequest)
		case user.ErrDuplicateKey:
			http.Error(w, "Key already exists.", http.StatusConflict)
		case user.ErrUserNotFound:
			http.Error(w, err.Error(), http.StatusNotFound)
		default:
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
	fmt.Fprint(w, "Key(s) successfully created")
}

func RemoveKey(w http.ResponseWriter, r *http.Request) {
	uName := r.URL.Query().Get(":name")
	kName := r.URL.Query().Get(":keyname")
	if err := user.RemoveKey(uName, kName); err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	fmt.Fprintf(w, "Key \"%s\" successfully removed", kName)
}

func ListKeys(w http.ResponseWriter, r *http.Request) {
	uName := r.URL.Query().Get(":name")
	keys, err := user.ListKeys(uName)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	out, err := json.Marshal(&keys)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(out)
}

type jsonUser struct {
	Name string
	Keys map[string]string
}

func NewUser(w http.ResponseWriter, r *http.Request) {
	var usr jsonUser
	if err := parseBody(r.Body, &usr); err != nil {
		http.Error(w, "Got error while parsing body: "+err.Error(), http.StatusBadRequest)
		return
	}
	u, err := user.New(usr.Name, usr.Keys)
	if err != nil {
		http.Error(w, "Got error while creating user: "+err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "User \"%s\" successfully created\n", u.Name)
}

func RemoveUser(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get(":name")
	if err := user.Remove(name); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "User \"%s\" successfully removed\n", name)
}

func NewRepository(w http.ResponseWriter, r *http.Request) {
	var repo repository.Repository
	if err := parseBody(r.Body, &repo); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	rep, err := repository.New(repo.Name, repo.Users, repo.IsPublic)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Repository \"%s\" successfully created\n", rep.Name)
}

func GetRepository(w http.ResponseWriter, r *http.Request) {
	repo, err := repository.Get(r.URL.Query().Get(":name"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	out, err := json.Marshal(&repo)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(out)
}

func RemoveRepository(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get(":name")
	if err := repository.Remove(name); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Repository \"%s\" successfully removed\n", name)
}

func RenameRepository(w http.ResponseWriter, r *http.Request) {
	var p struct{ Name string }
	defer r.Body.Close()
	err := parseBody(r.Body, &p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}
	name := r.URL.Query().Get(":name")
	err = repository.Rename(name, p.Name)
	if err != nil && err.Error() == "not found" {
		http.Error(w, err.Error(), http.StatusNotFound)
	} else if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func AddHook(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get(":name")
	if name != "post-receive" && name != "pre-receive" && name != "update" {
		http.Error(w,
			"Unsupported hook, valid options are: post-receive, pre-receive or update",
			http.StatusBadRequest)
		return
	}
	if err := hook.Add(name, r.Body); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprint(w, "hook ", name, " successfully created\n")
}

func parseBody(body io.ReadCloser, result interface{}) error {
	if reflect.ValueOf(result).Kind() == reflect.Struct {
		return errors.New("parseBody function cannot deal with struct. Use pointer")
	}
	b, err := ioutil.ReadAll(body)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(b, &result); err != nil {
		return errors.New(fmt.Sprintf("Could not parse json: %s", err.Error()))
	}
	return nil
}

func HealthCheck(w http.ResponseWriter, r *http.Request) {
	conn, err := db.Conn()
	if err != nil {
		return
	}
	defer conn.Close()
	if err := conn.User().Database.Session.Ping(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Failed to ping the database: %s\n", err)
		return
	}
	w.Write([]byte("WORKING"))
}
<commit_msg>api: don't let the request body opened after adding a hook<commit_after>// Copyright 2014 gandalf 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 api

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/tsuru/gandalf/db"
	"github.com/tsuru/gandalf/hook"
	"github.com/tsuru/gandalf/repository"
	"github.com/tsuru/gandalf/user"
	"io"
	"io/ioutil"
	"net/http"
	"reflect"
)

func accessParameters(body io.ReadCloser) (repositories, users []string, err error) {
	var params map[string][]string
	if err := parseBody(body, &params); err != nil {
		return []string{}, []string{}, err
	}
	users, ok := params["users"]
	if !ok {
		return []string{}, []string{}, errors.New("It is need a user list")
	}
	repositories, ok = params["repositories"]
	if !ok {
		return []string{}, []string{}, errors.New("It is need a repository list")
	}
	return repositories, users, nil
}

func GrantAccess(w http.ResponseWriter, r *http.Request) {
	// TODO: update README
	repositories, users, err := accessParameters(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if err := repository.GrantAccess(repositories, users); err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	fmt.Fprintf(w, "Successfully granted access to users \"%s\" into repository \"%s\"", users, repositories)
}

func RevokeAccess(w http.ResponseWriter, r *http.Request) {
	repositories, users, err := accessParameters(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if err := repository.RevokeAccess(repositories, users); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Successfully revoked access to users \"%s\" into repositories \"%s\"", users, repositories)
}

func AddKey(w http.ResponseWriter, r *http.Request) {
	keys := map[string]string{}
	if err := parseBody(r.Body, &keys); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if len(keys) == 0 {
		http.Error(w, "A key is needed", http.StatusBadRequest)
		return
	}
	uName := r.URL.Query().Get(":name")
	if err := user.AddKey(uName, keys); err != nil {
		switch err {
		case user.ErrInvalidKey:
			http.Error(w, err.Error(), http.StatusBadRequest)
		case user.ErrDuplicateKey:
			http.Error(w, "Key already exists.", http.StatusConflict)
		case user.ErrUserNotFound:
			http.Error(w, err.Error(), http.StatusNotFound)
		default:
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
	fmt.Fprint(w, "Key(s) successfully created")
}

func RemoveKey(w http.ResponseWriter, r *http.Request) {
	uName := r.URL.Query().Get(":name")
	kName := r.URL.Query().Get(":keyname")
	if err := user.RemoveKey(uName, kName); err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	fmt.Fprintf(w, "Key \"%s\" successfully removed", kName)
}

func ListKeys(w http.ResponseWriter, r *http.Request) {
	uName := r.URL.Query().Get(":name")
	keys, err := user.ListKeys(uName)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	out, err := json.Marshal(&keys)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(out)
}

type jsonUser struct {
	Name string
	Keys map[string]string
}

func NewUser(w http.ResponseWriter, r *http.Request) {
	var usr jsonUser
	if err := parseBody(r.Body, &usr); err != nil {
		http.Error(w, "Got error while parsing body: "+err.Error(), http.StatusBadRequest)
		return
	}
	u, err := user.New(usr.Name, usr.Keys)
	if err != nil {
		http.Error(w, "Got error while creating user: "+err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "User \"%s\" successfully created\n", u.Name)
}

func RemoveUser(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get(":name")
	if err := user.Remove(name); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "User \"%s\" successfully removed\n", name)
}

func NewRepository(w http.ResponseWriter, r *http.Request) {
	var repo repository.Repository
	if err := parseBody(r.Body, &repo); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	rep, err := repository.New(repo.Name, repo.Users, repo.IsPublic)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Repository \"%s\" successfully created\n", rep.Name)
}

func GetRepository(w http.ResponseWriter, r *http.Request) {
	repo, err := repository.Get(r.URL.Query().Get(":name"))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	out, err := json.Marshal(&repo)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(out)
}

func RemoveRepository(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get(":name")
	if err := repository.Remove(name); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Repository \"%s\" successfully removed\n", name)
}

func RenameRepository(w http.ResponseWriter, r *http.Request) {
	var p struct{ Name string }
	defer r.Body.Close()
	err := parseBody(r.Body, &p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}
	name := r.URL.Query().Get(":name")
	err = repository.Rename(name, p.Name)
	if err != nil && err.Error() == "not found" {
		http.Error(w, err.Error(), http.StatusNotFound)
	} else if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func AddHook(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Query().Get(":name")
	if name != "post-receive" && name != "pre-receive" && name != "update" {
		http.Error(w,
			"Unsupported hook, valid options are: post-receive, pre-receive or update",
			http.StatusBadRequest)
		return
	}
	defer r.Body.Close()
	if err := hook.Add(name, r.Body); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprint(w, "hook ", name, " successfully created\n")
}

func parseBody(body io.ReadCloser, result interface{}) error {
	if reflect.ValueOf(result).Kind() == reflect.Struct {
		return errors.New("parseBody function cannot deal with struct. Use pointer")
	}
	b, err := ioutil.ReadAll(body)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(b, &result); err != nil {
		return errors.New(fmt.Sprintf("Could not parse json: %s", err.Error()))
	}
	return nil
}

func HealthCheck(w http.ResponseWriter, r *http.Request) {
	conn, err := db.Conn()
	if err != nil {
		return
	}
	defer conn.Close()
	if err := conn.User().Database.Session.Ping(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Failed to ping the database: %s\n", err)
		return
	}
	w.Write([]byte("WORKING"))
}
<|endoftext|>


<commit_before>// Copyright 2013-2015 Bowery, Inc.

package prompt

import (
	"bufio"
	"errors"
	"io"
	"os"
	"strings"
)

var (
	// ErrCTRLC is returned when CTRL+C is pressed stopping the prompt.
	ErrCTRLC = errors.New("Interrupted (CTRL+C)")
	// ErrEOF is returned when CTRL+D is pressed stopping the prompt.
	ErrEOF = errors.New("EOF (CTRL+D)")
)

// Possible events that may occur when reading from input.
const (
	evChar = iota
	evSkip
	evReturn
	evEOF
	evCtrlC
	evBack
	evClear
	evHome
	evEnd
	evUp
	evDown
	evRight
	evLeft
	evDel
)

// IsNotTerminal checks if an error is related to the input not being a terminal.
func IsNotTerminal(err error) bool {
	return isNotTerminal(err)
}

// TerminalSize retrieves the columns/rows for the terminal connected to out.
func TerminalSize(out *os.File) (int, int, error) {
	return terminalSize(out)
}

// Terminal contains the state for raw terminal input.
type Terminal struct {
	In           *os.File
	Out          *os.File
	History      []string
	histIdx      int
	simpleReader *bufio.Reader
	t            *terminal
}

// NewTerminal creates a terminal and sets it to raw input mode.
func NewTerminal() (*Terminal, error) {
	in := os.Stdin

	term, err := newTerminal(in)
	if err != nil {
		return nil, err
	}

	return &Terminal{
		In:      in,
		Out:     os.Stdout,
		History: make([]string, 0, 10),
		histIdx: -1,
		t:       term,
	}, nil
}

// Basic gets input and if required tests to ensure input was given.
func (term *Terminal) Basic(prefix string, required bool) (string, error) {
	return term.Custom(prefix, func(input string) (string, bool) {
		if required && input == "" {
			return "", false
		}

		return input, true
	})
}

// BasicDefault gets input and if empty uses the given default.
func (term *Terminal) BasicDefault(prefix, def string) (string, error) {
	return term.Custom(prefix+" (Default: "+def+")", func(input string) (string, bool) {
		if input == "" {
			input = def
		}

		return input, true
	})
}

// Ask gets input and checks if it's truthy or not, and returns that
// in a boolean fashion.
func (term *Terminal) Ask(question string) (bool, error) {
	input, err := term.Custom(question+"? (y/n)", func(input string) (string, bool) {
		if input == "" {
			return "", false
		}
		input = strings.ToLower(input)

		if input == "y" || input == "yes" {
			return "yes", true
		}

		return "", true
	})

	var ok bool
	if input != "" {
		ok = true
	}

	return ok, err
}

// Custom gets input and calls the given test function with the input to
// check if the input is valid, a true return will return the string.
func (term *Terminal) Custom(prefix string, test func(string) (string, bool)) (string, error) {
	var err error
	var input string
	var ok bool

	for !ok {
		input, err = term.GetPrompt(prefix)
		if err != nil && err != io.EOF {
			return "", err
		}

		input, ok = test(input)
	}

	return input, nil
}

// Password retrieves a password from stdin without echoing it.
func (term *Terminal) Password(prefix string) (string, error) {
	var err error
	var input string

	for input == "" {
		input, err = term.GetPassword(prefix)
		if err != nil && err != io.EOF {
			return "", err
		}
	}

	return input, nil
}

// GetPrompt gets a line with the prefix and echos input.
func (term *Terminal) GetPrompt(prefix string) (string, error) {
	prefix += " "

	if !term.t.supportsEditing {
		return term.simplePrompt(prefix)
	}

	buf := NewBuffer(prefix, term.Out, true)
	return term.prompt(buf, NewAnsiReader(term.In))
}

// GetPassword gets a line with the prefix and doesn't echo input.
func (term *Terminal) GetPassword(prefix string) (string, error) {
	prefix += " "

	if !term.t.supportsEditing {
		return term.simplePrompt(prefix)
	}

	buf := NewBuffer(prefix, term.Out, false)
	return term.password(buf, NewAnsiReader(term.In))
}

// Close calls close on the internal terminal.
func (term *Terminal) Close() error {
	return term.t.Close()
}

// Reopen re-opens an internal terminal.
func (term *Terminal) Reopen() error {
	in := os.Stdin

	t, err := newTerminal(in)
	if err != nil {
		return err
	}

	term.t = t
	return nil
}

// simplePrompt is a fallback prompt without line editing support.
func (term *Terminal) simplePrompt(prefix string) (string, error) {
	if term.simpleReader == nil {
		term.simpleReader = bufio.NewReader(term.In)
	}

	_, err := term.Out.Write([]byte(prefix))
	if err != nil {
		return "", err
	}

	line, err := term.simpleReader.ReadString('\n')
	line = strings.TrimRight(line, "\r\n ")
	line = strings.TrimLeft(line, " ")

	return line, err
}

// setup initializes a prompt.
func (term *Terminal) setup(buf *Buffer, in io.Reader) (*bufio.Reader, error) {
	cols, _, err := TerminalSize(buf.Out)
	if err != nil {
		return nil, err
	}

	buf.Cols = cols
	input := bufio.NewReader(in)

	err = buf.Refresh()
	if err != nil {
		return nil, err
	}

	return input, nil
}

// read reads a rune and parses ANSI escape sequences found
func (term *Terminal) read(in *bufio.Reader) (int, rune, error) {
	char, _, err := in.ReadRune()
	if err != nil {
		return 0, 0, err
	}

	switch char {
	default:
		// Standard chars.
		return evChar, char, nil
	case tabKey, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlH, ctrlJ, ctrlK, ctrlN,
		ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX,
		ctrlY, ctrlZ:
		// Skip.
		return evSkip, char, nil
	case returnKey:
		// End of line.
		return evReturn, char, nil
	case ctrlD:
		// End of file.
		return evEOF, char, nil
	case ctrlC:
		// End of line, interrupted.
		return evCtrlC, char, nil
	case backKey:
		// Backspace.
		return evBack, char, nil
	case ctrlL:
		// Clear screen.
		return evClear, char, nil
	case escKey:
		// Functions like arrows, home, etc.
		esc := make([]byte, 2)
		_, err = in.Read(esc)
		if err != nil {
			return -1, char, err
		}

		// Home, end.
		if esc[0] == 'O' {
			switch esc[1] {
			case 'H':
				// Home.
				return evHome, char, nil
			case 'F':
				// End.
				return evEnd, char, nil
			}

			return evSkip, char, nil
		}

		// Arrows, delete, pgup, pgdown, insert.
		if esc[0] == '[' {
			switch esc[1] {
			case 'A':
				// Up.
				return evUp, char, nil
			case 'B':
				// Down.
				return evDown, char, nil
			case 'C':
				// Right.
				return evRight, char, nil
			case 'D':
				// Left.
				return evLeft, char, nil
			}

			// Delete, pgup, pgdown, insert.
			if esc[1] > '0' && esc[1] < '7' {
				extEsc := make([]byte, 3)
				_, err = in.Read(extEsc)
				if err != nil {
					return -1, char, err
				}

				if extEsc[0] == '~' {
					switch esc[1] {
					case '2', '5', '6':
						// Insert, pgup, pgdown.
						return evSkip, char, err
					case '3':
						// Delete.
						return evDel, char, err
					}
				}
			}
		}
	}

	return evSkip, char, nil
}

// prompt reads from in and parses ANSI escapes writing to buf.
func (term *Terminal) prompt(buf *Buffer, in io.Reader) (string, error) {
	input, err := term.setup(buf, in)
	if err != nil {
		return "", err
	}
	term.History = append(term.History, "")
	term.histIdx = len(term.History) - 1
	curHistIdx := term.histIdx

	for {
		typ, char, err := term.read(input)
		if err != nil {
			return buf.String(), err
		}

		switch typ {
		case evChar:
			err = buf.Insert(char)
			if err != nil {
				return buf.String(), err
			}

			term.History[curHistIdx] = buf.String()
		case evSkip:
			continue
		case evReturn:
			err = buf.EndLine()
			return buf.String(), err
		case evEOF:
			err = buf.EndLine()
			if err == nil {
				err = ErrEOF
			}

			return buf.String(), err
		case evCtrlC:
			err = buf.EndLine()
			if err == nil {
				err = ErrCTRLC
			}

			return buf.String(), err
		case evBack:
			err = buf.DelLeft()
			if err != nil {
				return buf.String(), err
			}

			term.History[curHistIdx] = buf.String()
		case evClear:
			err = buf.ClsScreen()
			if err != nil {
				return buf.String(), err
			}
		case evHome:
			err = buf.Start()
			if err != nil {
				return buf.String(), err
			}
		case evEnd:
			err = buf.End()
			if err != nil {
				return buf.String(), err
			}
		case evUp:
			idx := term.histIdx
			if term.histIdx > 0 {
				idx--
			}

			err = buf.Set([]rune(term.History[idx])...)
			if err != nil {
				return buf.String(), err
			}

			term.histIdx = idx
		case evDown:
			idx := term.histIdx
			if term.histIdx < len(term.History)-1 {
				idx++
			}

			err = buf.Set([]rune(term.History[idx])...)
			if err != nil {
				return buf.String(), err
			}

			term.histIdx = idx
		case evRight:
			err = buf.Right()
			if err != nil {
				return buf.String(), err
			}
		case evLeft:
			err = buf.Left()
			if err != nil {
				return buf.String(), err
			}
		case evDel:
			err = buf.Del()
			if err != nil {
				return buf.String(), err
			}

			term.History[curHistIdx] = buf.String()
		}
	}
}

// password reads from in and parses restricted ANSI escapes writing to buf.
func (term *Terminal) password(buf *Buffer, in io.Reader) (string, error) {
	input, err := term.setup(buf, in)
	if err != nil {
		return "", err
	}

	for {
		typ, char, err := term.read(input)
		if err != nil {
			return buf.String(), err
		}

		switch typ {
		case evChar:
			err = buf.Insert(char)
			if err != nil {
				return buf.String(), err
			}
		case evSkip, evHome, evEnd, evUp, evDown, evRight, evLeft, evDel:
			continue
		case evReturn:
			err = buf.EndLine()
			return buf.String(), err
		case evEOF:
			err = buf.EndLine()
			if err == nil {
				err = ErrEOF
			}

			return buf.String(), err
		case evCtrlC:
			err = buf.EndLine()
			if err == nil {
				err = ErrCTRLC
			}

			return buf.String(), err
		case evBack:
			err = buf.DelLeft()
			if err != nil {
				return buf.String(), err
			}
		case evClear:
			err = buf.ClsScreen()
			if err != nil {
				return buf.String(), err
			}
		}
	}
}
<commit_msg>fix: history was not being saved when reusing history<commit_after>// Copyright 2013-2015 Bowery, Inc.

package prompt

import (
	"bufio"
	"errors"
	"io"
	"os"
	"strings"
)

var (
	// ErrCTRLC is returned when CTRL+C is pressed stopping the prompt.
	ErrCTRLC = errors.New("Interrupted (CTRL+C)")
	// ErrEOF is returned when CTRL+D is pressed stopping the prompt.
	ErrEOF = errors.New("EOF (CTRL+D)")
)

// Possible events that may occur when reading from input.
const (
	evChar = iota
	evSkip
	evReturn
	evEOF
	evCtrlC
	evBack
	evClear
	evHome
	evEnd
	evUp
	evDown
	evRight
	evLeft
	evDel
)

// IsNotTerminal checks if an error is related to the input not being a terminal.
func IsNotTerminal(err error) bool {
	return isNotTerminal(err)
}

// TerminalSize retrieves the columns/rows for the terminal connected to out.
func TerminalSize(out *os.File) (int, int, error) {
	return terminalSize(out)
}

// Terminal contains the state for raw terminal input.
type Terminal struct {
	In           *os.File
	Out          *os.File
	History      []string
	histIdx      int
	simpleReader *bufio.Reader
	t            *terminal
}

// NewTerminal creates a terminal and sets it to raw input mode.
func NewTerminal() (*Terminal, error) {
	in := os.Stdin

	term, err := newTerminal(in)
	if err != nil {
		return nil, err
	}

	return &Terminal{
		In:      in,
		Out:     os.Stdout,
		History: make([]string, 0, 10),
		histIdx: -1,
		t:       term,
	}, nil
}

// Basic gets input and if required tests to ensure input was given.
func (term *Terminal) Basic(prefix string, required bool) (string, error) {
	return term.Custom(prefix, func(input string) (string, bool) {
		if required && input == "" {
			return "", false
		}

		return input, true
	})
}

// BasicDefault gets input and if empty uses the given default.
func (term *Terminal) BasicDefault(prefix, def string) (string, error) {
	return term.Custom(prefix+" (Default: "+def+")", func(input string) (string, bool) {
		if input == "" {
			input = def
		}

		return input, true
	})
}

// Ask gets input and checks if it's truthy or not, and returns that
// in a boolean fashion.
func (term *Terminal) Ask(question string) (bool, error) {
	input, err := term.Custom(question+"? (y/n)", func(input string) (string, bool) {
		if input == "" {
			return "", false
		}
		input = strings.ToLower(input)

		if input == "y" || input == "yes" {
			return "yes", true
		}

		return "", true
	})

	var ok bool
	if input != "" {
		ok = true
	}

	return ok, err
}

// Custom gets input and calls the given test function with the input to
// check if the input is valid, a true return will return the string.
func (term *Terminal) Custom(prefix string, test func(string) (string, bool)) (string, error) {
	var err error
	var input string
	var ok bool

	for !ok {
		input, err = term.GetPrompt(prefix)
		if err != nil && err != io.EOF {
			return "", err
		}

		input, ok = test(input)
	}

	return input, nil
}

// Password retrieves a password from stdin without echoing it.
func (term *Terminal) Password(prefix string) (string, error) {
	var err error
	var input string

	for input == "" {
		input, err = term.GetPassword(prefix)
		if err != nil && err != io.EOF {
			return "", err
		}
	}

	return input, nil
}

// GetPrompt gets a line with the prefix and echos input.
func (term *Terminal) GetPrompt(prefix string) (string, error) {
	prefix += " "

	if !term.t.supportsEditing {
		return term.simplePrompt(prefix)
	}

	buf := NewBuffer(prefix, term.Out, true)
	return term.prompt(buf, NewAnsiReader(term.In))
}

// GetPassword gets a line with the prefix and doesn't echo input.
func (term *Terminal) GetPassword(prefix string) (string, error) {
	prefix += " "

	if !term.t.supportsEditing {
		return term.simplePrompt(prefix)
	}

	buf := NewBuffer(prefix, term.Out, false)
	return term.password(buf, NewAnsiReader(term.In))
}

// Close calls close on the internal terminal.
func (term *Terminal) Close() error {
	return term.t.Close()
}

// Reopen re-opens an internal terminal.
func (term *Terminal) Reopen() error {
	in := os.Stdin

	t, err := newTerminal(in)
	if err != nil {
		return err
	}

	term.t = t
	return nil
}

// simplePrompt is a fallback prompt without line editing support.
func (term *Terminal) simplePrompt(prefix string) (string, error) {
	if term.simpleReader == nil {
		term.simpleReader = bufio.NewReader(term.In)
	}

	_, err := term.Out.Write([]byte(prefix))
	if err != nil {
		return "", err
	}

	line, err := term.simpleReader.ReadString('\n')
	line = strings.TrimRight(line, "\r\n ")
	line = strings.TrimLeft(line, " ")

	return line, err
}

// setup initializes a prompt.
func (term *Terminal) setup(buf *Buffer, in io.Reader) (*bufio.Reader, error) {
	cols, _, err := TerminalSize(buf.Out)
	if err != nil {
		return nil, err
	}

	buf.Cols = cols
	input := bufio.NewReader(in)

	err = buf.Refresh()
	if err != nil {
		return nil, err
	}

	return input, nil
}

// read reads a rune and parses ANSI escape sequences found
func (term *Terminal) read(in *bufio.Reader) (int, rune, error) {
	char, _, err := in.ReadRune()
	if err != nil {
		return 0, 0, err
	}

	switch char {
	default:
		// Standard chars.
		return evChar, char, nil
	case tabKey, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlH, ctrlJ, ctrlK, ctrlN,
		ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX,
		ctrlY, ctrlZ:
		// Skip.
		return evSkip, char, nil
	case returnKey:
		// End of line.
		return evReturn, char, nil
	case ctrlD:
		// End of file.
		return evEOF, char, nil
	case ctrlC:
		// End of line, interrupted.
		return evCtrlC, char, nil
	case backKey:
		// Backspace.
		return evBack, char, nil
	case ctrlL:
		// Clear screen.
		return evClear, char, nil
	case escKey:
		// Functions like arrows, home, etc.
		esc := make([]byte, 2)
		_, err = in.Read(esc)
		if err != nil {
			return -1, char, err
		}

		// Home, end.
		if esc[0] == 'O' {
			switch esc[1] {
			case 'H':
				// Home.
				return evHome, char, nil
			case 'F':
				// End.
				return evEnd, char, nil
			}

			return evSkip, char, nil
		}

		// Arrows, delete, pgup, pgdown, insert.
		if esc[0] == '[' {
			switch esc[1] {
			case 'A':
				// Up.
				return evUp, char, nil
			case 'B':
				// Down.
				return evDown, char, nil
			case 'C':
				// Right.
				return evRight, char, nil
			case 'D':
				// Left.
				return evLeft, char, nil
			}

			// Delete, pgup, pgdown, insert.
			if esc[1] > '0' && esc[1] < '7' {
				extEsc := make([]byte, 3)
				_, err = in.Read(extEsc)
				if err != nil {
					return -1, char, err
				}

				if extEsc[0] == '~' {
					switch esc[1] {
					case '2', '5', '6':
						// Insert, pgup, pgdown.
						return evSkip, char, err
					case '3':
						// Delete.
						return evDel, char, err
					}
				}
			}
		}
	}

	return evSkip, char, nil
}

// prompt reads from in and parses ANSI escapes writing to buf.
func (term *Terminal) prompt(buf *Buffer, in io.Reader) (string, error) {
	input, err := term.setup(buf, in)
	if err != nil {
		return "", err
	}
	term.History = append(term.History, "")
	term.histIdx = len(term.History) - 1
	curHistIdx := term.histIdx

	for {
		typ, char, err := term.read(input)
		if err != nil {
			return buf.String(), err
		}

		switch typ {
		case evChar:
			err = buf.Insert(char)
			if err != nil {
				return buf.String(), err
			}

			term.History[curHistIdx] = buf.String()
		case evSkip:
			continue
		case evReturn:
			err = buf.EndLine()
			term.History[curHistIdx] = buf.String()
			return buf.String(), err
		case evEOF:
			err = buf.EndLine()
			if err == nil {
				err = ErrEOF
			}

			return buf.String(), err
		case evCtrlC:
			err = buf.EndLine()
			if err == nil {
				err = ErrCTRLC
			}

			return buf.String(), err
		case evBack:
			err = buf.DelLeft()
			if err != nil {
				return buf.String(), err
			}

			term.History[curHistIdx] = buf.String()
		case evClear:
			err = buf.ClsScreen()
			if err != nil {
				return buf.String(), err
			}
		case evHome:
			err = buf.Start()
			if err != nil {
				return buf.String(), err
			}
		case evEnd:
			err = buf.End()
			if err != nil {
				return buf.String(), err
			}
		case evUp:
			idx := term.histIdx
			if term.histIdx > 0 {
				idx--
			}

			err = buf.Set([]rune(term.History[idx])...)
			if err != nil {
				return buf.String(), err
			}

			term.histIdx = idx
		case evDown:
			idx := term.histIdx
			if term.histIdx < len(term.History)-1 {
				idx++
			}

			err = buf.Set([]rune(term.History[idx])...)
			if err != nil {
				return buf.String(), err
			}

			term.histIdx = idx
		case evRight:
			err = buf.Right()
			if err != nil {
				return buf.String(), err
			}
		case evLeft:
			err = buf.Left()
			if err != nil {
				return buf.String(), err
			}
		case evDel:
			err = buf.Del()
			if err != nil {
				return buf.String(), err
			}

			term.History[curHistIdx] = buf.String()
		}
	}
}

// password reads from in and parses restricted ANSI escapes writing to buf.
func (term *Terminal) password(buf *Buffer, in io.Reader) (string, error) {
	input, err := term.setup(buf, in)
	if err != nil {
		return "", err
	}

	for {
		typ, char, err := term.read(input)
		if err != nil {
			return buf.String(), err
		}

		switch typ {
		case evChar:
			err = buf.Insert(char)
			if err != nil {
				return buf.String(), err
			}
		case evSkip, evHome, evEnd, evUp, evDown, evRight, evLeft, evDel:
			continue
		case evReturn:
			err = buf.EndLine()
			return buf.String(), err
		case evEOF:
			err = buf.EndLine()
			if err == nil {
				err = ErrEOF
			}

			return buf.String(), err
		case evCtrlC:
			err = buf.EndLine()
			if err == nil {
				err = ErrCTRLC
			}

			return buf.String(), err
		case evBack:
			err = buf.DelLeft()
			if err != nil {
				return buf.String(), err
			}
		case evClear:
			err = buf.ClsScreen()
			if err != nil {
				return buf.String(), err
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"hpack"
	"huffman"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
)

type jsonobject struct {
	Cases       []Case
	Draft       int
	Description string
}

type Case struct {
	Seqno   int
	Wire    string
	Headers []map[string]string
}

var TESTCASE = []string{
	"hpack-test-case/haskell-http2-naive/",
	"hpack-test-case/haskell-http2-naive-huffman/",
	"hpack-test-case/haskell-http2-static/",
	"hpack-test-case/haskell-http2-static-huffman/",
	"hpack-test-case/haskell-http2-linear/",
	"hpack-test-case/haskell-http2-linear-huffman/",
}

func EncType(testCase string) (fStatic, fHeader, isHuffman bool) {
	fHeader = strings.Contains(testCase, "linear")
	if fHeader {
		fStatic = true
	} else {
		fStatic = strings.Contains(testCase, "static")
	}
	isHuffman = strings.Contains(testCase, "huffman")
	return
}

func convertHeader(headers []map[string]string) (dist []hpack.Header) {
	for _, dict := range headers {
		for k, v := range dict {
			dist = append(dist, hpack.Header{k, v})
		}
	}
	return
}

func compHeaders(decoded, correct []hpack.Header, storyPass *bool) {
	if !reflect.DeepEqual(correct, decoded) {
		*storyPass = false
		if len(os.Args) == 3 && os.Args[2] == "-v" {
			fmt.Println(decoded)
			fmt.Println(correct)
		}
		os.Exit(-1)
	}
}

func compWire(encoded, correct string, storyPass *bool) {
	if encoded != correct {
		*storyPass = false
		if len(os.Args) == 3 && os.Args[2] == "-v" {
			fmt.Println(encoded)
			fmt.Println(correct)
		}
		//os.Exit(-1)
	}

}

func main() {
	fmt.Println(hex.EncodeToString(*hpack.PackIntRepresentation(3000000, 5)))
	nums, _ := hex.DecodeString(string("1fa18db701"))
	fmt.Println(hpack.ParseIntRepresentation(nums, 5))
	huffman.Root.CreateTree()
	for _, testCase := range TESTCASE {
		fStatic, fHeader, isHuffman := EncType(testCase)
		files, err := ioutil.ReadDir(testCase)
		if err != nil {
			panic(err)
		}
		for _, f := range files {
			encTable := hpack.InitTable()
			decTable := hpack.InitTable()
			data, err := ioutil.ReadFile(testCase + f.Name())
			if err != nil {
				panic(err)
			}
			var jsontype jsonobject
			json.Unmarshal(data, &jsontype)
			storyPass := true

			if len(os.Args) >= 2 && os.Args[1] == "-d" {
				for _, seq := range jsontype.Cases {
					Headers := hpack.Decode(seq.Wire, &decTable)
					correctHeaders := convertHeader(seq.Headers)
					compHeaders(Headers, correctHeaders, &storyPass)
					if !storyPass {
						fmt.Println("False in", testCase+f.Name(), "at seq", seq.Seqno)
						break
					}

				}
			} else if len(os.Args) >= 2 && (os.Args[1] == "-e" || os.Args[1] == "-a") {
				for _, seq := range jsontype.Cases {
					Headers := convertHeader(seq.Headers)
					Wire := hpack.Encode(Headers, fStatic, fHeader, isHuffman, &encTable, -1)
					if os.Args[1] == "-a" {
						distHeaders := hpack.Decode(Wire, &decTable)
						compHeaders(distHeaders, Headers, &storyPass)
						if !storyPass {
							fmt.Println("False in", testCase+f.Name(), "at seq", seq.Seqno)
							break
						}
					} else {
						compWire(Wire, seq.Wire, &storyPass)
						if !storyPass {
							fmt.Println("False in", testCase+f.Name(), "at seq", seq.Seqno)
							break
						}
					}
				}
			} else {
				fmt.Println("argument should be '-e', '-d', '-a' or none")
				os.Exit(-1)
			}
			if storyPass {
				fmt.Println("Pass in " + testCase + f.Name())
			}
		}
	}
}
<commit_msg>remove bug<commit_after>package main

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"hpack"
	"huffman"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
)

type jsonobject struct {
	Cases       []Case
	Draft       int
	Description string
}

type Case struct {
	Seqno   int
	Wire    string
	Headers []map[string]string
}

var TESTCASE = []string{
	"hpack-test-case/haskell-http2-naive/",
	"hpack-test-case/haskell-http2-naive-huffman/",
	"hpack-test-case/haskell-http2-static/",
	"hpack-test-case/haskell-http2-static-huffman/",
	"hpack-test-case/haskell-http2-linear/",
	"hpack-test-case/haskell-http2-linear-huffman/",
}

func EncType(testCase string) (fStatic, fHeader, isHuffman bool) {
	fHeader = strings.Contains(testCase, "linear")
	if fHeader {
		fStatic = true
	} else {
		fStatic = strings.Contains(testCase, "static")
	}
	isHuffman = strings.Contains(testCase, "huffman")
	return
}

func convertHeader(headers []map[string]string) (dist []hpack.Header) {
	for _, dict := range headers {
		for k, v := range dict {
			dist = append(dist, hpack.Header{k, v})
		}
	}
	return
}

func compHeaders(decoded, correct []hpack.Header, storyPass *bool) {
	if !reflect.DeepEqual(correct, decoded) {
		*storyPass = false
		if len(os.Args) == 3 && os.Args[2] == "-v" {
			fmt.Println(decoded)
			fmt.Println(correct)
		}
		//os.Exit(-1)
	}
}

func compWire(encoded, correct string, storyPass *bool) {
	if encoded != correct {
		*storyPass = false
		if len(os.Args) == 3 && os.Args[2] == "-v" {
			fmt.Println(encoded)
			fmt.Println(correct)
		}
		//os.Exit(-1)
	}

}

func main() {
	fmt.Println(hex.EncodeToString(*hpack.PackIntRepresentation(3000000, 5)))
	nums, _ := hex.DecodeString(string("1fa18db701"))
	fmt.Println(hpack.ParseIntRepresentation(nums, 5))
	huffman.Root.CreateTree()
	for _, testCase := range TESTCASE {
		fStatic, fHeader, isHuffman := EncType(testCase)
		files, err := ioutil.ReadDir(testCase)
		if err != nil {
			panic(err)
		}
		for _, f := range files {
			encTable := hpack.InitTable()
			decTable := hpack.InitTable()
			data, err := ioutil.ReadFile(testCase + f.Name())
			if err != nil {
				panic(err)
			}
			var jsontype jsonobject
			json.Unmarshal(data, &jsontype)
			storyPass := true

			if len(os.Args) >= 2 && os.Args[1] == "-d" {
				for _, seq := range jsontype.Cases {
					Headers := hpack.Decode(seq.Wire, &decTable)
					correctHeaders := convertHeader(seq.Headers)
					compHeaders(Headers, correctHeaders, &storyPass)
					if !storyPass {
						fmt.Println("False in", testCase+f.Name(), "at seq", seq.Seqno)
						break
					}

				}
			} else if len(os.Args) >= 2 && (os.Args[1] == "-e" || os.Args[1] == "-a") {
				for _, seq := range jsontype.Cases {
					Headers := convertHeader(seq.Headers)
					Wire := hpack.Encode(Headers, fStatic, fHeader, isHuffman, &encTable, -1)
					if os.Args[1] == "-a" {
						distHeaders := hpack.Decode(Wire, &decTable)
						compHeaders(distHeaders, Headers, &storyPass)
						if !storyPass {
							fmt.Println("False in", testCase+f.Name(), "at seq", seq.Seqno)
							break
						}
					} else {
						compWire(Wire, seq.Wire, &storyPass)
						if !storyPass {
							fmt.Println("False in", testCase+f.Name(), "at seq", seq.Seqno)
							break
						}
					}
				}
			} else {
				fmt.Println("argument should be '-e', '-d', '-a' or none")
				os.Exit(-1)
			}
			if storyPass {
				fmt.Println("Pass in " + testCase + f.Name())
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/namesgenerator"
	"github.com/dustin/go-humanize"
)

// CreateVolumeFromHumanSize creates a volume on the API with a human readable size
func CreateVolumeFromHumanSize(api *ScalewayAPI, size string) (*string, error) {
	bytes, err := humanize.ParseBytes(size)
	if err != nil {
		return nil, err
	}

	var newVolume ScalewayVolumeDefinition
	newVolume.Name = size
	newVolume.Size = bytes
	newVolume.Type = "l_ssd"

	volumeID, err := api.PostVolume(newVolume)
	if err != nil {
		return nil, err
	}

	return &volumeID, nil
}

// ScalewayResolvedIdentifier represents a list of matching identifier for a specifier pattern
type ScalewayResolvedIdentifier struct {
	// Identifiers holds matching identifiers
	Identifiers []ScalewayIdentifier

	// Needle is the criteria used to lookup identifiers
	Needle string
}

// resolveIdentifiers resolves needles provided by the user
func resolveIdentifiers(api *ScalewayAPI, needles []string, out chan ScalewayResolvedIdentifier) {
	// first attempt, only lookup from the cache
	var unresolved []string
	for _, needle := range needles {
		idents := api.Cache.LookUpIdentifiers(needle)
		if len(idents) == 0 {
			unresolved = append(unresolved, needle)
		} else {
			out <- ScalewayResolvedIdentifier{
				Identifiers: idents,
				Needle:      needle,
			}
		}
	}
	// fill the cache by fetching from the API and resolve missing identifiers
	if len(unresolved) > 0 {
		var wg sync.WaitGroup
		wg.Add(5)
		go func() {
			api.GetServers(true, 0)
			wg.Done()
		}()
		go func() {
			api.GetImages()
			wg.Done()
		}()
		go func() {
			api.GetSnapshots()
			wg.Done()
		}()
		go func() {
			api.GetVolumes()
			wg.Done()
		}()
		go func() {
			api.GetBootscripts()
			wg.Done()
		}()
		wg.Wait()
		for _, needle := range unresolved {
			idents := api.Cache.LookUpIdentifiers(needle)
			out <- ScalewayResolvedIdentifier{
				Identifiers: idents,
				Needle:      needle,
			}
		}
	}
	close(out)
}

// inspectIdentifiers inspects identifiers concurrently
func inspectIdentifiers(api *ScalewayAPI, ci chan ScalewayResolvedIdentifier, cj chan interface{}) {
	var wg sync.WaitGroup
	for {
		idents, ok := <-ci
		if !ok {
			break
		}
		if len(idents.Identifiers) != 1 {
			if len(idents.Identifiers) == 0 {
				log.Errorf("Unable to resolve identifier %s", idents.Needle)
			} else {
				log.Errorf("Too many candidates for %s (%d)", idents.Needle, len(idents.Identifiers))
				for _, identifier := range idents.Identifiers {
					// FIXME: also print the name
					log.Infof("- %s", identifier.Identifier)
				}
			}
		} else {
			ident := idents.Identifiers[0]
			wg.Add(1)
			go func() {
				if ident.Type == IdentifierServer {
					server, err := api.GetServer(ident.Identifier)
					if err == nil {
						cj <- server
					}
				} else if ident.Type == IdentifierImage {
					image, err := api.GetImage(ident.Identifier)
					if err == nil {
						cj <- image
					}
				} else if ident.Type == IdentifierSnapshot {
					snap, err := api.GetSnapshot(ident.Identifier)
					if err == nil {
						cj <- snap
					}
				} else if ident.Type == IdentifierVolume {
					snap, err := api.GetVolume(ident.Identifier)
					if err == nil {
						cj <- snap
					}
				} else if ident.Type == IdentifierBootscript {
					bootscript, err := api.GetBootscript(ident.Identifier)
					if err == nil {
						cj <- bootscript
					}
				}
				wg.Done()
			}()
		}
	}
	wg.Wait()
	close(cj)
}

func createServer(api *ScalewayAPI, imageName string, name string, bootscript string, env string, additionalVolumes string) (string, error) {
	if name == "" {
		name = strings.Replace(namesgenerator.GetRandomName(0), "_", "-", -1)
	}

	var server ScalewayServerDefinition
	server.Volumes = make(map[string]string)

	server.Tags = []string{}
	if env != "" {
		server.Tags = strings.Split(env, " ")
	}
	if additionalVolumes != "" {
		volumes := strings.Split(additionalVolumes, " ")
		for i := range volumes {
			volumeID, err := CreateVolumeFromHumanSize(api, volumes[i])
			if err != nil {
				return "", err
			}

			volumeIDx := fmt.Sprintf("%d", i+1)
			server.Volumes[volumeIDx] = *volumeID
		}
	}
	server.Name = name
	if bootscript != "" {
		bootscript := api.GetBootscriptID(bootscript)
		server.Bootscript = &bootscript
	}

	_, err := humanize.ParseBytes(imageName)
	if err == nil {
		// Create a new root volume
		volumeID, err := CreateVolumeFromHumanSize(api, imageName)
		if err != nil {
			return "", err
		}
		server.Volumes["0"] = *volumeID
	} else {
		// Use an existing image
		// FIXME: handle snapshots
		image := api.GetImageID(imageName)
		server.Image = &image
	}

	serverID, err := api.PostServer(server)
	if err != nil {
		return "", nil
	}

	return serverID, nil
}

// WaitForServerState asks API in a loop until a server matches a wanted state
func WaitForServerState(api *ScalewayAPI, serverID string, targetState string) (*ScalewayServer, error) {
	var server *ScalewayServer
	var err error

	for {
		server, err = api.GetServer(serverID)
		if err != nil {
			return nil, err
		}
		if server.State == targetState {
			break
		}
		time.Sleep(1 * time.Second)
	}

	return server, nil
}

// WaitForServerReady wait for a server state to be running, then wait for the SSH port to be available
func WaitForServerReady(api *ScalewayAPI, serverID string) (*ScalewayServer, error) {
	server, err := WaitForServerState(api, serverID, "running")
	if err != nil {
		return nil, err
	}

	dest := fmt.Sprintf("%s:22", server.PublicAddress.IP)

	err = WaitForTCPPortOpen(dest)
	if err != nil {
		return nil, err
	}

	return server, nil
}

// ScalewayImageInterface is an interface to multiple Scaleway items
type ScalewayImageInterface struct {
	CreationDate time.Time
	Identifier   string
	Name         string
	Tag          string
	VirtualSize  float64
	Public       bool
	Type         string
}

// ByCreationDate sorts images by CreationDate field
type ByCreationDate []ScalewayImageInterface

func (a ByCreationDate) Len() int           { return len(a) }
func (a ByCreationDate) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByCreationDate) Less(i, j int) bool { return a[j].CreationDate.Before(a[i].CreationDate) }

func startServer(api *ScalewayAPI, needle string, wait bool) error {
	server := api.GetServerID(needle)

	err := api.PostServerAction(server, "poweron")
	if err != nil {
		if err.Error() != "server should be stopped" {
			return fmt.Errorf("Server %s is already started: %v", server, err)
		}
	}

	if wait {
		_, err = WaitForServerReady(api, server)
		if err != nil {
			return fmt.Errorf("Failed to wait for server %s to be ready, %v", needle, err)
		}
	}
	return nil
}

func startServerOnce(api *ScalewayAPI, needle string, wait bool, successChan chan bool, errChan chan error) {
	err := startServer(api, needle, wait)

	if err != nil {
		errChan <- err
		return
	}

	fmt.Println(needle)
	successChan <- true
}
<commit_msg>Added resolveIdentifier and getIdentifier api helpers<commit_after>package main

import (
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/namesgenerator"
	"github.com/dustin/go-humanize"
)

// CreateVolumeFromHumanSize creates a volume on the API with a human readable size
func CreateVolumeFromHumanSize(api *ScalewayAPI, size string) (*string, error) {
	bytes, err := humanize.ParseBytes(size)
	if err != nil {
		return nil, err
	}

	var newVolume ScalewayVolumeDefinition
	newVolume.Name = size
	newVolume.Size = bytes
	newVolume.Type = "l_ssd"

	volumeID, err := api.PostVolume(newVolume)
	if err != nil {
		return nil, err
	}

	return &volumeID, nil
}

// ScalewayResolvedIdentifier represents a list of matching identifier for a specifier pattern
type ScalewayResolvedIdentifier struct {
	// Identifiers holds matching identifiers
	Identifiers []ScalewayIdentifier

	// Needle is the criteria used to lookup identifiers
	Needle string
}

// fillIdentifierCache fills the cache by fetching fro the API
func fillIdentifierCache(api *ScalewayAPI) {
	log.Debugf("Filling the cache")
	var wg sync.WaitGroup
	wg.Add(5)
	go func() {
		api.GetServers(true, 0)
		wg.Done()
	}()
	go func() {
		api.GetImages()
		wg.Done()
	}()
	go func() {
		api.GetSnapshots()
		wg.Done()
	}()
	go func() {
		api.GetVolumes()
		wg.Done()
	}()
	go func() {
		api.GetBootscripts()
		wg.Done()
	}()
	wg.Wait()
}

// getIdentifier returns a an identifier if the resolved needles only match one element, else, it exists the program
func getIdentifier(api *ScalewayAPI, needle string) *ScalewayIdentifier {
	idents := resolveIdentifier(api, needle)

	if len(idents) == 1 {
		return &idents[0]
	}
	if len(idents) == 0 {
		log.Fatalf("No such identifier: %s", needle)
	}
	log.Errorf("Too many candidates for %s (%d)", needle, len(idents))
	for _, identifier := range idents {
		// FIXME: also print the name
		log.Infof("- %s", identifier.Identifier)
	}
	os.Exit(1)
	return nil
}

// resolveIdentifier resolves needle provided by the user
func resolveIdentifier(api *ScalewayAPI, needle string) []ScalewayIdentifier {
	idents := api.Cache.LookUpIdentifiers(needle)
	if len(idents) > 0 {
		return idents
	}

	fillIdentifierCache(api)

	idents = api.Cache.LookUpIdentifiers(needle)
	return idents
}

// resolveIdentifiers resolves needles provided by the user
func resolveIdentifiers(api *ScalewayAPI, needles []string, out chan ScalewayResolvedIdentifier) {
	// first attempt, only lookup from the cache
	var unresolved []string
	for _, needle := range needles {
		idents := api.Cache.LookUpIdentifiers(needle)
		if len(idents) == 0 {
			unresolved = append(unresolved, needle)
		} else {
			out <- ScalewayResolvedIdentifier{
				Identifiers: idents,
				Needle:      needle,
			}
		}
	}
	// fill the cache by fetching from the API and resolve missing identifiers
	if len(unresolved) > 0 {
		fillIdentifierCache(api)

		for _, needle := range unresolved {
			idents := api.Cache.LookUpIdentifiers(needle)
			out <- ScalewayResolvedIdentifier{
				Identifiers: idents,
				Needle:      needle,
			}
		}
	}
	close(out)
}

// inspectIdentifiers inspects identifiers concurrently
func inspectIdentifiers(api *ScalewayAPI, ci chan ScalewayResolvedIdentifier, cj chan interface{}) {
	var wg sync.WaitGroup
	for {
		idents, ok := <-ci
		if !ok {
			break
		}
		if len(idents.Identifiers) != 1 {
			if len(idents.Identifiers) == 0 {
				log.Errorf("Unable to resolve identifier %s", idents.Needle)
			} else {
				log.Errorf("Too many candidates for %s (%d)", idents.Needle, len(idents.Identifiers))
				for _, identifier := range idents.Identifiers {
					// FIXME: also print the name
					log.Infof("- %s", identifier.Identifier)
				}
			}
		} else {
			ident := idents.Identifiers[0]
			wg.Add(1)
			go func() {
				if ident.Type == IdentifierServer {
					server, err := api.GetServer(ident.Identifier)
					if err == nil {
						cj <- server
					}
				} else if ident.Type == IdentifierImage {
					image, err := api.GetImage(ident.Identifier)
					if err == nil {
						cj <- image
					}
				} else if ident.Type == IdentifierSnapshot {
					snap, err := api.GetSnapshot(ident.Identifier)
					if err == nil {
						cj <- snap
					}
				} else if ident.Type == IdentifierVolume {
					snap, err := api.GetVolume(ident.Identifier)
					if err == nil {
						cj <- snap
					}
				} else if ident.Type == IdentifierBootscript {
					bootscript, err := api.GetBootscript(ident.Identifier)
					if err == nil {
						cj <- bootscript
					}
				}
				wg.Done()
			}()
		}
	}
	wg.Wait()
	close(cj)
}

func createServer(api *ScalewayAPI, imageName string, name string, bootscript string, env string, additionalVolumes string) (string, error) {
	if name == "" {
		name = strings.Replace(namesgenerator.GetRandomName(0), "_", "-", -1)
	}

	var server ScalewayServerDefinition
	server.Volumes = make(map[string]string)

	server.Tags = []string{}
	if env != "" {
		server.Tags = strings.Split(env, " ")
	}
	if additionalVolumes != "" {
		volumes := strings.Split(additionalVolumes, " ")
		for i := range volumes {
			volumeID, err := CreateVolumeFromHumanSize(api, volumes[i])
			if err != nil {
				return "", err
			}

			volumeIDx := fmt.Sprintf("%d", i+1)
			server.Volumes[volumeIDx] = *volumeID
		}
	}
	server.Name = name
	if bootscript != "" {
		bootscript := api.GetBootscriptID(bootscript)
		server.Bootscript = &bootscript
	}

	_, err := humanize.ParseBytes(imageName)
	if err == nil {
		// Create a new root volume
		volumeID, err := CreateVolumeFromHumanSize(api, imageName)
		if err != nil {
			return "", err
		}
		server.Volumes["0"] = *volumeID
	} else {
		// Use an existing image
		// FIXME: handle snapshots
		image := api.GetImageID(imageName)
		server.Image = &image
	}

	serverID, err := api.PostServer(server)
	if err != nil {
		return "", nil
	}

	return serverID, nil
}

// WaitForServerState asks API in a loop until a server matches a wanted state
func WaitForServerState(api *ScalewayAPI, serverID string, targetState string) (*ScalewayServer, error) {
	var server *ScalewayServer
	var err error

	for {
		server, err = api.GetServer(serverID)
		if err != nil {
			return nil, err
		}
		if server.State == targetState {
			break
		}
		time.Sleep(1 * time.Second)
	}

	return server, nil
}

// WaitForServerReady wait for a server state to be running, then wait for the SSH port to be available
func WaitForServerReady(api *ScalewayAPI, serverID string) (*ScalewayServer, error) {
	server, err := WaitForServerState(api, serverID, "running")
	if err != nil {
		return nil, err
	}

	dest := fmt.Sprintf("%s:22", server.PublicAddress.IP)

	err = WaitForTCPPortOpen(dest)
	if err != nil {
		return nil, err
	}

	return server, nil
}

// ScalewayImageInterface is an interface to multiple Scaleway items
type ScalewayImageInterface struct {
	CreationDate time.Time
	Identifier   string
	Name         string
	Tag          string
	VirtualSize  float64
	Public       bool
	Type         string
}

// ByCreationDate sorts images by CreationDate field
type ByCreationDate []ScalewayImageInterface

func (a ByCreationDate) Len() int           { return len(a) }
func (a ByCreationDate) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByCreationDate) Less(i, j int) bool { return a[j].CreationDate.Before(a[i].CreationDate) }

func startServer(api *ScalewayAPI, needle string, wait bool) error {
	server := api.GetServerID(needle)

	err := api.PostServerAction(server, "poweron")
	if err != nil {
		if err.Error() != "server should be stopped" {
			return fmt.Errorf("Server %s is already started: %v", server, err)
		}
	}

	if wait {
		_, err = WaitForServerReady(api, server)
		if err != nil {
			return fmt.Errorf("Failed to wait for server %s to be ready, %v", needle, err)
		}
	}
	return nil
}

func startServerOnce(api *ScalewayAPI, needle string, wait bool, successChan chan bool, errChan chan error) {
	err := startServer(api, needle, wait)

	if err != nil {
		errChan <- err
		return
	}

	fmt.Println(needle)
	successChan <- true
}
<|endoftext|>


<commit_before>package funcs

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"fmt"
	"log"
	"net/url"
	"unicode/utf8"

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

// Base64DecodeFunc constructs a function that decodes a string containing a base64 sequence.
var Base64DecodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		s := args[0].AsString()
		sDec, err := base64.StdEncoding.DecodeString(s)
		if err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode base64 data '%s'", s)
		}
		if !utf8.Valid([]byte(sDec)) {
			log.Printf("[DEBUG] the result of decoding the the provided string is not valid UTF-8: %s", sDec)
			return cty.UnknownVal(cty.String), fmt.Errorf("the result of decoding the the provided string is not valid UTF-8")
		}
		return cty.StringVal(string(sDec)), nil
	},
})

// Base64EncodeFunc constructs a function that encodes a string to a base64 sequence.
var Base64EncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(base64.StdEncoding.EncodeToString([]byte(args[0].AsString()))), nil
	},
})

// Base64GzipFunc constructs a function that compresses a string with gzip and then encodes the result in
// Base64 encoding.
var Base64GzipFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		s := args[0].AsString()

		var b bytes.Buffer
		gz := gzip.NewWriter(&b)
		if _, err := gz.Write([]byte(s)); err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to write gzip raw data: '%s'", s)
		}
		if err := gz.Flush(); err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to flush gzip writer: '%s'", s)
		}
		if err := gz.Close(); err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to close gzip writer: '%s'", s)
		}
		return cty.StringVal(base64.StdEncoding.EncodeToString(b.Bytes())), nil
	},
})

// URLEncodeFunc constructs a function that applies URL encoding to a given string.
var URLEncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(url.QueryEscape(args[0].AsString())), nil
	},
})

// Base64Decode decodes a string containing a base64 sequence.
//
// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
//
// Strings in the Terraform language are sequences of unicode characters rather
// than bytes, so this function will also interpret the resulting bytes as
// UTF-8. If the bytes after Base64 decoding are _not_ valid UTF-8, this function
// produces an error.
func Base64Decode(str cty.Value) (cty.Value, error) {
	return Base64DecodeFunc.Call([]cty.Value{str})
}

// Base64Encode applies Base64 encoding to a string.
//
// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
//
// Strings in the Terraform language are sequences of unicode characters rather
// than bytes, so this function will first encode the characters from the string
// as UTF-8, and then apply Base64 encoding to the result.
func Base64Encode(str cty.Value) (cty.Value, error) {
	return Base64EncodeFunc.Call([]cty.Value{str})
}

// Base64Gzip compresses a string with gzip and then encodes the result in
// Base64 encoding.
//
// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
//
// Strings in the Terraform language are sequences of unicode characters rather
// than bytes, so this function will first encode the characters from the string
// as UTF-8, then apply gzip compression, and then finally apply Base64 encoding.
func Base64Gzip(str cty.Value) (cty.Value, error) {
	return Base64GzipFunc.Call([]cty.Value{str})
}

// URLEncode applies URL encoding to a given string.
//
// This function identifies characters in the given string that would have a
// special meaning when included as a query string argument in a URL and
// escapes them using RFC 3986 "percent encoding".
//
// If the given string contains non-ASCII characters, these are first encoded as
// UTF-8 and then percent encoding is applied separately to each UTF-8 byte.
func URLEncode(str cty.Value) (cty.Value, error) {
	return URLEncodeFunc.Call([]cty.Value{str})
}
<commit_msg>fix typo in Base64DecodeFunc log<commit_after>package funcs

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"fmt"
	"log"
	"net/url"
	"unicode/utf8"

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

// Base64DecodeFunc constructs a function that decodes a string containing a base64 sequence.
var Base64DecodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		s := args[0].AsString()
		sDec, err := base64.StdEncoding.DecodeString(s)
		if err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to decode base64 data '%s'", s)
		}
		if !utf8.Valid([]byte(sDec)) {
			log.Printf("[DEBUG] the result of decoding the provided string is not valid UTF-8: %s", sDec)
			return cty.UnknownVal(cty.String), fmt.Errorf("the result of decoding the provided string is not valid UTF-8")
		}
		return cty.StringVal(string(sDec)), nil
	},
})

// Base64EncodeFunc constructs a function that encodes a string to a base64 sequence.
var Base64EncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(base64.StdEncoding.EncodeToString([]byte(args[0].AsString()))), nil
	},
})

// Base64GzipFunc constructs a function that compresses a string with gzip and then encodes the result in
// Base64 encoding.
var Base64GzipFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		s := args[0].AsString()

		var b bytes.Buffer
		gz := gzip.NewWriter(&b)
		if _, err := gz.Write([]byte(s)); err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to write gzip raw data: '%s'", s)
		}
		if err := gz.Flush(); err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to flush gzip writer: '%s'", s)
		}
		if err := gz.Close(); err != nil {
			return cty.UnknownVal(cty.String), fmt.Errorf("failed to close gzip writer: '%s'", s)
		}
		return cty.StringVal(base64.StdEncoding.EncodeToString(b.Bytes())), nil
	},
})

// URLEncodeFunc constructs a function that applies URL encoding to a given string.
var URLEncodeFunc = function.New(&function.Spec{
	Params: []function.Parameter{
		{
			Name: "str",
			Type: cty.String,
		},
	},
	Type: function.StaticReturnType(cty.String),
	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
		return cty.StringVal(url.QueryEscape(args[0].AsString())), nil
	},
})

// Base64Decode decodes a string containing a base64 sequence.
//
// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
//
// Strings in the Terraform language are sequences of unicode characters rather
// than bytes, so this function will also interpret the resulting bytes as
// UTF-8. If the bytes after Base64 decoding are _not_ valid UTF-8, this function
// produces an error.
func Base64Decode(str cty.Value) (cty.Value, error) {
	return Base64DecodeFunc.Call([]cty.Value{str})
}

// Base64Encode applies Base64 encoding to a string.
//
// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
//
// Strings in the Terraform language are sequences of unicode characters rather
// than bytes, so this function will first encode the characters from the string
// as UTF-8, and then apply Base64 encoding to the result.
func Base64Encode(str cty.Value) (cty.Value, error) {
	return Base64EncodeFunc.Call([]cty.Value{str})
}

// Base64Gzip compresses a string with gzip and then encodes the result in
// Base64 encoding.
//
// Terraform uses the "standard" Base64 alphabet as defined in RFC 4648 section 4.
//
// Strings in the Terraform language are sequences of unicode characters rather
// than bytes, so this function will first encode the characters from the string
// as UTF-8, then apply gzip compression, and then finally apply Base64 encoding.
func Base64Gzip(str cty.Value) (cty.Value, error) {
	return Base64GzipFunc.Call([]cty.Value{str})
}

// URLEncode applies URL encoding to a given string.
//
// This function identifies characters in the given string that would have a
// special meaning when included as a query string argument in a URL and
// escapes them using RFC 3986 "percent encoding".
//
// If the given string contains non-ASCII characters, these are first encoded as
// UTF-8 and then percent encoding is applied separately to each UTF-8 byte.
func URLEncode(str cty.Value) (cty.Value, error) {
	return URLEncodeFunc.Call([]cty.Value{str})
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nsf/termbox-go"
	"strings"
)

const (
	background = `
    wwwwwwwwwwww wwwwww
    w..........w w....w
    w..........w w....w
    w..........w w....w
    w..........w w....w
    w..........w wwwwww
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    wwwwwwwwwwww
	`
)

func refreshScreen() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	drawByText(background)
	termbox.Flush()
}

func drawByText(text string) {
	lines := strings.Split(text, "\n")

	for y, line := range lines {
		for x, char := range line {
			switch char {
			case 'w':
				termbox.SetCell(2*x-1, y, ' ', termbox.ColorDefault, termbox.ColorWhite|termbox.AttrBold)
				termbox.SetCell(2*x, y, ' ', termbox.ColorDefault, termbox.ColorWhite|termbox.AttrBold)
			case '.':
				termbox.SetCell(2*x-1, y, ' ', termbox.ColorDefault, termbox.ColorBlack)
				termbox.SetCell(2*x, y, ' ', termbox.ColorDefault, termbox.ColorBlack)
			}
		}
	}
}
<commit_msg>Refactor view logic<commit_after>package main

import (
	"github.com/nsf/termbox-go"
	"strings"
)

const (
	background = `
    wwwwwwwwwwww wwwwww
    w..........w w....w
    w..........w w....w
    w..........w w....w
    w..........w w....w
    w..........w wwwwww
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    w..........w
    wwwwwwwwwwww
	`
)

func refreshScreen() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)

	drawByText(background, 0, 0)

	termbox.Flush()
}

func drawByText(text string, left, top int) {
	lines := strings.Split(text, "\n")

	for y, line := range lines {
		for x, char := range line {
			switch char {
			case 'w':
				termbox.SetCell(2*left+2*x-1, top+y, ' ', termbox.ColorDefault, termbox.ColorWhite|termbox.AttrBold)
				termbox.SetCell(2*left+2*x, top+y, ' ', termbox.ColorDefault, termbox.ColorWhite|termbox.AttrBold)
			case '.':
				termbox.SetCell(2*left+2*x-1, top+y, ' ', termbox.ColorDefault, termbox.ColorBlack)
				termbox.SetCell(2*left+2*x, top+y, ' ', termbox.ColorDefault, termbox.ColorBlack)
			}
		}
	}
}
<|endoftext|>


<commit_before>package bimg

/*
#cgo pkg-config: vips
#include "vips.h"
*/
import "C"

import (
	"errors"
	"runtime"
	"strings"
	"unsafe"
)

type vipsImage C.struct__VipsImage

func init() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if C.VIPS_MAJOR_VERSION <= 7 && C.VIPS_MINOR_VERSION < 40 {
		panic("unsupported old vips version")
	}

	err := C.vips_init(C.CString("bimg"))
	if err != 0 {
		C.vips_shutdown()
		panic("unable to start vips!")
	}

	C.vips_concurrency_set(1)                   // single-thread
	C.vips_cache_set_max_mem(100 * 1024 * 1024) // 100 MB
	C.vips_cache_set_max(500)                   // 500 operations
}

type Vips struct {
	buf []byte
}

func vipsRotate(image *C.struct__VipsImage, angle Angle) (*C.struct__VipsImage, error) {
	var out *C.struct__VipsImage

	err := C.vips_rotate(image, &out, C.int(angle))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}
	defer C.g_object_unref(C.gpointer(out))

	return out, nil
}

func vipsFlip(image *C.struct__VipsImage, direction Direction) (*C.struct__VipsImage, error) {
	var out *C.struct__VipsImage

	err := C.vips_flip_custom(image, &out, C.int(direction))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}
	defer C.g_object_unref(C.gpointer(out))

	return out, nil
}

func vipsRead(buf []byte) (*C.struct__VipsImage, ImageType, error) {
	var image *C.struct__VipsImage
	imageType := vipsImageType(buf)

	if imageType == UNKNOWN {
		return nil, UNKNOWN, errors.New("Input buffer contains unsupported image format")
	}

	// feed it
	length := C.size_t(len(buf))
	imageBuf := unsafe.Pointer(&buf[0])
	imageTypeC := C.int(imageType)

	err := C.vips_init_image(imageBuf, length, imageTypeC, &image)
	if err != 0 {
		return nil, UNKNOWN, catchVipsError()
	}

	return image, imageType, nil
}

func vipsExtract(image *C.struct__VipsImage, left, top, width, height int) (*C.struct__VipsImage, error) {
	var buf *C.struct__VipsImage

	err := C.vips_extract_area_custom(image, &buf, C.int(left), C.int(top), C.int(width), C.int(height))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return buf, nil
}

func vipsShrinkJpeg(buf []byte, shrink int) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	err := C.vips_jpegload_buffer_shrink(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &image, C.int(shrink))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsShrink(input *C.struct__VipsImage, shrink int) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	err := C.vips_shrink_0(input, &image, C.double(float64(shrink)), C.double(float64(shrink)))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsEmbed(input *C.struct__VipsImage, left, top, width, height, extend int) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	err := C.vips_embed_custom(input, &image, C.int(left), C.int(top), C.int(width), C.int(height), C.int(extend))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsAffine(input *C.struct__VipsImage, residual float64, i Interpolator) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	istring := C.CString(i.String())
	interpolator := C.vips_interpolate_new(istring)

	// Perform affine transformation
	err := C.vips_affine_interpolator(input, &image, C.double(residual), 0, 0, C.double(residual), interpolator)
	C.g_object_unref(C.gpointer(image))
	C.free(unsafe.Pointer(istring))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsImageType(buf []byte) ImageType {
	imageType := UNKNOWN

	length := C.size_t(len(buf))
	imageBuf := unsafe.Pointer(&buf[0])
	bufferType := C.GoString(C.vips_foreign_find_load_buffer(imageBuf, length))

	switch {
	case strings.HasSuffix(bufferType, "JpegBuffer"):
		imageType = JPEG
		break
	case strings.HasSuffix(bufferType, "PngBuffer"):
		imageType = PNG
		break
	case strings.HasSuffix(bufferType, "TiffBuffer"):
		imageType = TIFF
		break
	case strings.HasSuffix(bufferType, "WebpBuffer"):
		imageType = WEBP
		break
	case strings.HasSuffix(bufferType, "MagickBuffer"):
		imageType = MAGICK
		break
	}

	return imageType
}

func vipsExifOrientation(image *C.struct__VipsImage) int {
	return int(C.vips_exif_orientation(image))
}

type vipsSaveOptions struct {
	Quality     int
	Compression int
	Type        ImageType
}

func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
	var ptr unsafe.Pointer
	length := C.size_t(0)
	err := C.int(0)

	switch {
	case o.Type == PNG:
		err = C.vips_pngsave_custom(image, &ptr, &length, 1, C.int(o.Compression), C.int(o.Quality), 0)
		break
	case o.Type == WEBP:
		err = C.vips_webpsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0)
		break
	default:
		err = C.vips_jpegsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0)
		break
	}

	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	buf := C.GoBytes(ptr, C.int(length))
	// cleanup
	C.g_free(C.gpointer(ptr))

	return buf, nil
}

func catchVipsError() error {
	s := C.GoString(C.vips_error_buffer())
	C.vips_error_clear()
	C.vips_thread_shutdown()
	return errors.New(s)
}
<commit_msg>refactor(vips)<commit_after>package bimg

/*
#cgo pkg-config: vips
#include "vips.h"
*/
import "C"

import (
	"errors"
	"runtime"
	"strings"
	"sync"
	"unsafe"
)

var (
	initialized bool = false
	m           sync.Mutex
)

type vipsImage C.struct__VipsImage

func init() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	if C.VIPS_MAJOR_VERSION <= 7 && C.VIPS_MINOR_VERSION < 40 {
		panic("unsupported old vips version")
	}

	Initialize()

	C.vips_concurrency_set(0)                   // single-thread
	C.vips_cache_set_max_mem(100 * 1024 * 1024) // 100 MB
	C.vips_cache_set_max(500)                   // 500 operations
}

func Initialize() {
	err := C.vips_init(C.CString("bimg"))
	if err != 0 {
		Shutdown()
		panic("unable to start vips!")
	}

	m.Lock()
	defer m.Unlock()
	initialized = true
}

func Shutdown() {
	m.Lock()
	defer m.Unlock()
	C.vips_shutdown()
	initialized = false
}

func vipsRotate(image *C.struct__VipsImage, angle Angle) (*C.struct__VipsImage, error) {
	var out *C.struct__VipsImage

	err := C.vips_rotate(image, &out, C.int(angle))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}
	defer C.g_object_unref(C.gpointer(out))

	return out, nil
}

func vipsFlip(image *C.struct__VipsImage, direction Direction) (*C.struct__VipsImage, error) {
	var out *C.struct__VipsImage

	err := C.vips_flip_custom(image, &out, C.int(direction))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}
	defer C.g_object_unref(C.gpointer(out))

	return out, nil
}

func vipsRead(buf []byte) (*C.struct__VipsImage, ImageType, error) {
	var image *C.struct__VipsImage
	imageType := vipsImageType(buf)

	if imageType == UNKNOWN {
		return nil, UNKNOWN, errors.New("Input buffer contains unsupported image format")
	}

	// feed it
	length := C.size_t(len(buf))
	imageBuf := unsafe.Pointer(&buf[0])
	imageTypeC := C.int(imageType)

	err := C.vips_init_image(imageBuf, length, imageTypeC, &image)
	if err != 0 {
		return nil, UNKNOWN, catchVipsError()
	}

	return image, imageType, nil
}

func vipsExtract(image *C.struct__VipsImage, left, top, width, height int) (*C.struct__VipsImage, error) {
	var buf *C.struct__VipsImage

	err := C.vips_extract_area_custom(image, &buf, C.int(left), C.int(top), C.int(width), C.int(height))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return buf, nil
}

func vipsShrinkJpeg(buf []byte, shrink int) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	err := C.vips_jpegload_buffer_shrink(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &image, C.int(shrink))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsShrink(input *C.struct__VipsImage, shrink int) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	err := C.vips_shrink_0(input, &image, C.double(float64(shrink)), C.double(float64(shrink)))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsEmbed(input *C.struct__VipsImage, left, top, width, height, extend int) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	err := C.vips_embed_custom(input, &image, C.int(left), C.int(top), C.int(width), C.int(height), C.int(extend))
	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsAffine(input *C.struct__VipsImage, residual float64, i Interpolator) (*C.struct__VipsImage, error) {
	var image *C.struct__VipsImage

	istring := C.CString(i.String())
	interpolator := C.vips_interpolate_new(istring)

	// Perform affine transformation
	err := C.vips_affine_interpolator(input, &image, C.double(residual), 0, 0, C.double(residual), interpolator)
	C.g_object_unref(C.gpointer(image))
	C.free(unsafe.Pointer(istring))
	if err != 0 {
		return nil, catchVipsError()
	}

	return image, nil
}

func vipsImageType(buf []byte) ImageType {
	imageType := UNKNOWN

	length := C.size_t(len(buf))
	imageBuf := unsafe.Pointer(&buf[0])
	bufferType := C.GoString(C.vips_foreign_find_load_buffer(imageBuf, length))

	switch {
	case strings.HasSuffix(bufferType, "JpegBuffer"):
		imageType = JPEG
		break
	case strings.HasSuffix(bufferType, "PngBuffer"):
		imageType = PNG
		break
	case strings.HasSuffix(bufferType, "TiffBuffer"):
		imageType = TIFF
		break
	case strings.HasSuffix(bufferType, "WebpBuffer"):
		imageType = WEBP
		break
	case strings.HasSuffix(bufferType, "MagickBuffer"):
		imageType = MAGICK
		break
	}

	return imageType
}

func vipsExifOrientation(image *C.struct__VipsImage) int {
	return int(C.vips_exif_orientation(image))
}

type vipsSaveOptions struct {
	Quality     int
	Compression int
	Type        ImageType
}

func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
	var ptr unsafe.Pointer
	length := C.size_t(0)
	err := C.int(0)

	switch {
	case o.Type == PNG:
		err = C.vips_pngsave_custom(image, &ptr, &length, 1, C.int(o.Compression), C.int(o.Quality), 0)
		break
	case o.Type == WEBP:
		err = C.vips_webpsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0)
		break
	default:
		err = C.vips_jpegsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0)
		break
	}

	C.g_object_unref(C.gpointer(image))
	if err != 0 {
		return nil, catchVipsError()
	}

	buf := C.GoBytes(ptr, C.int(length))
	// cleanup
	C.g_free(C.gpointer(ptr))

	return buf, nil
}

func catchVipsError() error {
	s := C.GoString(C.vips_error_buffer())
	C.vips_error_clear()
	C.vips_thread_shutdown()
	return errors.New(s)
}
<|endoftext|>


<commit_before>package main

import "fmt"

type Pool struct {
	taskQueue        chan Task
	workerQueue      chan chan Task
	poolSize         int
	queueCapacity    int
	numOfQueuedTasks int
	semaphore        chan int
}

func (p *Pool) startDispatcher() {
	fmt.Printf("Pool.poolSize: %d\n", p.poolSize)
	for i := 0; i < p.poolSize; i++ {
		fmt.Println("Starting worker[%d]", i)
		worker := NewWorker(i+1, p.workerQueue)
		worker.Start(p)
	}

	go func() {
		for {
			select {
			case task := <-p.taskQueue:
				fmt.Println("Received task")
				go func() {
					worker := <-p.workerQueue
					fmt.Println("Dispatching task")
					worker <- task
				}()
			}
		}
	}()
}

func NewPool(poolSize int, queueCapacity int) *Pool {
	semaphore := make(chan int, queueCapacity)
	for i := 0; i < queueCapacity; i++ {
		semaphore <- 1
	}
	pool := Pool{
		taskQueue:        make(chan Task, queueCapacity),
		workerQueue:      make(chan chan Task, poolSize),
		poolSize:         poolSize,
		numOfQueuedTasks: 0,
		queueCapacity:    queueCapacity,
		semaphore:        semaphore,
	}
	return &pool
}

func (pool *Pool) Submit(task Task) {
	pool.taskQueue <- task
}

type Worker struct {
	Id           int
	Task         chan Task
	WorkerQueue  chan chan Task
	ShutdownChan chan bool
}

func NewWorker(id int, workerQueue chan chan Task) Worker {
	worker := Worker{
		Id:           id,
		Task:         make(chan Task),
		WorkerQueue:  workerQueue,
		ShutdownChan: make(chan bool),
	}

	return worker
}

func (w Worker) Start(pool *Pool) {
	go func() {
		for {
			w.WorkerQueue <- w.Task
			select {
			case task := <-w.Task:
				fmt.Printf("worker[%d]: Received task\n", w.Id)
				task.Execute()
				pool.semaphore <- 1
			case <-w.ShutdownChan:
				fmt.Printf("worker[%d] stopping\n", w.Id)
			}
		}
	}()
}

type Task interface {
	Execute()
}
<commit_msg>Change package from `main` to `pool`<commit_after>package pool

import "fmt"

type Pool struct {
	taskQueue        chan Task
	workerQueue      chan chan Task
	poolSize         int
	queueCapacity    int
	numOfQueuedTasks int
	semaphore        chan int
}

func (p *Pool) startDispatcher() {
	fmt.Printf("Pool.poolSize: %d\n", p.poolSize)
	for i := 0; i < p.poolSize; i++ {
		fmt.Println("Starting worker[%d]", i)
		worker := NewWorker(i+1, p.workerQueue)
		worker.Start(p)
	}

	go func() {
		for {
			select {
			case task := <-p.taskQueue:
				fmt.Println("Received task")
				go func() {
					worker := <-p.workerQueue
					fmt.Println("Dispatching task")
					worker <- task
				}()
			}
		}
	}()
}

func NewPool(poolSize int, queueCapacity int) *Pool {
	semaphore := make(chan int, queueCapacity)
	for i := 0; i < queueCapacity; i++ {
		semaphore <- 1
	}
	pool := Pool{
		taskQueue:        make(chan Task, queueCapacity),
		workerQueue:      make(chan chan Task, poolSize),
		poolSize:         poolSize,
		numOfQueuedTasks: 0,
		queueCapacity:    queueCapacity,
		semaphore:        semaphore,
	}
	return &pool
}

func (pool *Pool) Submit(task Task) {
	pool.taskQueue <- task
}

type Worker struct {
	Id           int
	Task         chan Task
	WorkerQueue  chan chan Task
	ShutdownChan chan bool
}

func NewWorker(id int, workerQueue chan chan Task) Worker {
	worker := Worker{
		Id:           id,
		Task:         make(chan Task),
		WorkerQueue:  workerQueue,
		ShutdownChan: make(chan bool),
	}

	return worker
}

func (w Worker) Start(pool *Pool) {
	go func() {
		for {
			w.WorkerQueue <- w.Task
			select {
			case task := <-w.Task:
				fmt.Printf("worker[%d]: Received task\n", w.Id)
				task.Execute()
				pool.semaphore <- 1
			case <-w.ShutdownChan:
				fmt.Printf("worker[%d] stopping\n", w.Id)
			}
		}
	}()
}

type Task interface {
	Execute()
}
<|endoftext|>