<commit_before>package main

import (
	"encoding/json"
	"github.com/m4rw3r/uuid"
	"net/http"
	//"fmt"

	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"

	"github.com/ckpt/backend-services/players"
)

type appError struct {
	Error   error
	Message string
	Code    int
}

type appHandler func(web.C, http.ResponseWriter, *http.Request) *appError

var currentuser string

func (fn appHandler) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request) {
	if e := fn(c, w, r); e != nil {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(e.Code)
		encoder := json.NewEncoder(w)
		encoder.Encode(map[string]string{"error": e.Error.Error() +
			" (" + e.Message + ")"})
	}
}

func listAllPlayers(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	playerlist, err := players.AllPlayers()
	if err != nil {
		return &appError{err, "Cant load players", 500}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(playerlist)
	return nil
}

func getAllPlayerQuotes(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	playerlist, err := players.AllPlayers()
	if err != nil {
		return &appError{err, "Cant load players", 500}
	}
	quotes := make(map[string][]string)
	for _, player := range playerlist {
		pq := player.Quotes
		if len(pq) > 0 {
			quotes[player.UUID.String()] = append(quotes[player.UUID.String()], pq...)
		}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(quotes)
	return nil
}

func getPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(player)
	return nil
}

func getPlayerProfile(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(player.Profile)
	return nil
}

func updatePlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	tempPlayer := new(players.Player)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(tempPlayer); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}

	if err := player.SetActive(tempPlayer.Active); err != nil {
		return &appError{err, "Failed to set active status", 500}
	}
	if err := player.SetNick(tempPlayer.Nick); err != nil {
		return &appError{err, "Failed to set nick", 500}
	}
	if err := player.SetProfile(tempPlayer.Profile); err != nil {
		return &appError{err, "Failed to set player profile", 500}
	}
	w.WriteHeader(204)
	return nil
}

func updatePlayerProfile(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	tempProfile := new(players.Profile)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(tempProfile); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}

	if err := player.SetProfile(*tempProfile); err != nil {
		return &appError{err, "Failed to set player profile", 500}
	}
	w.WriteHeader(204)
	return nil
}

func createNewPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	nPlayer := new(players.Player)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(nPlayer); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	nPlayer, err := players.NewPlayer(nPlayer.Nick, nPlayer.Profile)
	if err != nil {
		return &appError{err, "Failed to create new player", 500}
	}
	w.Header().Set("Location", "/players/"+nPlayer.UUID.String())
	w.WriteHeader(201)
	return nil
}

func createNewUser(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	type newUser struct {
		Player uuid.UUID `json:"player"`
		players.User
	}
	nUser := new(newUser)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(nUser); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	_, err := players.NewUser(nUser.Player, &nUser.User)
	if err != nil {
		return &appError{err, "Failed to create new user", 500}
	}
	w.Header().Set("Location", "/players/"+nUser.Player.String()+"/user")
	w.WriteHeader(201)
	return nil
}

func getUserForPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(player.User)
	return nil
}

func setUserForPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	tempUser := new(players.User)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(tempUser); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	user, err := players.UserByName(tempUser.Username)
	if err != nil {
		return &appError{err, "Cant find user", 400}
	}

	if err := player.SetUser(*user); err != nil {
		return &appError{err, "Failed to set user for player", 500}
	}
	w.WriteHeader(204)
	return nil
}

func main() {
	//fmt.Printf("%+v\n", getMembers())
	currentuser = "mortenk"
	goji.Get("/players", appHandler(listAllPlayers))
	goji.Post("/players", appHandler(createNewPlayer))
	goji.Get("/players/quotes", appHandler(getAllPlayerQuotes))
	goji.Get("/players/:uuid", appHandler(getPlayer))
	goji.Put("/players/:uuid", appHandler(updatePlayer))
	goji.Get("/players/:uuid/profile", appHandler(getPlayerProfile))
	goji.Put("/players/:uuid/profile", appHandler(updatePlayerProfile))
	goji.Get("/players/:uuid/user", appHandler(getUserForPlayer))
	goji.Put("/players/:uuid/user", appHandler(setUserForPlayer))

	goji.Post("/users", appHandler(createNewUser))
	goji.Serve()
}
<commit_msg>Add login endpoint and proper cors support.<commit_after>package main

import (
	"encoding/json"
	"github.com/m4rw3r/uuid"
	"net/http"
	"errors"
	"fmt"

	"github.com/rs/cors"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"

	"github.com/ckpt/backend-services/players"
)

type appError struct {
	Error   error
	Message string
	Code    int
}

type appHandler func(web.C, http.ResponseWriter, *http.Request) *appError

var currentuser string

func (fn appHandler) ServeHTTPC(c web.C, w http.ResponseWriter, r *http.Request) {
	if e := fn(c, w, r); e != nil {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(e.Code)
		encoder := json.NewEncoder(w)
		encoder.Encode(map[string]string{"error": e.Error.Error() +
			" (" + e.Message + ")"})
	}
}

func listAllPlayers(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	playerlist, err := players.AllPlayers()
	if err != nil {
		return &appError{err, "Cant load players", 500}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(playerlist)
	return nil
}

func getAllPlayerQuotes(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	playerlist, err := players.AllPlayers()
	if err != nil {
		return &appError{err, "Cant load players", 500}
	}
	quotes := make(map[string][]string)
	for _, player := range playerlist {
		pq := player.Quotes
		if len(pq) > 0 {
			quotes[player.UUID.String()] = append(quotes[player.UUID.String()], pq...)
		}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(quotes)
	return nil
}

func getPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(player)
	return nil
}

func getPlayerProfile(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(player.Profile)
	return nil
}

func updatePlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	tempPlayer := new(players.Player)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(tempPlayer); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}

	if err := player.SetActive(tempPlayer.Active); err != nil {
		return &appError{err, "Failed to set active status", 500}
	}
	if err := player.SetNick(tempPlayer.Nick); err != nil {
		return &appError{err, "Failed to set nick", 500}
	}
	if err := player.SetProfile(tempPlayer.Profile); err != nil {
		return &appError{err, "Failed to set player profile", 500}
	}
	w.WriteHeader(204)
	return nil
}

func updatePlayerProfile(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	tempProfile := new(players.Profile)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(tempProfile); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}

	if err := player.SetProfile(*tempProfile); err != nil {
		return &appError{err, "Failed to set player profile", 500}
	}
	w.WriteHeader(204)
	return nil
}

func createNewPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	nPlayer := new(players.Player)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(nPlayer); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	nPlayer, err := players.NewPlayer(nPlayer.Nick, nPlayer.Profile)
	if err != nil {
		return &appError{err, "Failed to create new player", 500}
	}
	w.Header().Set("Location", "/players/"+nPlayer.UUID.String())
	w.WriteHeader(201)
	return nil
}

func createNewUser(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	type newUser struct {
		Player uuid.UUID `json:"player"`
		players.User
	}
	nUser := new(newUser)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(nUser); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	_, err := players.NewUser(nUser.Player, &nUser.User)
	if err != nil {
		return &appError{err, "Failed to create new user", 500}
	}
	w.Header().Set("Location", "/players/"+nUser.Player.String()+"/user")
	w.WriteHeader(201)
	return nil
}

func getUserForPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	encoder := json.NewEncoder(w)
	encoder.Encode(player.User)
	return nil
}

func setUserForPlayer(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	uuid, err := uuid.FromString(c.URLParams["uuid"])
	player, err := players.PlayerByUUID(uuid)
	if err != nil {
		return &appError{err, "Cant find player", 404}
	}
	tempUser := new(players.User)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(tempUser); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	user, err := players.UserByName(tempUser.Username)
	if err != nil {
		return &appError{err, "Cant find user", 400}
	}

	if err := player.SetUser(*user); err != nil {
		return &appError{err, "Failed to set user for player", 500}
	}
	w.WriteHeader(204)
	return nil
}

func login(c web.C, w http.ResponseWriter, r *http.Request) *appError {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	type LoginRequest struct {
		Username string
		Password string
	}

	loginReq := new(LoginRequest)
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(loginReq); err != nil {
		return &appError{err, "Invalid JSON", 400}
	}
	// Hard code for now
	fmt.Printf("%+v\n", loginReq)
	if (loginReq.Username == "mortenk" &&
		loginReq.Password == "testing123") {
		authUser, err := players.UserByName(loginReq.Username)
		if err != nil {
			return &appError{err, "Failed to fetch user data", 500}
		}
		if authUser.Locked {
			return &appError{errors.New("Locked"), "User locked", 403}
		}
		encoder := json.NewEncoder(w)
		encoder.Encode(authUser)
		return nil
	}

	// Else, forbidden
	w.WriteHeader(403)
	return nil
}

func main() {
	//fmt.Printf("%+v\n", getMembers())
	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
	})
	goji.Use(c.Handler)

	goji.Get("/players", appHandler(listAllPlayers))
	goji.Post("/players", appHandler(createNewPlayer))
	goji.Get("/players/quotes", appHandler(getAllPlayerQuotes))
	goji.Get("/players/:uuid", appHandler(getPlayer))
	goji.Put("/players/:uuid", appHandler(updatePlayer))
	goji.Get("/players/:uuid/profile", appHandler(getPlayerProfile))
	goji.Put("/players/:uuid/profile", appHandler(updatePlayerProfile))
	goji.Get("/players/:uuid/user", appHandler(getUserForPlayer))
	goji.Put("/players/:uuid/user", appHandler(setUserForPlayer))

	goji.Post("/users", appHandler(createNewUser))

	goji.Post("/login", appHandler(login))
	goji.Serve()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"

	"github.com/codeskyblue/proxylocal/pxlocal"
	"github.com/qiniu/log"
)

func main() {
	var serverMode bool
	var serverAddr string
	var proxyPort int
	var proxyAddr string
	var subDomain string
	var domain string
	var debug bool

	var defaultServerAddr = os.Getenv("PXL_SERVER_ADDR")
	if defaultServerAddr == "" {
		defaultServerAddr = "proxylocal.xyz"
	}
	flag.BoolVar(&serverMode, "server", false, "run in server mode")
	flag.StringVar(&serverAddr, "server-addr", defaultServerAddr, "server address")
	flag.StringVar(&domain, "server-domain", "", "proxy server domain name, optional")
	flag.StringVar(&subDomain, "subdomain", "", "proxy subdomain, used for http")
	flag.BoolVar(&debug, "debug", false, "open debug mode")
	flag.IntVar(&proxyPort, "port", 0, "proxy server listen port, used for tcp")

	flag.Usage = func() {
		fmt.Printf("Usage: %s [OPTIONS] <port | host:port>\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	if !serverMode && len(flag.Args()) != 1 {
		flag.Usage()
		return
	}
	if !debug {
		log.SetOutputLevel(log.Linfo)
	} else {
		log.SetOutputLevel(log.Ldebug)
	}

	if serverMode {
		_, port, _ := net.SplitHostPort(serverAddr)
		if port == "" {
			port = "80"
		}
		addr := net.JoinHostPort("0.0.0.0", port)
		if domain == "" {
			domain = serverAddr
		}
		fmt.Println("proxylocal: server listen on", addr)
		ps := pxlocal.NewProxyServer(domain)
		log.Fatal(http.ListenAndServe(addr, ps))
	}

	proxyAddr = flag.Arg(0)
	if !regexp.MustCompile("^(http|https|tcp)://").MatchString(proxyAddr) {
		if _, err := strconv.Atoi(proxyAddr); err == nil { // only contain port
			proxyAddr = "localhost:" + proxyAddr
		} else {
			//proxyAddr += ":80"
		}
		proxyAddr = "http://" + proxyAddr
	}
	pURL, err := url.Parse(proxyAddr)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("proxy URL:", pURL)
	pxlocal.StartAgent(pURL, subDomain, serverAddr, proxyPort)
}
<commit_msg>show version<commit_after>package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strconv"

	"github.com/codeskyblue/proxylocal/pxlocal"
	"github.com/qiniu/log"
)

