<commit_before>package core

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

type (
	Env struct {
		Namespaces    map[*string]*Namespace
		CoreNamespace *Namespace
		stdout        *Var
		stdin         *Var
		stderr        *Var
		printReadably *Var
		file          *Var
		args          *Var
		ns            *Var
		version       *Var
		Features      Set
	}
)

func versionMap() Map {
	res := EmptyArrayMap()
	parts := strings.Split(VERSION[1:], ".")
	i, _ := strconv.ParseInt(parts[0], 10, 64)
	res.Add(MakeKeyword("major"), Int{I: int(i)})
	i, _ = strconv.ParseInt(parts[1], 10, 64)
	res.Add(MakeKeyword("minor"), Int{I: int(i)})
	i, _ = strconv.ParseInt(parts[2], 10, 64)
	res.Add(MakeKeyword("incremental"), Int{I: int(i)})
	return res
}

func (env *Env) SetEnvArgs(newArgs []string) {
	args := EmptyVector
	for _, arg := range newArgs {
		args = args.Conjoin(String{S: arg})
	}
	if args.Count() > 0 {
		env.args.Value = args.Seq()
	} else {
		env.args.Value = NIL
	}
}

func NewEnv(currentNs Symbol, stdout *os.File, stdin *os.File, stderr *os.File) *Env {
	features := EmptySet()
	features.Add(MakeKeyword("default"))
	features.Add(MakeKeyword("joker"))
	res := &Env{
		Namespaces: make(map[*string]*Namespace),
		Features:   features,
	}
	res.CoreNamespace = res.EnsureNamespace(SYMBOLS.joker_core)
	res.CoreNamespace.meta = MakeMeta(nil, "Core library of Joker.", "1.0")
	res.ns = res.CoreNamespace.Intern(MakeSymbol("*ns*"))
	res.ns.Value = res.EnsureNamespace(currentNs)
	res.stdout = res.CoreNamespace.Intern(MakeSymbol("*out*"))
	res.stdout.Value = &File{stdout}
	res.stdin = res.CoreNamespace.Intern(MakeSymbol("*in*"))
	res.stdin.Value = &BufferedReader{bufio.NewReader(stdin)}
	res.stderr = res.CoreNamespace.Intern(MakeSymbol("*err*"))
	res.stderr.Value = &File{stderr}
	res.file = res.CoreNamespace.Intern(MakeSymbol("*file*"))
	res.version = res.CoreNamespace.InternVar("*joker-version*", versionMap(),
		MakeMeta(nil, `The version info for Clojure core, as a map containing :major :minor
			:incremental and :qualifier keys. Feature releases may increment
			:minor and/or :major, bugfix releases will increment :incremental.`, "1.0"))
	res.args = res.CoreNamespace.Intern(MakeSymbol("*command-line-args*"))
	res.SetEnvArgs(os.Args[1:])
	res.printReadably = res.CoreNamespace.Intern(MakeSymbol("*print-readably*"))
	res.printReadably.Value = Bool{B: true}
	res.CoreNamespace.Intern(MakeSymbol("*linter-mode*")).Value = Bool{B: LINTER_MODE}
	res.CoreNamespace.Intern(MakeSymbol("*linter-config*")).Value = EmptyArrayMap()
	return res
}

func (env *Env) CurrentNamespace() *Namespace {
	return AssertNamespace(env.ns.Value, "")
}

func (env *Env) EnsureNamespace(sym Symbol) *Namespace {
	if sym.ns != nil {
		panic(RT.NewError("Namespace's name cannot be qualified: " + sym.ToString(false)))
	}
	if env.Namespaces[sym.name] == nil {
		env.Namespaces[sym.name] = NewNamespace(sym)
	}
	return env.Namespaces[sym.name]
}

func (env *Env) NamespaceFor(ns *Namespace, s Symbol) *Namespace {
	var res *Namespace
	if s.ns == nil {
		res = ns
	} else {
		res = ns.aliases[s.ns]
		if res == nil {
			res = env.Namespaces[s.ns]
		}
	}
	return res
}

func (env *Env) ResolveIn(n *Namespace, s Symbol) (*Var, bool) {
	ns := env.NamespaceFor(n, s)
	if ns == nil {
		return nil, false
	}
	v, ok := ns.mappings[s.name]
	return v, ok
}

func (env *Env) Resolve(s Symbol) (*Var, bool) {
	return env.ResolveIn(env.CurrentNamespace(), s)
}

func (env *Env) FindNamespace(s Symbol) *Namespace {
	if s.ns != nil {
		return nil
	}
	return env.Namespaces[s.name]
}

func (env *Env) RemoveNamespace(s Symbol) *Namespace {
	if s.ns != nil {
		return nil
	}
	if s.Equals(SYMBOLS.joker_core) {
		panic(RT.NewError("Cannot remove core namespace"))
	}
	ns := env.Namespaces[s.name]
	delete(env.Namespaces, s.name)
	return ns
}

func (env *Env) ResolveSymbol(s Symbol) Symbol {
	if strings.ContainsRune(*s.name, '.') {
		return s
	}
	currentNs := env.CurrentNamespace()
	if s.ns != nil {
		ns := env.NamespaceFor(currentNs, s)
		if ns == nil || ns.Name.name == s.ns {
			if ns != nil {
				ns.isUsed = true
			}
			return s
		}
		ns.isUsed = true
		return Symbol{
			name: s.name,
			ns:   ns.Name.name,
		}
	}
	vr, ok := currentNs.mappings[s.name]
	if !ok {
		return Symbol{
			name: s.name,
			ns:   currentNs.Name.name,
		}
	}
	vr.isUsed = true
	vr.ns.isUsed = true
	return Symbol{
		name: vr.name.name,
		ns:   vr.ns.Name.name,
	}
}
<commit_msg>Revert "Make '*command-line-args*' a seq, not vector"<commit_after>package core

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

type (
	Env struct {
		Namespaces    map[*string]*Namespace
		CoreNamespace *Namespace
		stdout        *Var
		stdin         *Var
		stderr        *Var
		printReadably *Var
		file          *Var
		args          *Var
		ns            *Var
		version       *Var
		Features      Set
	}
)

func versionMap() Map {
	res := EmptyArrayMap()
	parts := strings.Split(VERSION[1:], ".")
	i, _ := strconv.ParseInt(parts[0], 10, 64)
	res.Add(MakeKeyword("major"), Int{I: int(i)})
	i, _ = strconv.ParseInt(parts[1], 10, 64)
	res.Add(MakeKeyword("minor"), Int{I: int(i)})
	i, _ = strconv.ParseInt(parts[2], 10, 64)
	res.Add(MakeKeyword("incremental"), Int{I: int(i)})
	return res
}

func (env *Env) SetEnvArgs(newArgs []string) {
	args := EmptyVector
	for _, arg := range newArgs {
		args = args.Conjoin(String{S: arg})
	}
	if args.Count() > 0 {
		env.args.Value = args
	} else {
		env.args.Value = NIL
	}
}

func NewEnv(currentNs Symbol, stdout *os.File, stdin *os.File, stderr *os.File) *Env {
	features := EmptySet()
	features.Add(MakeKeyword("default"))
	features.Add(MakeKeyword("joker"))
	res := &Env{
		Namespaces: make(map[*string]*Namespace),
		Features:   features,
	}
	res.CoreNamespace = res.EnsureNamespace(SYMBOLS.joker_core)
	res.CoreNamespace.meta = MakeMeta(nil, "Core library of Joker.", "1.0")
	res.ns = res.CoreNamespace.Intern(MakeSymbol("*ns*"))
	res.ns.Value = res.EnsureNamespace(currentNs)
	res.stdout = res.CoreNamespace.Intern(MakeSymbol("*out*"))
	res.stdout.Value = &File{stdout}
	res.stdin = res.CoreNamespace.Intern(MakeSymbol("*in*"))
	res.stdin.Value = &BufferedReader{bufio.NewReader(stdin)}
	res.stderr = res.CoreNamespace.Intern(MakeSymbol("*err*"))
	res.stderr.Value = &File{stderr}
	res.file = res.CoreNamespace.Intern(MakeSymbol("*file*"))
	res.version = res.CoreNamespace.InternVar("*joker-version*", versionMap(),
		MakeMeta(nil, `The version info for Clojure core, as a map containing :major :minor
			:incremental and :qualifier keys. Feature releases may increment
			:minor and/or :major, bugfix releases will increment :incremental.`, "1.0"))
	res.args = res.CoreNamespace.Intern(MakeSymbol("*command-line-args*"))
	res.SetEnvArgs(os.Args[1:])
	res.printReadably = res.CoreNamespace.Intern(MakeSymbol("*print-readably*"))
	res.printReadably.Value = Bool{B: true}
	res.CoreNamespace.Intern(MakeSymbol("*linter-mode*")).Value = Bool{B: LINTER_MODE}
	res.CoreNamespace.Intern(MakeSymbol("*linter-config*")).Value = EmptyArrayMap()
	return res
}

func (env *Env) CurrentNamespace() *Namespace {
	return AssertNamespace(env.ns.Value, "")
}

func (env *Env) EnsureNamespace(sym Symbol) *Namespace {
	if sym.ns != nil {
		panic(RT.NewError("Namespace's name cannot be qualified: " + sym.ToString(false)))
	}
	if env.Namespaces[sym.name] == nil {
		env.Namespaces[sym.name] = NewNamespace(sym)
	}
	return env.Namespaces[sym.name]
}

func (env *Env) NamespaceFor(ns *Namespace, s Symbol) *Namespace {
	var res *Namespace
	if s.ns == nil {
		res = ns
	} else {
		res = ns.aliases[s.ns]
		if res == nil {
			res = env.Namespaces[s.ns]
		}
	}
	return res
}

func (env *Env) ResolveIn(n *Namespace, s Symbol) (*Var, bool) {
	ns := env.NamespaceFor(n, s)
	if ns == nil {
		return nil, false
	}
	v, ok := ns.mappings[s.name]
	return v, ok
}

func (env *Env) Resolve(s Symbol) (*Var, bool) {
	return env.ResolveIn(env.CurrentNamespace(), s)
}

func (env *Env) FindNamespace(s Symbol) *Namespace {
	if s.ns != nil {
		return nil
	}
	return env.Namespaces[s.name]
}

func (env *Env) RemoveNamespace(s Symbol) *Namespace {
	if s.ns != nil {
		return nil
	}
	if s.Equals(SYMBOLS.joker_core) {
		panic(RT.NewError("Cannot remove core namespace"))
	}
	ns := env.Namespaces[s.name]
	delete(env.Namespaces, s.name)
	return ns
}

func (env *Env) ResolveSymbol(s Symbol) Symbol {
	if strings.ContainsRune(*s.name, '.') {
		return s
	}
	currentNs := env.CurrentNamespace()
	if s.ns != nil {
		ns := env.NamespaceFor(currentNs, s)
		if ns == nil || ns.Name.name == s.ns {
			if ns != nil {
				ns.isUsed = true
			}
			return s
		}
		ns.isUsed = true
		return Symbol{
			name: s.name,
			ns:   ns.Name.name,
		}
	}
	vr, ok := currentNs.mappings[s.name]
	if !ok {
		return Symbol{
			name: s.name,
			ns:   currentNs.Name.name,
		}
	}
	vr.isUsed = true
	vr.ns.isUsed = true
	return Symbol{
		name: vr.name.name,
		ns:   vr.ns.Name.name,
	}
}
<|endoftext|>


<commit_before>//Command to run test version:
//goapp serve app.yaml
//Command to deploy/update application:
//goapp deploy -application golangnode0 -version 0
//Command to test application without deploy
//goapp serve app.yaml

package main

import (
	"bytes"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
)

var statusContent string = "Default status"

type webPage struct {
	Title string
}

type gmailUser struct {
	name string
	pswd string
}

func sendMail(msg string) {
	mailUser := gmailUser{
		"golangapplication@gmail.com",
		"",
	}
	auth := smtp.PlainAuth("",
		mailUser.name,
		mailUser.pswd,
		"smtp.gmail.com",
	)
	err := smtp.SendMail(
		"smtp.gmail.com:587",
		auth,
		mailUser.name,
		[]string{"rec@mail.com"},
		[]byte(msg),
	)
	if err != nil {
		log.Fatal(err)
	}
}

