<commit_before>package main

import (
	"bytes"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type (
	Protocol struct {
		XMLName    xml.Name    `xml:"protocol"`
		Name       string      `xml:"name,attr"`
		Copyright  string      `xml:"copyright"`
		Interfaces []Interface `xml:"interface"`
	}

	Description struct {
		XMLName     xml.Name `xml:"description"`
		Summary     string   `xml:"summary,attr"`
		Description string   `xml:"description"`
	}

	Interface struct {
		XMLName     xml.Name    `xml:"interface"`
		Name        string      `xml:"name,attr"`
		Version     int         `xml:"version,attr"`
		Since       int         `xml:"since,attr"` // maybe in future versions
		Description Description `xml:"description"`
		Requests    []Request   `xml:"request"`
		Events      []Event     `xml:"event"`
		Enums       []Enum      `xml:"enum"`
	}

	Request struct {
		XMLName     xml.Name    `xml:"request"`
		Name        string      `xml:"name,attr"`
		Type        string      `xml:"type,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Arg struct {
		XMLName   xml.Name `xml:"arg"`
		Name      string   `xml:"name,attr"`
		Type      string   `xml:"type,attr"`
		Interface string   `xml:"interface,attr"`
		Enum      string   `xml:"enum,attr"`
		AllowNull bool     `xml:"allow-null,attr"`
		Summary   string   `xml:"summary,attr"`
	}

	Event struct {
		XMLName     xml.Name    `xml:"event"`
		Name        string      `xml:"name,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Enum struct {
		XMLName     xml.Name    `xml:"enum"`
		Name        string      `xml:"name,attr"`
		BitField    bool        `xml:"bitfield,attr"`
		Description Description `xml:"description"`
		Entries     []Entry     `xml:"entry"`
	}

	Entry struct {
		XMLName xml.Name `xml:"entry"`
		Name    string   `xml:"name,attr"`
		Value   string   `xml:"value,attr"`
		Summary string   `xml:"summary,attr"`
	}
)

var (
	wlTypes map[string]string = map[string]string{
		"int":    "int32",
		"uint":   "uint32",
		"string": "string",
		"fd":     "uintptr",
		"fixed":  "float32",
		"array":  "[]int32",
	}

	wlNames        map[string]string
	constBuffer    bytes.Buffer
	ifaceBuffer    bytes.Buffer
	reqCodesBuffer bytes.Buffer

	overwrite = flag.Bool("o", false, "Overwrite existing client.go file")
	develXml  = flag.Bool("dev", false, "Get development version of wayland.xml from repository")
)

func init() {
	flag.Parse()
	log.SetFlags(0)
}

func main() {
	var xmlFile *os.File

	if *develXml {
		file, err := getDevelXml()
		if err != nil {
			file.Close()
			log.Fatalf("Error while reading xml file : %s", err)
		}
		xmlFile = file
		xmlFile.Seek(0, 0)
	} else {
		xmlFilePath, err := filepath.Abs("wayland.xml")
		if err != nil {
			log.Fatalf("Cannot find wayland.xml: %s", err)
		}

		file, err := os.Open(xmlFilePath)
		if err != nil {
			log.Fatal("Cannot open wayland.xml")
		}
		xmlFile = file
	}

	defer xmlFile.Close()

	var protocol Protocol
	if err := xml.NewDecoder(xmlFile).Decode(&protocol); err != nil {
		log.Fatalf("Cannot decode wayland.xml : %s", err)
	}

	wlNames = make(map[string]string)

	constBuffer.WriteString("package wl")

	for _, iface := range protocol.Interfaces {
		//required for arg type's determine
		caseAndRegister(iface.Name)
	}

	reqCodesBuffer.WriteString("\n//Interface Request Codes\n") // request codes
	reqCodesBuffer.WriteString("\nconst (\n")                   // request codes

	for _, iface := range protocol.Interfaces {
		eventBuffer, eventNames := interfaceEvents(iface)
		eventBuffer.WriteTo(&ifaceBuffer)

		interfaceTypes(iface, eventNames)
		interfaceConstructor(iface, eventNames)
		interfaceRequests(iface)
		interfaceEnums(iface)
	}

	reqCodesBuffer.WriteString(")") // request codes end

	// if file exists
	if _, err := os.Stat("client.go"); err == nil {
		if !*overwrite {
			log.Printf("client.go exists if you want to overwrite try -o flag")
			return
		}
	}

	file, err := os.Create("client.go")
	if err != nil {
		log.Fatalf("Cannot create file: %s", err)
	}

	constBuffer.WriteTo(file)
	reqCodesBuffer.WriteTo(file)
	ifaceBuffer.WriteTo(file)

	file.Close()

	// go fmt file
	fmtFile()
}

// register names to map
func caseAndRegister(wlName string) string {
	var orj string = wlName
	wlName = CamelCase(wlName)
	wlNames[orj] = wlName
	return wlName
}

func enumArgName(ifaceName, enumName string) string {
	if strings.Index(enumName, ".") == -1 {
		return ifaceName + CamelCase(enumName)
	} else {
		parts := strings.Split(enumName, ".")
		if len(parts) != 2 {
			log.Fatal("enum args must be \"interface.enum\" format")
		}
		return CamelCase(parts[0]) + CamelCase(parts[1])
	}
}

func CamelCase(wlName string) string {
	if strings.HasPrefix(wlName, "wl_") {
		wlName = strings.TrimPrefix(wlName, "wl_")
	}

	// replace all "_" chars to " " chars
	wlName = strings.Replace(wlName, "_", " ", -1)

	// Capitalize first chars
	wlName = strings.Title(wlName)

	// remove all spaces
	wlName = strings.Replace(wlName, " ", "", -1)

	return wlName
}

func interfaceConstructor(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]

	// interface constructor
	ifaceBuffer.WriteString(fmt.Sprintf("\nfunc New%s(conn *Connection) *%s {\n", ifaceName, ifaceName))
	ifaceBuffer.WriteString(fmt.Sprintf("ret := new(%s)\n", ifaceName))
	for _, evName := range eventNames {
		ifaceBuffer.WriteString(fmt.Sprintf("ret.%s = make(chan %s)\n", evName+"Chan", ifaceName+evName+"Event"))
	}
	ifaceBuffer.WriteString("conn.Register(ret)\n")
	ifaceBuffer.WriteString("return ret\n")
	ifaceBuffer.WriteString("}\n")
}

func interfaceTypes(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]
	// interface type definition
	ifaceBuffer.WriteString(fmt.Sprintf("\ntype %s struct {\n", ifaceName))
	ifaceBuffer.WriteString("BaseProxy\n")
	for _, evName := range eventNames {
		ifaceBuffer.WriteString(fmt.Sprintf("%s chan %s\n", evName+"Chan", ifaceName+evName+"Event"))
	}
	ifaceBuffer.WriteString("}\n")
}

func interfaceRequests(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// interface method definitions (requests)
	// order used for request identification
	for order, req := range iface.Requests {
		reqName := CamelCase(req.Name)
		reqCodeName := strings.ToTitle(fmt.Sprintf("_%s_%s", ifaceName, reqName)) // first _ for not export constant
		reqCodesBuffer.WriteString(fmt.Sprintf("%s = %d\n", reqCodeName, order))

		ifaceBuffer.WriteString(fmt.Sprintf("\nfunc (p *%s) %s(", ifaceName, reqName))
		// get args buffer
		requestArgs(ifaceName, req).WriteTo(&ifaceBuffer)

		ifaceBuffer.WriteString(")") // close the args

		// get returns buffer
		requestRets(req).WriteTo(&ifaceBuffer)
		ifaceBuffer.WriteString("{\n")

		// get method body
		requestBody(req, reqCodeName).WriteTo(&ifaceBuffer)

		ifaceBuffer.WriteString("\n}\n")
	}
}

func interfaceEnums(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// Enums - Constants
	for _, enum := range iface.Enums {
		enumName := caseAndRegister(enum.Name)
		constTypeName := ifaceName + enumName
		constBuffer.WriteString(fmt.Sprintf("\ntype %s uint32\n", constTypeName)) // enums are uint
		constBuffer.WriteString("const (\n")
		for _, entry := range enum.Entries {
			entryName := caseAndRegister(entry.Name)
			constName := ifaceName + enumName + entryName
			constBuffer.WriteString(fmt.Sprintf("%s %s = %s\n", constName, constTypeName, entry.Value))
		}
		constBuffer.WriteString(")\n")
	}
}

func interfaceEvents(iface Interface) (bytes.Buffer, []string) {
	var (
		eventBuffer bytes.Buffer
		eventNames  []string
		ifaceName   = wlNames[iface.Name]
	)

	// Event struct types
	for _, event := range iface.Events {
		eventName := caseAndRegister(event.Name)
		typeName := ifaceName + eventName + "Event"
		eventBuffer.WriteString(fmt.Sprintf("\ntype %s struct {\n", typeName))
		for _, arg := range event.Args {
			if t, ok := wlTypes[arg.Type]; ok { // if basic type
				if arg.Type == "uint" && arg.Enum != "" { // enum type
					enumTypeName := ifaceName + CamelCase(arg.Enum)
					eventBuffer.WriteString(fmt.Sprintf("%s %s\n", CamelCase(arg.Name), enumTypeName))
				} else {
					eventBuffer.WriteString(fmt.Sprintf("%s %s\n", CamelCase(arg.Name), t))
				}
			} else { // interface type
				if (arg.Type == "object" || arg.Type == "new_id") && arg.Interface != "" {
					t = "*" + wlNames[arg.Interface]
				} else {
					t = "Proxy"
				}
				eventBuffer.WriteString(fmt.Sprintf("%s %s\n", CamelCase(arg.Name), t))
			}
		}

		eventNames = append(eventNames, eventName)
		eventBuffer.WriteString("}\n")
	}

	return eventBuffer, eventNames
}

func requestArgs(ifaceName string, req Request) *bytes.Buffer {
	var (
		args       []string
		argsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		// special type, for example registry.bind
		if arg.Type == "new_id" {
			if arg.Interface == "" {
				args = append(args, "iface string")
				args = append(args, "version uint32")
				args = append(args, fmt.Sprintf("%s Proxy", arg.Name))
			} else {
				continue
			}
		} else if arg.Type == "object" && arg.Interface != "" {
			argTypeName := wlNames[arg.Interface]
			args = append(args, fmt.Sprintf("%s *%s", arg.Name, argTypeName))
		} else if arg.Type == "uint" && arg.Enum != "" {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, enumArgName(ifaceName, arg.Enum)))
		} else {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, wlTypes[arg.Type]))
		}
	}

	argsBuffer.WriteString(strings.Join(args,","))

	return &argsBuffer
}

func requestRets(req Request) *bytes.Buffer {
	var (
		rets       []string
		retsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" && arg.Interface != "" {
			retTypeName := wlNames[arg.Interface]
			rets = append(rets, fmt.Sprintf("*%s", retTypeName))
		}
	}

	// all request have an error return
	rets = append(rets, "error")

	retstr := strings.Join(rets,",")

	if len(rets) > 1 {
		retsBuffer.WriteString("(")
		retsBuffer.WriteString(retstr)
		retsBuffer.WriteString(")")
	} else {
		retsBuffer.WriteString(retstr)
	}

	return &retsBuffer
}

func requestBody(req Request, reqCodeName string) *bytes.Buffer {
	var (
		params       []string
		bodyBuffer   bytes.Buffer
		paramsBuffer bytes.Buffer
		hasRetType   string
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" {
			if arg.Interface != "" {
				retTypeName := wlNames[arg.Interface]
				bodyBuffer.WriteString(fmt.Sprintf("ret := New%s(p.Connection())\n", retTypeName))
				params = append(params, "Proxy(ret)")
				hasRetType = "ret,"
			} else {
				params = append(params, "iface")
				params = append(params, "version")
				params = append(params, arg.Name)
			}
		} else {
			params = append(params, arg.Name)
		}
	}

	for _, param := range params {
		paramsBuffer.WriteString(fmt.Sprintf(",%s", param))
	}

	bodyBuffer.WriteString(fmt.Sprintf("return %s p.Connection().SendRequest(p,%s%s)", hasRetType, reqCodeName, paramsBuffer.String()))

	return &bodyBuffer
}