const (
	VERSION = "0.1"
)

func main() {
	var serverMode bool
	var serverAddr string
	var proxyPort int
	var proxyAddr string
	var subDomain string
	var domain string
	var debug bool

	var defaultServerAddr = os.Getenv("PXL_SERVER_ADDR")
	if defaultServerAddr == "" {
		defaultServerAddr = "proxylocal.xyz"
	}
	flag.BoolVar(&serverMode, "server", false, "run in server mode")
	flag.StringVar(&serverAddr, "server-addr", defaultServerAddr, "server address")
	flag.StringVar(&domain, "server-domain", "", "proxy server domain name, optional")
	flag.StringVar(&subDomain, "subdomain", "", "proxy subdomain, used for http")
	flag.BoolVar(&debug, "debug", false, "open debug mode")
	flag.IntVar(&proxyPort, "port", 0, "proxy server listen port, used for tcp")

	flag.Usage = func() {
		fmt.Printf("proxylocal version: %v\nUsage: %s [OPTIONS] <port | host:port>\n", VERSION, os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	if !serverMode && len(flag.Args()) != 1 {
		flag.Usage()
		return
	}
	if !debug {
		log.SetOutputLevel(log.Linfo)
	} else {
		log.SetOutputLevel(log.Ldebug)
	}

	if serverMode {
		_, port, _ := net.SplitHostPort(serverAddr)
		if port == "" {
			port = "80"
		}
		addr := net.JoinHostPort("0.0.0.0", port)
		if domain == "" {
			domain = serverAddr
		}
		fmt.Println("proxylocal: server listen on", addr)
		ps := pxlocal.NewProxyServer(domain)
		log.Fatal(http.ListenAndServe(addr, ps))
	}

	proxyAddr = flag.Arg(0)
	if !regexp.MustCompile("^(http|https|tcp)://").MatchString(proxyAddr) {
		if _, err := strconv.Atoi(proxyAddr); err == nil { // only contain port
			proxyAddr = "localhost:" + proxyAddr
		} else {
			//proxyAddr += ":80"
		}
		proxyAddr = "http://" + proxyAddr
	}
	pURL, err := url.Parse(proxyAddr)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("proxy URL:", pURL)
	pxlocal.StartAgent(pURL, subDomain, serverAddr, proxyPort)
}
<|endoftext|>


<commit_before><commit_msg>Command line interface<commit_after><|endoftext|>


<commit_before><commit_msg>Change the exit codes to something sensible<commit_after><|endoftext|>


<commit_before>package shell

import (
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"pfi/sensorbee/sensorbee/client"
	"strings"
)

const (
	topologiesHeader = "/topologies"
)

type currentTopologyState struct {
	name string
}

var (
	currentTopology currentTopologyState
)

// NewBQLCommands return command list to execute BQL statement.
func NewTopologiesCommands() []Command {
	return []Command{
		&changeTopologyCmd{},
		&bqlCmd{},
	}
}

type changeTopologyCmd struct {
	name string
}

func (ct *changeTopologyCmd) Init() error {
	return nil
}

func (ct *changeTopologyCmd) Name() []string {
	return []string{"use"}
}

func (ct *changeTopologyCmd) Input(input string) (cmdInputStatusType, error) {
	input = strings.Trim(input, " ")
	inputs := strings.Split(input, " ")
	if len(inputs) == 1 {
		return invalidCMD, fmt.Errorf("empty name is not supported")
	}
	if len(inputs) >= 3 {
		return invalidCMD, fmt.Errorf("name included spaces is not supported: %v",
			strings.Join(inputs[1:], " "))
	}

	ct.name = inputs[1]
	return preparedCMD, nil
}

func (ct *changeTopologyCmd) Eval(requester *client.Requester) {
	currentTopology.name = ct.name
}

type bqlCmd struct {
	buffer string
}

// Init BQL state.
func (b *bqlCmd) Init() error {
	return nil
}

// Name returns BQL start words.
func (b *bqlCmd) Name() []string {
	return []string{"select", "create", "update", "insert", "pause", "resume",
		"rewind", "drop", "save", "load"}
}

func (b *bqlCmd) Input(input string) (cmdInputStatusType, error) {
	if b.buffer == "" {
		b.buffer = input
	} else {
		b.buffer += "\n" + input
	}
	if !strings.HasSuffix(input, ";") {
		return continuousCMD, nil
	}

	return preparedCMD, nil
}

// Eval resolves input command to BQL statement
func (b *bqlCmd) Eval(requester *client.Requester) {
	// flush buffer and get complete statement
	queries := b.buffer
	b.buffer = ""

	fmt.Printf("BQL: %s\n", queries) // for debug, delete later
	sendBQLQueries(requester, queries)
}

func sendBQLQueries(requester *client.Requester, queries string) {
	uri := topologiesHeader + "/" + currentTopology.name + "/queries"
	res, err := requester.Do(client.Post, uri, map[string]interface{}{
		"queries": queries,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "request failed: %v\n", err)
		return
	}
	defer res.Close()

	if res.IsError() {
		// TODO: provide error reporting utility
		errRes, err := res.Error()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}

		// TODO: enhance error message
		fmt.Fprintf(os.Stderr, "request failed: %v: %v: %v\n", errRes.Code, errRes.Message, errRes.Meta)
		return
	}

	if res.IsStream() {
		showStreamResponses(res)
		return
	}
	// TODO: there isn't much information to show right now. Improve the server's response.
}

func showStreamResponses(res *client.Response) {
	ch, err := res.ReadStreamJSON()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	defer signal.Stop(sig)

	for {
		select {
		case js, ok := <-ch:
			if !ok {
				return
			}
			data, err := json.Marshal(js)
			if err != nil {
				fmt.Fprintf(os.Stderr, "cannot marshal a JSON: %v\n", err)
				return
			}
			fmt.Printf("%s\n", data)

		case <-sig:
			return // The response is closed by the caller
		}
	}
}
<commit_msg>adapt client to work with EVAL statement and print result<commit_after>package shell

import (
	"encoding/json"
	"fmt"
	"os"
	"os/signal"
	"pfi/sensorbee/sensorbee/client"
	"strings"
)

const (
	topologiesHeader = "/topologies"
)

type currentTopologyState struct {
	name string
}

var (
	currentTopology currentTopologyState
)

// NewBQLCommands return command list to execute BQL statement.
func NewTopologiesCommands() []Command {
	return []Command{
		&changeTopologyCmd{},
		&bqlCmd{},
	}
}

type changeTopologyCmd struct {
	name string
}

func (ct *changeTopologyCmd) Init() error {
	return nil
}

func (ct *changeTopologyCmd) Name() []string {
	return []string{"use"}
}

func (ct *changeTopologyCmd) Input(input string) (cmdInputStatusType, error) {
	input = strings.Trim(input, " ")
	inputs := strings.Split(input, " ")
	if len(inputs) == 1 {
		return invalidCMD, fmt.Errorf("empty name is not supported")
	}
	if len(inputs) >= 3 {
		return invalidCMD, fmt.Errorf("name included spaces is not supported: %v",
			strings.Join(inputs[1:], " "))
	}

	ct.name = inputs[1]
	return preparedCMD, nil
}

func (ct *changeTopologyCmd) Eval(requester *client.Requester) {
	currentTopology.name = ct.name
}

type bqlCmd struct {
	buffer string
}

// Init BQL state.
func (b *bqlCmd) Init() error {
	return nil
}

// Name returns BQL start words.
func (b *bqlCmd) Name() []string {
	return []string{"select", "create", "update", "insert", "pause", "resume",
		"rewind", "drop", "save", "load", "eval"}
}

func (b *bqlCmd) Input(input string) (cmdInputStatusType, error) {
	if b.buffer == "" {
		b.buffer = input
	} else {
		b.buffer += "\n" + input
	}
	if !strings.HasSuffix(input, ";") {
		return continuousCMD, nil
	}

	return preparedCMD, nil
}

// Eval resolves input command to BQL statement
func (b *bqlCmd) Eval(requester *client.Requester) {
	// flush buffer and get complete statement
	queries := b.buffer
	b.buffer = ""

	fmt.Printf("BQL: %s\n", queries) // for debug, delete later
	sendBQLQueries(requester, queries)
}

func sendBQLQueries(requester *client.Requester, queries string) {
	uri := topologiesHeader + "/" + currentTopology.name + "/queries"
	res, err := requester.Do(client.Post, uri, map[string]interface{}{
		"queries": queries,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "request failed: %v\n", err)
		return
	}
	defer res.Close()

	if res.IsError() {
		// TODO: provide error reporting utility
		errRes, err := res.Error()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			return
		}

		// TODO: enhance error message
		fmt.Fprintf(os.Stderr, "request failed: %v: %v: %v\n", errRes.Code, errRes.Message, errRes.Meta)
		return
	}

	if res.IsStream() {
		showStreamResponses(res)
		return
	} else {
		// check if we have a JSON body that contains a "result" field;
		// if so, print it.
		// NB. We should also display some more status information that
		// is reported by most statements.
		var data map[string]interface{}
		err := res.ReadJSON(&data)
		if err == nil {
			result, ok := data["result"]
			if ok {
				fmt.Println(result)
			}
		}
	}
}

func showStreamResponses(res *client.Response) {
	ch, err := res.ReadStreamJSON()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	defer signal.Stop(sig)

	for {
		select {
		case js, ok := <-ch:
			if !ok {
				return
			}
			data, err := json.Marshal(js)
			if err != nil {
				fmt.Fprintf(os.Stderr, "cannot marshal a JSON: %v\n", err)
				return
			}
			fmt.Printf("%s\n", data)

		case <-sig:
			return // The response is closed by the caller
		}
	}
}
<|endoftext|>


<commit_before>package diskv

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

const (
	defaultFilePerm os.FileMode = 0666
	defaultPathPerm os.FileMode = 0777
)