func echo() {

	url := "http://golangappnode1.appspot.com"

	var jsonStr = []byte(`{"msg":"Hello!"}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	statusContent = string(body)

}

func helloWorld(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func startPage(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		templatePage, _ := template.ParseFiles("start.html")
		templatePage.Execute(w, &webPage{"simplePage"})
	case "POST":
		r.ParseForm()
		//go sendMail("Hello from test golang webapp!")
		//go sender()
		go echo()
		fmt.Fprintf(w, "Successful read command/input from web-interface! Yeah! ")
	}
}

func statusServer(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		fmt.Fprintf(w, "Get status - "+statusContent)
	case "POST":
		fmt.Fprintf(w, "Get data by params in POST - OK")
		statusContent = "POST request handled"
	}
}

func showInfo(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Information page for test project.")
	fmt.Fprintln(w, "Language - Go;")
	fmt.Fprintln(w, "Platform - Google Application Engine;")
}

func init() {
	http.HandleFunc("/", startPage)
	http.HandleFunc("/helloworld", helloWorld)
	http.HandleFunc("/showinfo", showInfo)
	http.HandleFunc("/status", statusServer)

	//Wrong code for App Enine - server cant understand what it need to show
	//http.ListenAndServe(":80", nil)
}

//this func not needed for deploy on Google App Engine, init() func replace main()
/*
func main() {
	//fmt.Println("Hello, test server started on 8080 port.\n - /helloworld - show title page\n - /showinfo - show information about this thing")
	//http.ListenAndServe(":8080", nil)
	go sender()
}*/
<commit_msg>add some POST func for tetsts<commit_after>//Command to run test version:
//goapp serve app.yaml
//Command to deploy/update application:
//goapp deploy -application golangnode0 -version 0
//Command to test application without deploy
//goapp serve app.yaml

package main

import (
	"bytes"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"

	"appengine"
	"appengine/urlfetch"
)

var statusContent string = "Default status"

type webPage struct {
	Title string
}

type gmailUser struct {
	name string
	pswd string
}

func sendMail(msg string) {
	mailUser := gmailUser{
		"golangapplication@gmail.com",
		"",
	}
	auth := smtp.PlainAuth("",
		mailUser.name,
		mailUser.pswd,
		"smtp.gmail.com",
	)
	err := smtp.SendMail(
		"smtp.gmail.com:587",
		auth,
		mailUser.name,
		[]string{"rec@mail.com"},
		[]byte(msg),
	)
	if err != nil {
		log.Fatal(err)
	}
}

//wrong func for Google App Engine deployment. Need to use appengine libs...=(
func echo() {

	url := "http://golangappnode1.appspot.com"

	var jsonStr = []byte(`{"msg":"Hello!"}`)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	statusContent = string(body)

}

func helloWorld(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func startPage(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		templatePage, _ := template.ParseFiles("start.html")
		templatePage.Execute(w, &webPage{"simplePage"})
	case "POST":
		r.ParseForm()
		//go sendMail("Hello from test golang webapp!")
		//go sender()
		go echo()
		fmt.Fprintf(w, "Successful read command/input from web-interface! Yeah! ")
	}
}

func statusServer(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		fmt.Fprintf(w, "Get status - "+statusContent)
	case "POST":
		fmt.Fprintf(w, "Get data by params in POST - OK")
		statusContent = "POST request handled"
	}
}

func testEcho(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	bs := []byte{1, 2, 3}
	buf := bytes.NewBuffer(bs)
	client := http.Client{Transport: &urlfetch.Transport{Context: c}}
	if _, err := client.Post("http://localhost:8080/", "application/octet-stream", buf); err != nil {
		fmt.Println(err)
	}
}

func showInfo(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Information page for test project.")
	fmt.Fprintln(w, "Language - Go;")
	fmt.Fprintln(w, "Platform - Google Application Engine;")
}

func init() {
	http.HandleFunc("/", startPage)
	http.HandleFunc("/helloworld", helloWorld)
	http.HandleFunc("/showinfo", showInfo)
	http.HandleFunc("/status", statusServer)

	//Wrong code for App Enine - server cant understand what it need to show
	//http.ListenAndServe(":80", nil)
}

//this func not needed for deploy on Google App Engine, init() func replace main()
/*
func main() {
	//fmt.Println("Hello, test server started on 8080 port.\n - /helloworld - show title page\n - /showinfo - show information about this thing")
	//http.ListenAndServe(":8080", nil)
	go sender()
}*/
<|endoftext|>


<commit_before>package slack

import (
	"context"
	"net/url"
	"strconv"
)

type imChannel struct {
	ID string `json:"id"`
}

type imResponseFull struct {
	NoOp          bool      `json:"no_op"`
	AlreadyClosed bool      `json:"already_closed"`
	AlreadyOpen   bool      `json:"already_open"`
	Channel       imChannel `json:"channel"`
	IMs           []IM      `json:"ims"`
	History
	SlackResponse
}

// IM contains information related to the Direct Message channel
type IM struct {
	conversation
	IsIM          bool   `json:"is_im"`
	User          string `json:"user"`
	IsUserDeleted bool   `json:"is_user_deleted"`
}

func imRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*imResponseFull, error) {
	response := &imResponseFull{}
	err := postSlackMethod(ctx, client, path, values, response, d)
	if err != nil {
		return nil, err
	}

	return response, response.Err()
}

// CloseIMChannel closes the direct message channel
func (api *Client) CloseIMChannel(channel string) (bool, bool, error) {
	return api.CloseIMChannelContext(context.Background(), channel)
}

// CloseIMChannelContext closes the direct message channel with a custom context
func (api *Client) CloseIMChannelContext(ctx context.Context, channel string) (bool, bool, error) {
	values := url.Values{
		"token":   {api.token},
		"channel": {channel},
	}

	response, err := imRequest(ctx, api.httpclient, "im.close", values, api)
	if err != nil {
		return false, false, err
	}
	return response.NoOp, response.AlreadyClosed, nil
}

// OpenIMChannel opens a direct message channel to the user provided as argument
// Returns some status and the channel ID
func (api *Client) OpenIMChannel(user string) (bool, bool, string, error) {
	return api.OpenIMChannelContext(context.Background(), user)
}

// OpenIMChannelContext opens a direct message channel to the user provided as argument with a custom context
// Returns some status and the channel ID
func (api *Client) OpenIMChannelContext(ctx context.Context, user string) (bool, bool, string, error) {
	values := url.Values{
		"token": {api.token},
		"user":  {user},
	}

	response, err := imRequest(ctx, api.httpclient, "im.open", values, api)
	if err != nil {
		return false, false, "", err
	}
	return response.NoOp, response.AlreadyOpen, response.Channel.ID, nil
}

// MarkIMChannel sets the read mark of a direct message channel to a specific point
func (api *Client) MarkIMChannel(channel, ts string) (err error) {
	return api.MarkIMChannelContext(context.Background(), channel, ts)
}

// MarkIMChannelContext sets the read mark of a direct message channel to a specific point with a custom context
func (api *Client) MarkIMChannelContext(ctx context.Context, channel, ts string) error {
	values := url.Values{
		"token":   {api.token},
		"channel": {channel},
		"ts":      {ts},
	}

	_, err := imRequest(ctx, api.httpclient, "im.mark", values, api)
	return err
}

// GetIMHistory retrieves the direct message channel history
func (api *Client) GetIMHistory(channel string, params HistoryParameters) (*History, error) {
	return api.GetIMHistoryContext(context.Background(), channel, params)
}

// GetIMHistoryContext retrieves the direct message channel history with a custom context
func (api *Client) GetIMHistoryContext(ctx context.Context, channel string, params HistoryParameters) (*History, error) {
	values := url.Values{
		"token":   {api.token},
		"channel": {channel},
	}
	if params.Latest != DEFAULT_HISTORY_LATEST {
		values.Add("latest", params.Latest)
	}
	if params.Oldest != DEFAULT_HISTORY_OLDEST {
		values.Add("oldest", params.Oldest)
	}
	if params.Count != DEFAULT_HISTORY_COUNT {
		values.Add("count", strconv.Itoa(params.Count))
	}
	if params.Inclusive != DEFAULT_HISTORY_INCLUSIVE {
		if params.Inclusive {
			values.Add("inclusive", "1")
		} else {
			values.Add("inclusive", "0")
		}
	}
	if params.Unreads != DEFAULT_HISTORY_UNREADS {
		if params.Unreads {
			values.Add("unreads", "1")
		} else {
			values.Add("unreads", "0")
		}
	}

	response, err := imRequest(ctx, api.httpclient, "im.history", values, api)
	if err != nil {
		return nil, err
	}
	return &response.History, nil
}

// GetIMChannels returns the list of direct message channels
func (api *Client) GetIMChannels() ([]IM, error) {
	return api.GetIMChannelsContext(context.Background())
}

// GetIMChannelsContext returns the list of direct message channels with a custom context
func (api *Client) GetIMChannelsContext(ctx context.Context) ([]IM, error) {
	values := url.Values{
		"token": {api.token},
	}

	response, err := imRequest(ctx, api.httpclient, "im.list", values, api)
	if err != nil {
		return nil, err
	}
	return response.IMs, nil
}
<commit_msg>remove duplicated fields<commit_after>package slack

import (
	"context"
	"net/url"
	"strconv"
)

type imChannel struct {
	ID string `json:"id"`
}

type imResponseFull struct {
	NoOp          bool      `json:"no_op"`
	AlreadyClosed bool      `json:"already_closed"`
	AlreadyOpen   bool      `json:"already_open"`
	Channel       imChannel `json:"channel"`
	IMs           []IM      `json:"ims"`
	History
	SlackResponse
}

// IM contains information related to the Direct Message channel
type IM struct {
	conversation
	IsUserDeleted bool `json:"is_user_deleted"`
}

func imRequest(ctx context.Context, client httpClient, path string, values url.Values, d debug) (*imResponseFull, error) {
	response := &imResponseFull{}
	err := postSlackMethod(ctx, client, path, values, response, d)
	if err != nil {
		return nil, err
	}

	return response, response.Err()
}

// CloseIMChannel closes the direct message channel
func (api *Client) CloseIMChannel(channel string) (bool, bool, error) {
	return api.CloseIMChannelContext(context.Background(), channel)
}

// CloseIMChannelContext closes the direct message channel with a custom context
func (api *Client) CloseIMChannelContext(ctx context.Context, channel string) (bool, bool, error) {
	values := url.Values{
		"token":   {api.token},
		"channel": {channel},
	}

	response, err := imRequest(ctx, api.httpclient, "im.close", values, api)
	if err != nil {
		return false, false, err
	}
	return response.NoOp, response.AlreadyClosed, nil
}

// OpenIMChannel opens a direct message channel to the user provided as argument
// Returns some status and the channel ID
func (api *Client) OpenIMChannel(user string) (bool, bool, string, error) {
	return api.OpenIMChannelContext(context.Background(), user)
}

// OpenIMChannelContext opens a direct message channel to the user provided as argument with a custom context
// Returns some status and the channel ID
func (api *Client) OpenIMChannelContext(ctx context.Context, user string) (bool, bool, string, error) {
	values := url.Values{
		"token": {api.token},
		"user":  {user},
	}

	response, err := imRequest(ctx, api.httpclient, "im.open", values, api)
	if err != nil {
		return false, false, "", err
	}
	return response.NoOp, response.AlreadyOpen, response.Channel.ID, nil
}

// MarkIMChannel sets the read mark of a direct message channel to a specific point
func (api *Client) MarkIMChannel(channel, ts string) (err error) {
	return api.MarkIMChannelContext(context.Background(), channel, ts)
}

// MarkIMChannelContext sets the read mark of a direct message channel to a specific point with a custom context
func (api *Client) MarkIMChannelContext(ctx context.Context, channel, ts string) error {
	values := url.Values{
		"token":   {api.token},
		"channel": {channel},
		"ts":      {ts},
	}

	_, err := imRequest(ctx, api.httpclient, "im.mark", values, api)
	return err
}

// GetIMHistory retrieves the direct message channel history
func (api *Client) GetIMHistory(channel string, params HistoryParameters) (*History, error) {
	return api.GetIMHistoryContext(context.Background(), channel, params)
}

// GetIMHistoryContext retrieves the direct message channel history with a custom context
func (api *Client) GetIMHistoryContext(ctx context.Context, channel string, params HistoryParameters) (*History, error) {
	values := url.Values{
		"token":   {api.token},
		"channel": {channel},
	}
	if params.Latest != DEFAULT_HISTORY_LATEST {
		values.Add("latest", params.Latest)
	}
	if params.Oldest != DEFAULT_HISTORY_OLDEST {
		values.Add("oldest", params.Oldest)
	}
	if params.Count != DEFAULT_HISTORY_COUNT {
		values.Add("count", strconv.Itoa(params.Count))
	}
	if params.Inclusive != DEFAULT_HISTORY_INCLUSIVE {
		if params.Inclusive {
			values.Add("inclusive", "1")
		} else {
			values.Add("inclusive", "0")
		}
	}
	if params.Unreads != DEFAULT_HISTORY_UNREADS {
		if params.Unreads {
			values.Add("unreads", "1")
		} else {
			values.Add("unreads", "0")
		}
	}

	response, err := imRequest(ctx, api.httpclient, "im.history", values, api)
	if err != nil {
		return nil, err
	}
	return &response.History, nil
}

// GetIMChannels returns the list of direct message channels
func (api *Client) GetIMChannels() ([]IM, error) {
	return api.GetIMChannelsContext(context.Background())
}

// GetIMChannelsContext returns the list of direct message channels with a custom context
func (api *Client) GetIMChannelsContext(ctx context.Context) ([]IM, error) {
	values := url.Values{
		"token": {api.token},
	}

	response, err := imRequest(ctx, api.httpclient, "im.list", values, api)
	if err != nil {
		return nil, err
	}
	return response.IMs, nil
}
<|endoftext|>


<commit_before>package is

import (
	"fmt"
	"log"
	"reflect"
	"testing"
)

// Is provides methods that leverage the existing testing capabilities found
// in the Go test framework. The methods provided allow for a more natural,
// efficient and expressive approach to writing tests. The goal is to write
// fewer lines of code while improving communication of intent.
type Is struct {
	TB         testing.TB
	strict     bool
	failFormat string
	failArgs   []interface{}
}

// New creates a new instance of the Is object and stores a reference to the
// provided testing object.
func New(tb testing.TB) *Is {
	if tb == nil {
		log.Fatalln("You must provide a testing object.")
	}
	return &Is{TB: tb, strict: true}
}

// New creates a new copy of your Is object and replaces the internal testing
// object with the provided testing object. This is useful for re-initializing
// your `is` instance inside a subtest so that it doesn't panic when using
// Strict mode.
//
// For example, creating your initial instance as such
//  is := is.New(t)
// is the convention, but this obviously shadows the `is` package namespace.
// Inside your subtest, you can do the exact same thing to initialize a locally scoped
// variable that uses the subtest's testing.T object.
func (is *Is) New(tb testing.TB) *Is {
	return &Is{
		TB:         tb,
		strict:     is.strict,
		failFormat: is.failFormat,
		failArgs:   is.failArgs,
	}
}

// Msg defines a message to print in the event of a failure. This allows you
// to print out additional information about a failure if it happens.
func (is *Is) Msg(format string, args ...interface{}) *Is {
	return &Is{
		TB:         is.TB,
		strict:     is.strict,
		failFormat: format,
		failArgs:   args,
	}
}

// AddMsg appends a message to print in the event of a failure. This allows
// you to build a failure message in multiple steps. If no message was
// previously set, simply sets the message.
//
// This method is most useful as a way of setting a default error message,
// then adding additional information to the output for specific assertions.
// For example:
//
// is := is.New(t).Msg("User ID: %d",u.ID)
// /*do things*/
// is.AddMsg("Raw Response: %s",body).Equal(res.StatusCode, http.StatusCreated)
func (is *Is) AddMsg(format string, args ...interface{}) *Is {
	if is.failFormat == "" {
		return is.Msg(format, args...)
	}
	return &Is{
		TB:         is.TB,
		strict:     is.strict,
		failFormat: fmt.Sprintf("%s - %s", is.failFormat, format),
		failArgs:   append(is.failArgs, args...),
	}
}

// Lax returns a copy of this instance of Is which does not abort the test if
// a failure occurs. Use this to run a set of tests and see all the failures
// at once.
func (is *Is) Lax() *Is {
	return &Is{
		TB:         is.TB,
		strict:     false,
		failFormat: is.failFormat,
		failArgs:   is.failArgs,
	}
}

// Strict returns a copy of this instance of Is which aborts the test if a
// failure occurs. This is the default behavior, thus this method has no
// effect unless it is used to reverse a previous call to Lax.
func (is *Is) Strict() *Is {
	return &Is{
		TB:         is.TB,
		strict:     true,
		failFormat: is.failFormat,
		failArgs:   is.failArgs,
	}
}

// Equal performs a deep compare of the provided objects and fails if they are
// not equal.
//
// Equal does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) Equal(a interface{}, b interface{}) {
	is.TB.Helper()
	if !isEqual(a, b) {
		fail(is, "expected objects '%s' and '%s' to be equal, but got: %v and %v",
			objectTypeName(a),
			objectTypeName(b), a, b)
	}
}

// NotEqual performs a deep compare of the provided objects and fails if they are
// equal.
//
// NotEqual does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) NotEqual(a interface{}, b interface{}) {
	is.TB.Helper()
	if isEqual(a, b) {
		fail(is, "expected objects '%s' and '%s' not to be equal",
			objectTypeName(a),
			objectTypeName(b))
	}
}

// OneOf performs a deep compare of the provided object and an array of
// comparison objects. It fails if the first object is not equal to one of the
// comparison objects.
//
// OneOf does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) OneOf(a interface{}, b ...interface{}) {
	is.TB.Helper()
	result := false
	for _, o := range b {
		result = isEqual(a, o)
		if result {
			break
		}
	}
	if !result {
		fail(is, "expected object '%s' to be equal to one of '%s', but got: %v and %v",
			objectTypeName(a),
			objectTypeNames(b), a, b)
	}
}

// NotOneOf performs a deep compare of the provided object and an array of
// comparison objects. It fails if the first object is equal to one of the
// comparison objects.
//
// NotOneOf does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) NotOneOf(a interface{}, b ...interface{}) {
	is.TB.Helper()
	result := false
	for _, o := range b {
		result = isEqual(a, o)
		if result {
			break
		}
	}
	if result {
		fail(is, "expected object '%s' not to be equal to one of '%s', but got: %v and %v",
			objectTypeName(a),
			objectTypeNames(b), a, b)
	}
}

// Err checks the provided error object to determine if an error is present.
func (is *Is) Err(e error) {
	is.TB.Helper()
	if isNil(e) {
		fail(is, "expected error")
	}
}

// NotErr checks the provided error object to determine if an error is not
// present.
func (is *Is) NotErr(e error) {
	is.TB.Helper()
	if !isNil(e) {
		fail(is, "expected no error, but got: %v", e)
	}
}

// Nil checks the provided object to determine if it is nil.
func (is *Is) Nil(o interface{}) {
	is.TB.Helper()
	if !isNil(o) {
		fail(is, "expected object '%s' to be nil, but got: %v", objectTypeName(o), o)
	}
}

// NotNil checks the provided object to determine if it is not nil.
func (is *Is) NotNil(o interface{}) {
	is.TB.Helper()
	if isNil(o) {
		fail(is, "expected object '%s' not to be nil", objectTypeName(o))
	}
}

// True checks the provided boolean to determine if it is true.
func (is *Is) True(b bool) {
	is.TB.Helper()
	if !b {
		fail(is, "expected boolean to be true")
	}
}

// False checks the provided boolean to determine if is false.
func (is *Is) False(b bool) {
	is.TB.Helper()
	if b {
		fail(is, "expected boolean to be false")
	}
}

// Zero checks the provided object to determine if it is the zero value
// for the type of that object. The zero value is the same as what the object
// would contain when initialized but not assigned.
//
// This method, for example, would be used to determine if a string is empty,
// an array is empty or a map is empty. It could also be used to determine if
// a number is 0.
//
// In cases such as slice, map, array and chan, a nil value is treated the
// same as an object with len == 0
func (is *Is) Zero(o interface{}) {
	is.TB.Helper()
	if !isZero(o) {
		fail(is, "expected object '%s' to be zero value, but it was: %v", objectTypeName(o), o)
	}
}

// NotZero checks the provided object to determine if it is not the zero
// value for the type of that object. The zero value is the same as what the
// object would contain when initialized but not assigned.
//
// This method, for example, would be used to determine if a string is not
// empty, an array is not empty or a map is not empty. It could also be used
// to determine if a number is not 0.
//
// In cases such as slice, map, array and chan, a nil value is treated the
// same as an object with len == 0
func (is *Is) NotZero(o interface{}) {
	is.TB.Helper()
	if isZero(o) {
		fail(is, "expected object '%s' not to be zero value", objectTypeName(o))
	}
}

// Len checks the provided object to determine if it is the same length as the
// provided length argument.
//
// If the object is not one of type array, slice or map, it will fail.
func (is *Is) Len(o interface{}, l int) {
	is.TB.Helper()
	t := reflect.TypeOf(o)
	if o == nil ||
		(t.Kind() != reflect.Array &&
			t.Kind() != reflect.Slice &&
			t.Kind() != reflect.Map) {
		fail(is, "expected object '%s' to be of length '%d', but the object is not one of array, slice or map", objectTypeName(o), l)
		return
	}

	rLen := reflect.ValueOf(o).Len()
	if rLen != l {
		fail(is, "expected object '%s' to be of length '%d' but it was: %d", objectTypeName(o), l, rLen)
	}
}

// ShouldPanic expects the provided function to panic. If the function does
// not panic, this assertion fails.
func (is *Is) ShouldPanic(f func()) {
	is.TB.Helper()
	defer func() {
		r := recover()
		if r == nil {
			fail(is, "expected function to panic")
		}
	}()
	f()
}
<commit_msg>Update output for Equal<commit_after>package is

import (
	"fmt"
	"log"
	"reflect"
	"testing"
)

// Is provides methods that leverage the existing testing capabilities found
// in the Go test framework. The methods provided allow for a more natural,
// efficient and expressive approach to writing tests. The goal is to write
// fewer lines of code while improving communication of intent.
type Is struct {
	TB         testing.TB
	strict     bool
	failFormat string
	failArgs   []interface{}
}

// New creates a new instance of the Is object and stores a reference to the
// provided testing object.
func New(tb testing.TB) *Is {
	if tb == nil {
		log.Fatalln("You must provide a testing object.")
	}
	return &Is{TB: tb, strict: true}
}

// New creates a new copy of your Is object and replaces the internal testing
// object with the provided testing object. This is useful for re-initializing
// your `is` instance inside a subtest so that it doesn't panic when using
// Strict mode.
//
// For example, creating your initial instance as such
//  is := is.New(t)
// is the convention, but this obviously shadows the `is` package namespace.
// Inside your subtest, you can do the exact same thing to initialize a locally scoped
// variable that uses the subtest's testing.T object.
func (is *Is) New(tb testing.TB) *Is {
	return &Is{
		TB:         tb,
		strict:     is.strict,
		failFormat: is.failFormat,
		failArgs:   is.failArgs,
	}
}

// Msg defines a message to print in the event of a failure. This allows you
// to print out additional information about a failure if it happens.
func (is *Is) Msg(format string, args ...interface{}) *Is {
	return &Is{
		TB:         is.TB,
		strict:     is.strict,
		failFormat: format,
		failArgs:   args,
	}
}

// AddMsg appends a message to print in the event of a failure. This allows
// you to build a failure message in multiple steps. If no message was
// previously set, simply sets the message.
//
// This method is most useful as a way of setting a default error message,
// then adding additional information to the output for specific assertions.
// For example:
//
// is := is.New(t).Msg("User ID: %d",u.ID)
// /*do things*/
// is.AddMsg("Raw Response: %s",body).Equal(res.StatusCode, http.StatusCreated)
func (is *Is) AddMsg(format string, args ...interface{}) *Is {
	if is.failFormat == "" {
		return is.Msg(format, args...)
	}
	return &Is{
		TB:         is.TB,
		strict:     is.strict,
		failFormat: fmt.Sprintf("%s - %s", is.failFormat, format),
		failArgs:   append(is.failArgs, args...),
	}
}

// Lax returns a copy of this instance of Is which does not abort the test if
// a failure occurs. Use this to run a set of tests and see all the failures
// at once.
func (is *Is) Lax() *Is {
	return &Is{
		TB:         is.TB,
		strict:     false,
		failFormat: is.failFormat,
		failArgs:   is.failArgs,
	}
}

// Strict returns a copy of this instance of Is which aborts the test if a
// failure occurs. This is the default behavior, thus this method has no
// effect unless it is used to reverse a previous call to Lax.
func (is *Is) Strict() *Is {
	return &Is{
		TB:         is.TB,
		strict:     true,
		failFormat: is.failFormat,
		failArgs:   is.failArgs,
	}
}

// Equal performs a deep compare of the provided objects and fails if they are
// not equal.
//
// Equal does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) Equal(a interface{}, b interface{}) {
	is.TB.Helper()
	if !isEqual(a, b) {
		fail(is, "expected %v (%s). got %v (%s)",
			a, objectTypeName(a),
			b, objectTypeName(b))
	}
}

// NotEqual performs a deep compare of the provided objects and fails if they are
// equal.
//
// NotEqual does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) NotEqual(a interface{}, b interface{}) {
	is.TB.Helper()
	if isEqual(a, b) {
		fail(is, "expected objects '%s' and '%s' not to be equal",
			objectTypeName(a),
			objectTypeName(b))
	}
}

// OneOf performs a deep compare of the provided object and an array of
// comparison objects. It fails if the first object is not equal to one of the
// comparison objects.
//
// OneOf does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) OneOf(a interface{}, b ...interface{}) {
	is.TB.Helper()
	result := false
	for _, o := range b {
		result = isEqual(a, o)
		if result {
			break
		}
	}
	if !result {
		fail(is, "expected object '%s' to be equal to one of '%s', but got: %v and %v",
			objectTypeName(a),
			objectTypeNames(b), a, b)
	}
}

// NotOneOf performs a deep compare of the provided object and an array of
// comparison objects. It fails if the first object is equal to one of the
// comparison objects.
//
// NotOneOf does not respect type differences. If the types are different and
// comparable (eg int32 and int64), they will be compared as though they are
// the same type.
func (is *Is) NotOneOf(a interface{}, b ...interface{}) {
	is.TB.Helper()
	result := false
	for _, o := range b {
		result = isEqual(a, o)
		if result {
			break
		}
	}
	if result {
		fail(is, "expected object '%s' not to be equal to one of '%s', but got: %v and %v",
			objectTypeName(a),
			objectTypeNames(b), a, b)
	}
}

// Err checks the provided error object to determine if an error is present.
func (is *Is) Err(e error) {
	is.TB.Helper()
	if isNil(e) {
		fail(is, "expected error")
	}
}

// NotErr checks the provided error object to determine if an error is not
// present.
func (is *Is) NotErr(e error) {
	is.TB.Helper()
	if !isNil(e) {
		fail(is, "expected no error, but got: %v", e)
	}
}

// Nil checks the provided object to determine if it is nil.
func (is *Is) Nil(o interface{}) {
	is.TB.Helper()
	if !isNil(o) {
		fail(is, "expected object '%s' to be nil, but got: %v", objectTypeName(o), o)
	}
}

// NotNil checks the provided object to determine if it is not nil.
func (is *Is) NotNil(o interface{}) {
	is.TB.Helper()
	if isNil(o) {
		fail(is, "expected object '%s' not to be nil", objectTypeName(o))
	}
}

// True checks the provided boolean to determine if it is true.
func (is *Is) True(b bool) {
	is.TB.Helper()
	if !b {
		fail(is, "expected boolean to be true")
	}
}

// False checks the provided boolean to determine if is false.
func (is *Is) False(b bool) {
	is.TB.Helper()
	if b {
		fail(is, "expected boolean to be false")
	}
}

// Zero checks the provided object to determine if it is the zero value
// for the type of that object. The zero value is the same as what the object
// would contain when initialized but not assigned.
//
// This method, for example, would be used to determine if a string is empty,
// an array is empty or a map is empty. It could also be used to determine if
// a number is 0.
//
// In cases such as slice, map, array and chan, a nil value is treated the
// same as an object with len == 0
func (is *Is) Zero(o interface{}) {
	is.TB.Helper()
	if !isZero(o) {
		fail(is, "expected object '%s' to be zero value, but it was: %v", objectTypeName(o), o)
	}
}

// NotZero checks the provided object to determine if it is not the zero
// value for the type of that object. The zero value is the same as what the
// object would contain when initialized but not assigned.
//
// This method, for example, would be used to determine if a string is not
// empty, an array is not empty or a map is not empty. It could also be used
// to determine if a number is not 0.
//
// In cases such as slice, map, array and chan, a nil value is treated the
// same as an object with len == 0
func (is *Is) NotZero(o interface{}) {
	is.TB.Helper()
	if isZero(o) {
		fail(is, "expected object '%s' not to be zero value", objectTypeName(o))
	}
}

// Len checks the provided object to determine if it is the same length as the
// provided length argument.
//
// If the object is not one of type array, slice or map, it will fail.
func (is *Is) Len(o interface{}, l int) {
	is.TB.Helper()
	t := reflect.TypeOf(o)
	if o == nil ||
		(t.Kind() != reflect.Array &&
			t.Kind() != reflect.Slice &&
			t.Kind() != reflect.Map) {
		fail(is, "expected object '%s' to be of length '%d', but the object is not one of array, slice or map", objectTypeName(o), l)
		return
	}

	rLen := reflect.ValueOf(o).Len()
	if rLen != l {
		fail(is, "expected object '%s' to be of length '%d' but it was: %d", objectTypeName(o), l, rLen)
	}
}

// ShouldPanic expects the provided function to panic. If the function does
// not panic, this assertion fails.
func (is *Is) ShouldPanic(f func()) {
	is.TB.Helper()
	defer func() {
		r := recover()
		if r == nil {
			fail(is, "expected function to panic")
		}
	}()
	f()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"github.com/coreos/coreos-cloudinit/datasource"
	"github.com/coreos/coreos-cloudinit/initialize"
	"github.com/coreos/coreos-cloudinit/network"
	"github.com/coreos/coreos-cloudinit/system"
)

const version = "0.7.5"

func main() {
	var printVersion bool
	flag.BoolVar(&printVersion, "version", false, "Print the version and exit")

	var ignoreFailure bool
	flag.BoolVar(&ignoreFailure, "ignore-failure", false, "Exits with 0 status in the event of malformed input from user-data")

	var file string
	flag.StringVar(&file, "from-file", "", "Read user-data from provided file")

	var configdrive string
	flag.StringVar(&configdrive, "from-configdrive", "", "Read user-data from provided cloud-drive directory")

	var url string
	flag.StringVar(&url, "from-url", "", "Download user-data from provided url")

	var useProcCmdline bool
	flag.BoolVar(&useProcCmdline, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=<url>', using the cloud-config served by an HTTP GET to <url>", datasource.ProcCmdlineLocation, datasource.ProcCmdlineCloudConfigFlag))

	var convertNetconf string
	flag.StringVar(&convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files (requires the -from-configdrive flag)")

	var workspace string
	flag.StringVar(&workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data")

	var sshKeyName string
	flag.StringVar(&sshKeyName, "ssh-key-name", initialize.DefaultSSHKeyName, "Add SSH keys to the system with the given name")

	flag.Parse()

	if printVersion == true {
		fmt.Printf("coreos-cloudinit version %s\n", version)
		os.Exit(0)
	}

	var ds datasource.Datasource
	if file != "" {
		ds = datasource.NewLocalFile(file)
	} else if url != "" {
		ds = datasource.NewMetadataService(url)
	} else if configdrive != "" {
		ds = datasource.NewConfigDrive(configdrive)
	} else if useProcCmdline {
		ds = datasource.NewProcCmdline()
	} else {
		fmt.Println("Provide one of --from-file, --from-configdrive, --from-url or --from-proc-cmdline")
		os.Exit(1)
	}

	if convertNetconf != "" && configdrive == "" {
		fmt.Println("-convert-netconf flag requires -from-configdrive")
		os.Exit(1)
	}

	switch convertNetconf {
	case "":
	case "debian":
	default:
		fmt.Printf("Invalid option to -convert-netconf: '%s'. Supported options: 'debian'\n", convertNetconf)
		os.Exit(1)
	}

	fmt.Printf("Fetching user-data from datasource of type %q\n", ds.Type())
	userdataBytes, err := ds.Fetch()
	if err != nil {
		fmt.Printf("Failed fetching user-data from datasource: %v\n", err)
		if ignoreFailure {
			os.Exit(0)
		} else {
			os.Exit(1)
		}
	}

	env := initialize.NewEnvironment("/", workspace)
	if len(userdataBytes) > 0 {
		if err := processUserdata(string(userdataBytes), env); err != nil {
			fmt.Printf("Failed resolving user-data: %v\n", err)
			if !ignoreFailure {
				os.Exit(1)
			}
		}
	} else {
		fmt.Println("No user data to handle.")
	}

	if convertNetconf != "" {
		if err := processNetconf(convertNetconf, configdrive); err != nil {
			fmt.Printf("Failed to process network config: %v\n", err)
			if !ignoreFailure {
				os.Exit(1)
			}
		}
	}
}

func processUserdata(userdata string, env *initialize.Environment) error {
	userdata = env.Apply(userdata)

	parsed, err := initialize.ParseUserData(userdata)
	if err != nil {
		fmt.Printf("Failed parsing user-data: %v\n", err)
		return err
	}

	err = initialize.PrepWorkspace(env.Workspace())
	if err != nil {
		fmt.Printf("Failed preparing workspace: %v\n", err)
		return err
	}

	switch t := parsed.(type) {
	case initialize.CloudConfig:
		err = initialize.Apply(t, env)
	case system.Script:
		var path string
		path, err = initialize.PersistScriptInWorkspace(t, env.Workspace())
		if err == nil {
			var name string
			name, err = system.ExecuteScript(path)
			initialize.PersistUnitNameInWorkspace(name, env.Workspace())
		}
	}

	return err
}

func processNetconf(convertNetconf, configdrive string) error {
	openstackRoot := path.Join(configdrive, "openstack")
	metadataFilename := path.Join(openstackRoot, "latest", "meta_data.json")
	metadataBytes, err := ioutil.ReadFile(metadataFilename)
	if err != nil {
		return err
	}

	var metadata struct {
		NetworkConfig struct {
			ContentPath string `json:"content_path"`
		} `json:"network_config"`
	}
	if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
		return err
	}
	configPath := metadata.NetworkConfig.ContentPath
	if configPath == "" {
		fmt.Printf("No network config specified in %q.\n", metadataFilename)
		return nil
	}

	netconfBytes, err := ioutil.ReadFile(path.Join(openstackRoot, configPath))
	if err != nil {
		return err
	}

	var interfaces []network.InterfaceGenerator
	switch convertNetconf {
	case "debian":
		interfaces, err = network.ProcessDebianNetconf(string(netconfBytes))
	default:
		return fmt.Errorf("Unsupported network config format %q", convertNetconf)
	}

	if err != nil {
		return err
	}

	if err := system.WriteNetworkdConfigs(interfaces); err != nil {
		return err
	}
	return system.RestartNetwork(interfaces)
}
<commit_msg>chore(coreos-cloudinit): bump to 0.7.5+git<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"github.com/coreos/coreos-cloudinit/datasource"
	"github.com/coreos/coreos-cloudinit/initialize"
	"github.com/coreos/coreos-cloudinit/network"
	"github.com/coreos/coreos-cloudinit/system"
)

const version = "0.7.5+git"

func main() {
	var printVersion bool
	flag.BoolVar(&printVersion, "version", false, "Print the version and exit")

	var ignoreFailure bool
	flag.BoolVar(&ignoreFailure, "ignore-failure", false, "Exits with 0 status in the event of malformed input from user-data")

	var file string
	flag.StringVar(&file, "from-file", "", "Read user-data from provided file")

	var configdrive string
	flag.StringVar(&configdrive, "from-configdrive", "", "Read user-data from provided cloud-drive directory")

	var url string
	flag.StringVar(&url, "from-url", "", "Download user-data from provided url")

	var useProcCmdline bool
	flag.BoolVar(&useProcCmdline, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=<url>', using the cloud-config served by an HTTP GET to <url>", datasource.ProcCmdlineLocation, datasource.ProcCmdlineCloudConfigFlag))

	var convertNetconf string
	flag.StringVar(&convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files (requires the -from-configdrive flag)")

	var workspace string
	flag.StringVar(&workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data")

	var sshKeyName string
	flag.StringVar(&sshKeyName, "ssh-key-name", initialize.DefaultSSHKeyName, "Add SSH keys to the system with the given name")

	flag.Parse()

	if printVersion == true {
		fmt.Printf("coreos-cloudinit version %s\n", version)
		os.Exit(0)
	}

	var ds datasource.Datasource
	if file != "" {
		ds = datasource.NewLocalFile(file)
	} else if url != "" {
		ds = datasource.NewMetadataService(url)
	} else if configdrive != "" {
		ds = datasource.NewConfigDrive(configdrive)
	} else if useProcCmdline {
		ds = datasource.NewProcCmdline()
	} else {
		fmt.Println("Provide one of --from-file, --from-configdrive, --from-url or --from-proc-cmdline")
		os.Exit(1)
	}

	if convertNetconf != "" && configdrive == "" {
		fmt.Println("-convert-netconf flag requires -from-configdrive")
		os.Exit(1)
	}

	switch convertNetconf {
	case "":
	case "debian":
	default:
		fmt.Printf("Invalid option to -convert-netconf: '%s'. Supported options: 'debian'\n", convertNetconf)
		os.Exit(1)
	}

	fmt.Printf("Fetching user-data from datasource of type %q\n", ds.Type())
	userdataBytes, err := ds.Fetch()
	if err != nil {
		fmt.Printf("Failed fetching user-data from datasource: %v\n", err)
		if ignoreFailure {
			os.Exit(0)
		} else {
			os.Exit(1)
		}
	}

	env := initialize.NewEnvironment("/", workspace)
	if len(userdataBytes) > 0 {
		if err := processUserdata(string(userdataBytes), env); err != nil {
			fmt.Printf("Failed resolving user-data: %v\n", err)
			if !ignoreFailure {
				os.Exit(1)
			}
		}
	} else {
		fmt.Println("No user data to handle.")
	}

	if convertNetconf != "" {
		if err := processNetconf(convertNetconf, configdrive); err != nil {
			fmt.Printf("Failed to process network config: %v\n", err)
			if !ignoreFailure {
				os.Exit(1)
			}
		}
	}
}

func processUserdata(userdata string, env *initialize.Environment) error {
	userdata = env.Apply(userdata)

	parsed, err := initialize.ParseUserData(userdata)
	if err != nil {
		fmt.Printf("Failed parsing user-data: %v\n", err)
		return err
	}

	err = initialize.PrepWorkspace(env.Workspace())
	if err != nil {
		fmt.Printf("Failed preparing workspace: %v\n", err)
		return err
	}

	switch t := parsed.(type) {
	case initialize.CloudConfig:
		err = initialize.Apply(t, env)
	case system.Script:
		var path string
		path, err = initialize.PersistScriptInWorkspace(t, env.Workspace())
		if err == nil {
			var name string
			name, err = system.ExecuteScript(path)
			initialize.PersistUnitNameInWorkspace(name, env.Workspace())
		}
	}

	return err
}

func processNetconf(convertNetconf, configdrive string) error {
	openstackRoot := path.Join(configdrive, "openstack")
	metadataFilename := path.Join(openstackRoot, "latest", "meta_data.json")
	metadataBytes, err := ioutil.ReadFile(metadataFilename)
	if err != nil {
		return err
	}

	var metadata struct {
		NetworkConfig struct {
			ContentPath string `json:"content_path"`
		} `json:"network_config"`
	}
	if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
		return err
	}
	configPath := metadata.NetworkConfig.ContentPath
	if configPath == "" {
		fmt.Printf("No network config specified in %q.\n", metadataFilename)
		return nil
	}

	netconfBytes, err := ioutil.ReadFile(path.Join(openstackRoot, configPath))
	if err != nil {
		return err
	}

	var interfaces []network.InterfaceGenerator
	switch convertNetconf {
	case "debian":
		interfaces, err = network.ProcessDebianNetconf(string(netconfBytes))
	default:
		return fmt.Errorf("Unsupported network config format %q", convertNetconf)
	}

	if err != nil {
		return err
	}

	if err := system.WriteNetworkdConfigs(interfaces); err != nil {
		return err
	}
	return system.RestartNetwork(interfaces)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 Citrix Systems, Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package netscaler

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
)

func (c *NitroClient) BindResource(bindToResourceType string, bindToResourceName string, bindingResourceName string, bindingResourceType string, bindingStruct interface{}) error {
	if c.ResourceExists(bindToResourceName, bindToResourceType) == false {
		return fmt.Errorf("BindTo Resource %s of type %s does not exist", bindToResourceType, bindToResourceName)
	}

	if c.ResourceExists(bindingResourceName, bindingResourceType) == false {
		return fmt.Errorf("Binding Resource %s of type %s does not exist", bindingResourceType, bindingResourceName)
	}
	binding_name := bindToResourceType + "_" + bindingResourceType + "_binding"
	nsBinding := make(map[string]interface{})
	nsBinding[binding_name] = bindingStruct

	resourceJson, err := json.Marshal(nsBinding)

	body, err := c.createResource(binding_name, resourceJson)
	if err != nil {
		log.Fatal("Failed to bind resource %s to resource %s, err=%s", bindToResourceName, bindingResourceName, err)
		return err
	}
	_ = body
	return nil
}

func (c *NitroClient) AddResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(name, resourceType) == false {

		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct

		resourceJson, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJson))

		body, err := c.createResource(resourceType, resourceJson)
		if err != nil {
			log.Fatal("Failed to create resource of type %s, name=%s, err=%s", resourceType, name, err)
			return "", err
		}
		_ = body
	}

	return name, nil
}

func (c *NitroClient) UpdateResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(name, resourceType) == true {
		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct
		resourceJson, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJson))

		body, err := c.updateResource(resourceType, name, resourceJson)
		if err != nil {
			log.Fatal(fmt.Sprintf("Failed to update resource of type %s, name=%s err=%s", resourceType, name, err))
			return "", err
		}
		_ = body
	}

	return name, nil
}

func (c *NitroClient) DeleteResource(resourceType string, resourceName string) error {

	_, err := c.listResource(resourceType, resourceName)
	if err == nil { // resource exists
		log.Printf("Found resource of type %s: %s", resourceType, resourceName)
		_, err = c.deleteResource(resourceType, resourceName)
		if err != nil {
			log.Println(fmt.Sprintf("Failed to delete resourceType %s: %s, err=%s", resourceType, resourceName, err))
			return err
		}
	} else {
		log.Printf("Resource %s already deleted ", resourceName)
	}
	return nil
}

func (c *NitroClient) UnbindResource(boundToResourceType string, boundToResourceName string, boundResourceType string, boundResourceName string, bindingFilterName string) error {

	if c.ResourceExists(boundToResourceName, boundToResourceType) == false {
		log.Println(fmt.Sprintf("Unbind: BoundTo Resource %s of type %s does not exist", boundToResourceType, boundToResourceName))
		return nil
	}

	if c.ResourceExists(boundResourceName, boundResourceType) == false {
		log.Println("Unbind: Bound Resource %s of type %s does not exist", boundResourceType, boundResourceName)
		return nil
	}

	_, err := c.unbindResource(boundToResourceType, boundToResourceName, boundResourceType, boundResourceName, bindingFilterName)
	if err != nil {
		return fmt.Errorf("Failed to unbind  %s:%s from %s:%s, err=%s", boundResourceType, boundResourceName, boundToResourceType, boundToResourceName, err)
	}

	return nil
}

func (c *NitroClient) ResourceExists(resourceName string, resourceType string) bool {
	_, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return false
	}
	log.Printf("%s %s is already present", resourceType, resourceName)
	return true
}

func (c *NitroClient) FindResource(resourceName string, resourceType string) (map[string]interface{}, error) {
	var data map[string]interface{}
	result, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, errors.New(fmt.Sprintf("No resource %s of type %s found", resourceName, resourceType))
	}
	if err = json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return data, errors.New(fmt.Sprintf("Failed to unmarshal Netscaler Response:resource %s of type %s", resourceName, resourceType))
	}
	if data[resourceType] == nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, errors.New(fmt.Sprintf("No resource %s of type %s found", resourceName, resourceType))
	}
	resource := data[resourceType].([]interface{})[0] //only one resource obviously

	return resource.(map[string]interface{}), nil
}

func (c *NitroClient) ResourceBindingExists(resourceName string, resourceType string, boundResourceType string, boundResourceFilterName string, boundResourceFilterValue string) bool {
	result, err := c.listBoundResources(resourceName, resourceType, boundResourceType, boundResourceFilterName, boundResourceFilterValue)
	if err != nil {
		log.Printf("No %s %s to %s %s binding found", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
		return false
	}

	var data map[string]interface{}
	if err := json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return false
	}
	if data[fmt.Sprintf("%s_%s_binding", resourceType, boundResourceType)] == nil {
		return false
	}

	log.Printf("%s of type  %s is bound to %s type and name %s", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
	return true
}
<commit_msg>resource type first parameter - lets make this consistent, part 3<commit_after>/*
Copyright 2016 Citrix Systems, Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package netscaler

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
)

func (c *NitroClient) BindResource(bindToResourceType string, bindToResourceName string, bindingResourceName string, bindingResourceType string, bindingStruct interface{}) error {
	if c.ResourceExists(bindToResourceType, bindToResourceName) == false {
		return fmt.Errorf("BindTo Resource %s of type %s does not exist", bindToResourceType, bindToResourceName)
	}

	if c.ResourceExists(bindingResourceType, bindingResourceName) == false {
		return fmt.Errorf("Binding Resource %s of type %s does not exist", bindingResourceType, bindingResourceName)
	}
	binding_name := bindToResourceType + "_" + bindingResourceType + "_binding"
	nsBinding := make(map[string]interface{})
	nsBinding[binding_name] = bindingStruct

	resourceJson, err := json.Marshal(nsBinding)

	body, err := c.createResource(binding_name, resourceJson)
	if err != nil {
		log.Fatal("Failed to bind resource %s to resource %s, err=%s", bindToResourceName, bindingResourceName, err)
		return err
	}
	_ = body
	return nil
}

func (c *NitroClient) AddResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(resourceType, name) == false {

		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct

		resourceJson, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJson))

		body, err := c.createResource(resourceType, resourceJson)
		if err != nil {
			log.Fatal("Failed to create resource of type %s, name=%s, err=%s", resourceType, name, err)
			return "", err
		}
		_ = body
	}

	return name, nil
}

func (c *NitroClient) UpdateResource(resourceType string, name string, resourceStruct interface{}) (string, error) {

	if c.ResourceExists(resourceType, name) == true {
		nsResource := make(map[string]interface{})
		nsResource[resourceType] = resourceStruct
		resourceJson, err := json.Marshal(nsResource)

		log.Println("Resourcejson is " + string(resourceJson))

		body, err := c.updateResource(resourceType, name, resourceJson)
		if err != nil {
			log.Fatal(fmt.Sprintf("Failed to update resource of type %s, name=%s err=%s", resourceType, name, err))
			return "", err
		}
		_ = body
	}

	return name, nil
}

func (c *NitroClient) DeleteResource(resourceType string, resourceName string) error {

	_, err := c.listResource(resourceType, resourceName)
	if err == nil { // resource exists
		log.Printf("Found resource of type %s: %s", resourceType, resourceName)
		_, err = c.deleteResource(resourceType, resourceName)
		if err != nil {
			log.Println(fmt.Sprintf("Failed to delete resourceType %s: %s, err=%s", resourceType, resourceName, err))
			return err
		}
	} else {
		log.Printf("Resource %s already deleted ", resourceName)
	}
	return nil
}

func (c *NitroClient) UnbindResource(boundToResourceType string, boundToResourceName string, boundResourceType string, boundResourceName string, bindingFilterName string) error {

	if c.ResourceExists(boundToResourceType, boundToResourceName) == false {
		log.Println(fmt.Sprintf("Unbind: BoundTo Resource %s of type %s does not exist", boundToResourceType, boundToResourceName))
		return nil
	}

	if c.ResourceExists(boundResourceType, boundResourceName) == false {
		log.Println("Unbind: Bound Resource %s of type %s does not exist", boundResourceType, boundResourceName)
		return nil
	}

	_, err := c.unbindResource(boundToResourceType, boundToResourceName, boundResourceType, boundResourceName, bindingFilterName)
	if err != nil {
		return fmt.Errorf("Failed to unbind  %s:%s from %s:%s, err=%s", boundResourceType, boundResourceName, boundToResourceType, boundToResourceName, err)
	}

	return nil
}

func (c *NitroClient) ResourceExists(resourceType string, resourceName string) bool {
	_, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return false
	}
	log.Printf("%s %s is already present", resourceType, resourceName)
	return true
}

func (c *NitroClient) FindResource(resourceType string, resourceName string) (map[string]interface{}, error) {
	var data map[string]interface{}
	result, err := c.listResource(resourceType, resourceName)
	if err != nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, errors.New(fmt.Sprintf("No resource %s of type %s found", resourceName, resourceType))
	}
	if err = json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return data, errors.New(fmt.Sprintf("Failed to unmarshal Netscaler Response:resource %s of type %s", resourceName, resourceType))
	}
	if data[resourceType] == nil {
		log.Printf("No %s %s found", resourceType, resourceName)
		return data, errors.New(fmt.Sprintf("No resource %s of type %s found", resourceName, resourceType))
	}
	resource := data[resourceType].([]interface{})[0] //only one resource obviously

	return resource.(map[string]interface{}), nil
}

func (c *NitroClient) ResourceBindingExists(resourceName string, resourceType string, boundResourceType string, boundResourceFilterName string, boundResourceFilterValue string) bool {
	result, err := c.listBoundResources(resourceName, resourceType, boundResourceType, boundResourceFilterName, boundResourceFilterValue)
	if err != nil {
		log.Printf("No %s %s to %s %s binding found", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
		return false
	}

	var data map[string]interface{}
	if err := json.Unmarshal(result, &data); err != nil {
		log.Println("Failed to unmarshal Netscaler Response!")
		return false
	}
	if data[fmt.Sprintf("%s_%s_binding", resourceType, boundResourceType)] == nil {
		return false
	}

	log.Printf("%s of type  %s is bound to %s type and name %s", resourceType, resourceName, boundResourceType, boundResourceFilterValue)
	return true
}
<|endoftext|>


<commit_before>// Plaform-dependent routines of nimble.
// This file implements them using SDL 2.

package nimble

// typedef unsigned char Uint8;
// void getSoundSamplesAdaptor(void *userdata, Uint8 *stream, int len);
import "C"

import (
	"fmt"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/sdl_ttf"
	"os"
	"reflect"
	"runtime"
	"unsafe"
)

type renderClient interface {
	Init(width, height int32) // Inform client of window size
	Render(pm PixMap)
}

var renderClientList []renderClient

func AddRenderClient(r renderClient) {
	renderClientList = append(renderClientList, r)
}

var keyMap = map[sdl.Keycode]Key{
	sdl.K_RETURN:    KeyReturn,
	sdl.K_ESCAPE:    KeyEscape,
	sdl.K_LEFT:      KeyLeft,
	sdl.K_RIGHT:     KeyRight,
	sdl.K_UP:        KeyUp,
	sdl.K_DOWN:      KeyDown,
	sdl.K_DELETE:    KeyDelete,
	sdl.K_BACKSPACE: KeyBackspace,
	sdl.K_TAB:       KeyTab,
}

// Get time in seconds.  Time zero is platform specific.
func Now() float64 {
	return float64(sdl.GetTicks()) * 0.001
}

// Creates a slice of Pixel from a raw pointer
func sliceFromPixelPtr(data unsafe.Pointer, length int) (pixels []Pixel) {
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&pixels))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(data)
	return
}

func lockTexture(tex *sdl.Texture, width int, height int) (pixels []Pixel, pitch int) {
	var data unsafe.Pointer
	err := tex.Lock(nil, &data, &pitch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "tex.Lock: %v", err)
		panic(err)
	}
	// Convert pitch units from byte to pixels
	pitch /= 4
	pixels = sliceFromPixelPtr(data, width*height)
	return
}

var winTitle string = "FIXME"
var winWidth, winHeight int = 800, 600

func sliceFromAudioStream(data unsafe.Pointer, length int) (samples []float32) {
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&samples))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(data)
	return
}

//export getSoundSamplesAdaptor
func getSoundSamplesAdaptor(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
	buf := sliceFromAudioStream(unsafe.Pointer(stream), int(length)/4)
	for i := range buf {
		buf[i] = 0
	}
	getSoundSamples(buf)
}

func Run() int {
	// All SDL calls must come from same thread.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := sdl.Init(sdl.INIT_EVERYTHING)
	if err != nil {
		panic(err)
	}
	defer sdl.Quit()

	// Install audio callback
	spec := &sdl.AudioSpec{
		Freq:     SampleRate,
		Format:   sdl.AUDIO_F32SYS,
		Channels: 1,
		Samples:  4096,
		Callback: sdl.AudioCallback(C.getSoundSamplesAdaptor),
	}
	audioDevice, err := sdl.OpenAudioDevice("", false, spec, nil, 0)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open audio device: %v\n", err)
		panic(err)
	}
	if audioDevice < 2 {
		fmt.Fprintf(os.Stderr, "Audio device=%v < 2 contrary to SDL-2 documentation\n", audioDevice, err)
	}
	sdl.PauseAudioDevice(audioDevice, false)

	// Create window
	window, err := sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		winWidth, winHeight, sdl.WINDOW_SHOWN)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %v\n", err)
		panic(err)
	}
	defer window.Destroy()

	// Create renderer
	width, height := window.GetSize()
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create renderer: %v\n", err)
		panic(err)
	}
	defer renderer.Destroy()

	// Create texture
	tex, err := renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, width, height)
	if err != nil {
		fmt.Fprintf(os.Stderr, "renderer.CreateTexture: %v\n", err)
		panic(err)
	}
	defer tex.Destroy()

	for _, r := range renderClientList {
		r.Init(int32(width), int32(height))
	}

	for {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch e := event.(type) {
			case *sdl.QuitEvent:
				return 0
			case *sdl.MouseMotionEvent:
				// Go equivalent of SDL_PRESSED seems to be missing, so compare with zero.
				if e.State != 0 {
					forwardMouseEvent(MouseDrag, int32(e.X), int32(e.Y))
				} else {
					forwardMouseEvent(MouseMove, int32(e.X), int32(e.Y))
				}
			case *sdl.MouseButtonEvent:
				switch e.Type {
				case sdl.MOUSEBUTTONDOWN:
					forwardMouseEvent(MouseDown, int32(e.X), int32(e.Y))
				case sdl.MOUSEBUTTONUP:
					forwardMouseEvent(MouseUp, int32(e.X), int32(e.Y))
				}
			case *sdl.KeyDownEvent:
				var k Key
				if 0x20 <= e.Keysym.Sym && e.Keysym.Sym < 0x7F {
					// Printable ASCII
					k = Key(e.Keysym.Sym)
				} else {
					// Try special character table
					k = keyMap[e.Keysym.Sym]
				}
				if k != 0 {
					forwardKeyEvent(k)
				}
			}
		}

		pixels, pitch := lockTexture(tex, width, height)
		pm := MakePixMap(int32(width), int32(height), pixels, int32(pitch))
		for _, r := range renderClientList {
			r.Render(pm)
		}
		tex.Unlock()

		err := renderer.Clear()
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Clear: %v", err)
			panic(err)
		}
		renderer.Copy(tex, nil, nil)
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Copy: %v", err)
			panic(err)
		}
		renderer.Present()
	}
}

// Causes Run() to return after processing any pending events.
func Quit() {
	sdl.PushEvent(&sdl.QuitEvent{Type: sdl.QUIT})
}

type Font ttf.Font

func OpenFont(filename string, size int) (*Font, error) {
	if !ttf.WasInit() {
		ttf.Init()
	}
	f, err := ttf.OpenFont(filename, size)
	return (*Font)(f), err
}

func (f *Font) Close() {
	f.Close()
}

func (pm *PixMap) DrawText(x, y int32, text string, color Pixel, font *Font) (width, height int32) {
	c := sdl.Color{R: uint8(color >> redShift),
		G: uint8(color >> greenShift),
		B: uint8(color >> blueShift),
		A: uint8(color >> alphaShift)}
	tmp, err := (*ttf.Font)(font).RenderUTF8_Solid(text, c)
	if err != nil {
		fmt.Fprintf(os.Stderr, "RenderUTF8_Solid: %v", err)
		panic(err)
	}
	defer tmp.Free()
	width, height = tmp.W, tmp.H
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&pm.buf))
	dst, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(sliceHeader.Data),
		int(pm.width), int(pm.height), 32, int(pm.vstride*4),
		0xFF<<redShift, 0xFF<<greenShift, 0xFF<<blueShift, 0xFF<<alphaShift)
	if err != nil {
		fmt.Fprintf(os.Stderr, "CreateRGBSurfaceFrom: %v", err)
		panic(err)
	}
	defer dst.Free()
	err = tmp.Blit(nil, dst, &sdl.Rect{X: x, Y: y, W: tmp.W, H: tmp.H})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Blit: %v\n", err)
		panic(err)
	}
	return
}

func (f *Font) Height() int32 {
    return int32((*ttf.Font)(f).Height())
}

func (f *Font) Size(text string) (width, height int32) {
	w, h, err := (*ttf.Font)(f).SizeUTF8(text)
	if err != nil {
		fmt.Fprintf(os.Stderr, "SizeUTF8: %v\n", err)
		panic(err)
	}
	return int32(w), int32(h)
}
<commit_msg>Fix problem with drawig empty string of text.<commit_after>// Plaform-dependent routines of nimble.
// This file implements them using SDL 2.

package nimble

// typedef unsigned char Uint8;
// void getSoundSamplesAdaptor(void *userdata, Uint8 *stream, int len);
import "C"

import (
	"fmt"
	"github.com/veandco/go-sdl2/sdl"
	"github.com/veandco/go-sdl2/sdl_ttf"
	"os"
	"reflect"
	"runtime"
	"unsafe"
)

type renderClient interface {
	Init(width, height int32) // Inform client of window size
	Render(pm PixMap)
}

var renderClientList []renderClient

func AddRenderClient(r renderClient) {
	renderClientList = append(renderClientList, r)
}

var keyMap = map[sdl.Keycode]Key{
	sdl.K_RETURN:    KeyReturn,
	sdl.K_ESCAPE:    KeyEscape,
	sdl.K_LEFT:      KeyLeft,
	sdl.K_RIGHT:     KeyRight,
	sdl.K_UP:        KeyUp,
	sdl.K_DOWN:      KeyDown,
	sdl.K_DELETE:    KeyDelete,
	sdl.K_BACKSPACE: KeyBackspace,
	sdl.K_TAB:       KeyTab,
}

// Get time in seconds.  Time zero is platform specific.
func Now() float64 {
	return float64(sdl.GetTicks()) * 0.001
}

// Creates a slice of Pixel from a raw pointer
func sliceFromPixelPtr(data unsafe.Pointer, length int) (pixels []Pixel) {
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&pixels))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(data)
	return
}

func lockTexture(tex *sdl.Texture, width int, height int) (pixels []Pixel, pitch int) {
	var data unsafe.Pointer
	err := tex.Lock(nil, &data, &pitch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "tex.Lock: %v", err)
		panic(err)
	}
	// Convert pitch units from byte to pixels
	pitch /= 4
	pixels = sliceFromPixelPtr(data, width*height)
	return
}

var winTitle string = "FIXME"
var winWidth, winHeight int = 800, 600

func sliceFromAudioStream(data unsafe.Pointer, length int) (samples []float32) {
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&samples))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(data)
	return
}

//export getSoundSamplesAdaptor
func getSoundSamplesAdaptor(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
	buf := sliceFromAudioStream(unsafe.Pointer(stream), int(length)/4)
	for i := range buf {
		buf[i] = 0
	}
	getSoundSamples(buf)
}

func Run() int {
	// All SDL calls must come from same thread.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := sdl.Init(sdl.INIT_EVERYTHING)
	if err != nil {
		panic(err)
	}
	defer sdl.Quit()

	// Install audio callback
	spec := &sdl.AudioSpec{
		Freq:     SampleRate,
		Format:   sdl.AUDIO_F32SYS,
		Channels: 1,
		Samples:  4096,
		Callback: sdl.AudioCallback(C.getSoundSamplesAdaptor),
	}
	audioDevice, err := sdl.OpenAudioDevice("", false, spec, nil, 0)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open audio device: %v\n", err)
		panic(err)
	}
	if audioDevice < 2 {
		fmt.Fprintf(os.Stderr, "Audio device=%v < 2 contrary to SDL-2 documentation\n", audioDevice, err)
	}
	sdl.PauseAudioDevice(audioDevice, false)

	// Create window
	window, err := sdl.CreateWindow(winTitle, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		winWidth, winHeight, sdl.WINDOW_SHOWN)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create window: %v\n", err)
		panic(err)
	}
	defer window.Destroy()

	// Create renderer
	width, height := window.GetSize()
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create renderer: %v\n", err)
		panic(err)
	}
	defer renderer.Destroy()

	// Create texture
	tex, err := renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, width, height)
	if err != nil {
		fmt.Fprintf(os.Stderr, "renderer.CreateTexture: %v\n", err)
		panic(err)
	}
	defer tex.Destroy()

	for _, r := range renderClientList {
		r.Init(int32(width), int32(height))
	}

	for {
		for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
			switch e := event.(type) {
			case *sdl.QuitEvent:
				return 0
			case *sdl.MouseMotionEvent:
				// Go equivalent of SDL_PRESSED seems to be missing, so compare with zero.
				if e.State != 0 {
					forwardMouseEvent(MouseDrag, int32(e.X), int32(e.Y))
				} else {
					forwardMouseEvent(MouseMove, int32(e.X), int32(e.Y))
				}
			case *sdl.MouseButtonEvent:
				switch e.Type {
				case sdl.MOUSEBUTTONDOWN:
					forwardMouseEvent(MouseDown, int32(e.X), int32(e.Y))
				case sdl.MOUSEBUTTONUP:
					forwardMouseEvent(MouseUp, int32(e.X), int32(e.Y))
				}
			case *sdl.KeyDownEvent:
				var k Key
				if 0x20 <= e.Keysym.Sym && e.Keysym.Sym < 0x7F {
					// Printable ASCII
					k = Key(e.Keysym.Sym)
				} else {
					// Try special character table
					k = keyMap[e.Keysym.Sym]
				}
				if k != 0 {
					forwardKeyEvent(k)
				}
			}
		}

		pixels, pitch := lockTexture(tex, width, height)
		pm := MakePixMap(int32(width), int32(height), pixels, int32(pitch))
		for _, r := range renderClientList {
			r.Render(pm)
		}
		tex.Unlock()

		err := renderer.Clear()
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Clear: %v", err)
			panic(err)
		}
		renderer.Copy(tex, nil, nil)
		if err != nil {
			fmt.Fprintf(os.Stderr, "renderer.Copy: %v", err)
			panic(err)
		}
		renderer.Present()
	}
}

// Causes Run() to return after processing any pending events.
func Quit() {
	sdl.PushEvent(&sdl.QuitEvent{Type: sdl.QUIT})
}

type Font ttf.Font

func OpenFont(filename string, size int) (*Font, error) {
	if !ttf.WasInit() {
		ttf.Init()
	}
	f, err := ttf.OpenFont(filename, size)
	return (*Font)(f), err
}

func (f *Font) Close() {
	f.Close()
}

func (pm *PixMap) DrawText(x, y int32, text string, color Pixel, font *Font) (width, height int32) {
	if text == "" {
		return 0, font.Height()
	}
	c := sdl.Color{R: uint8(color >> redShift),
		G: uint8(color >> greenShift),
		B: uint8(color >> blueShift),
		A: uint8(color >> alphaShift)}
	tmp, err := (*ttf.Font)(font).RenderUTF8_Solid(text, c)
	if err != nil {
		fmt.Fprintf(os.Stderr, "RenderUTF8_Solid: %v", err)
		panic(err)
	}
	defer tmp.Free()
	width, height = tmp.W, tmp.H
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&pm.buf))
	dst, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(sliceHeader.Data),
		int(pm.width), int(pm.height), 32, int(pm.vstride*4),
		0xFF<<redShift, 0xFF<<greenShift, 0xFF<<blueShift, 0xFF<<alphaShift)
	if err != nil {
		fmt.Fprintf(os.Stderr, "CreateRGBSurfaceFrom: %v", err)
		panic(err)
	}
	defer dst.Free()
	err = tmp.Blit(nil, dst, &sdl.Rect{X: x, Y: y, W: tmp.W, H: tmp.H})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Blit: %v\n", err)
		panic(err)
	}
	return
}

func (f *Font) Height() int32 {
	return int32((*ttf.Font)(f).Height())
}

func (f *Font) Size(text string) (width, height int32) {
	w, h, err := (*ttf.Font)(f).SizeUTF8(text)
	if err != nil {
		fmt.Fprintf(os.Stderr, "SizeUTF8: %v\n", err)
		panic(err)
	}
	return int32(w), int32(h)
}
<|endoftext|>


<commit_before>package nomad

import (
	"fmt"
	"math"
	"time"

	"github.com/hashicorp/nomad/nomad/state"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/scheduler"
)

// CoreScheduler is a special "scheduler" that is registered
// as "_core". It is used to run various administrative work
// across the cluster.
type CoreScheduler struct {
	srv  *Server
	snap *state.StateSnapshot
}

// NewCoreScheduler is used to return a new system scheduler instance
func NewCoreScheduler(srv *Server, snap *state.StateSnapshot) scheduler.Scheduler {
	s := &CoreScheduler{
		srv:  srv,
		snap: snap,
	}
	return s
}

// Process is used to implement the scheduler.Scheduler interface
func (s *CoreScheduler) Process(eval *structs.Evaluation) error {
	switch eval.JobID {
	case structs.CoreJobEvalGC:
		return s.evalGC(eval)
	case structs.CoreJobNodeGC:
		return s.nodeGC(eval)
	case structs.CoreJobJobGC:
		return s.jobGC(eval)
	default:
		return fmt.Errorf("core scheduler cannot handle job '%s'", eval.JobID)
	}
}

// jobGC is used to garbage collect eligible jobs.
func (c *CoreScheduler) jobGC(eval *structs.Evaluation) error {
	// Get all the jobs eligible for garbage collection.
	iter, err := c.snap.JobsByGC(true)
	if err != nil {
		return err
	}

	var oldThreshold uint64
	if eval.TriggeredBy == structs.EvalTriggerForceGC {
		// The GC was forced, so set the threshold to its maximum so everything
		// will GC.
		oldThreshold = math.MaxUint64
		c.srv.logger.Println("[DEBUG] sched.core: forced job GC")
	} else {
		// Get the time table to calculate GC cutoffs.
		tt := c.srv.fsm.TimeTable()
		cutoff := time.Now().UTC().Add(-1 * c.srv.config.JobGCThreshold)
		oldThreshold = tt.NearestIndex(cutoff)
	}
	c.srv.logger.Printf("[DEBUG] sched.core: job GC: scanning before index %d (%v)",
		oldThreshold, c.srv.config.JobGCThreshold)

	// Collect the allocations, evaluations and jobs to GC
	var gcAlloc, gcEval, gcJob []string

OUTER:
	for i := iter.Next(); i != nil; i = iter.Next() {
		job := i.(*structs.Job)

		// Ignore new jobs.
		if job.CreateIndex > oldThreshold {
			continue
		}

		evals, err := c.snap.EvalsByJob(job.ID)
		if err != nil {
			c.srv.logger.Printf("[ERR] sched.core: failed to get evals for job %s: %v", job.ID, err)
			continue
		}

		for _, eval := range evals {
			gc, allocs, err := c.gcEval(eval, oldThreshold)
			if err != nil || !gc {
				continue OUTER
			}

			gcEval = append(gcEval, eval.ID)
			gcAlloc = append(gcAlloc, allocs...)
		}

		// Job is eligible for garbage collection
		gcJob = append(gcJob, job.ID)
	}

	// Fast-path the nothing case
	if len(gcEval) == 0 && len(gcAlloc) == 0 && len(gcJob) == 0 {
		return nil
	}
	c.srv.logger.Printf("[DEBUG] sched.core: job GC: %d jobs, %d evaluations, %d allocs eligible",
		len(gcJob), len(gcEval), len(gcAlloc))

	// Reap the evals and allocs
	if err := c.evalReap(gcEval, gcAlloc); err != nil {
		return err
	}

	// Call to the leader to deregister the jobs.
	for _, job := range gcJob {
		req := structs.JobDeregisterRequest{
			JobID: job,
			WriteRequest: structs.WriteRequest{
				Region: c.srv.config.Region,
			},
		}
		var resp structs.JobDeregisterResponse
		if err := c.srv.RPC("Job.Deregister", &req, &resp); err != nil {
			c.srv.logger.Printf("[ERR] sched.core: job deregister failed: %v", err)
			return err
		}
	}

	return nil
}

// evalGC is used to garbage collect old evaluations
func (c *CoreScheduler) evalGC(eval *structs.Evaluation) error {
	// Iterate over the evaluations
	iter, err := c.snap.Evals()
	if err != nil {
		return err
	}

	var oldThreshold uint64
	if eval.TriggeredBy == structs.EvalTriggerForceGC {
		// The GC was forced, so set the threshold to its maximum so everything
		// will GC.
		oldThreshold = math.MaxUint64
		c.srv.logger.Println("[DEBUG] sched.core: forced eval GC")
	} else {
		// Compute the old threshold limit for GC using the FSM
		// time table.  This is a rough mapping of a time to the
		// Raft index it belongs to.
		tt := c.srv.fsm.TimeTable()
		cutoff := time.Now().UTC().Add(-1 * c.srv.config.EvalGCThreshold)
		oldThreshold = tt.NearestIndex(cutoff)
	}
	c.srv.logger.Printf("[DEBUG] sched.core: eval GC: scanning before index %d (%v)",
		oldThreshold, c.srv.config.EvalGCThreshold)

	// Collect the allocations and evaluations to GC
	var gcAlloc, gcEval []string
	for raw := iter.Next(); raw != nil; raw = iter.Next() {
		eval := raw.(*structs.Evaluation)
		gc, allocs, err := c.gcEval(eval, oldThreshold)
		if err != nil {
			return err
		}

		if gc {
			gcEval = append(gcEval, eval.ID)
			gcAlloc = append(gcAlloc, allocs...)
		}
	}

	// Fast-path the nothing case
	if len(gcEval) == 0 && len(gcAlloc) == 0 {
		return nil
	}
	c.srv.logger.Printf("[DEBUG] sched.core: eval GC: %d evaluations, %d allocs eligible",
		len(gcEval), len(gcAlloc))

	return c.evalReap(gcEval, gcAlloc)
}

// gcEval returns whether the eval should be garbage collected given a raft
// threshold index. The eval disqualifies for garbage collection if it or its
// allocs are not older than the threshold. If the eval should be garbage
// collected, the associated alloc ids that should also be removed are also
// returned
func (c *CoreScheduler) gcEval(eval *structs.Evaluation, thresholdIndex uint64) (
	bool, []string, error) {
	// Ignore non-terminal and new evaluations
	if !eval.TerminalStatus() || eval.ModifyIndex > thresholdIndex {
		return false, nil, nil
	}

	// Get the allocations by eval
	allocs, err := c.snap.AllocsByEval(eval.ID)
	if err != nil {
		c.srv.logger.Printf("[ERR] sched.core: failed to get allocs for eval %s: %v",
			eval.ID, err)
		return false, nil, err
	}

	// Scan the allocations to ensure they are terminal and old
	for _, alloc := range allocs {
		// TODO: This can go away once the scheduler marks an alloc as
		// DesiredStatusStop when a client fails.
		allocTerminal := alloc.TerminalStatus() ||
			alloc.ClientStatus == structs.AllocClientStatusDead ||
			alloc.ClientStatus == structs.AllocClientStatusFailed
		if !allocTerminal || alloc.ModifyIndex > thresholdIndex {
			return false, nil, nil
		}
	}

	allocIds := make([]string, len(allocs))
	for i, alloc := range allocs {
		allocIds[i] = alloc.ID
	}

	// Evaluation is eligible for garbage collection
	return true, allocIds, nil
}

// evalReap contacts the leader and issues a reap on the passed evals and
// allocs.
func (c *CoreScheduler) evalReap(evals, allocs []string) error {
	// Call to the leader to issue the reap
	req := structs.EvalDeleteRequest{
		Evals:  evals,
		Allocs: allocs,
		WriteRequest: structs.WriteRequest{
			Region: c.srv.config.Region,
		},
	}
	var resp structs.GenericResponse
	if err := c.srv.RPC("Eval.Reap", &req, &resp); err != nil {
		c.srv.logger.Printf("[ERR] sched.core: eval reap failed: %v", err)
		return err
	}

	return nil
}

// nodeGC is used to garbage collect old nodes
func (c *CoreScheduler) nodeGC(eval *structs.Evaluation) error {
	// Iterate over the evaluations
	iter, err := c.snap.Nodes()
	if err != nil {
		return err
	}

	var oldThreshold uint64
	if eval.TriggeredBy == structs.EvalTriggerForceGC {
		// The GC was forced, so set the threshold to its maximum so everything
		// will GC.
		oldThreshold = math.MaxUint64
		c.srv.logger.Println("[DEBUG] sched.core: forced node GC")
	} else {
		// Compute the old threshold limit for GC using the FSM
		// time table.  This is a rough mapping of a time to the
		// Raft index it belongs to.
		tt := c.srv.fsm.TimeTable()
		cutoff := time.Now().UTC().Add(-1 * c.srv.config.NodeGCThreshold)
		oldThreshold = tt.NearestIndex(cutoff)
	}
	c.srv.logger.Printf("[DEBUG] sched.core: node GC: scanning before index %d (%v)",
		oldThreshold, c.srv.config.NodeGCThreshold)

	// Collect the nodes to GC
	var gcNode []string
	for {
		raw := iter.Next()
		if raw == nil {
			break
		}
		node := raw.(*structs.Node)

		// Ignore non-terminal and new nodes
		if !node.TerminalStatus() || node.ModifyIndex > oldThreshold {
			continue
		}

		// Get the allocations by node
		allocs, err := c.snap.AllocsByNode(node.ID)
		if err != nil {
			c.srv.logger.Printf("[ERR] sched.core: failed to get allocs for node %s: %v",
				eval.ID, err)
			continue
		}

		// If there are any allocations, skip the node
		if len(allocs) > 0 {
			continue
		}

		// Node is eligible for garbage collection
		gcNode = append(gcNode, node.ID)
	}

	// Fast-path the nothing case
	if len(gcNode) == 0 {
		return nil
	}
	c.srv.logger.Printf("[DEBUG] sched.core: node GC: %d nodes eligible", len(gcNode))

	// Call to the leader to issue the reap
	for _, nodeID := range gcNode {
		req := structs.NodeDeregisterRequest{
			NodeID: nodeID,
			WriteRequest: structs.WriteRequest{
				Region: c.srv.config.Region,
			},
		}
		var resp structs.NodeUpdateResponse
		if err := c.srv.RPC("Node.Deregister", &req, &resp); err != nil {
			c.srv.logger.Printf("[ERR] sched.core: node '%s' reap failed: %v", nodeID, err)
			return err
		}
	}
	return nil
}
<commit_msg>Dead->Complete<commit_after>package nomad

import (
	"fmt"
	"math"
	"time"

	"github.com/hashicorp/nomad/nomad/state"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/scheduler"
)

// CoreScheduler is a special "scheduler" that is registered
// as "_core". It is used to run various administrative work
// across the cluster.
type CoreScheduler struct {
	srv  *Server
	snap *state.StateSnapshot
}

// NewCoreScheduler is used to return a new system scheduler instance
func NewCoreScheduler(srv *Server, snap *state.StateSnapshot) scheduler.Scheduler {
	s := &CoreScheduler{
		srv:  srv,
		snap: snap,
	}
	return s
}

// Process is used to implement the scheduler.Scheduler interface
func (s *CoreScheduler) Process(eval *structs.Evaluation) error {
	switch eval.JobID {
	case structs.CoreJobEvalGC:
		return s.evalGC(eval)
	case structs.CoreJobNodeGC:
		return s.nodeGC(eval)
	case structs.CoreJobJobGC:
		return s.jobGC(eval)
	default:
		return fmt.Errorf("core scheduler cannot handle job '%s'", eval.JobID)
	}
}

// jobGC is used to garbage collect eligible jobs.
func (c *CoreScheduler) jobGC(eval *structs.Evaluation) error {
	// Get all the jobs eligible for garbage collection.
	iter, err := c.snap.JobsByGC(true)
	if err != nil {
		return err
	}

	var oldThreshold uint64
	if eval.TriggeredBy == structs.EvalTriggerForceGC {
		// The GC was forced, so set the threshold to its maximum so everything
		// will GC.
		oldThreshold = math.MaxUint64
		c.srv.logger.Println("[DEBUG] sched.core: forced job GC")
	} else {
		// Get the time table to calculate GC cutoffs.
		tt := c.srv.fsm.TimeTable()
		cutoff := time.Now().UTC().Add(-1 * c.srv.config.JobGCThreshold)
		oldThreshold = tt.NearestIndex(cutoff)
	}
	c.srv.logger.Printf("[DEBUG] sched.core: job GC: scanning before index %d (%v)",
		oldThreshold, c.srv.config.JobGCThreshold)

	// Collect the allocations, evaluations and jobs to GC
	var gcAlloc, gcEval, gcJob []string

OUTER:
	for i := iter.Next(); i != nil; i = iter.Next() {
		job := i.(*structs.Job)

		// Ignore new jobs.
		if job.CreateIndex > oldThreshold {
			continue
		}

		evals, err := c.snap.EvalsByJob(job.ID)
		if err != nil {
			c.srv.logger.Printf("[ERR] sched.core: failed to get evals for job %s: %v", job.ID, err)
			continue
		}

		for _, eval := range evals {
			gc, allocs, err := c.gcEval(eval, oldThreshold)
			if err != nil || !gc {
				continue OUTER
			}

			gcEval = append(gcEval, eval.ID)
			gcAlloc = append(gcAlloc, allocs...)
		}

		// Job is eligible for garbage collection
		gcJob = append(gcJob, job.ID)
	}

	// Fast-path the nothing case
	if len(gcEval) == 0 && len(gcAlloc) == 0 && len(gcJob) == 0 {
		return nil
	}
	c.srv.logger.Printf("[DEBUG] sched.core: job GC: %d jobs, %d evaluations, %d allocs eligible",
		len(gcJob), len(gcEval), len(gcAlloc))

	// Reap the evals and allocs
	if err := c.evalReap(gcEval, gcAlloc); err != nil {
		return err
	}

	// Call to the leader to deregister the jobs.
	for _, job := range gcJob {
		req := structs.JobDeregisterRequest{
			JobID: job,
			WriteRequest: structs.WriteRequest{
				Region: c.srv.config.Region,
			},
		}
		var resp structs.JobDeregisterResponse
		if err := c.srv.RPC("Job.Deregister", &req, &resp); err != nil {
			c.srv.logger.Printf("[ERR] sched.core: job deregister failed: %v", err)
			return err
		}
	}

	return nil
}

// evalGC is used to garbage collect old evaluations
func (c *CoreScheduler) evalGC(eval *structs.Evaluation) error {
	// Iterate over the evaluations
	iter, err := c.snap.Evals()
	if err != nil {
		return err
	}

	var oldThreshold uint64
	if eval.TriggeredBy == structs.EvalTriggerForceGC {
		// The GC was forced, so set the threshold to its maximum so everything
		// will GC.
		oldThreshold = math.MaxUint64
		c.srv.logger.Println("[DEBUG] sched.core: forced eval GC")
	} else {
		// Compute the old threshold limit for GC using the FSM
		// time table.  This is a rough mapping of a time to the
		// Raft index it belongs to.
		tt := c.srv.fsm.TimeTable()
		cutoff := time.Now().UTC().Add(-1 * c.srv.config.EvalGCThreshold)
		oldThreshold = tt.NearestIndex(cutoff)
	}
	c.srv.logger.Printf("[DEBUG] sched.core: eval GC: scanning before index %d (%v)",
		oldThreshold, c.srv.config.EvalGCThreshold)

	// Collect the allocations and evaluations to GC
	var gcAlloc, gcEval []string
	for raw := iter.Next(); raw != nil; raw = iter.Next() {
		eval := raw.(*structs.Evaluation)
		gc, allocs, err := c.gcEval(eval, oldThreshold)
		if err != nil {
			return err
		}

		if gc {
			gcEval = append(gcEval, eval.ID)
			gcAlloc = append(gcAlloc, allocs...)
		}
	}

	// Fast-path the nothing case
	if len(gcEval) == 0 && len(gcAlloc) == 0 {
		return nil
	}
	c.srv.logger.Printf("[DEBUG] sched.core: eval GC: %d evaluations, %d allocs eligible",
		len(gcEval), len(gcAlloc))

	return c.evalReap(gcEval, gcAlloc)
}

// gcEval returns whether the eval should be garbage collected given a raft
// threshold index. The eval disqualifies for garbage collection if it or its
// allocs are not older than the threshold. If the eval should be garbage
// collected, the associated alloc ids that should also be removed are also
// returned
func (c *CoreScheduler) gcEval(eval *structs.Evaluation, thresholdIndex uint64) (
	bool, []string, error) {
	// Ignore non-terminal and new evaluations
	if !eval.TerminalStatus() || eval.ModifyIndex > thresholdIndex {
		return false, nil, nil
	}

	// Get the allocations by eval
	allocs, err := c.snap.AllocsByEval(eval.ID)
	if err != nil {
		c.srv.logger.Printf("[ERR] sched.core: failed to get allocs for eval %s: %v",
			eval.ID, err)
		return false, nil, err
	}

	// Scan the allocations to ensure they are terminal and old
	for _, alloc := range allocs {
		// TODO: This can go away once the scheduler marks an alloc as
		// DesiredStatusStop when a client fails.
		allocTerminal := alloc.TerminalStatus() ||
			alloc.ClientStatus == structs.AllocClientStatusComplete ||
			alloc.ClientStatus == structs.AllocClientStatusFailed
		if !allocTerminal || alloc.ModifyIndex > thresholdIndex {
			return false, nil, nil
		}
	}

	allocIds := make([]string, len(allocs))
	for i, alloc := range allocs {
		allocIds[i] = alloc.ID
	}

	// Evaluation is eligible for garbage collection
	return true, allocIds, nil
}

// evalReap contacts the leader and issues a reap on the passed evals and
// allocs.
func (c *CoreScheduler) evalReap(evals, allocs []string) error {
	// Call to the leader to issue the reap
	req := structs.EvalDeleteRequest{
		Evals:  evals,
		Allocs: allocs,
		WriteRequest: structs.WriteRequest{
			Region: c.srv.config.Region,
		},
	}
	var resp structs.GenericResponse
	if err := c.srv.RPC("Eval.Reap", &req, &resp); err != nil {
		c.srv.logger.Printf("[ERR] sched.core: eval reap failed: %v", err)
		return err
	}

	return nil
}

// nodeGC is used to garbage collect old nodes
func (c *CoreScheduler) nodeGC(eval *structs.Evaluation) error {
	// Iterate over the evaluations
	iter, err := c.snap.Nodes()
	if err != nil {
		return err
	}

	var oldThreshold uint64
	if eval.TriggeredBy == structs.EvalTriggerForceGC {
		// The GC was forced, so set the threshold to its maximum so everything
		// will GC.
		oldThreshold = math.MaxUint64
		c.srv.logger.Println("[DEBUG] sched.core: forced node GC")
	} else {
		// Compute the old threshold limit for GC using the FSM
		// time table.  This is a rough mapping of a time to the
		// Raft index it belongs to.
		tt := c.srv.fsm.TimeTable()
		cutoff := time.Now().UTC().Add(-1 * c.srv.config.NodeGCThreshold)
		oldThreshold = tt.NearestIndex(cutoff)
	}
	c.srv.logger.Printf("[DEBUG] sched.core: node GC: scanning before index %d (%v)",
		oldThreshold, c.srv.config.NodeGCThreshold)

	// Collect the nodes to GC
	var gcNode []string
	for {
		raw := iter.Next()
		if raw == nil {
			break
		}
		node := raw.(*structs.Node)

		// Ignore non-terminal and new nodes
		if !node.TerminalStatus() || node.ModifyIndex > oldThreshold {
			continue
		}

		// Get the allocations by node
		allocs, err := c.snap.AllocsByNode(node.ID)
		if err != nil {
			c.srv.logger.Printf("[ERR] sched.core: failed to get allocs for node %s: %v",
				eval.ID, err)
			continue
		}

		// If there are any allocations, skip the node
		if len(allocs) > 0 {
			continue
		}

		// Node is eligible for garbage collection
		gcNode = append(gcNode, node.ID)
	}

	// Fast-path the nothing case
	if len(gcNode) == 0 {
		return nil
	}
	c.srv.logger.Printf("[DEBUG] sched.core: node GC: %d nodes eligible", len(gcNode))

	// Call to the leader to issue the reap
	for _, nodeID := range gcNode {
		req := structs.NodeDeregisterRequest{
			NodeID: nodeID,
			WriteRequest: structs.WriteRequest{
				Region: c.srv.config.Region,
			},
		}
		var resp structs.NodeUpdateResponse
		if err := c.srv.RPC("Node.Deregister", &req, &resp); err != nil {
			c.srv.logger.Printf("[ERR] sched.core: node '%s' reap failed: %v", nodeID, err)
			return err
		}
	}
	return nil
}
<|endoftext|>