func getDevelXml() (*os.File, error) {
	url := "https://cgit.freedesktop.org/wayland/wayland/plain/protocol/wayland.xml"
	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("http get error")
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Cannot get wayland.xml StatusCode error")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot read response body")
	} else {
		file, err := ioutil.TempFile("", "devel_wayland_xml")
		if err != nil {
			return nil, fmt.Errorf("Cannot create temp file")
		} else {
			file.Write(body)
			return file, nil
		}
	}
}

func fmtFile() {
	goex, err := exec.LookPath("go")
	if err != nil {
		log.Println("go executable cannot found run \"go fmt client.go\" yourself")
	} else {
		cmd := exec.Command(goex, "fmt", "client.go")
		err := cmd.Run()
		if err != nil {
			log.Fatalf("Cannot run cmd : %s", err)
		}
	}
}
<commit_msg>use fmt.Fprintf and some updates<commit_after>package main

import (
	"bytes"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

type (
	Protocol struct {
		XMLName    xml.Name    `xml:"protocol"`
		Name       string      `xml:"name,attr"`
		Copyright  string      `xml:"copyright"`
		Interfaces []Interface `xml:"interface"`
	}

	Description struct {
		XMLName     xml.Name `xml:"description"`
		Summary     string   `xml:"summary,attr"`
		Description string   `xml:"description"`
	}

	Interface struct {
		XMLName     xml.Name    `xml:"interface"`
		Name        string      `xml:"name,attr"`
		Version     int         `xml:"version,attr"`
		Since       int         `xml:"since,attr"` // maybe in future versions
		Description Description `xml:"description"`
		Requests    []Request   `xml:"request"`
		Events      []Event     `xml:"event"`
		Enums       []Enum      `xml:"enum"`
	}

	Request struct {
		XMLName     xml.Name    `xml:"request"`
		Name        string      `xml:"name,attr"`
		Type        string      `xml:"type,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Arg struct {
		XMLName   xml.Name `xml:"arg"`
		Name      string   `xml:"name,attr"`
		Type      string   `xml:"type,attr"`
		Interface string   `xml:"interface,attr"`
		Enum      string   `xml:"enum,attr"`
		AllowNull bool     `xml:"allow-null,attr"`
		Summary   string   `xml:"summary,attr"`
	}

	Event struct {
		XMLName     xml.Name    `xml:"event"`
		Name        string      `xml:"name,attr"`
		Since       int         `xml:"since,attr"`
		Description Description `xml:"description"`
		Args        []Arg       `xml:"arg"`
	}

	Enum struct {
		XMLName     xml.Name    `xml:"enum"`
		Name        string      `xml:"name,attr"`
		BitField    bool        `xml:"bitfield,attr"`
		Description Description `xml:"description"`
		Entries     []Entry     `xml:"entry"`
	}

	Entry struct {
		XMLName xml.Name `xml:"entry"`
		Name    string   `xml:"name,attr"`
		Value   string   `xml:"value,attr"`
		Summary string   `xml:"summary,attr"`
	}
)

var (
	wlTypes map[string]string = map[string]string{
		"int":    "int32",
		"uint":   "uint32",
		"string": "string",
		"fd":     "uintptr",
		"fixed":  "float32",
		"array":  "[]int32",
	}

	wlNames        map[string]string
	constBuffer    bytes.Buffer
	ifaceBuffer    bytes.Buffer
	reqCodesBuffer bytes.Buffer

	overwrite = flag.Bool("o", false, "Overwrite existing client.go file")
	develXml  = flag.Bool("dev", false, "Get development version of wayland.xml from repository")
)

func init() {
	flag.Parse()
	log.SetFlags(0)
}

func main() {
	var xmlFile *os.File

	if *develXml {
		file, err := getDevelXml()
		if err != nil {
			file.Close()
			log.Fatalf("Error while reading xml file : %s", err)
		}
		xmlFile = file
		xmlFile.Seek(0, 0)
	} else {
		xmlFilePath, err := filepath.Abs("wayland.xml")
		if err != nil {
			log.Fatalf("Cannot find wayland.xml: %s", err)
		}

		file, err := os.Open(xmlFilePath)
		if err != nil {
			log.Fatal("Cannot open wayland.xml")
		}
		xmlFile = file
	}

	defer xmlFile.Close()

	var protocol Protocol
	if err := xml.NewDecoder(xmlFile).Decode(&protocol); err != nil {
		log.Fatalf("Cannot decode wayland.xml : %s", err)
	}

	wlNames = make(map[string]string)

	fmt.Fprint(&constBuffer,"package wl")

	for _, iface := range protocol.Interfaces {
		//required for arg type's determine
		caseAndRegister(iface.Name)
	}

	fmt.Fprint(&reqCodesBuffer,"\n//Interface Request Codes\n") // request codes
	fmt.Fprint(&reqCodesBuffer,"\nconst (\n")                   // request codes

	for _, iface := range protocol.Interfaces {
		eventBuffer, eventNames := interfaceEvents(iface)
		eventBuffer.WriteTo(&ifaceBuffer)

		interfaceTypes(iface, eventNames)
		interfaceConstructor(iface, eventNames)
		interfaceRequests(iface)
		interfaceEnums(iface)
	}

	fmt.Fprint(&reqCodesBuffer,")") // request codes end

	// if file exists
	if _, err := os.Stat("client.go"); err == nil {
		if !*overwrite {
			log.Print("client.go exists if you want to overwrite try -o flag")
			return
		}
	}

	file, err := os.Create("client.go")
	if err != nil {
		log.Fatalf("Cannot create file: %s", err)
	}

	constBuffer.WriteTo(file)
	reqCodesBuffer.WriteTo(file)
	ifaceBuffer.WriteTo(file)

	file.Close()

	// go fmt file
	fmtFile()
}

// register names to map
func caseAndRegister(wlName string) string {
	var orj string = wlName
	wlName = CamelCase(wlName)
	wlNames[orj] = wlName
	return wlName
}

func enumArgName(ifaceName, enumName string) string {
	if strings.Index(enumName, ".") == -1 {
		return ifaceName + CamelCase(enumName)
	} else {
		parts := strings.Split(enumName, ".")
		if len(parts) != 2 {
			log.Fatal("enum args must be \"interface.enum\" format")
		}
		return CamelCase(parts[0]) + CamelCase(parts[1])
	}
}

func CamelCase(wlName string) string {
	if strings.HasPrefix(wlName, "wl_") {
		wlName = strings.TrimPrefix(wlName, "wl_")
	}

	// replace all "_" chars to " " chars
	wlName = strings.Replace(wlName, "_", " ", -1)

	// Capitalize first chars
	wlName = strings.Title(wlName)

	// remove all spaces
	wlName = strings.Replace(wlName, " ", "", -1)

	return wlName
}

func interfaceConstructor(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]

	// interface constructor
	fmt.Fprintf(&ifaceBuffer, "\nfunc New%s(conn *Connection) *%s {\n", ifaceName, ifaceName)
	fmt.Fprintf(&ifaceBuffer, "ret := new(%s)\n", ifaceName)
	for _, evName := range eventNames {
		fmt.Fprintf(&ifaceBuffer, "ret.%sChan = make(chan %s%sEvent)\n", evName, ifaceName , evName)
	}

	fmt.Fprint(&ifaceBuffer, "conn.Register(ret)\n")
	fmt.Fprint(&ifaceBuffer, "return ret\n")
	fmt.Fprint(&ifaceBuffer, "}\n")
}

func interfaceTypes(iface Interface, eventNames []string) {
	ifaceName := wlNames[iface.Name]
	// interface type definition
	fmt.Fprintf(&ifaceBuffer,"\ntype %s struct {\n", ifaceName)
	fmt.Fprint(&ifaceBuffer,"BaseProxy\n")
	for _, evName := range eventNames {
		fmt.Fprintf(&ifaceBuffer,"%sChan chan %s%sEvent\n", evName, ifaceName , evName)
	}
	fmt.Fprint(&ifaceBuffer,"}\n")
}

func interfaceRequests(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// interface method definitions (requests)
	// order used for request identification
	for order, req := range iface.Requests {
		reqName := CamelCase(req.Name)
		reqCodeName := strings.ToTitle(fmt.Sprintf("_%s_%s", ifaceName, reqName)) // first _ for not export constant
		fmt.Fprintf(&reqCodesBuffer,"%s = %d\n", reqCodeName, order)

		fmt.Fprintf(&ifaceBuffer,"\nfunc (p *%s) %s(", ifaceName, reqName)
		// get args buffer
		requestArgs(ifaceName, req).WriteTo(&ifaceBuffer)

		fmt.Fprint(&ifaceBuffer,")") // close the args

		// get returns buffer
		requestRets(req).WriteTo(&ifaceBuffer)
		fmt.Fprint(&ifaceBuffer,"{\n")

		// get method body
		requestBody(req, reqCodeName).WriteTo(&ifaceBuffer)

		fmt.Fprint(&ifaceBuffer,"\n}\n")
	}
}

func interfaceEnums(iface Interface) {
	ifaceName := wlNames[iface.Name]

	// Enums - Constants
	for _, enum := range iface.Enums {
		enumName := caseAndRegister(enum.Name)
		constTypeName := ifaceName + enumName
		fmt.Fprintf(&constBuffer,"\ntype %s uint32\n", constTypeName) // enums are uint
		fmt.Fprint(&constBuffer,"const (\n")
		for _, entry := range enum.Entries {
			entryName := caseAndRegister(entry.Name)
			constName := ifaceName + enumName + entryName
			fmt.Fprintf(&constBuffer,"%s %s = %s\n", constName, constTypeName, entry.Value)
		}
		fmt.Fprint(&constBuffer,")\n")
	}
}

func interfaceEvents(iface Interface) (bytes.Buffer, []string) {
	var (
		eventBuffer bytes.Buffer
		eventNames  []string
		ifaceName   = wlNames[iface.Name]
	)

	// Event struct types
	for _, event := range iface.Events {
		eventName := caseAndRegister(event.Name)
		fmt.Fprintf(&eventBuffer,"\ntype %s%sEvent struct {\n", ifaceName , eventName)
		for _, arg := range event.Args {
			if t, ok := wlTypes[arg.Type]; ok { // if basic type
				if arg.Type == "uint" && arg.Enum != "" { // enum type
					enumTypeName := ifaceName + CamelCase(arg.Enum)
					fmt.Fprintf(&eventBuffer,"%s %s\n", CamelCase(arg.Name), enumTypeName)
				} else {
					fmt.Fprintf(&eventBuffer,"%s %s\n", CamelCase(arg.Name), t)
				}
			} else { // interface type
				if (arg.Type == "object" || arg.Type == "new_id") && arg.Interface != "" {
					t = "*" + wlNames[arg.Interface]
				} else {
					t = "Proxy"
				}
				fmt.Fprintf(&eventBuffer,"%s %s\n", CamelCase(arg.Name), t)
			}
		}

		eventNames = append(eventNames, eventName)
		fmt.Fprint(&eventBuffer,"}\n")
	}

	return eventBuffer, eventNames
}

func requestArgs(ifaceName string, req Request) *bytes.Buffer {
	var (
		args       []string
		argsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		// special type, for example registry.bind
		if arg.Type == "new_id" {
			if arg.Interface == "" {
				args = append(args, "iface string")
				args = append(args, "version uint32")
				args = append(args, fmt.Sprintf("%s Proxy", arg.Name))
			} else {
				continue
			}
		} else if arg.Type == "object" && arg.Interface != "" {
			argTypeName := wlNames[arg.Interface]
			args = append(args, fmt.Sprintf("%s *%s", arg.Name, argTypeName))
		} else if arg.Type == "uint" && arg.Enum != "" {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, enumArgName(ifaceName, arg.Enum)))
		} else {
			args = append(args, fmt.Sprintf("%s %s", arg.Name, wlTypes[arg.Type]))
		}
	}

	fmt.Fprint(&argsBuffer,strings.Join(args, ","))

	return &argsBuffer
}

func requestRets(req Request) *bytes.Buffer {
	var (
		rets       []string
		retsBuffer bytes.Buffer
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" && arg.Interface != "" {
			retTypeName := wlNames[arg.Interface]
			rets = append(rets, fmt.Sprintf("*%s", retTypeName))
		}
	}

	// all request have an error return
	rets = append(rets, "error")

	retstr := strings.Join(rets, ",")

	if len(rets) > 1 {
		fmt.Fprintf(&retsBuffer,"( %s )",retstr)
	} else {
		fmt.Fprint(&retsBuffer,retstr)
	}

	return &retsBuffer
}

func requestBody(req Request, reqCodeName string) *bytes.Buffer {
	var (
		params       []string
		bodyBuffer   bytes.Buffer
		paramsBuffer bytes.Buffer
		hasRet   string
	)

	for _, arg := range req.Args {
		if arg.Type == "new_id" {
			if arg.Interface != "" {
				retTypeName := wlNames[arg.Interface]
				fmt.Fprintf(&bodyBuffer,"ret := New%s(p.Connection())\n", retTypeName)
				params = append(params, "Proxy(ret)")
				hasRet = "ret,"
			} else {
				params = append(params, "iface")
				params = append(params, "version")
				params = append(params, arg.Name)
			}
		} else {
			params = append(params, arg.Name)
		}
	}

	for _, param := range params {
		fmt.Fprintf(&paramsBuffer,",%s", param)
	}

	fmt.Fprintf(&bodyBuffer,"return %s p.Connection().SendRequest(p,%s%s)", hasRet, reqCodeName, paramsBuffer.String())

	return &bodyBuffer
}

func getDevelXml() (*os.File, error) {
	url := "https://cgit.freedesktop.org/wayland/wayland/plain/protocol/wayland.xml"
	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("http get error")
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Cannot get wayland.xml StatusCode error")
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot read response body")
	} else {
		file, err := ioutil.TempFile("", "devel_wayland_xml")
		if err != nil {
			return nil, fmt.Errorf("Cannot create temp file")
		} else {
			file.Write(body)
			return file, nil
		}
	}
}

func fmtFile() {
	goex, err := exec.LookPath("go")
	if err != nil {
		log.Println("go executable cannot found run \"go fmt client.go\" yourself")
	} else {
		cmd := exec.Command(goex, "fmt", "client.go")
		err := cmd.Run()
		if err != nil {
			log.Fatalf("Cannot run cmd : %s", err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright © 2015-2020 Hilko Bengen <bengen@hilluzination.de>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

package yara

/*
#include <yara.h>
#include "compat.h"

int scanCallbackFunc(YR_SCAN_CONTEXT*, int, void*, void*);
*/
import "C"
import (
	"errors"
	"runtime"
	"time"
	"unsafe"
)

// Scanner contains a YARA scanner (YR_SCANNER). The main difference
// to Rules (YR_RULES) is that it is possible to set variables in a
// thread-safe manner (cf.
// https://github.com/VirusTotal/yara/issues/350).
//
// Since this type contains a C pointer to a YR_SCANNER structure that
// may be automatically freed, it should not be copied.
type Scanner struct {
	cptr *C.YR_SCANNER
	// The Scanner struct has to hold a pointer to the rules
	// it wraps, as otherwise it may be be garbage collected.
	rules *Rules
	// Current callback object, set by SetCallback
	Callback ScanCallback
	// Scan flags are set just before scanning.
	flags ScanFlags
	// userData stores handle of the currently set callback object. It is
	// allocated using malloc so that the GC does not mess with it.
	userData *cgoHandle
}

// NewScanner creates a YARA scanner.
func NewScanner(r *Rules) (*Scanner, error) {
	var yrScanner *C.YR_SCANNER
	if err := newError(C.yr_scanner_create(r.cptr, &yrScanner)); err != nil {
		return nil, err
	}
	s := &Scanner{cptr: yrScanner, rules: r, userData: (*cgoHandle)(C.malloc(C.size_t(unsafe.Sizeof(cgoHandle(0)))))}
	*s.userData = 0
	runtime.SetFinalizer(s, (*Scanner).Destroy)
	return s, nil
}

// Destroy destroys the YARA data structure representing a scanner.
//
// It should not be necessary to call this method directly.
func (s *Scanner) Destroy() {
	if s.cptr != nil {
		C.yr_scanner_destroy(s.cptr)
		s.cptr = nil
	}
	if s.userData != nil {
		C.free(unsafe.Pointer(s.userData))
		s.userData = nil
	}
	runtime.SetFinalizer(s, nil)
}

// DefineVariable defines a named variable for use by the scanner.
// Boolean, int64, float64, and string types are supported.
func (s *Scanner) DefineVariable(identifier string, value interface{}) (err error) {
	cid := C.CString(identifier)
	defer C.free(unsafe.Pointer(cid))
	switch value.(type) {
	case bool:
		var v int
		if value.(bool) {
			v = 1
		}
		err = newError(C.yr_scanner_define_boolean_variable(
			s.cptr, cid, C.int(v)))
	case int, int8, int16, int32, int64, uint, uint8, uint32, uint64:
		value := toint64(value)
		err = newError(C.yr_scanner_define_integer_variable(
			s.cptr, cid, C.int64_t(value)))
	case float64:
		err = newError(C.yr_scanner_define_float_variable(
			s.cptr, cid, C.double(value.(float64))))
	case string:
		cvalue := C.CString(value.(string))
		defer C.free(unsafe.Pointer(cvalue))
		err = newError(C.yr_scanner_define_string_variable(
			s.cptr, cid, cvalue))
	default:
		err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
	}
	runtime.KeepAlive(s)
	return
}

// SetFlags sets flags for the scanner.
func (s *Scanner) SetFlags(flags ScanFlags) *Scanner {
	s.flags = flags
	return s
}

// SetTimeout sets a timeout for the scanner.
func (s *Scanner) SetTimeout(timeout time.Duration) *Scanner {
	C.yr_scanner_set_timeout(s.cptr, C.int(timeout/time.Second))
	return s
}

// SetCallback sets a callback object for the scanner. For every event
// emitted by libyara during subsequent scan, the appropriate method
// on the ScanCallback object is called.
//
// For the common case where only a list of matched rules is relevant,
// setting a callback object is not necessary.
func (s *Scanner) SetCallback(cb ScanCallback) *Scanner {
	s.Callback = cb
	return s
}

// putCallbackData stores the scanner's callback object in
// a cgoHandle. If no callback object has been
// set, it is initialized with the pointer to an empty ScanRules
// object. The handle must be deleted by the calling ScanXxxx function.
func (s *Scanner) putCallbackData() {
	if _, ok := s.Callback.(ScanCallback); !ok {
		s.Callback = &MatchRules{}
	}
	if *s.userData != 0 {
		s.userData.Delete()
		*s.userData = 0
	}
	*s.userData = cgoNewHandle(makeScanCallbackContainer(s.Callback, s.rules))
	C.yr_scanner_set_callback(s.cptr, C.YR_CALLBACK_FUNC(C.scanCallbackFunc), unsafe.Pointer(s.userData))
}

// ScanMem scans an in-memory buffer using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanMem(buf []byte) (err error) {
	var ptr *C.uint8_t
	if len(buf) > 0 {
		ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
	}
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_mem(
		s.cptr,
		ptr,
		C.size_t(len(buf))))
	runtime.KeepAlive(s)
	runtime.KeepAlive(buf)
	return
}

// ScanFile scans a file using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanFile(filename string) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_file(
		s.cptr,
		cfilename,
	))
	runtime.KeepAlive(s)
	return
}

// ScanFileDescriptor scans a file using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanFileDescriptor(fd uintptr) (err error) {
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C._yr_scanner_scan_fd(
		s.cptr,
		C.int(fd),
	))
	runtime.KeepAlive(s)
	return
}

// ScanProc scans a live process using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanProc(pid int) (err error) {
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_proc(
		s.cptr,
		C.int(pid),
	))
	runtime.KeepAlive(s)
	return
}

// ScanMemBlocks scans over a MemoryBlockIterator using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanMemBlocks(mbi MemoryBlockIterator) (err error) {
	c := makeMemoryBlockIteratorContainer(mbi)
	defer c.free()
	cmbi := makeCMemoryBlockIterator(c)
	defer C.free(cmbi.context)
	defer ((*cgoHandle)(cmbi.context)).Delete()
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_mem_blocks(
		s.cptr,
		cmbi,
	))
	runtime.KeepAlive(s)
	runtime.KeepAlive(mbi)
	runtime.KeepAlive(cmbi)
	return
}

// GetLastErrorRule returns the Rule which caused the last error.
//
// The result is nil, if scanner returned no rule
func (s *Scanner) GetLastErrorRule() (r *Rule) {
	ptr := C.yr_scanner_last_error_rule(s.cptr)
	if ptr != nil {
		r = &Rule{ptr, s.rules}
	}
	runtime.KeepAlive(s)
	return
}

// GetLastErrorString returns the String which caused the last error.
//
// The result is nil, if scanner returned no string
func (s *Scanner) GetLastErrorString() (r *String) {
	ptr := C.yr_scanner_last_error_string(s.cptr)
	if ptr != nil {
		r = &String{ptr, s.rules}
	}
	runtime.KeepAlive(s)
	return
}

type RuleProfilingInfo struct {
	Rule
	Cost uint64
}

// GetProfilingInfo retrieves profiling information from the Scanner.
func (s *Scanner) GetProfilingInfo() (rpis []RuleProfilingInfo) {
	for rpi := C.yr_scanner_get_profiling_info(s.cptr); rpi.rule != nil; rpi = (*C.YR_RULE_PROFILING_INFO)(unsafe.Pointer(uintptr(unsafe.Pointer(rpi)) + unsafe.Sizeof(*rpi))) {
		rpis = append(rpis, RuleProfilingInfo{Rule{rpi.rule, s.rules}, uint64(rpi.cost)})
	}
	return
}

// ResetProfilingInfo resets the Scanner's profiling information
func (s *Scanner) ResetProfilingInfo() {
	C.yr_scanner_reset_profiling_info(s.cptr)
}
<commit_msg>fix: release callback data handle<commit_after>// Copyright © 2015-2020 Hilko Bengen <bengen@hilluzination.de>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

package yara

/*
#include <yara.h>
#include "compat.h"

int scanCallbackFunc(YR_SCAN_CONTEXT*, int, void*, void*);
*/
import "C"
import (
	"errors"
	"runtime"
	"time"
	"unsafe"
)

// Scanner contains a YARA scanner (YR_SCANNER). The main difference
// to Rules (YR_RULES) is that it is possible to set variables in a
// thread-safe manner (cf.
// https://github.com/VirusTotal/yara/issues/350).
//
// Since this type contains a C pointer to a YR_SCANNER structure that
// may be automatically freed, it should not be copied.
type Scanner struct {
	cptr *C.YR_SCANNER
	// The Scanner struct has to hold a pointer to the rules
	// it wraps, as otherwise it may be be garbage collected.
	rules *Rules
	// Current callback object, set by SetCallback
	Callback ScanCallback
	// Scan flags are set just before scanning.
	flags ScanFlags
	// userData stores handle of the currently set callback object. It is
	// allocated using malloc so that the GC does not mess with it.
	userData *cgoHandle
}

// NewScanner creates a YARA scanner.
func NewScanner(r *Rules) (*Scanner, error) {
	var yrScanner *C.YR_SCANNER
	if err := newError(C.yr_scanner_create(r.cptr, &yrScanner)); err != nil {
		return nil, err
	}
	s := &Scanner{cptr: yrScanner, rules: r, userData: (*cgoHandle)(C.malloc(C.size_t(unsafe.Sizeof(cgoHandle(0)))))}
	*s.userData = 0
	runtime.SetFinalizer(s, (*Scanner).Destroy)
	return s, nil
}

// Destroy destroys the YARA data structure representing a scanner.
//
// It should not be necessary to call this method directly.
func (s *Scanner) Destroy() {
	if s.cptr != nil {
		C.yr_scanner_destroy(s.cptr)
		s.cptr = nil
	}
	if s.userData != nil {
		if *s.userData != 0 {
			s.userData.Delete()
		}
		C.free(unsafe.Pointer(s.userData))
		s.userData = nil
	}
	runtime.SetFinalizer(s, nil)
}

// DefineVariable defines a named variable for use by the scanner.
// Boolean, int64, float64, and string types are supported.
func (s *Scanner) DefineVariable(identifier string, value interface{}) (err error) {
	cid := C.CString(identifier)
	defer C.free(unsafe.Pointer(cid))
	switch value.(type) {
	case bool:
		var v int
		if value.(bool) {
			v = 1
		}
		err = newError(C.yr_scanner_define_boolean_variable(
			s.cptr, cid, C.int(v)))
	case int, int8, int16, int32, int64, uint, uint8, uint32, uint64:
		value := toint64(value)
		err = newError(C.yr_scanner_define_integer_variable(
			s.cptr, cid, C.int64_t(value)))
	case float64:
		err = newError(C.yr_scanner_define_float_variable(
			s.cptr, cid, C.double(value.(float64))))
	case string:
		cvalue := C.CString(value.(string))
		defer C.free(unsafe.Pointer(cvalue))
		err = newError(C.yr_scanner_define_string_variable(
			s.cptr, cid, cvalue))
	default:
		err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
	}
	runtime.KeepAlive(s)
	return
}

// SetFlags sets flags for the scanner.
func (s *Scanner) SetFlags(flags ScanFlags) *Scanner {
	s.flags = flags
	return s
}

// SetTimeout sets a timeout for the scanner.
func (s *Scanner) SetTimeout(timeout time.Duration) *Scanner {
	C.yr_scanner_set_timeout(s.cptr, C.int(timeout/time.Second))
	return s
}

// SetCallback sets a callback object for the scanner. For every event
// emitted by libyara during subsequent scan, the appropriate method
// on the ScanCallback object is called.
//
// For the common case where only a list of matched rules is relevant,
// setting a callback object is not necessary.
func (s *Scanner) SetCallback(cb ScanCallback) *Scanner {
	s.Callback = cb
	return s
}

// putCallbackData stores the scanner's callback object in
// a cgoHandle. If no callback object has been
// set, it is initialized with the pointer to an empty ScanRules
// object. The handle must be deleted by the calling ScanXxxx function.
func (s *Scanner) putCallbackData() {
	if _, ok := s.Callback.(ScanCallback); !ok {
		s.Callback = &MatchRules{}
	}
	if *s.userData != 0 {
		s.userData.Delete()
		*s.userData = 0
	}
	*s.userData = cgoNewHandle(makeScanCallbackContainer(s.Callback, s.rules))
	C.yr_scanner_set_callback(s.cptr, C.YR_CALLBACK_FUNC(C.scanCallbackFunc), unsafe.Pointer(s.userData))
}

// ScanMem scans an in-memory buffer using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanMem(buf []byte) (err error) {
	var ptr *C.uint8_t
	if len(buf) > 0 {
		ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
	}
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_mem(
		s.cptr,
		ptr,
		C.size_t(len(buf))))
	runtime.KeepAlive(s)
	runtime.KeepAlive(buf)
	return
}

// ScanFile scans a file using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanFile(filename string) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_file(
		s.cptr,
		cfilename,
	))
	runtime.KeepAlive(s)
	return
}

// ScanFileDescriptor scans a file using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanFileDescriptor(fd uintptr) (err error) {
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C._yr_scanner_scan_fd(
		s.cptr,
		C.int(fd),
	))
	runtime.KeepAlive(s)
	return
}

// ScanProc scans a live process using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanProc(pid int) (err error) {
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_proc(
		s.cptr,
		C.int(pid),
	))
	runtime.KeepAlive(s)
	return
}

// ScanMemBlocks scans over a MemoryBlockIterator using the scanner.
//
// If no callback object has been set for the scanner using
// SetCAllback, it is initialized with an empty MatchRules object.
func (s *Scanner) ScanMemBlocks(mbi MemoryBlockIterator) (err error) {
	c := makeMemoryBlockIteratorContainer(mbi)
	defer c.free()
	cmbi := makeCMemoryBlockIterator(c)
	defer C.free(cmbi.context)
	defer ((*cgoHandle)(cmbi.context)).Delete()
	s.putCallbackData()
	C.yr_scanner_set_flags(s.cptr, s.flags.withReportFlags(s.Callback))
	err = newError(C.yr_scanner_scan_mem_blocks(
		s.cptr,
		cmbi,
	))
	runtime.KeepAlive(s)
	runtime.KeepAlive(mbi)
	runtime.KeepAlive(cmbi)
	return
}

// GetLastErrorRule returns the Rule which caused the last error.
//
// The result is nil, if scanner returned no rule
func (s *Scanner) GetLastErrorRule() (r *Rule) {
	ptr := C.yr_scanner_last_error_rule(s.cptr)
	if ptr != nil {
		r = &Rule{ptr, s.rules}
	}
	runtime.KeepAlive(s)
	return
}

// GetLastErrorString returns the String which caused the last error.
//
// The result is nil, if scanner returned no string
func (s *Scanner) GetLastErrorString() (r *String) {
	ptr := C.yr_scanner_last_error_string(s.cptr)
	if ptr != nil {
		r = &String{ptr, s.rules}
	}
	runtime.KeepAlive(s)
	return
}

type RuleProfilingInfo struct {
	Rule
	Cost uint64
}

// GetProfilingInfo retrieves profiling information from the Scanner.
func (s *Scanner) GetProfilingInfo() (rpis []RuleProfilingInfo) {
	for rpi := C.yr_scanner_get_profiling_info(s.cptr); rpi.rule != nil; rpi = (*C.YR_RULE_PROFILING_INFO)(unsafe.Pointer(uintptr(unsafe.Pointer(rpi)) + unsafe.Sizeof(*rpi))) {
		rpis = append(rpis, RuleProfilingInfo{Rule{rpi.rule, s.rules}, uint64(rpi.cost)})
	}
	return
}

// ResetProfilingInfo resets the Scanner's profiling information
func (s *Scanner) ResetProfilingInfo() {
	C.yr_scanner_reset_profiling_info(s.cptr)
}
<|endoftext|>


<commit_before>package terraform

import (
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/state/remote"
)

func dataSourceRemoteState() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceRemoteStateRead,

		Schema: map[string]*schema.Schema{
			"backend": {
				Type:     schema.TypeString,
				Required: true,
			},

			"config": {
				Type:     schema.TypeMap,
				Optional: true,
			},

			"__has_dynamic_attributes": {
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func dataSourceRemoteStateRead(d *schema.ResourceData, meta interface{}) error {
	backend := d.Get("backend").(string)
	config := make(map[string]string)
	for k, v := range d.Get("config").(map[string]interface{}) {
		config[k] = v.(string)
	}

	// Create the client to access our remote state
	log.Printf("[DEBUG] Initializing remote state client: %s", backend)
	client, err := remote.NewClient(backend, config)
	if err != nil {
		return err
	}

	// Create the remote state itself and refresh it in order to load the state
	log.Printf("[DEBUG] Loading remote state...")
	state := &remote.State{Client: client}
	if err := state.RefreshState(); err != nil {
		return err
	}

	d.SetId(time.Now().UTC().String())

	outputMap := make(map[string]interface{})
	for key, val := range state.State().RootModule().Outputs {
		outputMap[key] = val.Value
	}

	mappedOutputs := remoteStateFlatten(outputMap)

	for key, val := range mappedOutputs {
		d.UnsafeSetFieldRaw(key, val)
	}
	return nil
}
<commit_msg>Fix panic when there is no remote state<commit_after>package terraform

import (
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/state/remote"
)

func dataSourceRemoteState() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceRemoteStateRead,

		Schema: map[string]*schema.Schema{
			"backend": {
				Type:     schema.TypeString,
				Required: true,
			},

			"config": {
				Type:     schema.TypeMap,
				Optional: true,
			},

			"__has_dynamic_attributes": {
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func dataSourceRemoteStateRead(d *schema.ResourceData, meta interface{}) error {
	backend := d.Get("backend").(string)
	config := make(map[string]string)
	for k, v := range d.Get("config").(map[string]interface{}) {
		config[k] = v.(string)
	}

	// Create the client to access our remote state
	log.Printf("[DEBUG] Initializing remote state client: %s", backend)
	client, err := remote.NewClient(backend, config)
	if err != nil {
		return err
	}

	// Create the remote state itself and refresh it in order to load the state
	log.Printf("[DEBUG] Loading remote state...")
	state := &remote.State{Client: client}
	if err := state.RefreshState(); err != nil {
		return err
	}

	d.SetId(time.Now().UTC().String())

	outputMap := make(map[string]interface{})

	remoteState := state.State()
	if remoteState.Empty() {
		log.Println("[DEBUG] empty remote state")
		return nil
	}

	for key, val := range remoteState.RootModule().Outputs {
		outputMap[key] = val.Value
	}

	mappedOutputs := remoteStateFlatten(outputMap)

	for key, val := range mappedOutputs {
		d.UnsafeSetFieldRaw(key, val)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Doctl Authors 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 commands

import (
	"bytes"
	"fmt"

	"github.com/spf13/cobra"
)

const (
	completionLong = `
completion is used to output completion code for bash/zsh/fish shell.

Before using completion features, you have to source completion code
from your .profile or .bashrc/.zshrc file. This is done by adding
following line to one of above files:
	source <(doctl completion SHELL)

Bash users can as well save it to file and copy it to:
	/etc/bash_completion.d/

Correct arguments for SHELL are: "bash", "zsh" and "fish".

Notes:
1) zsh completions requires zsh 5.2 or newer.

2) macOS users have to install bash-completion framework to utilize
completion features. This can be done using homebrew:
	brew install bash-completion

Once installed, you must load bash_completion by adding following
line to your .profile or .bashrc/.zshrc:
	source $(brew --prefix)/etc/bash_completion
`
	doctlLicense = `# Copyright 2017 The Doctl Authors 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.

`
)

// Completion creates the completion command
func Completion() *Command {
	cmd := &Command{
		Command: &cobra.Command{
			Use:   "completion",
			Short: "completion commands",
			Long:  completionLong,
		},
		IsIndex: true,
	}

	CmdBuilder(cmd, RunCompletionBash, "bash", "generate bash completion code",
		Writer, aliasOpt("b"))

	CmdBuilder(cmd, RunCompletionZsh, "zsh", "generate zsh completion code",
		Writer, aliasOpt("z"))

	CmdBuilder(cmd, RunCompletionFish, "fish", "generate fish completion code",
		Writer, aliasOpt("f"))

	return cmd
}

// RunCompletionBash outputs completion code for bash.
func RunCompletionBash(c *CmdConfig) error {
	var buf bytes.Buffer

	_, err := buf.Write([]byte(doctlLicense))
	if err != nil {
		return fmt.Errorf("error while generating bash completion: %v", err)
	}

	err = DoitCmd.GenBashCompletion(&buf)
	if err != nil {
		return fmt.Errorf("error while generating bash completion: %v", err)
	}

	fmt.Printf("%s", buf.String())

	return nil
}

// RunCompletionZsh outputs completion code for zsh shell.
func RunCompletionZsh(c *CmdConfig) error {
	var buf bytes.Buffer

	// zshInit represents intialization code needed to convert bash completion
	// code to zsh completion.
	zshInit := `
__doctl_bash_source() {
	alias shopt=':'
	alias _expand=_bash_expand
	alias _complete=_bash_comp
	emulate -L sh
	setopt kshglob noshglob braceexpand

	source "$@"
}

__doctl_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift

		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__doctl_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}