// A TransformFunc transforms a key into a slice of strings, with each
// element in the slice representing a directory in the file path
// where the key's entry will eventually be stored.
//
// For example, if TransformFunc transforms "abcdef" to ["ab", "cde", "f"],
// the final location of the data file will be <basedir>/ab/cde/f/abcdef
type TransformFunction func(s string) []string

// TODO
type Index interface {
	Initialize(less LessFunction, keys <-chan string)
	Insert(key string)
	Delete(key string)
	Keys(from string, n int) <-chan string
}

// TODO
type LessFunction func(string, string) bool

// TODO
type Options struct {
	BasePath     string
	Transform    TransformFunction
	CacheSizeMax uint64 // bytes
	PathPerm     os.FileMode
	FilePerm     os.FileMode

	Index       Index
	IndexLess   LessFunction
	Compression io.ReadWriteCloser
}

type Diskv struct {
	sync.RWMutex
	Options
	cache     map[string][]byte
	cacheSize uint64
}

// New returns an initialized Diskv structure, ready to use.
// If the path identified by baseDir already contains data,
// it will be accessible, but not yet cached.
func New(options Options) *Diskv {
	if options.PathPerm == 0 {
		options.PathPerm = defaultPathPerm
	}
	if options.FilePerm == 0 {
		options.FilePerm = defaultFilePerm
	}

	d := &Diskv{
		Options:   options,
		cache:     map[string][]byte{},
		cacheSize: 0,
	}

	if d.Index != nil && d.IndexLess != nil {
		d.Index.Initialize(d.IndexLess, d.Keys())
	}

	return d
}

// Write synchronously writes the key-value pair to disk,
// making it immediately available for reads.
func (d *Diskv) Write(key string, val []byte) error {
	if len(key) <= 0 {
		return fmt.Errorf("empty key")
	}

	d.Lock()
	defer d.Unlock()
	if err := d.ensurePath(key); err != nil {
		return err
	}

	compressedVal, err := d.compress(val)
	if err != nil {
		return err
	}

	mode := os.O_WRONLY | os.O_CREATE | os.O_TRUNC // overwrite if exists
	f, err := os.OpenFile(d.completeFilename(key), mode, d.FilePerm)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err = f.Write(compressedVal); err != nil {
		return err
	}

	if d.Index != nil {
		d.Index.Insert(key)
	}

	delete(d.cache, key) // cache only on read
	return nil
}

// Read reads the key and returns the value.
// If the key is available in the cache, Read won't touch the disk.
// If the key is not in the cache, Read will have the side-effect of
// lazily caching the value.
func (d *Diskv) Read(key string) ([]byte, error) {
	d.RLock()
	defer d.RUnlock()

	// check cache first
	if val, ok := d.cache[key]; ok {
		return d.decompress(val)
	}

	// read from disk
	val, err := ioutil.ReadFile(d.completeFilename(key))
	if err != nil {
		return []byte{}, err
	}

	// cache lazily
	go d.cacheWithoutLock(key, val)

	// return
	return d.decompress(val)
}

// Erase synchronously erases the given key from the disk and the cache.
func (d *Diskv) Erase(key string) error {
	d.Lock()
	defer d.Unlock()

	// erase from cache
	if val, ok := d.cache[key]; ok {
		d.cacheSize -= uint64(len(val))
		delete(d.cache, key)
	}

	// erase from index
	if d.Index != nil {
		d.Index.Delete(key)
	}

	// erase from disk
	filename := d.completeFilename(key)
	if s, err := os.Stat(filename); err == nil {
		if !!s.IsDir() {
			return fmt.Errorf("bad key")
		}
		if err = os.Remove(filename); err != nil {
			return err
		}
	} else {
		return err
	}

	// clean up and return
	d.pruneDirs(key)
	return nil
}

// Flush will delete all of the data from the store, both
// in the cache and on the disk. Note that Flush doesn't
// distinguish diskv-related data from non-diskv-related data.
// Care should be taken to always specify a diskv base directory
// that is exclusively for diskv data.
func (d *Diskv) Flush() error {
	d.Lock()
	defer d.Unlock()
	d.cache = make(map[string][]byte)
	d.cacheSize = 0
	return os.RemoveAll(d.BasePath)
}

// Keys returns a channel that will yield every key
// accessible by the store in undefined order.
func (d *Diskv) Keys() <-chan string {
	c := make(chan string)
	go func() {
		filepath.Walk(d.BasePath, walker(c))
		close(c)
	}()
	return c
}

//
//
//

func (d *Diskv) compress(val []byte) ([]byte, error) {
	if d.Compression != nil {
		return val, nil // TODO
	}
	return val, nil
}

func (d *Diskv) decompress(val []byte) ([]byte, error) {
	if d.Compression != nil {
		return val, nil // TODO
	}
	return val, nil
}

// walker returns a function which satisfies the filepath.WalkFunc interface.
// It sends every non-directory file entry down the channel c.
func walker(c chan string) func(path string, info os.FileInfo, err error) error {
	return func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() {
			c <- info.Name()
		}
		return nil // "pass"
	}
}

// pathFor returns the absolute path for location on the filesystem
// where the data for the given key will be stored.
func (d *Diskv) pathFor(key string) string {
	return fmt.Sprintf(
		"%s%c%s",
		d.BasePath,
		os.PathSeparator,
		strings.Join(d.Transform(key), string(os.PathSeparator)),
	)
}

// ensureDir is a helper function that generates all necessary
// directories on the filesystem for the given key.
func (d *Diskv) ensurePath(key string) error {
	return os.MkdirAll(d.pathFor(key), d.PathPerm)
}

// completeFilename returns the absolute path to the file for the given key.
func (d *Diskv) completeFilename(key string) string {
	return fmt.Sprintf("%s%c%s", d.pathFor(key), os.PathSeparator, key)
}

// cacheWithLock attempts to cache the given key-value pair in the
// store's cache. It can fail if the value is larger than the cache's
// maximum size.
func (d *Diskv) cacheWithLock(key string, val []byte) error {
	valueSize := uint64(len(val))
	if err := d.ensureCacheSpaceFor(valueSize); err != nil {
		return fmt.Errorf("%s; not caching", err)
	}

	if (d.cacheSize + valueSize) > d.CacheSizeMax {
		panic(
			fmt.Sprintf(
				"failed to make room for value (%d/%d)",
				valueSize,
				d.CacheSizeMax,
			),
		)
	}

	d.cache[key] = val
	d.cacheSize += valueSize
	return nil
}

// cacheWithoutLock acquires the store's (write) mutex
// and calls cacheWithLock.
func (d *Diskv) cacheWithoutLock(key string, val []byte) error {
	d.Lock()
	defer d.Unlock()
	return d.cacheWithLock(key, val)
}

// pruneDirs deletes empty directories in the path walk leading to the key k.
// Typically this function is called after an Erase is made.
func (d *Diskv) pruneDirs(key string) error {
	pathlist := d.Transform(key)
	for i := range pathlist {
		pslice := pathlist[:len(pathlist)-i]
		dir := fmt.Sprintf(
			"%s%c%s",
			d.BasePath,
			os.PathSeparator,
			strings.Join(pslice, string(os.PathSeparator)),
		)

		// thanks to Steven Blenkinsop for this snippet
		switch fi, err := os.Stat(dir); true {
		case err != nil:
			return err
		case !fi.IsDir():
			panic(fmt.Sprintf("corrupt dirstate at %s", dir))
		}

		nlinks, err := filepath.Glob(fmt.Sprintf("%s%c*", dir, os.PathSeparator))
		if err != nil {
			return err
		} else if len(nlinks) > 0 {
			return nil // has subdirs -- do not prune
		}
		if err = os.Remove(dir); err != nil {
			return err
		}
	}

	return nil
}

// ensureCacheSpaceFor deletes entries from the cache in arbitrary order
// until the cache has at least valueSize bytes available.
func (d *Diskv) ensureCacheSpaceFor(valueSize uint64) error {
	if valueSize > d.CacheSizeMax {
		return fmt.Errorf(
			"value size (%d bytes) too large for cache (%d bytes)",
			valueSize,
			d.CacheSizeMax,
		)
	}

	safe := func() bool { return (d.cacheSize + valueSize) <= d.CacheSizeMax }
	for key, val := range d.cache {
		if safe() {
			break
		}
		delete(d.cache, key)            // delete is safe, per spec
		d.cacheSize -= uint64(len(val)) // len should return uint :|
	}
	if !safe() {
		panic(fmt.Sprintf(
			"%d bytes still won't fit in the cache! (max %d bytes)",
			valueSize,
			d.CacheSizeMax,
		))
	}

	return nil
}
<commit_msg>Small commentary + cleanup<commit_after>package diskv

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

const (
	defaultBasePath             = "diskv"
	defaultFilePerm os.FileMode = 0666
	defaultPathPerm os.FileMode = 0777
)

var (
	defaultTransform = func(s string) []string { return []string{""} }
)

// A TransformFunc transforms a key into a slice of strings, with each
// element in the slice representing a directory in the file path
// where the key's entry will eventually be stored.
//
// For example, if TransformFunc transforms "abcdef" to ["ab", "cde", "f"],
// the final location of the data file will be <basedir>/ab/cde/f/abcdef
type TransformFunction func(s string) []string

// Index is a generic interface for things that can
// provide an ordered list of keys.
type Index interface {
	Initialize(less LessFunction, keys <-chan string)
	Insert(key string)
	Delete(key string)
	Keys(from string, n int) <-chan string
}

// LessFunction is used to initialize an Index of keys in a specific order.
type LessFunction func(string, string) bool

// Options define a set of properties that dictate Diskv behavior.
// All values are optional.
type Options struct {
	BasePath     string
	Transform    TransformFunction
	CacheSizeMax uint64 // bytes
	PathPerm     os.FileMode
	FilePerm     os.FileMode

	Index     Index
	IndexLess LessFunction

	Compression io.ReadWriteCloser
}

// Diskv implements the Diskv interface. You shouldn't construct Diskv
// structures directly; instead, use the New constructor.
type Diskv struct {
	sync.RWMutex
	Options
	cache     map[string][]byte
	cacheSize uint64
}

// New returns an initialized Diskv structure, ready to use.
// If the path identified by baseDir already contains data,
// it will be accessible, but not yet cached.
func New(options Options) *Diskv {
	if options.BasePath == "" {
		options.BasePath = defaultBasePath
	}
	if options.Transform == nil {
		options.Transform = defaultTransform
	}
	if options.PathPerm == 0 {
		options.PathPerm = defaultPathPerm
	}
	if options.FilePerm == 0 {
		options.FilePerm = defaultFilePerm
	}

	d := &Diskv{
		Options:   options,
		cache:     map[string][]byte{},
		cacheSize: 0,
	}

	if d.Index != nil && d.IndexLess != nil {
		d.Index.Initialize(d.IndexLess, d.Keys())
	}

	return d
}