__doctl_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?

	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}

__doctl_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}

__doctl_declare() {
	if [ "$1" == "-F" ]; then
		whence -w "$@"
	else
		builtin declare "$@"
	fi
}

__doctl_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}

__doctl_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}

__doctl_filedir() {
	local RET OLD_IFS w qw

	__debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi

	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"

	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"

	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__doctl_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}

__doctl_quote() {
    if [[ $1 == \'* || $1 == \"* ]]; then
        # Leave out first character
        printf %q "${1:1}"
    else
    	printf %q "$1"
    fi
}

autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit

# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi

__doctl_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__doctl_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__doctl_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__doctl_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__doctl_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__doctl_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/__doctl_declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__doctl_type/g" \
	<<'BASH_COMPLETION_EOF'
`

	// zshFinalize is code going to the end of completion file
	// that calls conversion bash to zsh.
	zshFinalize := `
BASH_COMPLETION_EOF
}

__doctl_bash_source <(__doctl_convert_bash_to_zsh)
	`

	_, err := buf.Write([]byte(doctlLicense))
	if err != nil {
		return fmt.Errorf("error while generating zsh completion: %v", err)
	}

	_, err = buf.Write([]byte(zshInit))

	err = DoitCmd.GenBashCompletion(&buf)
	if err != nil {
		return fmt.Errorf("error wheil generating zsh completion: %v", err)
	}

	_, err = buf.Write([]byte(zshFinalize))
	if err != nil {
		return fmt.Errorf("error while generating zsh completion: %v", err)
	}

	fmt.Printf("%s", buf.String())

	return nil
}

// RunCompletionFish outputs completion code for fish shell.
func RunCompletionFish(c *CmdConfig) error {
	return fmt.Errorf("Fish completion generation is not supported for now")
}
<commit_msg>Remove fish placeholder<commit_after>/*
Copyright 2017 The Doctl Authors 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 commands

import (
	"bytes"
	"fmt"

	"github.com/spf13/cobra"
)

const (
	completionLong = `
completion is used to output completion code for bash/zsh/fish shell.

Before using completion features, you have to source completion code
from your .profile or .bashrc/.zshrc file. This is done by adding
following line to one of above files:
	source <(doctl completion SHELL)

Bash users can as well save it to file and copy it to:
	/etc/bash_completion.d/

Correct arguments for SHELL are: "bash", "zsh" and "fish".

Notes:
1) zsh completions requires zsh 5.2 or newer.

2) macOS users have to install bash-completion framework to utilize
completion features. This can be done using homebrew:
	brew install bash-completion

Once installed, you must load bash_completion by adding following
line to your .profile or .bashrc/.zshrc:
	source $(brew --prefix)/etc/bash_completion
`
	doctlLicense = `# Copyright 2017 The Doctl Authors 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.

`
)

// Completion creates the completion command
func Completion() *Command {
	cmd := &Command{
		Command: &cobra.Command{
			Use:   "completion",
			Short: "completion commands",
			Long:  completionLong,
		},
		IsIndex: true,
	}

	CmdBuilder(cmd, RunCompletionBash, "bash", "generate bash completion code",
		Writer, aliasOpt("b"))

	CmdBuilder(cmd, RunCompletionZsh, "zsh", "generate zsh completion code",
		Writer, aliasOpt("z"))

	return cmd
}

// RunCompletionBash outputs completion code for bash.
func RunCompletionBash(c *CmdConfig) error {
	var buf bytes.Buffer

	_, err := buf.Write([]byte(doctlLicense))
	if err != nil {
		return fmt.Errorf("error while generating bash completion: %v", err)
	}

	err = DoitCmd.GenBashCompletion(&buf)
	if err != nil {
		return fmt.Errorf("error while generating bash completion: %v", err)
	}

	fmt.Printf("%s", buf.String())

	return nil
}

// RunCompletionZsh outputs completion code for zsh shell.
func RunCompletionZsh(c *CmdConfig) error {
	var buf bytes.Buffer

	// zshInit represents intialization code needed to convert bash completion
	// code to zsh completion.
	zshInit := `