// Write synchronously writes the key-value pair to disk,
// making it immediately available for reads.
func (d *Diskv) Write(key string, val []byte) error {
	if len(key) <= 0 {
		return fmt.Errorf("empty key")
	}

	d.Lock()
	defer d.Unlock()
	if err := d.ensurePath(key); err != nil {
		return err
	}

	compressedVal, err := d.compress(val)
	if err != nil {
		return err
	}

	mode := os.O_WRONLY | os.O_CREATE | os.O_TRUNC // overwrite if exists
	f, err := os.OpenFile(d.completeFilename(key), mode, d.FilePerm)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err = f.Write(compressedVal); err != nil {
		return err
	}

	if d.Index != nil {
		d.Index.Insert(key)
	}

	delete(d.cache, key) // cache only on read
	return nil
}

// Read reads the key and returns the value.
// If the key is available in the cache, Read won't touch the disk.
// If the key is not in the cache, Read will have the side-effect of
// lazily caching the value.
func (d *Diskv) Read(key string) ([]byte, error) {
	d.RLock()
	defer d.RUnlock()

	// check cache first
	if val, ok := d.cache[key]; ok {
		return d.decompress(val)
	}

	// read from disk
	val, err := ioutil.ReadFile(d.completeFilename(key))
	if err != nil {
		return []byte{}, err
	}

	// cache lazily
	go d.cacheWithoutLock(key, val)

	// return
	return d.decompress(val)
}

// Erase synchronously erases the given key from the disk and the cache.
func (d *Diskv) Erase(key string) error {
	d.Lock()
	defer d.Unlock()

	// erase from cache
	if val, ok := d.cache[key]; ok {
		d.cacheSize -= uint64(len(val))
		delete(d.cache, key)
	}

	// erase from index
	if d.Index != nil {
		d.Index.Delete(key)
	}

	// erase from disk
	filename := d.completeFilename(key)
	if s, err := os.Stat(filename); err == nil {
		if !!s.IsDir() {
			return fmt.Errorf("bad key")
		}
		if err = os.Remove(filename); err != nil {
			return err
		}
	} else {
		return err
	}

	// clean up and return
	d.pruneDirs(key)
	return nil
}

// Flush will delete all of the data from the store, both
// in the cache and on the disk. Note that Flush doesn't
// distinguish diskv-related data from non-diskv-related data.
// Care should be taken to always specify a diskv base directory
// that is exclusively for diskv data.
func (d *Diskv) Flush() error {
	d.Lock()
	defer d.Unlock()
	d.cache = make(map[string][]byte)
	d.cacheSize = 0
	return os.RemoveAll(d.BasePath)
}

// Keys returns a channel that will yield every key
// accessible by the store in undefined order.
func (d *Diskv) Keys() <-chan string {
	c := make(chan string)
	go func() {
		filepath.Walk(d.BasePath, walker(c))
		close(c)
	}()
	return c
}

//
//
//

func (d *Diskv) compress(val []byte) ([]byte, error) {
	if d.Compression != nil {
		return val, nil // TODO
	}
	return val, nil
}

func (d *Diskv) decompress(val []byte) ([]byte, error) {
	if d.Compression != nil {
		return val, nil // TODO
	}
	return val, nil
}

// walker returns a function which satisfies the filepath.WalkFunc interface.
// It sends every non-directory file entry down the channel c.
func walker(c chan string) func(path string, info os.FileInfo, err error) error {
	return func(path string, info os.FileInfo, err error) error {
		if err == nil && !info.IsDir() {
			c <- info.Name()
		}
		return nil // "pass"
	}
}

// pathFor returns the absolute path for location on the filesystem
// where the data for the given key will be stored.
func (d *Diskv) pathFor(key string) string {
	return fmt.Sprintf(
		"%s%c%s",
		d.BasePath,
		os.PathSeparator,
		strings.Join(d.Transform(key), string(os.PathSeparator)),
	)
}

// ensureDir is a helper function that generates all necessary
// directories on the filesystem for the given key.
func (d *Diskv) ensurePath(key string) error {
	return os.MkdirAll(d.pathFor(key), d.PathPerm)
}

// completeFilename returns the absolute path to the file for the given key.
func (d *Diskv) completeFilename(key string) string {
	return fmt.Sprintf("%s%c%s", d.pathFor(key), os.PathSeparator, key)
}

// cacheWithLock attempts to cache the given key-value pair in the
// store's cache. It can fail if the value is larger than the cache's
// maximum size.
func (d *Diskv) cacheWithLock(key string, val []byte) error {
	valueSize := uint64(len(val))
	if err := d.ensureCacheSpaceFor(valueSize); err != nil {
		return fmt.Errorf("%s; not caching", err)
	}

	if (d.cacheSize + valueSize) > d.CacheSizeMax {
		panic(
			fmt.Sprintf(
				"failed to make room for value (%d/%d)",
				valueSize,
				d.CacheSizeMax,
			),
		)
	}

	d.cache[key] = val
	d.cacheSize += valueSize
	return nil
}

// cacheWithoutLock acquires the store's (write) mutex
// and calls cacheWithLock.
func (d *Diskv) cacheWithoutLock(key string, val []byte) error {
	d.Lock()
	defer d.Unlock()
	return d.cacheWithLock(key, val)
}

// pruneDirs deletes empty directories in the path walk leading to the key k.
// Typically this function is called after an Erase is made.
func (d *Diskv) pruneDirs(key string) error {
	pathlist := d.Transform(key)
	for i := range pathlist {
		pslice := pathlist[:len(pathlist)-i]
		dir := fmt.Sprintf(
			"%s%c%s",
			d.BasePath,
			os.PathSeparator,
			strings.Join(pslice, string(os.PathSeparator)),
		)

		// thanks to Steven Blenkinsop for this snippet
		switch fi, err := os.Stat(dir); true {
		case err != nil:
			return err
		case !fi.IsDir():
			panic(fmt.Sprintf("corrupt dirstate at %s", dir))
		}

		nlinks, err := filepath.Glob(fmt.Sprintf("%s%c*", dir, os.PathSeparator))
		if err != nil {
			return err
		} else if len(nlinks) > 0 {
			return nil // has subdirs -- do not prune
		}
		if err = os.Remove(dir); err != nil {
			return err
		}
	}

	return nil
}

// ensureCacheSpaceFor deletes entries from the cache in arbitrary order
// until the cache has at least valueSize bytes available.
func (d *Diskv) ensureCacheSpaceFor(valueSize uint64) error {
	if valueSize > d.CacheSizeMax {
		return fmt.Errorf(
			"value size (%d bytes) too large for cache (%d bytes)",
			valueSize,
			d.CacheSizeMax,
		)
	}

	safe := func() bool { return (d.cacheSize + valueSize) <= d.CacheSizeMax }
	for key, val := range d.cache {
		if safe() {
			break
		}
		delete(d.cache, key)            // delete is safe, per spec
		d.cacheSize -= uint64(len(val)) // len should return uint :|
	}
	if !safe() {
		panic(fmt.Sprintf(
			"%d bytes still won't fit in the cache! (max %d bytes)",
			valueSize,
			d.CacheSizeMax,
		))
	}

	return nil
}
<|endoftext|>


<commit_before>package grift

import (
	"fmt"
	"io"
	"log"
	"os"
	"sort"
	"strings"
	"sync"
	"time"
)

var CommandName = "grift"
var griftList = map[string]Grift{}
var descriptions = map[string]string{}
var lock = &sync.Mutex{}
var namespace string

type Grift func(c *Context) error

// Namespace will place all tasks within the given prefix.
func Namespace(name string, s func()) error {
	defer func() {
		namespace = ""
	}()

	namespace = applyNamespace(name)
	s()
	return nil
}

func applyNamespace(name string) string {
	if namespace != "" {
		if strings.HasPrefix(name, ":") {
			return name[1:]
		}
		if name == "default" {
			return name
		}
		return fmt.Sprintf("%s:%s", namespace, name)
	}

	return name
}

// Add a grift. If there is already a grift
// with the given name the two grifts will
// be bundled together.
func Add(name string, grift Grift) error {
	lock.Lock()
	defer lock.Unlock()

	name = applyNamespace(name)

	if griftList[name] != nil {
		fn := griftList[name]
		griftList[name] = func(c *Context) error {
			err := fn(c)
			if err != nil {
				return err
			}
			return grift(c)
		}
	} else {
		griftList[name] = grift
	}
	return nil
}

// Set a grift. This is similar to `Add` but it will
// overwrite an existing grift with the same name.
func Set(name string, grift Grift) error {
	lock.Lock()
	defer lock.Unlock()
	name = applyNamespace(name)
	griftList[name] = grift
	return nil
}

// Rename a grift. Useful if you want to re-define
// an existing grift, but don't want to write over
// the original.
func Rename(oldName string, newName string) error {
	lock.Lock()
	defer lock.Unlock()

	oldName = applyNamespace(oldName)
	newName = applyNamespace(newName)

	if griftList[oldName] == nil {
		return fmt.Errorf("No task named %s defined!", oldName)
	}
	griftList[newName] = griftList[oldName]
	delete(griftList, oldName)
	return nil
}

// Remove a grift. Not incredibly useful, but here for
// completeness.
func Remove(name string) error {
	lock.Lock()
	defer lock.Unlock()

	name = applyNamespace(name)

	delete(griftList, name)
	delete(descriptions, name)
	return nil
}

// Desc sets a helpful descriptive text for a grift.
// This description will be shown when `grift list`
// is run.
func Desc(name string, description string) error {
	lock.Lock()
	defer lock.Unlock()

	name = applyNamespace(name)

	descriptions[name] = description
	return nil
}

// Run a grift. This allows for the chaining for grifts.
// One grift can Run another grift and so on.
func Run(name string, c *Context) error {
	name = applyNamespace(name)

	if griftList[name] == nil {
		if name == "list" {
			PrintGrifts(os.Stdout)
			return nil
		}
		return fmt.Errorf("No task named '%s' defined!", name)
	}
	if c.Verbose {
		defer func(start time.Time) {
			log.Printf("Completed task %s in %s\n", name, time.Now().Sub(start))
		}(time.Now())
		log.Printf("Starting task %s\n", name)
	}
	return griftList[name](c)
}

// List of the names of the defined grifts.
func List() []string {
	keys := []string{}
	for k := range griftList {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}

// Exec the grift stack. This is the main "entry point" to
// the grift system.
func Exec(args []string, verbose bool) error {
	name := "list"
	if len(args) >= 1 {
		name = args[0]
	}
	switch name {
	case "list":
		PrintGrifts(os.Stdout)
	default:
		c := NewContext(name)
		c.Verbose = verbose
		if len(args) >= 1 {
			c.Args = args[1:]
		}
		return Run(name, c)
	}
	return nil
}

// PrintGrifts to the screen, nice, sorted, and with descriptions,
// should they exist.
func PrintGrifts(w io.Writer) {
	fmt.Fprint(w, "Available grifts\n================\n")

	cnLen := len(CommandName)
	maxLen := cnLen
	l := List()

	for _, k := range l {
		if (len(k) + cnLen) > maxLen {
			maxLen = len(k) + cnLen
		}
	}

	for _, k := range l {
		m := strings.Join([]string{CommandName, k}, " ")
		suffix := strings.Repeat(" ", (maxLen+3)-len(m)) + " #"

		fmt.Fprintln(w, strings.Join([]string{m, suffix, descriptions[k]}, " "))
	}
}
<commit_msg>Add RunSource<commit_after>package grift

import (
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"sort"
	"strings"
	"sync"
	"time"
)

var CommandName = "grift"
var griftList = map[string]Grift{}
var descriptions = map[string]string{}
var lock = &sync.Mutex{}
var namespace string

type Grift func(c *Context) error

// Namespace will place all tasks within the given prefix.
func Namespace(name string, s func()) error {
	defer func() {
		namespace = ""
	}()

	namespace = applyNamespace(name)
	s()
	return nil
}

func applyNamespace(name string) string {
	if namespace != "" {
		if strings.HasPrefix(name, ":") {
			return name[1:]
		}
		if name == "default" {
			return name
		}
		return fmt.Sprintf("%s:%s", namespace, name)
	}

	return name
}

// Add a grift. If there is already a grift
// with the given name the two grifts will
// be bundled together.
func Add(name string, grift Grift) error {
	lock.Lock()
	defer lock.Unlock()

	name = applyNamespace(name)

	if griftList[name] != nil {
		fn := griftList[name]
		griftList[name] = func(c *Context) error {
			err := fn(c)
			if err != nil {
				return err
			}
			return grift(c)
		}
	} else {
		griftList[name] = grift
	}
	return nil
}

// Set a grift. This is similar to `Add` but it will
// overwrite an existing grift with the same name.
func Set(name string, grift Grift) error {
	lock.Lock()
	defer lock.Unlock()
	name = applyNamespace(name)
	griftList[name] = grift
	return nil
}

// Rename a grift. Useful if you want to re-define
// an existing grift, but don't want to write over
// the original.
func Rename(oldName string, newName string) error {
	lock.Lock()
	defer lock.Unlock()

	oldName = applyNamespace(oldName)
	newName = applyNamespace(newName)

	if griftList[oldName] == nil {
		return fmt.Errorf("No task named %s defined!", oldName)
	}
	griftList[newName] = griftList[oldName]
	delete(griftList, oldName)
	return nil
}

// Remove a grift. Not incredibly useful, but here for
// completeness.
func Remove(name string) error {
	lock.Lock()
	defer lock.Unlock()

	name = applyNamespace(name)

	delete(griftList, name)
	delete(descriptions, name)
	return nil
}

// Desc sets a helpful descriptive text for a grift.
// This description will be shown when `grift list`
// is run.
func Desc(name string, description string) error {
	lock.Lock()
	defer lock.Unlock()

	name = applyNamespace(name)

	descriptions[name] = description
	return nil
}

// Run a grift. This allows for the chaining for grifts.
// One grift can Run another grift and so on.
func Run(name string, c *Context) error {
	name = applyNamespace(name)

	if griftList[name] == nil {
		if name == "list" {
			PrintGrifts(os.Stdout)
			return nil
		}
		return fmt.Errorf("No task named '%s' defined!", name)
	}
	if c.Verbose {
		defer func(start time.Time) {
			log.Printf("Completed task %s in %s\n", name, time.Now().Sub(start))
		}(time.Now())
		log.Printf("Starting task %s\n", name)
	}
	return griftList[name](c)
}

// List of the names of the defined grifts.
func List() []string {
	keys := []string{}
	for k := range griftList {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	return keys
}

// Exec the grift stack. This is the main "entry point" to
// the grift system.
func Exec(args []string, verbose bool) error {
	name := "list"
	if len(args) >= 1 {
		name = args[0]
	}
	switch name {
	case "list":
		PrintGrifts(os.Stdout)
	default:
		c := NewContext(name)
		c.Verbose = verbose
		if len(args) >= 1 {
			c.Args = args[1:]
		}
		return Run(name, c)
	}
	return nil
}

// PrintGrifts to the screen, nice, sorted, and with descriptions,
// should they exist.
func PrintGrifts(w io.Writer) {
	fmt.Fprint(w, "Available grifts\n================\n")

	cnLen := len(CommandName)
	maxLen := cnLen
	l := List()

	for _, k := range l {
		if (len(k) + cnLen) > maxLen {
			maxLen = len(k) + cnLen
		}
	}

	for _, k := range l {
		m := strings.Join([]string{CommandName, k}, " ")
		suffix := strings.Repeat(" ", (maxLen+3)-len(m)) + " #"

		fmt.Fprintln(w, strings.Join([]string{m, suffix, descriptions[k]}, " "))
	}
}
// RunSource executes the command passed as argument,
// in the current shell/context
func RunSource(cmd exec.Command) error{
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}<|endoftext|>


<commit_before>package mocks

import "github.com/stretchr/testify/mock"

import "github.com/control-center/serviced/domain/applicationendpoint"
import "github.com/control-center/serviced/domain/host"
import "github.com/control-center/serviced/domain/pool"
import "github.com/control-center/serviced/facade"
import "github.com/control-center/serviced/volume"

type ClientInterface struct {
	mock.Mock
}

func (_m *ClientInterface) Close() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) GetHost(hostID string) (*host.Host, error) {
	ret := _m.Called(hostID)

	var r0 *host.Host
	if rf, ok := ret.Get(0).(func(string) *host.Host); ok {
		r0 = rf(hostID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*host.Host)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(hostID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetHosts() ([]host.Host, error) {
	ret := _m.Called()

	var r0 []host.Host
	if rf, ok := ret.Get(0).(func() []host.Host); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]host.Host)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetActiveHostIDs() ([]string, error) {
	ret := _m.Called()

	var r0 []string
	if rf, ok := ret.Get(0).(func() []string); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]string)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) AddHost(targetHost host.Host) error {
	ret := _m.Called(targetHost)

	var r0 error
	if rf, ok := ret.Get(0).(func(host.Host) error); ok {
		r0 = rf(targetHost)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) UpdateHost(targetHost host.Host) error {
	ret := _m.Called(targetHost)

	var r0 error
	if rf, ok := ret.Get(0).(func(host.Host) error); ok {
		r0 = rf(targetHost)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) RemoveHost(hostID string) error {
	ret := _m.Called(hostID)

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(hostID)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) FindHostsInPool(poolID string) ([]host.Host, error) {
	ret := _m.Called(poolID)

	var r0 []host.Host
	if rf, ok := ret.Get(0).(func(string) []host.Host); ok {
		r0 = rf(poolID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]host.Host)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(poolID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetResourcePool(poolID string) (*pool.ResourcePool, error) {
	ret := _m.Called(poolID)

	var r0 *pool.ResourcePool
	if rf, ok := ret.Get(0).(func(string) *pool.ResourcePool); ok {
		r0 = rf(poolID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*pool.ResourcePool)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(poolID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetResourcePools() ([]pool.ResourcePool, error) {
	ret := _m.Called()

	var r0 []pool.ResourcePool
	if rf, ok := ret.Get(0).(func() []pool.ResourcePool); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]pool.ResourcePool)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) AddResourcePool(pool pool.ResourcePool) error {
	ret := _m.Called(pool)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.ResourcePool) error); ok {
		r0 = rf(pool)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) UpdateResourcePool(pool pool.ResourcePool) error {
	ret := _m.Called(pool)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.ResourcePool) error); ok {
		r0 = rf(pool)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) RemoveResourcePool(poolID string) error {
	ret := _m.Called(poolID)

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(poolID)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) GetPoolIPs(poolID string) (*facade.PoolIPs, error) {
	ret := _m.Called(poolID)

	var r0 *facade.PoolIPs
	if rf, ok := ret.Get(0).(func(string) *facade.PoolIPs); ok {
		r0 = rf(poolID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*facade.PoolIPs)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(poolID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) AddVirtualIP(requestVirtualIP pool.VirtualIP) error {
	ret := _m.Called(requestVirtualIP)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.VirtualIP) error); ok {
		r0 = rf(requestVirtualIP)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) RemoveVirtualIP(requestVirtualIP pool.VirtualIP) error {
	ret := _m.Called(requestVirtualIP)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.VirtualIP) error); ok {
		r0 = rf(requestVirtualIP)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) ServiceUse(serviceID string, imageID string, registry string, replaceImgs []string, noOp bool) (string, error) {
	ret := _m.Called(serviceID, imageID, registry, replaceImgs, noOp)

	var r0 string
	if rf, ok := ret.Get(0).(func(string, string, string, []string, bool) string); ok {
		r0 = rf(serviceID, imageID, registry, replaceImgs, noOp)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string, string, string, []string, bool) error); ok {
		r1 = rf(serviceID, imageID, registry, replaceImgs, noOp)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetVolumeStatus() (*volume.Statuses, error) {
	ret := _m.Called()

	var r0 *volume.Statuses
	if rf, ok := ret.Get(0).(func() *volume.Statuses); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*volume.Statuses)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetServiceEndpoints(serviceIDs []string, reportImports bool, reportExports bool, validate bool) ([]applicationendpoint.EndpointReport, error) {
	ret := _m.Called(serviceIDs, reportImports, reportExports, validate)

	var r0 []applicationendpoint.EndpointReport
	if rf, ok := ret.Get(0).(func([]string, bool, bool, bool) []applicationendpoint.EndpointReport); ok {
		r0 = rf(serviceIDs, reportImports, reportExports, validate)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]applicationendpoint.EndpointReport)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func([]string, bool, bool, bool) error); ok {
		r1 = rf(serviceIDs, reportImports, reportExports, validate)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) ResetRegistry() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) SyncRegistry() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) UpgradeRegistry(endpoint string, override bool) error {
	ret := _m.Called(endpoint, override)

	var r0 error
	if rf, ok := ret.Get(0).(func(string, bool) error); ok {
		r0 = rf(endpoint, override)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
<commit_msg>fixed pool name collision<commit_after>package mocks

import "github.com/stretchr/testify/mock"

import "github.com/control-center/serviced/domain/applicationendpoint"
import "github.com/control-center/serviced/domain/host"
import "github.com/control-center/serviced/domain/pool"
import "github.com/control-center/serviced/facade"
import "github.com/control-center/serviced/volume"

type ClientInterface struct {
	mock.Mock
}

func (_m *ClientInterface) Close() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) GetHost(hostID string) (*host.Host, error) {
	ret := _m.Called(hostID)

	var r0 *host.Host
	if rf, ok := ret.Get(0).(func(string) *host.Host); ok {
		r0 = rf(hostID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*host.Host)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(hostID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetHosts() ([]host.Host, error) {
	ret := _m.Called()

	var r0 []host.Host
	if rf, ok := ret.Get(0).(func() []host.Host); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]host.Host)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetActiveHostIDs() ([]string, error) {
	ret := _m.Called()

	var r0 []string
	if rf, ok := ret.Get(0).(func() []string); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]string)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) AddHost(targetHost host.Host) error {
	ret := _m.Called(targetHost)

	var r0 error
	if rf, ok := ret.Get(0).(func(host.Host) error); ok {
		r0 = rf(targetHost)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) UpdateHost(targetHost host.Host) error {
	ret := _m.Called(targetHost)

	var r0 error
	if rf, ok := ret.Get(0).(func(host.Host) error); ok {
		r0 = rf(targetHost)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) RemoveHost(hostID string) error {
	ret := _m.Called(hostID)

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(hostID)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) FindHostsInPool(poolID string) ([]host.Host, error) {
	ret := _m.Called(poolID)

	var r0 []host.Host
	if rf, ok := ret.Get(0).(func(string) []host.Host); ok {
		r0 = rf(poolID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]host.Host)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(poolID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetResourcePool(poolID string) (*pool.ResourcePool, error) {
	ret := _m.Called(poolID)

	var r0 *pool.ResourcePool
	if rf, ok := ret.Get(0).(func(string) *pool.ResourcePool); ok {
		r0 = rf(poolID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*pool.ResourcePool)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(poolID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetResourcePools() ([]pool.ResourcePool, error) {
	ret := _m.Called()

	var r0 []pool.ResourcePool
	if rf, ok := ret.Get(0).(func() []pool.ResourcePool); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]pool.ResourcePool)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) AddResourcePool(targetPool pool.ResourcePool) error {
	ret := _m.Called(targetPool)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.ResourcePool) error); ok {
		r0 = rf(targetPool)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) UpdateResourcePool(targetPool pool.ResourcePool) error {
	ret := _m.Called(targetPool)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.ResourcePool) error); ok {
		r0 = rf(targetPool)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) RemoveResourcePool(poolID string) error {
	ret := _m.Called(poolID)

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(poolID)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) GetPoolIPs(poolID string) (*facade.PoolIPs, error) {
	ret := _m.Called(poolID)

	var r0 *facade.PoolIPs
	if rf, ok := ret.Get(0).(func(string) *facade.PoolIPs); ok {
		r0 = rf(poolID)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*facade.PoolIPs)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string) error); ok {
		r1 = rf(poolID)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) AddVirtualIP(requestVirtualIP pool.VirtualIP) error {
	ret := _m.Called(requestVirtualIP)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.VirtualIP) error); ok {
		r0 = rf(requestVirtualIP)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) RemoveVirtualIP(requestVirtualIP pool.VirtualIP) error {
	ret := _m.Called(requestVirtualIP)

	var r0 error
	if rf, ok := ret.Get(0).(func(pool.VirtualIP) error); ok {
		r0 = rf(requestVirtualIP)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) ServiceUse(serviceID string, imageID string, registry string, replaceImgs []string, noOp bool) (string, error) {
	ret := _m.Called(serviceID, imageID, registry, replaceImgs, noOp)

	var r0 string
	if rf, ok := ret.Get(0).(func(string, string, string, []string, bool) string); ok {
		r0 = rf(serviceID, imageID, registry, replaceImgs, noOp)
	} else {
		r0 = ret.Get(0).(string)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(string, string, string, []string, bool) error); ok {
		r1 = rf(serviceID, imageID, registry, replaceImgs, noOp)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetVolumeStatus() (*volume.Statuses, error) {
	ret := _m.Called()

	var r0 *volume.Statuses
	if rf, ok := ret.Get(0).(func() *volume.Statuses); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*volume.Statuses)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func() error); ok {
		r1 = rf()
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) GetServiceEndpoints(serviceIDs []string, reportImports bool, reportExports bool, validate bool) ([]applicationendpoint.EndpointReport, error) {
	ret := _m.Called(serviceIDs, reportImports, reportExports, validate)

	var r0 []applicationendpoint.EndpointReport
	if rf, ok := ret.Get(0).(func([]string, bool, bool, bool) []applicationendpoint.EndpointReport); ok {
		r0 = rf(serviceIDs, reportImports, reportExports, validate)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]applicationendpoint.EndpointReport)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func([]string, bool, bool, bool) error); ok {
		r1 = rf(serviceIDs, reportImports, reportExports, validate)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}
func (_m *ClientInterface) ResetRegistry() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) SyncRegistry() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
func (_m *ClientInterface) UpgradeRegistry(endpoint string, override bool) error {
	ret := _m.Called(endpoint, override)

	var r0 error
	if rf, ok := ret.Get(0).(func(string, bool) error); ok {
		r0 = rf(endpoint, override)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"gopkg.in/yaml.v2"
)

// yaml special keys
const (
	DEFAULT_KEY = "default"
	SOURCE_KEY  = "source"
	TARGET_KEY  = "target"
)

// environment variable names
const (
	HOME_DIRECTORY = "HOME"
)

// temporary definitions for dev
const (
	SETTINGS_FILE_NAME = "dotorrc.sample.yml"
	SOURCE_PATH        = "/Users/janus/work/dev/github/dotfiles"
)

func main() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintln(os.Stderr, r)
		}
	}()

	settings, err := ReadSettings(SETTINGS_FILE_NAME)
	if err != nil {
		panic(err)
	}

	rules, err := BuildRules(settings)
	if err != nil {
		panic(err)
	}

	err = CreateSymbolicLinks(rules, SOURCE_PATH)
	if err != nil {
		panic(err)
	}
}

func ReadSettings(filepath string) (map[interface{}]interface{}, error) {
	file, err := ioutil.ReadFile(filepath)
	if err != nil {
		return nil, err
	}

	settings := make(map[interface{}]interface{})
	if err := yaml.Unmarshal(file, &settings); err != nil {
		return nil, err
	}

	return settings, nil
}

func BuildRules(settings map[interface{}]interface{}) (map[string]string, error) {
	defaultRules, err := BuildSpecificOsRules(DEFAULT_KEY, settings)
	if err != nil {
		return nil, err
	}

	osRules, err := BuildSpecificOsRules(runtime.GOOS, settings)
	if err != nil {
		return nil, err
	}

	rules := Extend(defaultRules, osRules)
	return rules, err
}

func BuildSpecificOsRules(os string, settings map[interface{}]interface{}) (map[string]string, error) {
	rules := make(map[string]string)
	if _, hasKey := settings[os]; !hasKey {
		return rules, nil
	}

	for _, value := range settings[os].([]interface{}) {
		switch value.(type) {
		case string:
			rules[value.(string)] = value.(string)
		case map[interface{}]interface{}:
			setting := value.(map[interface{}]interface{})
			_, hasSource := setting[SOURCE_KEY]
			_, hasTarget := setting[TARGET_KEY]
			if !(hasSource && hasTarget) {
				return nil, fmt.Errorf("specify key-values in format of \"%s:<source file name>\" and \"%s:<target file name>\" to change sysmbolic link names", SOURCE_KEY, TARGET_KEY)
			}
			source := setting[SOURCE_KEY].(string)
			target := setting[TARGET_KEY].(string)
			rules[source] = target
		}
	}

	return rules, nil
}

func Extend(m1, m2 map[string]string) map[string]string {
	result := map[string]string{}

	for v, k := range m1 {
		result[k] = v
	}
	for v, k := range m2 {
		result[k] = v
	}
	return (result)
}

func CreateSymbolicLinks(rules map[string]string, sourceDirectoryPath string) error {
	targetDirectoryAbsolutePath, err := GetHomeDirectory()
	if err != nil {
		return err
	}
	sourceDirectoryAbsolutePath, err := filepath.Abs(sourceDirectoryPath)
	if err != nil {
		return err
	}

	fmt.Printf("%s => %s\n", sourceDirectoryAbsolutePath, targetDirectoryAbsolutePath)

	for source, target := range rules {
		sourceAbsolutePath := filepath.Join(sourceDirectoryAbsolutePath, source)
		targetAbsolutePath := filepath.Join(targetDirectoryAbsolutePath, target)
		if !ExistsPath(sourceAbsolutePath) {
			fmt.Printf("source file \"%s\" is not exists. skipping.\n", targetAbsolutePath)
			continue
		}
		if ExistsPath(targetAbsolutePath) {
			fmt.Printf("target file \"%s\" is already exists. skipping.\n", targetAbsolutePath)
			continue
		}
		fmt.Printf("creating symbolic link: %s => %s\n", sourceAbsolutePath, targetAbsolutePath)
		// TODO: use os.Symlink()
	}

	return nil
}

func GetHomeDirectory() (dir string, err error) {
	environmentVariables := GetEnvironmentVariables()
	if _, ok := environmentVariables[HOME_DIRECTORY]; !ok {
		return "", fmt.Errorf("Define the environment variable \"%s\"", HOME_DIRECTORY)
	}
	return environmentVariables[HOME_DIRECTORY], nil
}

func GetEnvironmentVariables() map[string]string {
	environmentVariables := make(map[string]string)
	for _, item := range os.Environ() {
		splited := strings.Split(item, "=")
		environmentVariables[splited[0]] = splited[1]
	}
	return environmentVariables
}

func ExistsPath(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}
<commit_msg>[WIP] fix comments<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"gopkg.in/yaml.v2"
)

// special keys in settings
const (
	DEFAULT_KEY = "default"
	SOURCE_KEY  = "source"
	TARGET_KEY  = "target"
)

// environment variable names
const (
	HOME_DIRECTORY = "HOME"
)

// temporary definitions for dev
const (
	SETTINGS_FILE_NAME = "dotorrc.sample.yml"
	SOURCE_PATH        = "/Users/janus/work/dev/github/dotfiles"
)

func main() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintln(os.Stderr, r)
		}
	}()

	settings, err := ReadSettings(SETTINGS_FILE_NAME)
	if err != nil {
		panic(err)
	}

	rules, err := BuildRules(settings)
	if err != nil {
		panic(err)
	}

	err = CreateSymbolicLinks(rules, SOURCE_PATH)
	if err != nil {
		panic(err)
	}
}