__doctl_bash_source() {
	alias shopt=':'
	alias _expand=_bash_expand
	alias _complete=_bash_comp
	emulate -L sh
	setopt kshglob noshglob braceexpand

	source "$@"
}

__doctl_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift

		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__doctl_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}

__doctl_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?

	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}

__doctl_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}

__doctl_declare() {
	if [ "$1" == "-F" ]; then
		whence -w "$@"
	else
		builtin declare "$@"
	fi
}

__doctl_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}

__doctl_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}

__doctl_filedir() {
	local RET OLD_IFS w qw

	__debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi

	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"

	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"

	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__doctl_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}

__doctl_quote() {
    if [[ $1 == \'* || $1 == \"* ]]; then
        # Leave out first character
        printf %q "${1:1}"
    else
    	printf %q "$1"
    fi
}

autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit

# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi

__doctl_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__doctl_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__doctl_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__doctl_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__doctl_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__doctl_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/__doctl_declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__doctl_type/g" \
	<<'BASH_COMPLETION_EOF'
`

	// zshFinalize is code going to the end of completion file
	// that calls conversion bash to zsh.
	zshFinalize := `
BASH_COMPLETION_EOF
}

__doctl_bash_source <(__doctl_convert_bash_to_zsh)
	`

	_, err := buf.Write([]byte(doctlLicense))
	if err != nil {
		return fmt.Errorf("error while generating zsh completion: %v", err)
	}

	_, err = buf.Write([]byte(zshInit))

	err = DoitCmd.GenBashCompletion(&buf)
	if err != nil {
		return fmt.Errorf("error wheil generating zsh completion: %v", err)
	}

	_, err = buf.Write([]byte(zshFinalize))
	if err != nil {
		return fmt.Errorf("error while generating zsh completion: %v", err)
	}

	fmt.Printf("%s", buf.String())

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/environs/localstorage"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/upstart"
	"launchpad.net/juju-core/utils"
)

// A request may fail to due "eventual consistency" semantics, which
// should resolve fairly quickly.  A request may also fail due to a slow
// state transition (for instance an instance taking a while to release
// a security group after termination).  The former failure mode is
// dealt with by shortAttempt, the latter by longAttempt.
var shortAttempt = utils.AttemptStrategy{
	Total: 1 * time.Second,
	Delay: 50 * time.Millisecond,
}

// localEnviron implements Environ.
var _ environs.Environ = (*localEnviron)(nil)

type localEnviron struct {
	localMutex      sync.Mutex
	config          *environConfig
	name            string
	publicListener  net.Listener
	privateListener net.Listener
}

// Name is specified in the Environ interface.
func (env *localEnviron) Name() string {
	return env.name
}

func (env *localEnviron) mongoServiceName() string {
	return "juju-db-" + env.config.namespace()
}

// Bootstrap is specified in the Environ interface.
func (env *localEnviron) Bootstrap(cons constraints.Value) error {
	logger.Infof("bootstrapping environment %q", env.name)

	// If the state file exists, it might actually have just been
	// removed by Destroy, and eventual consistency has not caught
	// up yet, so we retry to verify if that is happening.
	if err := environs.VerifyBootstrapInit(env, shortAttempt); err != nil {
		return err
	}

	if err := env.setupLocalMongoService(); err != nil {
		return err
	}

	// Work out the ip address of the lxc bridge, and use that for the mongo config.

	// Create a fake machine 0 in state to represent the machine, need an instance id.
	// "localhost" makes sense for that.

	return nil
}

// StateInfo is specified in the Environ interface.
func (env *localEnviron) StateInfo() (*state.Info, *api.Info, error) {
	return nil, nil, fmt.Errorf("not implemented")
}

// Config is specified in the Environ interface.
func (env *localEnviron) Config() *config.Config {
	env.localMutex.Lock()
	defer env.localMutex.Unlock()
	return env.config.Config
}

func createLocalStorageListener(dir string) (net.Listener, error) {
	if err := os.MkdirAll(dir, 0755); err != nil {
		logger.Errorf("failed to make directory for storage at %s: %v", dir, err)
		return nil, err
	}
	return localstorage.Serve("localhost:0", dir)
}

// SetConfig is specified in the Environ interface.
func (env *localEnviron) SetConfig(cfg *config.Config) error {
	config, err := provider.newConfig(cfg)
	if err != nil {
		logger.Errorf("failed to create new environ config: %v", err)
		return err
	}
	env.localMutex.Lock()
	defer env.localMutex.Unlock()
	env.config = config
	env.name = config.Name()
	// Well... this works fine as long as the config has set from the clients
	// local machine.
	publicListener, err := createLocalStorageListener(config.sharedStorageDir())
	if err != nil {
		return err
	}

	privateListener, err := createLocalStorageListener(config.storageDir())
	if err != nil {
		publicListener.Close()
		return err
	}
	env.publicListener = publicListener
	env.privateListener = privateListener
	return nil
}

// StartInstance is specified in the Environ interface.
func (env *localEnviron) StartInstance(
	machineId, machineNonce, series string,
	cons constraints.Value,
	info *state.Info,
	apiInfo *api.Info,
) (instance.Instance, *instance.HardwareCharacteristics, error) {
	return nil, nil, fmt.Errorf("not implemented")
}

// StopInstances is specified in the Environ interface.
func (env *localEnviron) StopInstances([]instance.Instance) error {
	return fmt.Errorf("not implemented")
}

// Instances is specified in the Environ interface.
func (env *localEnviron) Instances(ids []instance.Id) ([]instance.Instance, error) {
	return nil, fmt.Errorf("not implemented")
}

// AllInstances is specified in the Environ interface.
func (env *localEnviron) AllInstances() ([]instance.Instance, error) {
	return nil, fmt.Errorf("not implemented")
}

// Storage is specified in the Environ interface.
func (env *localEnviron) Storage() environs.Storage {
	return localstorage.Client(env.privateListener.Addr().String())
}

// PublicStorage is specified in the Environ interface.
func (env *localEnviron) PublicStorage() environs.StorageReader {
	return localstorage.Client(env.publicListener.Addr().String())
}

// Destroy is specified in the Environ interface.
func (env *localEnviron) Destroy(insts []instance.Instance) error {

	logger.Infof("removing service %s", env.mongoServiceName())
	mongo := upstart.NewService(env.mongoServiceName())
	if err := mongo.Remove(); err != nil {
		logger.Errorf("could not remove mongo service: %v", err)
		return err
	}

	return nil
}

// OpenPorts is specified in the Environ interface.
func (env *localEnviron) OpenPorts(ports []instance.Port) error {
	return fmt.Errorf("not implemented")
}

// ClosePorts is specified in the Environ interface.
func (env *localEnviron) ClosePorts(ports []instance.Port) error {
	return fmt.Errorf("not implemented")
}

// Ports is specified in the Environ interface.
func (env *localEnviron) Ports() ([]instance.Port, error) {
	return nil, fmt.Errorf("not implemented")
}

// Provider is specified in the Environ interface.
func (env *localEnviron) Provider() environs.EnvironProvider {
	return &provider
}

func (env *localEnviron) setupLocalMongoService() error {
	journalDir := filepath.Join(env.config.mongoDir(), "journal")
	logger.Debugf("create mongo journal dir: %v", journalDir)
	if err := os.MkdirAll(journalDir, 0755); err != nil {
		logger.Errorf("failed to make mongo journal dir %s: %v", journalDir, err)
		return err
	}

	logger.Debugf("generate server cert")
	cert, key, err := env.config.GenerateStateServerCertAndKey()
	if err != nil {
		logger.Errorf("failed to generate server cert: %v", err)
		return err
	}
	if err := ioutil.WriteFile(
		env.config.configFile("server.pem"),
		append(cert, key...),
		0600); err != nil {
		logger.Errorf("failed to write server.pem: %v", err)
		return err
	}

	// TODO(thumper): work out how to get the user to sudo bits...
	mongo := upstart.MongoUpstartService(
		env.mongoServiceName(),
		env.config.rootDir(),
		env.config.mongoDir(),
		env.config.StatePort())
	logger.Infof("installing service %s", env.mongoServiceName())
	if err := mongo.Install(); err != nil {
		logger.Errorf("could not install mongo service: %v", err)
		return err
	}
}
<commit_msg>Add the missing return statement.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/environs/localstorage"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/upstart"
	"launchpad.net/juju-core/utils"
)

// A request may fail to due "eventual consistency" semantics, which
// should resolve fairly quickly.  A request may also fail due to a slow
// state transition (for instance an instance taking a while to release
// a security group after termination).  The former failure mode is
// dealt with by shortAttempt, the latter by longAttempt.
var shortAttempt = utils.AttemptStrategy{
	Total: 1 * time.Second,
	Delay: 50 * time.Millisecond,
}

// localEnviron implements Environ.
var _ environs.Environ = (*localEnviron)(nil)

type localEnviron struct {
	localMutex      sync.Mutex
	config          *environConfig
	name            string
	publicListener  net.Listener
	privateListener net.Listener
}

// Name is specified in the Environ interface.
func (env *localEnviron) Name() string {
	return env.name
}

func (env *localEnviron) mongoServiceName() string {
	return "juju-db-" + env.config.namespace()
}

// Bootstrap is specified in the Environ interface.
func (env *localEnviron) Bootstrap(cons constraints.Value) error {
	logger.Infof("bootstrapping environment %q", env.name)

	// If the state file exists, it might actually have just been
	// removed by Destroy, and eventual consistency has not caught
	// up yet, so we retry to verify if that is happening.
	if err := environs.VerifyBootstrapInit(env, shortAttempt); err != nil {
		return err
	}

	if err := env.setupLocalMongoService(); err != nil {
		return err
	}

	// Work out the ip address of the lxc bridge, and use that for the mongo config.

	// Create a fake machine 0 in state to represent the machine, need an instance id.
	// "localhost" makes sense for that.

	return nil
}

// StateInfo is specified in the Environ interface.
func (env *localEnviron) StateInfo() (*state.Info, *api.Info, error) {
	return nil, nil, fmt.Errorf("not implemented")
}

// Config is specified in the Environ interface.
func (env *localEnviron) Config() *config.Config {
	env.localMutex.Lock()
	defer env.localMutex.Unlock()
	return env.config.Config
}

func createLocalStorageListener(dir string) (net.Listener, error) {
	if err := os.MkdirAll(dir, 0755); err != nil {
		logger.Errorf("failed to make directory for storage at %s: %v", dir, err)
		return nil, err
	}
	return localstorage.Serve("localhost:0", dir)
}

// SetConfig is specified in the Environ interface.
func (env *localEnviron) SetConfig(cfg *config.Config) error {
	config, err := provider.newConfig(cfg)
	if err != nil {
		logger.Errorf("failed to create new environ config: %v", err)
		return err
	}
	env.localMutex.Lock()
	defer env.localMutex.Unlock()
	env.config = config
	env.name = config.Name()
	// Well... this works fine as long as the config has set from the clients
	// local machine.
	publicListener, err := createLocalStorageListener(config.sharedStorageDir())
	if err != nil {
		return err
	}

	privateListener, err := createLocalStorageListener(config.storageDir())
	if err != nil {
		publicListener.Close()
		return err
	}
	env.publicListener = publicListener
	env.privateListener = privateListener
	return nil
}

// StartInstance is specified in the Environ interface.
func (env *localEnviron) StartInstance(
	machineId, machineNonce, series string,
	cons constraints.Value,
	info *state.Info,
	apiInfo *api.Info,
) (instance.Instance, *instance.HardwareCharacteristics, error) {
	return nil, nil, fmt.Errorf("not implemented")
}

// StopInstances is specified in the Environ interface.
func (env *localEnviron) StopInstances([]instance.Instance) error {
	return fmt.Errorf("not implemented")
}

// Instances is specified in the Environ interface.
func (env *localEnviron) Instances(ids []instance.Id) ([]instance.Instance, error) {
	return nil, fmt.Errorf("not implemented")
}

// AllInstances is specified in the Environ interface.
func (env *localEnviron) AllInstances() ([]instance.Instance, error) {
	return nil, fmt.Errorf("not implemented")
}

// Storage is specified in the Environ interface.
func (env *localEnviron) Storage() environs.Storage {
	return localstorage.Client(env.privateListener.Addr().String())
}

// PublicStorage is specified in the Environ interface.
func (env *localEnviron) PublicStorage() environs.StorageReader {
	return localstorage.Client(env.publicListener.Addr().String())
}

// Destroy is specified in the Environ interface.
func (env *localEnviron) Destroy(insts []instance.Instance) error {

	logger.Infof("removing service %s", env.mongoServiceName())
	mongo := upstart.NewService(env.mongoServiceName())
	if err := mongo.Remove(); err != nil {
		logger.Errorf("could not remove mongo service: %v", err)
		return err
	}

	return nil
}

// OpenPorts is specified in the Environ interface.
func (env *localEnviron) OpenPorts(ports []instance.Port) error {
	return fmt.Errorf("not implemented")
}

// ClosePorts is specified in the Environ interface.
func (env *localEnviron) ClosePorts(ports []instance.Port) error {
	return fmt.Errorf("not implemented")
}

// Ports is specified in the Environ interface.
func (env *localEnviron) Ports() ([]instance.Port, error) {
	return nil, fmt.Errorf("not implemented")
}

// Provider is specified in the Environ interface.
func (env *localEnviron) Provider() environs.EnvironProvider {
	return &provider
}

func (env *localEnviron) setupLocalMongoService() error {
	journalDir := filepath.Join(env.config.mongoDir(), "journal")
	logger.Debugf("create mongo journal dir: %v", journalDir)
	if err := os.MkdirAll(journalDir, 0755); err != nil {
		logger.Errorf("failed to make mongo journal dir %s: %v", journalDir, err)
		return err
	}

	logger.Debugf("generate server cert")
	cert, key, err := env.config.GenerateStateServerCertAndKey()
	if err != nil {
		logger.Errorf("failed to generate server cert: %v", err)
		return err
	}
	if err := ioutil.WriteFile(
		env.config.configFile("server.pem"),
		append(cert, key...),
		0600); err != nil {
		logger.Errorf("failed to write server.pem: %v", err)
		return err
	}

	// TODO(thumper): work out how to get the user to sudo bits...
	mongo := upstart.MongoUpstartService(
		env.mongoServiceName(),
		env.config.rootDir(),
		env.config.mongoDir(),
		env.config.StatePort())
	logger.Infof("installing service %s", env.mongoServiceName())
	if err := mongo.Install(); err != nil {
		logger.Errorf("could not install mongo service: %v", err)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package signal

import (
	"context"
	"sync"
	"time"

	"v2ray.com/core/common"
	"v2ray.com/core/common/task"
)

type ActivityUpdater interface {
	Update()
}

type ActivityTimer struct {
	sync.RWMutex
	updated   chan struct{}
	checkTask *task.Periodic
	onTimeout func()
}

func (t *ActivityTimer) Update() {
	select {
	case t.updated <- struct{}{}:
	default:
	}
}

func (t *ActivityTimer) check() error {
	select {
	case <-t.updated:
	default:
		t.finish()
	}
	return nil
}

func (t *ActivityTimer) finish() {
	t.Lock()
	defer t.Unlock()

	if t.onTimeout != nil {
		t.onTimeout()
		t.onTimeout = nil
	}
	if t.checkTask != nil {
		t.checkTask.Close() // nolint: errcheck
		t.checkTask = nil
	}
}

func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
	if timeout == 0 {
		t.finish()
		return
	}

	t.Lock()

	if t.checkTask != nil {
		t.checkTask.Close() // nolint: errcheck
	}
	t.checkTask = &task.Periodic{
		Interval: timeout,
		Execute:  t.check,
	}
	t.Unlock()
	t.Update()
	common.Must(t.checkTask.Start())
}

func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
	timer := &ActivityTimer{
		updated:   make(chan struct{}, 1),
		onTimeout: cancel,
	}
	timer.SetTimeout(timeout)
	return timer
}
<commit_msg>fix race condition in ActivityTimer<commit_after>package signal

import (
	"context"
	"sync"
	"time"

	"v2ray.com/core/common"
	"v2ray.com/core/common/task"
)

type ActivityUpdater interface {
	Update()
}

type ActivityTimer struct {
	sync.RWMutex
	updated   chan struct{}
	checkTask *task.Periodic
	onTimeout func()
}

func (t *ActivityTimer) Update() {
	select {
	case t.updated <- struct{}{}:
	default:
	}
}

func (t *ActivityTimer) check() error {
	select {
	case <-t.updated:
	default:
		t.finish()
	}
	return nil
}

func (t *ActivityTimer) finish() {
	t.Lock()
	defer t.Unlock()

	if t.onTimeout != nil {
		t.onTimeout()
		t.onTimeout = nil
	}
	if t.checkTask != nil {
		t.checkTask.Close() // nolint: errcheck
		t.checkTask = nil
	}
}

func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
	if timeout == 0 {
		t.finish()
		return
	}

	checkTask := &task.Periodic{
		Interval: timeout,
		Execute:  t.check,
	}

	t.Lock()

	if t.checkTask != nil {
		t.checkTask.Close() // nolint: errcheck
	}
	t.checkTask = checkTask
	t.Unlock()
	t.Update()
	common.Must(checkTask.Start())
}

func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
	timer := &ActivityTimer{
		updated:   make(chan struct{}, 1),
		onTimeout: cancel,
	}
	timer.SetTimeout(timeout)
	return timer
}
<|endoftext|>


<commit_before>package km

import (
	"fmt"
	"log"
	"time"

	"github.com/coopernurse/gorp"
	_ "github.com/lib/pq"
)

type Kilometers struct {
	Id                            int64
	Date                          time.Time
	Begin, Eerste, Laatste, Terug int
	Comment                       string
}

type Field struct {
	Km   int
	Time string
	Name string
}

func (k *Kilometers) getMax() int {
	if k.Terug > 0 {
		return k.Terug
	}
	if k.Laatste > 0 {
		return k.Laatste
	}
	if k.Eerste > 0 {
		return k.Eerste
	}
	if k.Begin > 0 {
		return k.Begin
	}
	return 0
}

func (k *Kilometers) AddFields(fields []Field) {
	for _, field := range fields {
		switch field.Name {
		case "Begin":
			k.Begin = field.Km
		case "Eerste":
			k.Eerste = field.Km
		case "Laatste":
			k.Laatste = field.Km
		case "Terug":
			k.Terug = field.Km
		}

	}
}

func SaveKilometers(dbmap *gorp.DbMap, date time.Time, fields []Field) (err error) {
	dateStr := fmt.Sprintf("%d-%d-%d", date.Month(), date.Day(), date.Year())
	kms := new(Kilometers)
	err = dbmap.SelectOne(kms, "select * from kilometers where date=$1", dateStr)
	if err == nil { // there is already data for km (so use update)
		kms.AddFields(fields)
		_, err = dbmap.Update(kms)
		if err != nil {
			return
		}
	} else { // nog niks opgeslagen voor vandaag}
		log.Println("error after Selectone: ", err)
		log.Printf("%+v\n", kms)
		//kms := new(Kilometers)
		//kms.Date = date
		//kms.AddFields(fields)
		//err = dbmap.Insert(kms)
		//if err != nil {
		//return
		//}
	}
	return nil
}
<commit_msg>kilometers back in working order, got commented out with testing in previous commit<commit_after>package km

import (
	"fmt"
	"time"

	"github.com/coopernurse/gorp"
	_ "github.com/lib/pq"
)

type Kilometers struct {
	Id                            int64
	Date                          time.Time
	Begin, Eerste, Laatste, Terug int
	Comment                       string
}

type Field struct {
	Km   int
	Time string
	Name string
}

func (k *Kilometers) getMax() int {
	if k.Terug > 0 {
		return k.Terug
	}
	if k.Laatste > 0 {
		return k.Laatste
	}
	if k.Eerste > 0 {
		return k.Eerste
	}
	if k.Begin > 0 {
		return k.Begin
	}
	return 0
}

func (k *Kilometers) AddFields(fields []Field) {
	for _, field := range fields {
		switch field.Name {
		case "Begin":
			k.Begin = field.Km
		case "Eerste":
			k.Eerste = field.Km
		case "Laatste":
			k.Laatste = field.Km
		case "Terug":
			k.Terug = field.Km
		}

	}
}

func SaveKilometers(dbmap *gorp.DbMap, date time.Time, fields []Field) (err error) {
	dateStr := fmt.Sprintf("%d-%d-%d", date.Month(), date.Day(), date.Year())
	kms := new(Kilometers)
	err = dbmap.SelectOne(kms, "select * from kilometers where date=$1", dateStr)
	if err == nil { // there is already data for km (so use update)
		kms.AddFields(fields)
		_, err = dbmap.Update(kms)
		if err != nil {
			return
		}
	} else { // nog niks opgeslagen voor vandaag}
		if err.Error() != "sql: no rows in result set" {
			return
		}
		kms := new(Kilometers)
		kms.Date = date
		kms.AddFields(fields)
		err = dbmap.Insert(kms)
		if err != nil {
			return
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2012 Caoimhe Chaos <caoimhechaos@protonmail.com>,
 *                    Ancient Solutions. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions  of source code must retain  the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions  in   binary  form  must   reproduce  the  above
 *    copyright  notice, this  list  of conditions  and the  following
 *    disclaimer in the  documentation and/or other materials provided
 *    with the distribution.
 *
 * THIS  SOFTWARE IS  PROVIDED BY  ANCIENT SOLUTIONS  AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO,  THE IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS
 * FOR A  PARTICULAR PURPOSE  ARE DISCLAIMED.  IN  NO EVENT  SHALL THE
 * FOUNDATION  OR CONTRIBUTORS  BE  LIABLE FOR  ANY DIRECT,  INDIRECT,
 * INCIDENTAL,   SPECIAL,    EXEMPLARY,   OR   CONSEQUENTIAL   DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net"
	"net/rpc"
	"os"

	"ancientsolutions.com/doozer/exportedservice"
	"ancientsolutions.com/geocolo"
	"code.google.com/p/goprotobuf/proto"
)

func main() {
	var service *geocolo.GeoProximityService
	var exporter *exportedservice.ServiceExporter
	var config *geocolo.GeoProximityServiceConfig
	var configpath, doozer_uri, boot_uri string
	var listen_net, listen_ip, listen_servicename string
	var listener net.Listener
	var configfile *os.File
	var bdata []byte
	var err error

	flag.StringVar(&configpath, "config", "",
		"Path to the geocolo service configuration")
	flag.StringVar(&doozer_uri, "doozer-uri", "",
		"URI of the Doozer service")
	flag.StringVar(&boot_uri, "doozer-boot-uri", "",
		"Boot URI of the Doozer service")
	flag.StringVar(&listen_net, "listen-proto", "tcp",
		"Protocol type to listen on (e.g. tcp)")
	flag.StringVar(&listen_ip, "listen-addr", "[::]",
		"IP address to listen on")
	flag.StringVar(&listen_servicename, "export-service", "geocolo",
		"Service name to export as")
	flag.Parse()

	config = new(geocolo.GeoProximityServiceConfig)
	configfile, err = os.Open(configpath)
	if err != nil {
		log.Fatal("Error opening ", configpath, ": ", err)
	}

	bdata, err = ioutil.ReadAll(configfile)
	if err != nil {
		configfile.Close()
		log.Fatal("Error reading ", configpath, ": ", err)
	}

	err = proto.Unmarshal(bdata, config)
	if err != nil {
		configfile.Close()
		log.Fatal("Error parsing ", configpath, ": ", err)
	}

	err = configfile.Close()
	if err != nil {
		log.Print("Error closing ", configpath, ": ", err)
	}

	service, err = geocolo.NewGeoProximityService(config)
	if err != nil {
		log.Fatal("Error creating GeoProximityService: ", err)
	}

	rpc.Register(service)
	rpc.HandleHTTP()

	exporter, err = exportedservice.NewExporter(doozer_uri, boot_uri)
	if err != nil {
		log.Fatal("Error opening port exporter: ", err)
	}

	listener, err = exporter.NewExportedPort(listen_net, listen_ip,
		listen_servicename)
	if err != nil {
		log.Fatal("Error opening exported port: ", err)
	}

	rpc.Accept(listener)
}
<commit_msg>Fetch doozer URIs from environment if applicable.<commit_after>/*-
 * Copyright (c) 2012 Caoimhe Chaos <caoimhechaos@protonmail.com>,
 *                    Ancient Solutions. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions  of source code must retain  the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions  in   binary  form  must   reproduce  the  above
 *    copyright  notice, this  list  of conditions  and the  following
 *    disclaimer in the  documentation and/or other materials provided
 *    with the distribution.
 *
 * THIS  SOFTWARE IS  PROVIDED BY  ANCIENT SOLUTIONS  AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO,  THE IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS
 * FOR A  PARTICULAR PURPOSE  ARE DISCLAIMED.  IN  NO EVENT  SHALL THE
 * FOUNDATION  OR CONTRIBUTORS  BE  LIABLE FOR  ANY DIRECT,  INDIRECT,
 * INCIDENTAL,   SPECIAL,    EXEMPLARY,   OR   CONSEQUENTIAL   DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net"
	"net/rpc"
	"os"

	"ancientsolutions.com/doozer/exportedservice"
	"ancientsolutions.com/geocolo"
	"code.google.com/p/goprotobuf/proto"
)

func main() {
	var service *geocolo.GeoProximityService
	var exporter *exportedservice.ServiceExporter
	var config *geocolo.GeoProximityServiceConfig
	var configpath, doozer_uri, boot_uri string
	var listen_net, listen_ip, listen_servicename string
	var listener net.Listener
	var configfile *os.File
	var bdata []byte
	var err error

	flag.StringVar(&configpath, "config", "",
		"Path to the geocolo service configuration")
	flag.StringVar(&doozer_uri, "doozer-uri", os.Getenv("DOOZER_URI"),
		"URI of the Doozer service")
	flag.StringVar(&boot_uri, "doozer-boot-uri",
		os.Getenv("DOOZER_BOOT_URI"),
		"Boot URI of the Doozer service")
	flag.StringVar(&listen_net, "listen-proto", "tcp",
		"Protocol type to listen on (e.g. tcp)")
	flag.StringVar(&listen_ip, "listen-addr", "[::]",
		"IP address to listen on")
	flag.StringVar(&listen_servicename, "export-service", "geocolo",
		"Service name to export as")
	flag.Parse()

	config = new(geocolo.GeoProximityServiceConfig)
	configfile, err = os.Open(configpath)
	if err != nil {
		log.Fatal("Error opening ", configpath, ": ", err)
	}

	bdata, err = ioutil.ReadAll(configfile)
	if err != nil {
		configfile.Close()
		log.Fatal("Error reading ", configpath, ": ", err)
	}

	err = proto.Unmarshal(bdata, config)
	if err != nil {
		configfile.Close()
		log.Fatal("Error parsing ", configpath, ": ", err)
	}

	err = configfile.Close()
	if err != nil {
		log.Print("Error closing ", configpath, ": ", err)
	}

	service, err = geocolo.NewGeoProximityService(config)
	if err != nil {
		log.Fatal("Error creating GeoProximityService: ", err)
	}

	rpc.Register(service)
	rpc.HandleHTTP()

	exporter, err = exportedservice.NewExporter(doozer_uri, boot_uri)
	if err != nil {
		log.Fatal("Error opening port exporter: ", err)
	}

	listener, err = exporter.NewExportedPort(listen_net, listen_ip,
		listen_servicename)
	if err != nil {
		log.Fatal("Error opening exported port: ", err)
	}

	rpc.Accept(listener)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"io/ioutil"
	"time"
	"net/http"
	"flapjack"
	"encoding/json"
	"gopkg.in/alecthomas/kingpin.v1"
	"github.com/go-martini/martini"
)

// handler caches
func CreateState(newState chan flapjack.Event, w http.ResponseWriter, r *http.Request) {
	var state flapjack.Event

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Printf(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	err = json.Unmarshal(body, &state)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Println(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	// Populate a time if none has been set.
	if state.Time == 0 {
		state.Time = time.Now().Unix()
	}

	if len(state.Type) == 0 {
		state.Type = "service"
	}

	newState <- state

	json, _ := json.Marshal(state)
	message := "Caching state: %s\n"
	log.Printf(message, json)
	fmt.Fprintf(w, message, json)
}

// cacheState stores a cache of event state to be sent to Flapjack.
// The event state is queried later when submitting events periodically
// to Flapjack.
func cacheState(newState chan flapjack.Event, state map[string]flapjack.Event) {
	for ns := range newState {
		key := ns.Entity + ":" + ns.Check
		state[key] = ns
	}
}

// submitCachedState periodically samples the cached state, sends it to Flapjack.
func submitCachedState(states map[string]flapjack.Event, config Config) {
	transport, err := flapjack.Dial(config.Server, config.Database)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}

	for {
		log.Printf("Number of cached states: %d\n", len(states))
		for id, state := range(states) {
			event := flapjack.Event{
				Entity:  state.Entity,
				Check:   state.Check,
				Type:    state.Type,
				State:   state.State,
				Summary: state.Summary,
				Time:    time.Now().Unix(),
			}
			if config.Debug {
				log.Printf("Sending event data for %s\n", id)
			}
			transport.Send(event)
		}
		time.Sleep(config.Interval)
	}
}

var (
	port		= kingpin.Flag("port", "Address to bind HTTP server (default 3090)").Default("3090").OverrideDefaultFromEnvar("PORT").String()
	server		= kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
	database	= kingpin.Flag("database", "Redis database to connect to (default 0)").Int() // .Default("13").Int()
	interval	= kingpin.Flag("interval", "How often to submit events (default 10s)").Default("10s").Duration()
	debug		= kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
)

type Config struct {
	Port		string
	Server		string
	Database	int
	Interval	time.Duration
	Debug		bool
}

func main() {
	kingpin.Version("0.0.1")
	kingpin.Parse()

	config := Config{
		Server: 	*server,
		Database: 	*database,
		Interval: 	*interval,
		Debug:		*debug,
		Port: 		":" + *port,
	}
	if config.Debug {
		log.Printf("Booting with config: %+v\n", config)
	}

	updates := make(chan State)
	state := map[string]State{}

	go cacheState(updates, state)
	go submitCachedState(state, config)

	m := martini.Classic()
	m.Group("/state", func(r martini.Router) {
		r.Post("", func(res http.ResponseWriter, req *http.Request) {
			CreateState(updates, res, req)
		})
		r.Get("", func() []byte {
			data, _ := json.Marshal(state)
			return data
		})
	})

	log.Fatal(http.ListenAndServe(config.Port, m))
}
<commit_msg>Add state staleness check:<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"io/ioutil"
	"time"
	"net/http"
	"flapjack"
	"encoding/json"
	"gopkg.in/alecthomas/kingpin.v1"
	"github.com/go-martini/martini"
)

// State is a basic representation of a Flapjack event, with some extra field.
// The extra fields handle state expiry.
// Find more at https://github.com/flapjack/flapjack/wiki/DATA_STRUCTURES
type State struct {
	flapjack.Event
	TTL	int64  `json:"ttl"`
}

// handler caches
func CreateState(updates chan State, w http.ResponseWriter, r *http.Request) {
	var state State

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Printf(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	err = json.Unmarshal(body, &state)
	if err != nil {
		message := "Error: Couldn't read request body: %s\n"
		log.Println(message, err)
		fmt.Fprintf(w, message, err)
		return
	}

	// Populate a time if none has been set.
	if state.Time == 0 {
		state.Time = time.Now().Unix()
	}

	if len(state.Type) == 0 {
		state.Type = "service"
	}

	if state.TTL == 0 {
		state.TTL = 300
	}

	updates <- state

	json, _ := json.Marshal(state)
	message := "Caching state: %s\n"
	log.Printf(message, json)
	fmt.Fprintf(w, message, json)
}

// cacheState stores a cache of event state to be sent to Flapjack.
// The event state is queried later when submitting events periodically
// to Flapjack.
func cacheState(updates chan State, state map[string]State) {
	for ns := range updates {
		key := ns.Entity + ":" + ns.Check
		state[key] = ns
	}
}

// submitCachedState periodically samples the cached state, sends it to Flapjack.
func submitCachedState(states map[string]State, config Config) {
	transport, err := flapjack.Dial(config.Server, config.Database)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}

	for {
		log.Printf("Number of cached states: %d\n", len(states))
		for id, state := range(states) {
			now := time.Now().Unix()
			event := flapjack.Event{
				Entity:  state.Entity,
				Check:   state.Check,
				Type:    state.Type,
				State:   state.State,
				Summary: state.Summary,
				Time:    now,
			}

			// Stale state sends UNKNOWNs
			if now - state.Time > state.TTL {
				log.Printf("State for %s is stale. Sending UNKNOWN.\n", id)
				event.State = "UNKNOWN"
				event.Summary = fmt.Sprintf("httpbroker: Cached state is stale (>%ds old)", state.TTL)
			}
			if config.Debug {
				log.Printf("Sending event data for %s\n", id)
			}
			transport.Send(event)
		}
		time.Sleep(config.Interval)
	}
}

var (
	port		= kingpin.Flag("port", "Address to bind HTTP server (default 3090)").Default("3090").OverrideDefaultFromEnvar("PORT").String()
	server		= kingpin.Flag("server", "Redis server to connect to (default localhost:6380)").Default("localhost:6380").String()
	database	= kingpin.Flag("database", "Redis database to connect to (default 0)").Int() // .Default("13").Int()
	interval	= kingpin.Flag("interval", "How often to submit events (default 10s)").Default("10s").Duration()
	debug		= kingpin.Flag("debug", "Enable verbose output (default false)").Bool()
)

type Config struct {
	Port		string
	Server		string
	Database	int
	Interval	time.Duration
	Debug		bool
}

func main() {
	kingpin.Version("0.0.1")
	kingpin.Parse()

	config := Config{
		Server: 	*server,
		Database: 	*database,
		Interval: 	*interval,
		Debug:		*debug,
		Port: 		":" + *port,
	}
	if config.Debug {
		log.Printf("Booting with config: %+v\n", config)
	}

	updates := make(chan State)
	state := map[string]State{}

	go cacheState(updates, state)
	go submitCachedState(state, config)

	m := martini.Classic()
	m.Group("/state", func(r martini.Router) {
		r.Post("", func(res http.ResponseWriter, req *http.Request) {
			CreateState(updates, res, req)
		})
		r.Get("", func() []byte {
			data, _ := json.Marshal(state)
			return data
		})
	})

	log.Fatal(http.ListenAndServe(config.Port, m))
}
<|endoftext|>


<commit_before>package shlike

import "io/ioutil"
import "os"
import "testing"

import . "github.com/smartystreets/goconvey/convey"

func stderrFor(fn func()) string {
	defer func(stderr *os.File) { os.Stderr = stderr }(os.Stderr)
	os.Stderr, _ = ioutil.TempFile("", "shlike.test.")
	fn()
	os.Stderr.Sync()
	os.Stderr.Seek(0, 0)
	stderrb, _ := ioutil.ReadAll(os.Stderr)
	return string(stderrb)
}

func TestLexer(t *testing.T) {
	Convey("Lexical Analysis", t, func() {
		var c = NewConfig()

		Convey("Word and line splitting and escaping", func() {
			Convey("Smoke test", func() {
				c.Eval(`
foo bar
baz
quux
tony halik
`)
				So(c.lines, ShouldResemble, [][]string{
					{"foo", "bar"},
					{"baz"},
					{"quux"},
					{"tony", "halik"},
				})
			})

			Convey("Escaping", func() {
				c.Eval(`
Tony\ Halik 'Tony Halik' "Tony Halik" \
\T'o'"n"y' H'alik
'$tota#lly' \$what\$0\#\"ever\' '"' "'"
'foo
bar' "baz
quux" "xy\
zzy" 'what\
ever'
`)
				Println(c.Eval("cr\r\nlf\\\r\n\"cr\\\r\nlf\""))
				So(c.lines, ShouldResemble, [][]string{
					{"Tony Halik", "Tony Halik", "Tony Halik", "Tony Halik"},
					{"$tota#lly", "$what$0#\"ever'", "\"", "'"},
					{"foo\nbar", "baz\nquux", "xyzzy", "what\\\never"},
					{"cr"}, {"lf", "crlf"},
				})
			})

			Convey("Empty strings", func() {
				c.Eval("Tony Hal\"\"ik '' Tony\\ Ha''lik \"\" ")
				So(c.lines, ShouldResemble, [][]string{{"Tony", "Halik", "", "Tony Halik", ""}})
			})

			Convey("Comments", func() {
				c.Eval("Tony Halik # tu byłem")
				So(c.lines, ShouldResemble, [][]string{{"Tony", "Halik"}})
			})
		})

		Convey("Variable setting", func() {
			c.Set("FOO", "Foo")
			c.Set("BAR", "Bar")
			c.Set("BAZ", "Baz")
			c.Eval(`
FOO = Tony Halik
BAR ?= Tony Halik
BAZ += Quux
QUUX = Quux
`)
			So(c.Get("FOO"), ShouldResemble, []string{"Tony", "Halik"})
			So(c.Get("BAR"), ShouldResemble, []string{"Bar"})
			So(c.Get("BAZ"), ShouldResemble, []string{"Baz", "Quux"})
			So(c.Get("QUUX"), ShouldResemble, []string{"Quux"})
		})

		Convey("Variable expansion", func() {
			c.Set("FOO", "Tony", "Halik")
			c.Eval(`$FOO "$FOO" '$FOO' ${FOO} "${FOO}" '${FOO}' tu${FOO}byłem "tu${FOO}byłem" tam$FOO-też "tam$FOO-też"`)
			So(c.lines, ShouldResemble, [][]string{{
				"Tony", "Halik", // bare/unquoted
				"Tony Halik",    // bare/doublequoted
				"$FOO",          // bare/singlequoted
				"Tony", "Halik", // braced/unquoted
				"Tony Halik",                   // braced/doublequoted
				"${FOO}",                       // braced/singlequoted
				"tu", "Tony", "Halik", "byłem", // braced, surronded, unquoted
				"tuTony Halikbyłem",            // braced, surrounded, doublequoted
				"tam", "Tony", "Halik", "-też", // unbraced, surrounded, unquoted
				"tamTony Halik-też", // unbraced, surrounded, doublequoted
			}})
		})

		Convey("Invalid input", func() {
			So(c.Eval(`'foo`), ShouldNotBeNil)
			So(c.Eval(`"foo`), ShouldNotBeNil)
			So(c.Eval("fo\ro"), ShouldNotBeNil)
		})

		Convey("Undefined variable warnings", func() {
			So(stderrFor(func() { c.Eval("$undef") }), ShouldEndWith, "WARNING: Undefined variable \"undef\"\n")
		})
	})
}
<commit_msg>Delete debut Println()<commit_after>package shlike

import "io/ioutil"
import "os"
import "testing"

import . "github.com/smartystreets/goconvey/convey"

func stderrFor(fn func()) string {
	defer func(stderr *os.File) { os.Stderr = stderr }(os.Stderr)
	os.Stderr, _ = ioutil.TempFile("", "shlike.test.")
	fn()
	os.Stderr.Sync()
	os.Stderr.Seek(0, 0)
	stderrb, _ := ioutil.ReadAll(os.Stderr)
	return string(stderrb)
}

func TestLexer(t *testing.T) {
	Convey("Lexical Analysis", t, func() {
		var c = NewConfig()

		Convey("Word and line splitting and escaping", func() {
			Convey("Smoke test", func() {
				c.Eval(`
foo bar
baz
quux
tony halik
`)
				So(c.lines, ShouldResemble, [][]string{
					{"foo", "bar"},
					{"baz"},
					{"quux"},
					{"tony", "halik"},
				})
			})

			Convey("Escaping", func() {
				c.Eval(`
Tony\ Halik 'Tony Halik' "Tony Halik" \
\T'o'"n"y' H'alik
'$tota#lly' \$what\$0\#\"ever\' '"' "'"
'foo
bar' "baz
quux" "xy\
zzy" 'what\
ever'
`)
				c.Eval("cr\r\nlf\\\r\n\"cr\\\r\nlf\"")
				So(c.lines, ShouldResemble, [][]string{
					{"Tony Halik", "Tony Halik", "Tony Halik", "Tony Halik"},
					{"$tota#lly", "$what$0#\"ever'", "\"", "'"},
					{"foo\nbar", "baz\nquux", "xyzzy", "what\\\never"},
					{"cr"}, {"lf", "crlf"},
				})
			})

			Convey("Empty strings", func() {
				c.Eval("Tony Hal\"\"ik '' Tony\\ Ha''lik \"\" ")
				So(c.lines, ShouldResemble, [][]string{{"Tony", "Halik", "", "Tony Halik", ""}})
			})

			Convey("Comments", func() {
				c.Eval("Tony Halik # tu byłem")
				So(c.lines, ShouldResemble, [][]string{{"Tony", "Halik"}})
			})
		})

		Convey("Variable setting", func() {
			c.Set("FOO", "Foo")
			c.Set("BAR", "Bar")
			c.Set("BAZ", "Baz")
			c.Eval(`
FOO = Tony Halik
BAR ?= Tony Halik
BAZ += Quux
QUUX = Quux
`)
			So(c.Get("FOO"), ShouldResemble, []string{"Tony", "Halik"})
			So(c.Get("BAR"), ShouldResemble, []string{"Bar"})
			So(c.Get("BAZ"), ShouldResemble, []string{"Baz", "Quux"})
			So(c.Get("QUUX"), ShouldResemble, []string{"Quux"})
		})

		Convey("Variable expansion", func() {
			c.Set("FOO", "Tony", "Halik")
			c.Eval(`$FOO "$FOO" '$FOO' ${FOO} "${FOO}" '${FOO}' tu${FOO}byłem "tu${FOO}byłem" tam$FOO-też "tam$FOO-też"`)
			So(c.lines, ShouldResemble, [][]string{{
				"Tony", "Halik", // bare/unquoted
				"Tony Halik",    // bare/doublequoted
				"$FOO",          // bare/singlequoted
				"Tony", "Halik", // braced/unquoted
				"Tony Halik",                   // braced/doublequoted
				"${FOO}",                       // braced/singlequoted
				"tu", "Tony", "Halik", "byłem", // braced, surronded, unquoted
				"tuTony Halikbyłem",            // braced, surrounded, doublequoted
				"tam", "Tony", "Halik", "-też", // unbraced, surrounded, unquoted
				"tamTony Halik-też", // unbraced, surrounded, doublequoted
			}})
		})

		Convey("Invalid input", func() {
			So(c.Eval(`'foo`), ShouldNotBeNil)
			So(c.Eval(`"foo`), ShouldNotBeNil)
			So(c.Eval("fo\ro"), ShouldNotBeNil)
		})

		Convey("Undefined variable warnings", func() {
			So(stderrFor(func() { c.Eval("$undef") }), ShouldEndWith, "WARNING: Undefined variable \"undef\"\n")
		})
	})
}
<|endoftext|>