func ReadSettings(filepath string) (map[interface{}]interface{}, error) {
	file, err := ioutil.ReadFile(filepath)
	if err != nil {
		return nil, err
	}

	settings := make(map[interface{}]interface{})
	if err := yaml.Unmarshal(file, &settings); err != nil {
		return nil, err
	}

	return settings, nil
}

func BuildRules(settings map[interface{}]interface{}) (map[string]string, error) {
	defaultRules, err := BuildSpecificOsRules(DEFAULT_KEY, settings)
	if err != nil {
		return nil, err
	}

	osRules, err := BuildSpecificOsRules(runtime.GOOS, settings)
	if err != nil {
		return nil, err
	}

	rules := Extend(defaultRules, osRules)
	return rules, err
}

func BuildSpecificOsRules(os string, settings map[interface{}]interface{}) (map[string]string, error) {
	rules := make(map[string]string)
	if _, hasKey := settings[os]; !hasKey {
		return rules, nil
	}

	for _, value := range settings[os].([]interface{}) {
		switch value.(type) {
		case string:
			rules[value.(string)] = value.(string)
		case map[interface{}]interface{}:
			setting := value.(map[interface{}]interface{})
			_, hasSource := setting[SOURCE_KEY]
			_, hasTarget := setting[TARGET_KEY]
			if !(hasSource && hasTarget) {
				return nil, fmt.Errorf("specify key-values in format of \"%s:<source file name>\" and \"%s:<target file name>\" to change sysmbolic link names", SOURCE_KEY, TARGET_KEY)
			}
			source := setting[SOURCE_KEY].(string)
			target := setting[TARGET_KEY].(string)
			rules[source] = target
		}
	}

	return rules, nil
}

func Extend(m1, m2 map[string]string) map[string]string {
	result := map[string]string{}

	for v, k := range m1 {
		result[k] = v
	}
	for v, k := range m2 {
		result[k] = v
	}
	return (result)
}

func CreateSymbolicLinks(rules map[string]string, sourceDirectoryPath string) error {
	targetDirectoryAbsolutePath, err := GetHomeDirectory()
	if err != nil {
		return err
	}
	sourceDirectoryAbsolutePath, err := filepath.Abs(sourceDirectoryPath)
	if err != nil {
		return err
	}

	fmt.Printf("%s => %s\n", sourceDirectoryAbsolutePath, targetDirectoryAbsolutePath)

	for source, target := range rules {
		sourceAbsolutePath := filepath.Join(sourceDirectoryAbsolutePath, source)
		targetAbsolutePath := filepath.Join(targetDirectoryAbsolutePath, target)
		if !ExistsPath(sourceAbsolutePath) {
			fmt.Printf("source file \"%s\" is not exists. skipping.\n", targetAbsolutePath)
			continue
		}
		if ExistsPath(targetAbsolutePath) {
			fmt.Printf("target file \"%s\" is already exists. skipping.\n", targetAbsolutePath)
			continue
		}
		fmt.Printf("creating symbolic link: %s => %s\n", sourceAbsolutePath, targetAbsolutePath)
		// TODO: use os.Symlink()
	}

	return nil
}

func GetHomeDirectory() (dir string, err error) {
	environmentVariables := GetEnvironmentVariables()
	if _, ok := environmentVariables[HOME_DIRECTORY]; !ok {
		return "", fmt.Errorf("Define the environment variable \"%s\"", HOME_DIRECTORY)
	}
	return environmentVariables[HOME_DIRECTORY], nil
}

func GetEnvironmentVariables() map[string]string {
	environmentVariables := make(map[string]string)
	for _, item := range os.Environ() {
		splited := strings.Split(item, "=")
		environmentVariables[splited[0]] = splited[1]
	}
	return environmentVariables
}

func ExistsPath(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/organizations"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsOrganizationsAccount() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsOrganizationsAccountCreate,
		Read:   resourceAwsOrganizationsAccountRead,
		Update: resourceAwsOrganizationsAccountUpdate,
		Delete: resourceAwsOrganizationsAccountDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"joined_method": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"joined_timestamp": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"parent_id": {
				Type:         schema.TypeString,
				Computed:     true,
				Optional:     true,
				ValidateFunc: validation.StringMatch(regexp.MustCompile("^(r-[0-9a-z]{4,32})|(ou-[0-9a-z]{4,32}-[a-z0-9]{8,32})$"), "see https://docs.aws.amazon.com/organizations/latest/APIReference/API_MoveAccount.html#organizations-MoveAccount-request-DestinationParentId"),
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"name": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validation.StringLenBetween(1, 50),
			},
			"email": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateAwsOrganizationsAccountEmail,
			},
			"iam_user_access_to_billing": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringInSlice([]string{organizations.IAMUserAccessToBillingAllow, organizations.IAMUserAccessToBillingDeny}, true),
			},
			"role_name": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateAwsOrganizationsAccountRoleName,
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsOrganizationsAccountCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn

	// Create the account
	createOpts := &organizations.CreateAccountInput{
		AccountName: aws.String(d.Get("name").(string)),
		Email:       aws.String(d.Get("email").(string)),
	}
	if role, ok := d.GetOk("role_name"); ok {
		createOpts.RoleName = aws.String(role.(string))
	}

	if iam_user, ok := d.GetOk("iam_user_access_to_billing"); ok {
		createOpts.IamUserAccessToBilling = aws.String(iam_user.(string))
	}

	log.Printf("[DEBUG] Creating AWS Organizations Account: %s", createOpts)

	var resp *organizations.CreateAccountOutput
	err := resource.Retry(4*time.Minute, func() *resource.RetryError {
		var err error

		resp, err = conn.CreateAccount(createOpts)

		if isAWSErr(err, organizations.ErrCodeFinalizingOrganizationException, "") {
			return resource.RetryableError(err)
		}

		if err != nil {
			return resource.NonRetryableError(err)
		}

		return nil
	})

	if isResourceTimeoutError(err) {
		resp, err = conn.CreateAccount(createOpts)
	}

	if err != nil {
		return fmt.Errorf("Error creating account: %s", err)
	}

	requestId := *resp.CreateAccountStatus.Id

	// Wait for the account to become available
	log.Printf("[DEBUG] Waiting for account request (%s) to succeed", requestId)

	stateConf := &resource.StateChangeConf{
		Pending:      []string{organizations.CreateAccountStateInProgress},
		Target:       []string{organizations.CreateAccountStateSucceeded},
		Refresh:      resourceAwsOrganizationsAccountStateRefreshFunc(conn, requestId),
		PollInterval: 10 * time.Second,
		Timeout:      5 * time.Minute,
	}
	stateResp, stateErr := stateConf.WaitForState()
	if stateErr != nil {
		return fmt.Errorf(
			"Error waiting for account request (%s) to become available: %s",
			requestId, stateErr)
	}

	// Store the ID
	accountId := stateResp.(*organizations.CreateAccountStatus).AccountId
	d.SetId(*accountId)

	if v, ok := d.GetOk("parent_id"); ok {
		newParentID := v.(string)

		existingParentID, err := resourceAwsOrganizationsAccountGetParentId(conn, d.Id())

		if err != nil {
			return fmt.Errorf("error getting AWS Organizations Account (%s) parent: %s", d.Id(), err)
		}

		if newParentID != existingParentID {
			input := &organizations.MoveAccountInput{
				AccountId:           accountId,
				SourceParentId:      aws.String(existingParentID),
				DestinationParentId: aws.String(newParentID),
			}

			if _, err := conn.MoveAccount(input); err != nil {
				return fmt.Errorf("error moving AWS Organizations Account (%s): %s", d.Id(), err)
			}
		}
	}

	if v := d.Get("tags").(map[string]interface{}); len(v) > 0 {
		if err := keyvaluetags.OrganizationsUpdateTags(conn, d.Id(), nil, v); err != nil {
			return fmt.Errorf("error adding AWS Organizations Account (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsOrganizationsAccountRead(d, meta)
}

func resourceAwsOrganizationsAccountRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn
	describeOpts := &organizations.DescribeAccountInput{
		AccountId: aws.String(d.Id()),
	}
	resp, err := conn.DescribeAccount(describeOpts)

	if isAWSErr(err, organizations.ErrCodeAccountNotFoundException, "") {
		log.Printf("[WARN] Account does not exist, removing from state: %s", d.Id())
		d.SetId("")
		return nil
	}

	if err != nil {
		return fmt.Errorf("error describing AWS Organizations Account (%s): %s", d.Id(), err)
	}

	account := resp.Account
	if account == nil {
		log.Printf("[WARN] Account does not exist, removing from state: %s", d.Id())
		d.SetId("")
		return nil
	}

	parentId, err := resourceAwsOrganizationsAccountGetParentId(conn, d.Id())
	if err != nil {
		return fmt.Errorf("error getting AWS Organizations Account (%s) parent: %s", d.Id(), err)
	}

	d.Set("arn", account.Arn)
	d.Set("email", account.Email)
	d.Set("joined_method", account.JoinedMethod)
	d.Set("joined_timestamp", aws.TimeValue(account.JoinedTimestamp).Format(time.RFC3339))
	d.Set("name", account.Name)
	d.Set("parent_id", parentId)
	d.Set("status", account.Status)

	tags, err := keyvaluetags.OrganizationsListTags(conn, d.Id())

	if err != nil {
		return fmt.Errorf("error listing tags for AWS Organizations Account (%s): %s", d.Id(), err)
	}

	if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func resourceAwsOrganizationsAccountUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn

	if d.HasChange("parent_id") {
		o, n := d.GetChange("parent_id")

		input := &organizations.MoveAccountInput{
			AccountId:           aws.String(d.Id()),
			SourceParentId:      aws.String(o.(string)),
			DestinationParentId: aws.String(n.(string)),
		}

		if _, err := conn.MoveAccount(input); err != nil {
			return fmt.Errorf("error moving AWS Organizations Account (%s): %s", d.Id(), err)
		}
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.OrganizationsUpdateTags(conn, d.Id(), o, n); err != nil {
			return fmt.Errorf("error updating AWS Organizations Account (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsOrganizationsAccountRead(d, meta)
}

func resourceAwsOrganizationsAccountDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn

	input := &organizations.RemoveAccountFromOrganizationInput{
		AccountId: aws.String(d.Id()),
	}
	log.Printf("[DEBUG] Removing AWS account from organization: %s", input)
	_, err := conn.RemoveAccountFromOrganization(input)
	if err != nil {
		if isAWSErr(err, organizations.ErrCodeAccountNotFoundException, "") {
			return nil
		}
		return err
	}
	return nil
}

// resourceAwsOrganizationsAccountStateRefreshFunc returns a resource.StateRefreshFunc
// that is used to watch a CreateAccount request
func resourceAwsOrganizationsAccountStateRefreshFunc(conn *organizations.Organizations, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		opts := &organizations.DescribeCreateAccountStatusInput{
			CreateAccountRequestId: aws.String(id),
		}
		resp, err := conn.DescribeCreateAccountStatus(opts)
		if err != nil {
			if isAWSErr(err, organizations.ErrCodeCreateAccountStatusNotFoundException, "") {
				resp = nil
			} else {
				log.Printf("Error on OrganizationAccountStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our account yet. Return an empty state.
			return nil, "", nil
		}

		accountStatus := resp.CreateAccountStatus
		if *accountStatus.State == organizations.CreateAccountStateFailed {
			return nil, *accountStatus.State, fmt.Errorf(*accountStatus.FailureReason)
		}
		return accountStatus, *accountStatus.State, nil
	}
}

func validateAwsOrganizationsAccountEmail(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if !regexp.MustCompile(`^[^\s@]+@[^\s@]+\.[^\s@]+$`).MatchString(value) {
		errors = append(errors, fmt.Errorf(
			"%q must be a valid email address", value))
	}

	if len(value) < 6 {
		errors = append(errors, fmt.Errorf(
			"%q cannot be less than 6 characters", value))
	}

	if len(value) > 64 {
		errors = append(errors, fmt.Errorf(
			"%q cannot be greater than 64 characters", value))
	}

	return
}

func validateAwsOrganizationsAccountRoleName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if !regexp.MustCompile(`^[\w+=,.@-]{1,64}$`).MatchString(value) {
		errors = append(errors, fmt.Errorf(
			"%q must consist of uppercase letters, lowercase letters, digits with no spaces, and any of the following characters: =,.@-", value))
	}

	return
}

func resourceAwsOrganizationsAccountGetParentId(conn *organizations.Organizations, childId string) (string, error) {
	input := &organizations.ListParentsInput{
		ChildId: aws.String(childId),
	}
	var parents []*organizations.Parent

	err := conn.ListParentsPages(input, func(page *organizations.ListParentsOutput, lastPage bool) bool {
		parents = append(parents, page.Parents...)

		return !lastPage
	})

	if err != nil {
		return "", err
	}

	if len(parents) == 0 {
		return "", nil
	}

	// assume there is only a single parent
	// https://docs.aws.amazon.com/organizations/latest/APIReference/API_ListParents.html
	parent := parents[0]
	return aws.StringValue(parent.Id), nil
}
<commit_msg>r/organizations_account: tech debt: replace custom validation funcs<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/organizations"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsOrganizationsAccount() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsOrganizationsAccountCreate,
		Read:   resourceAwsOrganizationsAccountRead,
		Update: resourceAwsOrganizationsAccountUpdate,
		Delete: resourceAwsOrganizationsAccountDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"joined_method": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"joined_timestamp": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"parent_id": {
				Type:         schema.TypeString,
				Computed:     true,
				Optional:     true,
				ValidateFunc: validation.StringMatch(regexp.MustCompile("^(r-[0-9a-z]{4,32})|(ou-[0-9a-z]{4,32}-[a-z0-9]{8,32})$"), "see https://docs.aws.amazon.com/organizations/latest/APIReference/API_MoveAccount.html#organizations-MoveAccount-request-DestinationParentId"),
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"name": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validation.StringLenBetween(1, 50),
			},
			"email": {
				ForceNew: true,
				Type:     schema.TypeString,
				Required: true,
				ValidateFunc: validation.All(
					validation.StringLenBetween(6, 64),
					validation.StringMatch(regexp.MustCompile(`^[^\s@]+@[^\s@]+\.[^\s@]+$`), "must be a valid email address"),
				),
			},
			"iam_user_access_to_billing": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringInSlice([]string{organizations.IAMUserAccessToBillingAllow, organizations.IAMUserAccessToBillingDeny}, true),
			},
			"role_name": {
				ForceNew:     true,
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[\w+=,.@-]{1,64}$`), "must consist of uppercase letters, lowercase letters, digits with no spaces, and any of the following characters"),
			},
			"tags": tagsSchema(),
		},
	}
}

func resourceAwsOrganizationsAccountCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn

	// Create the account
	createOpts := &organizations.CreateAccountInput{
		AccountName: aws.String(d.Get("name").(string)),
		Email:       aws.String(d.Get("email").(string)),
	}
	if role, ok := d.GetOk("role_name"); ok {
		createOpts.RoleName = aws.String(role.(string))
	}

	if iam_user, ok := d.GetOk("iam_user_access_to_billing"); ok {
		createOpts.IamUserAccessToBilling = aws.String(iam_user.(string))
	}

	log.Printf("[DEBUG] Creating AWS Organizations Account: %s", createOpts)

	var resp *organizations.CreateAccountOutput
	err := resource.Retry(4*time.Minute, func() *resource.RetryError {
		var err error

		resp, err = conn.CreateAccount(createOpts)

		if isAWSErr(err, organizations.ErrCodeFinalizingOrganizationException, "") {
			return resource.RetryableError(err)
		}

		if err != nil {
			return resource.NonRetryableError(err)
		}

		return nil
	})

	if isResourceTimeoutError(err) {
		resp, err = conn.CreateAccount(createOpts)
	}

	if err != nil {
		return fmt.Errorf("Error creating account: %s", err)
	}

	requestId := *resp.CreateAccountStatus.Id

	// Wait for the account to become available
	log.Printf("[DEBUG] Waiting for account request (%s) to succeed", requestId)

	stateConf := &resource.StateChangeConf{
		Pending:      []string{organizations.CreateAccountStateInProgress},
		Target:       []string{organizations.CreateAccountStateSucceeded},
		Refresh:      resourceAwsOrganizationsAccountStateRefreshFunc(conn, requestId),
		PollInterval: 10 * time.Second,
		Timeout:      5 * time.Minute,
	}
	stateResp, stateErr := stateConf.WaitForState()
	if stateErr != nil {
		return fmt.Errorf(
			"Error waiting for account request (%s) to become available: %s",
			requestId, stateErr)
	}

	// Store the ID
	accountId := stateResp.(*organizations.CreateAccountStatus).AccountId
	d.SetId(*accountId)

	if v, ok := d.GetOk("parent_id"); ok {
		newParentID := v.(string)

		existingParentID, err := resourceAwsOrganizationsAccountGetParentId(conn, d.Id())

		if err != nil {
			return fmt.Errorf("error getting AWS Organizations Account (%s) parent: %s", d.Id(), err)
		}

		if newParentID != existingParentID {
			input := &organizations.MoveAccountInput{
				AccountId:           accountId,
				SourceParentId:      aws.String(existingParentID),
				DestinationParentId: aws.String(newParentID),
			}

			if _, err := conn.MoveAccount(input); err != nil {
				return fmt.Errorf("error moving AWS Organizations Account (%s): %s", d.Id(), err)
			}
		}
	}

	if v := d.Get("tags").(map[string]interface{}); len(v) > 0 {
		if err := keyvaluetags.OrganizationsUpdateTags(conn, d.Id(), nil, v); err != nil {
			return fmt.Errorf("error adding AWS Organizations Account (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsOrganizationsAccountRead(d, meta)
}

func resourceAwsOrganizationsAccountRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn
	describeOpts := &organizations.DescribeAccountInput{
		AccountId: aws.String(d.Id()),
	}
	resp, err := conn.DescribeAccount(describeOpts)

	if isAWSErr(err, organizations.ErrCodeAccountNotFoundException, "") {
		log.Printf("[WARN] Account does not exist, removing from state: %s", d.Id())
		d.SetId("")
		return nil
	}

	if err != nil {
		return fmt.Errorf("error describing AWS Organizations Account (%s): %s", d.Id(), err)
	}

	account := resp.Account
	if account == nil {
		log.Printf("[WARN] Account does not exist, removing from state: %s", d.Id())
		d.SetId("")
		return nil
	}

	parentId, err := resourceAwsOrganizationsAccountGetParentId(conn, d.Id())
	if err != nil {
		return fmt.Errorf("error getting AWS Organizations Account (%s) parent: %s", d.Id(), err)
	}

	d.Set("arn", account.Arn)
	d.Set("email", account.Email)
	d.Set("joined_method", account.JoinedMethod)
	d.Set("joined_timestamp", aws.TimeValue(account.JoinedTimestamp).Format(time.RFC3339))
	d.Set("name", account.Name)
	d.Set("parent_id", parentId)
	d.Set("status", account.Status)

	tags, err := keyvaluetags.OrganizationsListTags(conn, d.Id())

	if err != nil {
		return fmt.Errorf("error listing tags for AWS Organizations Account (%s): %s", d.Id(), err)
	}

	if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}

	return nil
}

func resourceAwsOrganizationsAccountUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn

	if d.HasChange("parent_id") {
		o, n := d.GetChange("parent_id")

		input := &organizations.MoveAccountInput{
			AccountId:           aws.String(d.Id()),
			SourceParentId:      aws.String(o.(string)),
			DestinationParentId: aws.String(n.(string)),
		}

		if _, err := conn.MoveAccount(input); err != nil {
			return fmt.Errorf("error moving AWS Organizations Account (%s): %s", d.Id(), err)
		}
	}

	if d.HasChange("tags") {
		o, n := d.GetChange("tags")

		if err := keyvaluetags.OrganizationsUpdateTags(conn, d.Id(), o, n); err != nil {
			return fmt.Errorf("error updating AWS Organizations Account (%s) tags: %s", d.Id(), err)
		}
	}

	return resourceAwsOrganizationsAccountRead(d, meta)
}

func resourceAwsOrganizationsAccountDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).organizationsconn

	input := &organizations.RemoveAccountFromOrganizationInput{
		AccountId: aws.String(d.Id()),
	}
	log.Printf("[DEBUG] Removing AWS account from organization: %s", input)
	_, err := conn.RemoveAccountFromOrganization(input)
	if err != nil {
		if isAWSErr(err, organizations.ErrCodeAccountNotFoundException, "") {
			return nil
		}
		return err
	}
	return nil
}

// resourceAwsOrganizationsAccountStateRefreshFunc returns a resource.StateRefreshFunc
// that is used to watch a CreateAccount request
func resourceAwsOrganizationsAccountStateRefreshFunc(conn *organizations.Organizations, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		opts := &organizations.DescribeCreateAccountStatusInput{
			CreateAccountRequestId: aws.String(id),
		}
		resp, err := conn.DescribeCreateAccountStatus(opts)
		if err != nil {
			if isAWSErr(err, organizations.ErrCodeCreateAccountStatusNotFoundException, "") {
				resp = nil
			} else {
				log.Printf("Error on OrganizationAccountStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our account yet. Return an empty state.
			return nil, "", nil
		}

		accountStatus := resp.CreateAccountStatus
		if *accountStatus.State == organizations.CreateAccountStateFailed {
			return nil, *accountStatus.State, fmt.Errorf(*accountStatus.FailureReason)
		}
		return accountStatus, *accountStatus.State, nil
	}
}

func resourceAwsOrganizationsAccountGetParentId(conn *organizations.Organizations, childId string) (string, error) {
	input := &organizations.ListParentsInput{
		ChildId: aws.String(childId),
	}
	var parents []*organizations.Parent

	err := conn.ListParentsPages(input, func(page *organizations.ListParentsOutput, lastPage bool) bool {
		parents = append(parents, page.Parents...)

		return !lastPage
	})

	if err != nil {
		return "", err
	}

	if len(parents) == 0 {
		return "", nil
	}

	// assume there is only a single parent
	// https://docs.aws.amazon.com/organizations/latest/APIReference/API_ListParents.html
	parent := parents[0]
	return aws.StringValue(parent.Id), nil
}
<|endoftext|>