<commit_before>package activitystreams

import (
	"github.com/pkg/errors"

	"fknsrs.biz/p/don/atom"
	"fknsrs.biz/p/don/commonxml"
)

func Fetch(u string) (*Feed, error) {
	var v Feed
	if err := commonxml.Fetch(u, &v); err != nil {
		return nil, errors.Wrap(err, "Fetch")
	}

	return &v, nil
}

type Feed struct {
	atom.Feed

	Author *Author  `xml:"author" json:"author,omitempty"`
	Entry  []Object `xml:"entry" json:"entry,omitempty"`
}

type Author struct {
	atom.Author

	ObjectType        string `xml:"http://activitystrea.ms/spec/1.0/ object-type" json:"objectType,omitempty"`
	PreferredUsername string `xml:"http://portablecontacts.net/spec/1.0 preferredUsername" json:"preferredUsername,omitempty"`
	DisplayName       string `xml:"http://portablecontacts.net/spec/1.0 displayName" json:"displayName,omitempty"`
	Note              string `xml:"http://portablecontacts.net/spec/1.0 note" json:"note,omitempty"`
	Scope             string `xml:"http://mastodon.social/schema/1.0 scope" json:"scope,omitempty"`
}

type Object struct {
	atom.Entry

	Author     *Author         `xml:"author" json:"author,omitempty"`
	Verb       string          `xml:"http://activitystrea.ms/spec/1.0/ verb" json:"verb,omitempty"`
	ObjectType string          `xml:"http://activitystrea.ms/spec/1.0/ object-type" json:"objectType,omitempty"`
	Object     *Object         `xml:"http://activitystrea.ms/spec/1.0/ object" json:"object,omitempty"`
	InReplyTo  *commonxml.Link `xml:"http://purl.org/syndication/thread/1.0 in-reply-to" json:"inReplyTo,omitempty"`
}
<commit_msg>add Acct method for getting user@host from activity authors<commit_after>package activitystreams

import (
	"github.com/pkg/errors"
	"net/url"

	"fknsrs.biz/p/don/atom"
	"fknsrs.biz/p/don/commonxml"
)

func Fetch(u string) (*Feed, error) {
	var v Feed
	if err := commonxml.Fetch(u, &v); err != nil {
		return nil, errors.Wrap(err, "Fetch")
	}

	return &v, nil
}

type Feed struct {
	atom.Feed

	Author *Author  `xml:"author" json:"author,omitempty"`
	Entry  []Object `xml:"entry" json:"entry,omitempty"`
}

type Author struct {
	atom.Author

	ObjectType        string `xml:"http://activitystrea.ms/spec/1.0/ object-type" json:"objectType,omitempty"`
	PreferredUsername string `xml:"http://portablecontacts.net/spec/1.0 preferredUsername" json:"preferredUsername,omitempty"`
	DisplayName       string `xml:"http://portablecontacts.net/spec/1.0 displayName" json:"displayName,omitempty"`
	Note              string `xml:"http://portablecontacts.net/spec/1.0 note" json:"note,omitempty"`
	Scope             string `xml:"http://mastodon.social/schema/1.0 scope" json:"scope,omitempty"`
}

func (a *Author) Acct() string {
	if a.Email != "" {
		return a.Email
	}

	if a.URI != "" && a.PreferredUsername != "" {
		if u, err := url.Parse(a.URI); err == nil {
			return a.PreferredUsername + "@" + u.Host
		}
	}

	return ""
}

type Object struct {
	atom.Entry

	Author     *Author         `xml:"author" json:"author,omitempty"`
	Verb       string          `xml:"http://activitystrea.ms/spec/1.0/ verb" json:"verb,omitempty"`
	ObjectType string          `xml:"http://activitystrea.ms/spec/1.0/ object-type" json:"objectType,omitempty"`
	Object     *Object         `xml:"http://activitystrea.ms/spec/1.0/ object" json:"object,omitempty"`
	InReplyTo  *commonxml.Link `xml:"http://purl.org/syndication/thread/1.0 in-reply-to" json:"inReplyTo,omitempty"`
}
<|endoftext|>


<commit_before>package api

import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/go-connections/nat"
)

func CreateContainer(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) (bool, string, error) {
	formattedImageName := FormatImageName(dc.ServiceName)

	// 2.1 make labels
	labelsMap := make(map[string]string)
	if len(dc.ComposeService.Labels) > 0 {
		for _, v := range dc.ComposeService.Labels {
			onelabel := FormatLabels(v)
			labelsMap[onelabel[0]] = onelabel[1]
		}
	}

	// reuse container if already running
	meliService := labelsMap["meli_service"]
	filters := filters.NewArgs()
	filters.Add("label", fmt.Sprintf("meli_service=%s", meliService))
	containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
		Quiet:   true,
		All:     true,
		Filters: filters})
	if err != nil {
		log.Println(" :unable to list containers")
	}
	if len(containers) > 0 {
		return true, containers[0].ID, nil
	}

	//2.2 make ports
	portsMap := make(map[nat.Port]struct{})
	portBindingMap := make(map[nat.Port][]nat.PortBinding)
	if len(dc.ComposeService.Ports) > 0 {
		for _, v := range dc.ComposeService.Ports {
			oneport := FormatPorts(v)
			hostport := oneport[0]
			containerport := oneport[1]
			port, err := nat.NewPort("tcp", containerport)
			myPortBinding := nat.PortBinding{HostPort: hostport}
			if err != nil {
				log.Println(err, " :unable to create a nat.Port")
			}
			portsMap[port] = EmptyStruct{}
			portBindingMap[port] = []nat.PortBinding{myPortBinding}
		}
	}
	//2.3 create command
	cmd := strslice.StrSlice{}
	if dc.ComposeService.Command != "" {
		sliceCommand := strings.Fields(dc.ComposeService.Command)
		cmd = strslice.StrSlice(sliceCommand)
	}
	//2.4 create restart policy
	restartPolicy := container.RestartPolicy{}
	if dc.ComposeService.Restart != "" {
		// You cannot set MaximumRetryCount for the following restart policies;
		// always, no, unless-stopped
		if dc.ComposeService.Restart == "on-failure" {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart, MaximumRetryCount: 3}
		} else {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart}
		}

	}
	//2.5 build image
	imageNamePtr := &dc.ComposeService.Image
	if dc.ComposeService.Build != (Buildstruct{}) {
		imageName, err := BuildDockerImage(ctx, cli, dc)
		if err != nil {
			return false, "", &popagateError{originalErr: err}
		}
		// done this way so that we can manipulate the value of the
		// imageName inside this scope
		imageNamePtr = &imageName
	}
	imageName := *imageNamePtr

	//2.6 add volumes
	volume := make(map[string]struct{})
	binds := []string{}
	if len(dc.ComposeService.Volumes) > 0 {
		for _, v := range dc.ComposeService.Volumes {
			vol := FormatServiceVolumes(v, dc.DockerComposeFile)
			volume[vol[1]] = EmptyStruct{}
			// TODO: handle other read/write modes
			whatToBind := vol[0] + ":" + vol[1] + ":rw"
			binds = append(binds, whatToBind)
		}
	}

	containerCreateResp, err := cli.ContainerCreate(
		ctx,
		&container.Config{
			Image:        imageName,
			Labels:       labelsMap,
			Env:          dc.ComposeService.Environment,
			ExposedPorts: portsMap,
			Cmd:          cmd,
			Volumes:      volume},
		&container.HostConfig{
			DNS: []string{
				"8.8.8.8",
				"8.8.4.4",
				"2001:4860:4860::8888",
				"2001:4860:4860::8844"},
			DNSSearch: []string{
				"8.8.8.8",
				"8.8.4.4",
				"2001:4860:4860::8888",
				"2001:4860:4860::8844"},
			PublishAllPorts: false,
			PortBindings:    portBindingMap,
			NetworkMode:     container.NetworkMode(dc.NetworkName),
			RestartPolicy:   restartPolicy,
			Binds:           binds,
			Links:           dc.ComposeService.Links},
		nil,
		formattedImageName)
	if err != nil {
		return false, "", &popagateError{
			originalErr: err,
			newErr:      errors.New(" :unable to create container")}
	}

	dc.UpdateContainerID(containerCreateResp.ID)
	return false, containerCreateResp.ID, nil
}

func ContainerStart(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	err := cli.ContainerStart(
		ctx,
		dc.ContainerID,
		types.ContainerStartOptions{})
	if err != nil {
		return &popagateError{
			originalErr: err,
			newErr:      fmt.Errorf(" :unable to start container %s", dc.ContainerID)}

	}
	return nil
}

func ContainerLogs(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	containerLogResp, err := cli.ContainerLogs(
		ctx,
		dc.ContainerID,
		types.ContainerLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Timestamps: true,
			Follow:     dc.FollowLogs,
			Details:    true,
			Tail:       "all"})

	if err != nil {
		if err != nil {
			return &popagateError{
				originalErr: err,
				newErr:      fmt.Errorf(" :unable to get container logs %s", dc.ContainerID)}
		}
	}
	defer containerLogResp.Close()

	// supplying your own buffer is perfomant than letting the system do it for you
	buff := make([]byte, 2048)
	io.CopyBuffer(dc.LogMedium, containerLogResp, buff)

	return nil
}
<commit_msg>fix xomments<commit_after>package api

import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/go-connections/nat"
)

func CreateContainer(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) (bool, string, error) {
	// 1. make labels
	labelsMap := make(map[string]string)
	if len(dc.ComposeService.Labels) > 0 {
		for _, v := range dc.ComposeService.Labels {
			onelabel := FormatLabels(v)
			labelsMap[onelabel[0]] = onelabel[1]
		}
	}

	// reuse container if already running
	meliService := labelsMap["meli_service"]
	filters := filters.NewArgs()
	filters.Add("label", fmt.Sprintf("meli_service=%s", meliService))
	containers, err := cli.ContainerList(ctx, types.ContainerListOptions{
		Quiet:   true,
		All:     true,
		Filters: filters})
	if err != nil {
		log.Println(" :unable to list containers")
	}
	if len(containers) > 0 {
		return true, containers[0].ID, nil
	}

	// 2. make ports
	portsMap := make(map[nat.Port]struct{})
	portBindingMap := make(map[nat.Port][]nat.PortBinding)
	if len(dc.ComposeService.Ports) > 0 {
		for _, v := range dc.ComposeService.Ports {
			oneport := FormatPorts(v)
			hostport := oneport[0]
			containerport := oneport[1]
			port, err := nat.NewPort("tcp", containerport)
			myPortBinding := nat.PortBinding{HostPort: hostport}
			if err != nil {
				log.Println(err, " :unable to create a nat.Port")
			}
			portsMap[port] = EmptyStruct{}
			portBindingMap[port] = []nat.PortBinding{myPortBinding}
		}
	}
	// 3. create command
	cmd := strslice.StrSlice{}
	if dc.ComposeService.Command != "" {
		sliceCommand := strings.Fields(dc.ComposeService.Command)
		cmd = strslice.StrSlice(sliceCommand)
	}
	// 4. create restart policy
	restartPolicy := container.RestartPolicy{}
	if dc.ComposeService.Restart != "" {
		// You cannot set MaximumRetryCount for the following restart policies;
		// always, no, unless-stopped
		if dc.ComposeService.Restart == "on-failure" {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart, MaximumRetryCount: 3}
		} else {
			restartPolicy = container.RestartPolicy{Name: dc.ComposeService.Restart}
		}

	}
	// 5. build image
	imageNamePtr := &dc.ComposeService.Image
	if dc.ComposeService.Build != (Buildstruct{}) {
		imageName, err := BuildDockerImage(ctx, cli, dc)
		if err != nil {
			return false, "", &popagateError{originalErr: err}
		}
		// done this way so that we can manipulate the value of the
		// imageName inside this scope
		imageNamePtr = &imageName
	}
	imageName := *imageNamePtr

	// 6. add volumes
	volume := make(map[string]struct{})
	binds := []string{}
	if len(dc.ComposeService.Volumes) > 0 {
		for _, v := range dc.ComposeService.Volumes {
			vol := FormatServiceVolumes(v, dc.DockerComposeFile)
			volume[vol[1]] = EmptyStruct{}
			// TODO: handle other read/write modes
			whatToBind := vol[0] + ":" + vol[1] + ":rw"
			binds = append(binds, whatToBind)
		}
	}

	containerCreateResp, err := cli.ContainerCreate(
		ctx,
		&container.Config{
			Image:        imageName,
			Labels:       labelsMap,
			Env:          dc.ComposeService.Environment,
			ExposedPorts: portsMap,
			Cmd:          cmd,
			Volumes:      volume},
		&container.HostConfig{
			DNS: []string{
				"8.8.8.8",
				"8.8.4.4",
				"2001:4860:4860::8888",
				"2001:4860:4860::8844"},
			DNSSearch: []string{
				"8.8.8.8",
				"8.8.4.4",
				"2001:4860:4860::8888",
				"2001:4860:4860::8844"},
			PublishAllPorts: false,
			PortBindings:    portBindingMap,
			NetworkMode:     container.NetworkMode(dc.NetworkName),
			RestartPolicy:   restartPolicy,
			Binds:           binds,
			Links:           dc.ComposeService.Links},
		nil,
		FormatImageName(dc.ServiceName))
	if err != nil {
		return false, "", &popagateError{
			originalErr: err,
			newErr:      errors.New(" :unable to create container")}
	}

	dc.UpdateContainerID(containerCreateResp.ID)
	return false, containerCreateResp.ID, nil
}

func ContainerStart(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	err := cli.ContainerStart(
		ctx,
		dc.ContainerID,
		types.ContainerStartOptions{})
	if err != nil {
		return &popagateError{
			originalErr: err,
			newErr:      fmt.Errorf(" :unable to start container %s", dc.ContainerID)}

	}
	return nil
}

func ContainerLogs(ctx context.Context, cli MeliAPiClient, dc *DockerContainer) error {
	containerLogResp, err := cli.ContainerLogs(
		ctx,
		dc.ContainerID,
		types.ContainerLogsOptions{
			ShowStdout: true,
			ShowStderr: true,
			Timestamps: true,
			Follow:     dc.FollowLogs,
			Details:    true,
			Tail:       "all"})

	if err != nil {
		if err != nil {
			return &popagateError{
				originalErr: err,
				newErr:      fmt.Errorf(" :unable to get container logs %s", dc.ContainerID)}
		}
	}
	defer containerLogResp.Close()

	// supplying your own buffer is perfomant than letting the system do it for you
	buff := make([]byte, 2048)
	io.CopyBuffer(dc.LogMedium, containerLogResp, buff)

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"strings"

	"sync"

	"github.com/getgauge/gauge/util"
	"github.com/sourcegraph/go-langserver/pkg/lsp"
)

type files struct {
	cache map[lsp.DocumentURI][]string
	sync.Mutex
}

func (file *files) add(uri lsp.DocumentURI, text string) {
	file.Lock()
	defer file.Unlock()
	file.cache[uri] = util.GetLinesFromText(text)
}

func (file *files) remove(uri lsp.DocumentURI) {
	file.Lock()
	defer file.Unlock()
	delete(file.cache, uri)
}

func (file *files) line(uri lsp.DocumentURI, lineNo int) string {
	file.Lock()
	defer file.Unlock()
	return file.cache[uri][lineNo]
}

func (file *files) content(uri lsp.DocumentURI) []string {
	file.Lock()
	defer file.Unlock()
	return file.cache[uri]
}

func (file *files) contentRange(uri lsp.DocumentURI, start, end int) []string {
	file.Lock()
	defer file.Unlock()
	return file.cache[uri][start-1 : end]
}

func (file *files) exists(uri lsp.DocumentURI) bool {
	file.Lock()
	defer file.Unlock()
	_, ok := file.cache[uri]
	return ok
}

var openFilesCache = &files{cache: make(map[lsp.DocumentURI][]string)}

func openFile(params lsp.DidOpenTextDocumentParams) {
	openFilesCache.add(params.TextDocument.URI, params.TextDocument.Text)
}

func closeFile(params lsp.DidCloseTextDocumentParams) {
	openFilesCache.remove(params.TextDocument.URI)
}

func changeFile(params lsp.DidChangeTextDocumentParams) {
	openFilesCache.add(params.TextDocument.URI, params.ContentChanges[0].Text)
}

func getLine(uri lsp.DocumentURI, line int) string {
	return openFilesCache.line(uri, line)
}

func getContent(uri lsp.DocumentURI) string {
	return strings.Join(openFilesCache.content(uri), "\n")
}

func getLineCount(uri lsp.DocumentURI) int {
	return len(openFilesCache.content(uri))
}

func isOpen(uri lsp.DocumentURI) bool {
	return openFilesCache.exists(uri)
}

func getContentRange(uri lsp.DocumentURI, start, end int) []string {
	return openFilesCache.contentRange(uri, start, end)
}
<commit_msg>Return empty string is content not present is file cache, #994<commit_after>// Copyright 2018 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"strings"

	"sync"

	"github.com/getgauge/gauge/util"
	"github.com/sourcegraph/go-langserver/pkg/lsp"
)

type files struct {
	cache map[lsp.DocumentURI][]string
	sync.Mutex
}

func (file *files) add(uri lsp.DocumentURI, text string) {
	file.Lock()
	defer file.Unlock()
	file.cache[uri] = util.GetLinesFromText(text)
}

func (file *files) remove(uri lsp.DocumentURI) {
	file.Lock()
	defer file.Unlock()
	delete(file.cache, uri)
}

func (file *files) line(uri lsp.DocumentURI, lineNo int) string {
	file.Lock()
	defer file.Unlock()
	if len(file.cache[uri]) < lineNo {
		return ""
	}
	return file.cache[uri][lineNo]
}

func (file *files) content(uri lsp.DocumentURI) []string {
	file.Lock()
	defer file.Unlock()
	return file.cache[uri]
}

func (file *files) contentRange(uri lsp.DocumentURI, start, end int) []string {
	file.Lock()
	defer file.Unlock()
	return file.cache[uri][start-1 : end]
}

func (file *files) exists(uri lsp.DocumentURI) bool {
	file.Lock()
	defer file.Unlock()
	_, ok := file.cache[uri]
	return ok
}

var openFilesCache = &files{cache: make(map[lsp.DocumentURI][]string)}

func openFile(params lsp.DidOpenTextDocumentParams) {
	openFilesCache.add(params.TextDocument.URI, params.TextDocument.Text)
}

func closeFile(params lsp.DidCloseTextDocumentParams) {
	openFilesCache.remove(params.TextDocument.URI)
}

func changeFile(params lsp.DidChangeTextDocumentParams) {
	openFilesCache.add(params.TextDocument.URI, params.ContentChanges[0].Text)
}

func getLine(uri lsp.DocumentURI, line int) string {
	return openFilesCache.line(uri, line)
}

func getContent(uri lsp.DocumentURI) string {
	return strings.Join(openFilesCache.content(uri), "\n")
}

func getLineCount(uri lsp.DocumentURI) int {
	return len(openFilesCache.content(uri))
}

func isOpen(uri lsp.DocumentURI) bool {
	return openFilesCache.exists(uri)
}

func getContentRange(uri lsp.DocumentURI, start, end int) []string {
	return openFilesCache.contentRange(uri, start, end)
}
<|endoftext|>


<commit_before>package unit

import (
	"fmt"
	"github.com/timeredbull/tsuru/log"
	"os/exec"
)

type Unit struct {
	Type string
	Name string
}

func (u *Unit) Create() error {
	cmd := exec.Command("juju", "deploy", "--repository=/home/charms", "local:oneiric/"+u.Type, u.Name)
	log.Print("deploying %s with name %s", u.Type, u.Name)
	return cmd.Start()
}

func (u *Unit) Destroy() error {
	cmd := exec.Command("juju", "destroy-service", u.Name)
	log.Print("destroying %s with name %s", u.Type, u.Name)
	return cmd.Start()
}

func (u *Unit) AddRelation(su *Unit) error {
	cmd := exec.Command("juju", "add-relation", u.Name, su.Name)
	log.Print("relating %s with service %s", u.Name, su.Name)
	return cmd.Start()
}

func (u *Unit) RemoveRelation(su *Unit) error {
	cmd := exec.Command("juju", "remove-relation", u.Name, su.Name)
	log.Print("unrelating %s with service %s", u.Name, su.Name)
	return cmd.Start()
}

func (u *Unit) Command(command string) ([]byte, error) {
	cmd := exec.Command("juju", "ssh", "-o", "StrictHostKeyChecking no", u.Name+"/0", command)
	log.Print("executing %s on %s", command, u.Name)
	return cmd.CombinedOutput()
}

func (u *Unit) SendFile(srcPath, dstPath string) error {
	cmd := exec.Command("juju", "scp", "-r", "-o", "StrictHostKeyChecking no", srcPath, u.Name+"/0:"+dstPath)
	log.Print("sending %s to %s on %s", srcPath, dstPath, u.Name)
	return cmd.Start()
}

func (u *Unit) ExecuteHook(hook string) error {
	cmd := fmt.Sprintf("/var/lib/tsuru/hooks/%s", hook)
	output, err := u.Command(cmd)
	log.Print(string(output))
	return err
}
<commit_msg>using Printf for unit logs<commit_after>package unit

import (
	"fmt"
	"github.com/timeredbull/tsuru/log"
	"os/exec"
)

type Unit struct {
	Type string
	Name string
}

func (u *Unit) Create() error {
	cmd := exec.Command("juju", "deploy", "--repository=/home/charms", "local:oneiric/"+u.Type, u.Name)
	log.Printf("deploying %s with name %s", u.Type, u.Name)
	return cmd.Start()
}

func (u *Unit) Destroy() error {
	cmd := exec.Command("juju", "destroy-service", u.Name)
	log.Printf("destroying %s with name %s", u.Type, u.Name)
	return cmd.Start()
}

func (u *Unit) AddRelation(su *Unit) error {
	cmd := exec.Command("juju", "add-relation", u.Name, su.Name)
	log.Printf("relating %s with service %s", u.Name, su.Name)
	return cmd.Start()
}

func (u *Unit) RemoveRelation(su *Unit) error {
	cmd := exec.Command("juju", "remove-relation", u.Name, su.Name)
	log.Printf("unrelating %s with service %s", u.Name, su.Name)
	return cmd.Start()
}

func (u *Unit) Command(command string) ([]byte, error) {
	cmd := exec.Command("juju", "ssh", "-o", "StrictHostKeyChecking no", u.Name+"/0", command)
	log.Printf("executing %s on %s", command, u.Name)
	return cmd.CombinedOutput()
}

func (u *Unit) SendFile(srcPath, dstPath string) error {
	cmd := exec.Command("juju", "scp", "-r", "-o", "StrictHostKeyChecking no", srcPath, u.Name+"/0:"+dstPath)
	log.Printf("sending %s to %s on %s", srcPath, dstPath, u.Name)
	return cmd.Start()
}

func (u *Unit) ExecuteHook(hook string) error {
	cmd := fmt.Sprintf("/var/lib/tsuru/hooks/%s", hook)
	output, err := u.Command(cmd)
	log.Print(string(output))
	return err
}
<|endoftext|>


<commit_before>package api

import (
    "apiGO/dbmodels"
    "apiGO/filter"
    "apiGO/service"
    "encoding/json"
    "gopkg.in/mgo.v2/bson"
    "net/http"
)

func (api *Api) GetUser(vars *ApiVar, resp *ApiResponse) error {
    userId, err, found := filter.GetIdFromParams(vars.RequestForm)
    if found {
        if err != nil {
            return badRequest(resp, err.Error())
        }

        return getUser(vars, resp, userId)
    }

    limit, err, found := filter.GetIntValueFromParams("limit", vars.RequestForm)
    if found {
        if err != nil {
            return badRequest(resp, err.Error())
        }

        return getAllUsers(vars, resp, limit)
    }

    return getAllUsers(vars, resp, -1)

}

func (api *Api) PostUser(vars *ApiVar, resp *ApiResponse) error {
    user := &dbmodels.User{}

    err := user.DeserializeJson(vars.RequestBody)
    if err != nil {
        return badRequest(resp, "The entity was not in the correct format")
    }

    if !filter.CheckUserIntegrity(user) {
        return badRequest(resp, "The entity doesn't comply to the integrity requirements")
    }

    err = service.CreateUser(user)
    if err != nil {
        return internalServerError(resp, "The entity could not be processed")
    }

    resp.StatusCode = http.StatusCreated
    resp.Message, _ = user.SerializeJson()

    return nil
}

func (api *Api) PutUser(vars *ApiVar, resp *ApiResponse) error {
    user := &dbmodels.User{}
    err := user.DeserializeJson(vars.RequestBody)

    if err != nil {
        return badRequest(resp, "The entity was not in the correct format")
    }

    if user.Id == "" {
        return badRequest(resp, "No id was specified for the user to be updated")
    }

    if !filter.CheckUserIntegrity(user) {
        return badRequest(resp, "The entity doesn't comply to the integrity requirements")
    }

    err = service.UpdateUser(user)
    if err != nil {
        return notFound(resp, "The user with the specified id could not be found")
    }

    resp.StatusCode = http.StatusOK
    resp.Message, _ = user.SerializeJson()

    return nil
}

func (api *Api) DeleteUser(vars *ApiVar, resp *ApiResponse) error {
    userId, err, found := filter.GetIdFromParams(vars.RequestForm)

    if found {
        if err != nil {
            return badRequest(resp, err.Error())
        }

        err = service.DeleteUser(userId)
        if err != nil {
            return notFound(resp, err.Error())
        }

        resp.StatusCode = http.StatusOK
        return nil
    }

    return badRequest(resp, err.Error())
}

func getAllUsers(vars *ApiVar, resp *ApiResponse, limit int) error {
    var users []dbmodels.User
    var err error

    if limit == 0 {
        return badRequest(resp, "The limit cannot be 0. Use the value -1 for retrieving all the entities")
    }

    if limit != -1 {
        users, err = service.GetAllUsersLimited(limit)
    } else {
        users, err = service.GetAllUsers()
    }

    if err != nil {
        return internalServerError(resp, err.Error())
    }

    usersJson, err := json.MarshalIndent(users, "", "  ")

    if err != nil {
        return internalServerError(resp, err.Error())
    }

    resp.StatusCode = http.StatusOK
    resp.Message = usersJson

    return nil
}

func getUser(vars *ApiVar, resp *ApiResponse, userId bson.ObjectId) error {
    user, err := service.GetUser(userId)

    if err != nil {
        if err.Error() == "not found" {
            return notFound(resp, err.Error())
        } else {
            return internalServerError(resp, err.Error())
        }
    }

    if user == nil {
        return notFound(resp, "No User with the selected id was found")
    }

    userJson, err := user.SerializeJson()

    if err != nil {
        return internalServerError(resp, err.Error())
    }

    resp.StatusCode = http.StatusOK
    resp.Message = userJson

    return nil
}
<commit_msg>Made the users endpoint to communicate with the client using full jsons, not relational ones that appear in the database<commit_after>package api

import (
    "apiGO/dbmodels"
    "apiGO/filter"
    "apiGO/interfaces"
    "apiGO/models"
    "apiGO/service"
    "encoding/json"
    "gopkg.in/mgo.v2/bson"
    "net/http"
)

func (api *Api) GetUser(vars *ApiVar, resp *ApiResponse) error {
    userId, err, found := filter.GetIdFromParams(vars.RequestForm)
    if found {
        if err != nil {
            return badRequest(resp, err.Error())
        }

        return getUser(vars, resp, userId)
    }

    limit, err, found := filter.GetIntValueFromParams("limit", vars.RequestForm)
    if found {
        if err != nil {
            return badRequest(resp, err.Error())
        }

        return getAllUsers(vars, resp, limit)
    }

    return getAllUsers(vars, resp, -1)

}

func (api *Api) PostUser(vars *ApiVar, resp *ApiResponse) error {
    expandedUser := &models.User{}

    err := expandedUser.DeserializeJson(vars.RequestBody)
    if err != nil {
        return badRequest(resp, "The entity was not in the correct format")
    }

    if !filter.CheckUserIntegrity(expandedUser) {
        return badRequest(resp, "The entity doesn't comply to the integrity requirements")
    }

    user, err := expandedUser.Collapse()
    if err != nil {
        return internalServerError(resp, err.Error())
    }

    user, err = service.CreateUser(user)
    if err != nil || user == nil {
        return internalServerError(resp, "The entity could not be processed")
    }

    resp.StatusCode = http.StatusCreated
    resp.Message, _ = user.SerializeJson()

    return nil
}

func (api *Api) PutUser(vars *ApiVar, resp *ApiResponse) error {
    expandedUser := &models.User{}

    err := expandedUser.DeserializeJson(vars.RequestBody)
    if err != nil {
        return badRequest(resp, "The entity was not in the correct format")
    }

    if expandedUser.Id == "" {
        return badRequest(resp, "No id was specified for the user to be updated")
    }

    if !filter.CheckUserIntegrity(expandedUser) {
        return badRequest(resp, "The entity doesn't comply to the integrity requirements")
    }

    user, err := expandedUser.Collapse()
    if err != nil {
        return internalServerError(resp, err.Error())
    }

    err = service.UpdateUser(user)
    if err != nil {
        return notFound(resp, "The user with the specified id could not be found")
    }

    resp.StatusCode = http.StatusOK
    resp.Message, _ = user.SerializeJson()

    return nil
}

func (api *Api) DeleteUser(vars *ApiVar, resp *ApiResponse) error {
    userId, err, found := filter.GetIdFromParams(vars.RequestForm)

    if found {
        if err != nil {
            return badRequest(resp, err.Error())
        }

        err = service.DeleteUser(userId)
        if err != nil {
            return notFound(resp, err.Error())
        }

        resp.StatusCode = http.StatusOK
        return nil
    }

    return badRequest(resp, err.Error())
}

func getAllUsers(vars *ApiVar, resp *ApiResponse, limit int) error {
    var users []dbmodels.User
    var err error

    if limit == 0 {
        return badRequest(resp, "The limit cannot be 0. Use the value -1 for retrieving all the entities")
    }

    if limit != -1 {
        users, err = service.GetAllUsersLimited(limit)
    } else {
        users, err = service.GetAllUsers()
    }

    if err != nil {
        return internalServerError(resp, err.Error())
    }

    var expandedUsers []models.User
    expandedUsers = make([]models.User, len(users))

    for i := 0; i < len(users); i++ {
        err = expandedUsers[i].Expand(users[i])

        if err != nil {
            return internalServerError(resp, err.Error())
        }
    }

    usersJson, err := json.MarshalIndent(expandedUsers, interfaces.JsonPrefix, interfaces.JsonIndent)

    if err != nil {
        return internalServerError(resp, err.Error())
    }

    resp.StatusCode = http.StatusOK
    resp.Message = usersJson

    return nil
}

func getUser(vars *ApiVar, resp *ApiResponse, userId bson.ObjectId) error {
    user, err := service.GetUser(userId)

    if err != nil {
        if err.Error() == "not found" {
            return notFound(resp, err.Error())
        } else {
            return internalServerError(resp, err.Error())
        }
    }

    if user == nil {
        return notFound(resp, "No User with the selected id was found")
    }

    var expandedUser models.User
    err = expandedUser.Expand(*user)

    if err != nil {
        return internalServerError(resp, err.Error())
    }

    userJson, err := expandedUser.SerializeJson()
    if err != nil {
        return internalServerError(resp, err.Error())
    }

    resp.StatusCode = http.StatusOK
    resp.Message = userJson

    return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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 duck defines logic for defining and consuming "duck typed"
// Kubernetes resources.  Producers define partial resource definitions
// that resource authors may choose to implement to interoperate with
// consumers of these "duck typed" interfaces.
// For more information see:
// TODO(mattmoor): Add link to doc.
package duck
<commit_msg>Link to the doc on Duck Typing, which I missed adding before. (#105)<commit_after>/*
Copyright 2018 The Knative Authors

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 duck defines logic for defining and consuming "duck typed"
// Kubernetes resources.  Producers define partial resource definitions
// that resource authors may choose to implement to interoperate with
// consumers of these "duck typed" interfaces.
// For more information see:
// https://docs.google.com/document/d/16j8C91jML4fQRQPhnHihNJUJDcbvW0RM1YAX2REHgyY/edit#
package duck
<|endoftext|>


<commit_before>package backend

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"sort"
	"strings"
	"time"

	"github.com/cblomart/vsphere-graphite/utils"
	"github.com/valyala/fasthttp"
)

// ThinPrometheusClient tries to export metrics to prometheus as simply as possible
type ThinPrometheusClient struct {
	Hostname string
	Port     int
	address  string
}

const defaultPort = 9155

// NewThinPrometheusClient creates a new thin prometheus
func NewThinPrometheusClient(server string, port int) (ThinPrometheusClient, error) {
	//create the port
	if port == 0 {
		port = defaultPort
	} else if port < 1000 || port > 65535 {
		return ThinPrometheusClient{}, errors.New("port is not in a user range")
	}
	address := ""
	if len(server) > 0 {
		address = server
	}
	address = fmt.Sprintf("%s:%d", address, port)
	return ThinPrometheusClient{Hostname: server, Port: port, address: address}, nil
}

// ListenAndServe will start the listen thead for metric requests
func (client *ThinPrometheusClient) ListenAndServe() error {
	log.Printf("Start listening for metric request at %s\n", client.address)
	return fasthttp.ListenAndServe(client.address, fasthttp.CompressHandlerLevel(requestHandler, 9))
}

func requestHandler(ctx *fasthttp.RequestCtx) {
	if string(ctx.Path()) != "/metrics" {
		ctx.Error("Unsupported path", fasthttp.StatusNotFound)
		return
	}
	// prepare the channels for the request
	request := make(chan Point, 100)
	done := make(chan bool)
	channels := Channels{Request: &request, Done: &done}
	// create a buffer to organise metrics per type
	buffer := map[string][]string{}
	log.Println("Thin Prometheus Sending Query Request")
	// start the queriess
	select {
	case *queries <- channels:
		log.Println("Thin Prometheus Sent Query Request")
	default:
		ctx.Error("Query buffer full", fasthttp.StatusConflict)
		return
	}
	// start a timeout
	timeout := time.NewTimer(10 * time.Second)
	// wait for the results
	wait := true
	log.Println("Thin Prometheus is waiting for query results")
	for wait {
		select {
		case point := <-*channels.Request:
			// reset timer
			if !timeout.Stop() {
				<-timeout.C
			}
			timeout.Reset(10 * time.Second)
			// add point to the buffer
			addToThinPrometheusBuffer(buffer, &point)
		case <-*channels.Done:
			// finish consuming metrics and break loop
			log.Println("Thin Prometheus was signaled the end of the collection")
			wait = false
		case <-timeout.C:
			// stop timer
			timeout.Stop()
			log.Println("Thin Prometheus was signaled a timeout")
			wait = false
			ctx.Error("Timeout while gathering data", fasthttp.StatusRequestTimeout)
			return
		}
	}
	ctx.SetContentType("text/plain; charset=utf8")
	var outbuff bytes.Buffer
	for key, vals := range buffer {
		utils.MustWriteString(&outbuff, "#HELP ")
		utils.MustWriteString(&outbuff, key)
		utils.MustWriteString(&outbuff, " ")
		utils.MustWriteString(&outbuff, strings.Replace(key, "_", " ", -1))
		utils.MustWriteString(&outbuff, "\n")
		utils.MustWriteString(&outbuff, "#TYPE ")
		utils.MustWriteString(&outbuff, key)
		utils.MustWriteString(&outbuff, " gauge\n")
		for _, val := range vals {
			utils.MustWriteString(&outbuff, key)
			utils.MustWriteString(&outbuff, val)
			utils.MustWriteString(&outbuff, "\n")
		}
		_, err := ctx.Write(outbuff.Bytes())
		if err != nil {
			log.Printf("Error writing to buffer %s\n", err)
		}
		outbuff.Reset()
	}
	log.Println("Thin Prometheus Sended Response to request")
}

func addToThinPrometheusBuffer(metrics map[string][]string, point *Point) {
	var buffer bytes.Buffer
	utils.MustWriteString(&buffer, prefix)
	utils.MustWriteString(&buffer, "_")
	utils.MustWriteString(&buffer, point.Group)
	utils.MustWriteString(&buffer, "_")
	utils.MustWriteString(&buffer, point.Counter)
	utils.MustWriteString(&buffer, "_")
	utils.MustWriteString(&buffer, point.Rollup)
	metric := buffer.String()
	buffer.Reset()
	tags := point.GetTags(false, ",")
	var keys = make([]string, len(tags))
	for key := range tags {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	var tmp []string
	for _, key := range keys {
		if len(tags[key]) == 0 {
			continue
		}
		utils.MustWriteString(&buffer, key)
		utils.MustWriteString(&buffer, "=\"")
		utils.MustWriteString(&buffer, tags[key])
		utils.MustWriteString(&buffer, "\"")
		tmp = append(tmp, buffer.String())
		buffer.Reset()
	}
	strtags := strings.Join(tmp, ",")
	utils.MustWriteString(&buffer, "{")
	utils.MustWriteString(&buffer, strtags)
	utils.MustWriteString(&buffer, "} ")
	utils.MustWriteString(&buffer, utils.ValToString(point.Value, ",", false))

	if metrics[metric] == nil {
		metrics[metric] = []string{buffer.String()}
	} else {
		metrics[metric] = append(metrics[metric], buffer.String())
	}
	buffer.Reset()
}
<commit_msg>delayed timeout on thinprometheus<commit_after>package backend

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"sort"
	"strings"
	"time"

	"github.com/cblomart/vsphere-graphite/utils"
	"github.com/valyala/fasthttp"
)

// ThinPrometheusClient tries to export metrics to prometheus as simply as possible
type ThinPrometheusClient struct {
	Hostname string
	Port     int
	address  string
}

const defaultPort = 9155

// NewThinPrometheusClient creates a new thin prometheus
func NewThinPrometheusClient(server string, port int) (ThinPrometheusClient, error) {
	//create the port
	if port == 0 {
		port = defaultPort
	} else if port < 1000 || port > 65535 {
		return ThinPrometheusClient{}, errors.New("port is not in a user range")
	}
	address := ""
	if len(server) > 0 {
		address = server
	}
	address = fmt.Sprintf("%s:%d", address, port)
	return ThinPrometheusClient{Hostname: server, Port: port, address: address}, nil
}

// ListenAndServe will start the listen thead for metric requests
func (client *ThinPrometheusClient) ListenAndServe() error {
	log.Printf("Start listening for metric request at %s\n", client.address)
	return fasthttp.ListenAndServe(client.address, fasthttp.CompressHandlerLevel(requestHandler, 9))
}

func requestHandler(ctx *fasthttp.RequestCtx) {
	if string(ctx.Path()) != "/metrics" {
		ctx.Error("Unsupported path", fasthttp.StatusNotFound)
		return
	}
	// prepare the channels for the request
	request := make(chan Point, 100)
	done := make(chan bool)
	channels := Channels{Request: &request, Done: &done}
	// create a buffer to organise metrics per type
	buffer := map[string][]string{}
	log.Println("Thin Prometheus Sending Query Request")
	// start the queriess
	select {
	case *queries <- channels:
		log.Println("Thin Prometheus Sent Query Request")
	default:
		ctx.Error("Query buffer full", fasthttp.StatusConflict)
		return
	}
	// start a timeout
	timeout := time.NewTimer(300 * time.Millisecond)
	// recieve done
	recdone := false
	log.Println("Thin Prometheus is waiting for query results")
	for {
		select {
		case point := <-*channels.Request:
			// reset timer
			if !timeout.Stop() {
				<-timeout.C
			}
			timeout.Reset(300 * time.Millisecond)
			// add point to the buffer
			addToThinPrometheusBuffer(buffer, &point)
		case <-*channels.Done:
			// finish consuming metrics and break loop
			log.Println("Thin Prometheus was signaled the end of the collection")
			recdone = true
		case <-timeout.C:
			// stop timer
			if recdone {
				timeout.Stop()
				log.Println("Thin Prometheus was signaled a timeout")
				break
			}
		}
		if recdone {
			break
		}
	}
	ctx.SetContentType("text/plain; charset=utf8")
	var outbuff bytes.Buffer
	for key, vals := range buffer {
		utils.MustWriteString(&outbuff, "#HELP ")
		utils.MustWriteString(&outbuff, key)
		utils.MustWriteString(&outbuff, " ")
		utils.MustWriteString(&outbuff, strings.Replace(key, "_", " ", -1))
		utils.MustWriteString(&outbuff, "\n")
		utils.MustWriteString(&outbuff, "#TYPE ")
		utils.MustWriteString(&outbuff, key)
		utils.MustWriteString(&outbuff, " gauge\n")
		for _, val := range vals {
			utils.MustWriteString(&outbuff, key)
			utils.MustWriteString(&outbuff, val)
			utils.MustWriteString(&outbuff, "\n")
		}
		_, err := ctx.Write(outbuff.Bytes())
		if err != nil {
			log.Printf("Error writing to buffer %s\n", err)
		}
		outbuff.Reset()
	}
	log.Println("Thin Prometheus Sended Response to request")
}

func addToThinPrometheusBuffer(metrics map[string][]string, point *Point) {
	var buffer bytes.Buffer
	utils.MustWriteString(&buffer, prefix)
	utils.MustWriteString(&buffer, "_")
	utils.MustWriteString(&buffer, point.Group)
	utils.MustWriteString(&buffer, "_")
	utils.MustWriteString(&buffer, point.Counter)
	utils.MustWriteString(&buffer, "_")
	utils.MustWriteString(&buffer, point.Rollup)
	metric := buffer.String()
	buffer.Reset()
	tags := point.GetTags(false, ",")
	var keys = make([]string, len(tags))
	for key := range tags {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	var tmp []string
	for _, key := range keys {
		if len(tags[key]) == 0 {
			continue
		}
		utils.MustWriteString(&buffer, key)
		utils.MustWriteString(&buffer, "=\"")
		utils.MustWriteString(&buffer, tags[key])
		utils.MustWriteString(&buffer, "\"")
		tmp = append(tmp, buffer.String())
		buffer.Reset()
	}
	strtags := strings.Join(tmp, ",")
	utils.MustWriteString(&buffer, "{")
	utils.MustWriteString(&buffer, strtags)
	utils.MustWriteString(&buffer, "} ")
	utils.MustWriteString(&buffer, utils.ValToString(point.Value, ",", false))

	if metrics[metric] == nil {
		metrics[metric] = []string{buffer.String()}
	} else {
		metrics[metric] = append(metrics[metric], buffer.String())
	}
	buffer.Reset()
}
<|endoftext|>


<commit_before>// UVa 10074 - Take the Land

package main

import (
	"fmt"
	"os"
)

type cell struct{ tree, up int }

func verticalSum(land [][]cell) {
	for i := range land {
		for j := range land[i] {
			if land[i][j].tree == 1 {
				land[i][j].up = 0
			} else {
				land[i][j].up = 1
				if i > 0 {
					land[i][j].up += land[i-1][j].up
				}
			}
		}
	}
}

func solve(land [][]cell) int {
	verticalSum(land)
	var maxArea int
	for i := range land {
		for j := range land[i] {
			sum := land[i][j].up
			for k := j + 1; k < len(land[i]) && land[i][k].up >= land[i][j].up; k++ {
				sum += land[i][j].up
			}
			for k := j - 1; k >= 0 && land[i][k].up >= land[i][j].up; k-- {
				sum += land[i][j].up
			}
			if sum > maxArea {
				maxArea = sum
			}
		}
	}
	return maxArea
}

func main() {
	in, _ := os.Open("10074.in")
	defer in.Close()
	out, _ := os.Create("10074.out")
	defer out.Close()

	var m, n int
	for {
		if fmt.Fscanf(in, "%d%d", &m, &n); m == 0 && n == 0 {
			break
		}
		land := make([][]cell, m)
		for i := range land {
			land[i] = make([]cell, n)
			for j := range land[i] {
				fmt.Fscanf(in, "%d", &land[i][j].tree)
			}
		}
		fmt.Fprintln(out, solve(land))
	}
}
<commit_msg>code clean up<commit_after>// UVa 10074 - Take the Land

package main

import (
	"fmt"
	"os"
)

type cell struct{ tree, up int }

func verticalSum(land [][]cell) {
	for i := range land {
		for j := range land[i] {
			if land[i][j].tree == 1 {
				land[i][j].up = 0
			} else {
				if i == 0 {
					land[i][j].up = 1
				} else {
					land[i][j].up = land[i-1][j].up + 1
				}
			}
		}
	}
}

func solve(n int, land [][]cell) int {
	verticalSum(land)
	var maxArea int
	for i := range land {
		for j := range land[i] {
			sum := land[i][j].up
			for k := j + 1; k < n && land[i][k].up >= land[i][j].up; k++ {
				sum += land[i][j].up
			}
			for k := j - 1; k >= 0 && land[i][k].up >= land[i][j].up; k-- {
				sum += land[i][j].up
			}
			if sum > maxArea {
				maxArea = sum
			}
		}
	}
	return maxArea
}

func main() {
	in, _ := os.Open("10074.in")
	defer in.Close()
	out, _ := os.Create("10074.out")
	defer out.Close()

	var m, n int
	for {
		if fmt.Fscanf(in, "%d%d", &m, &n); m == 0 && n == 0 {
			break
		}
		land := make([][]cell, m)
		for i := range land {
			land[i] = make([]cell, n)
			for j := range land[i] {
				fmt.Fscanf(in, "%d", &land[i][j].tree)
			}
		}
		fmt.Fprintln(out, solve(n, land))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
    "fmt"
	"encoding/xml"
    "../src"
)

func TestXmlEncode(t *testing.T) {
    s := &supersocket.ServerConfig { Name: "TestServer" }

    s.Listeners = append(s.Listeners, supersocket.ListenerConfig { Address: "Any:1012" })
    s.Listeners = append(s.Listeners, supersocket.ListenerConfig { Address: "Any:1013" })

    output, err := xml.MarshalIndent(s, "", "    ")
    if err != nil {
        t.Fatal(err.Error())
    }

    fmt.Print(xml.Header)
    fmt.Print(string(output))
    fmt.Println()

	var ds supersocket.ServerConfig
    err = xml.Unmarshal(output, &ds)

    if err != nil {
        t.Fatal(err.Error())
    }

    if (ds.Name != "TestServer") {
        t.Error("Unexpected server name")
    }

    if (len(ds.Listeners) != 2) {
        t.Error("Unexpected listener count")
    }

    if (ds.Listeners[0].Address != "Any:1012") {
        t.Error("Unexpected listener 0 address")
    }

    if (ds.Listeners[1].Address != "Any:1013") {
        t.Error("Unexpected listener 1 address")
    }
}<commit_msg>improved the xml test code<commit_after>package main

import (
	"testing"
    "fmt"
	"encoding/xml"
    "../src"
)

func TestXmlEncode(t *testing.T) {
    var s = supersocket.ServerConfig { Name: "TestServer" }

    s.Listeners = append(s.Listeners, supersocket.ListenerConfig { Address: "Any:1012" })
    s.Listeners = append(s.Listeners, supersocket.ListenerConfig { Address: "Any:1013" })

    output, err := xml.MarshalIndent(&s, "", "    ")
    if err != nil {
        t.Fatal(err.Error())
    }

    fmt.Print(xml.Header)
    fmt.Print(string(output))
    fmt.Println()

    var ds supersocket.ServerConfig
    err = xml.Unmarshal(output, &ds)

    if err != nil {
        t.Fatal(err.Error())
    }

    if (ds.Name != "TestServer") {
        t.Error("Unexpected server name")
    }

    if (len(ds.Listeners) != 2) {
        t.Error("Unexpected listener count")
    }

    if (ds.Listeners[0].Address != "Any:1012") {
        t.Error("Unexpected listener 0 address")
    }

    if (ds.Listeners[1].Address != "Any:1013") {
        t.Error("Unexpected listener 1 address")
    }
}<|endoftext|>


<commit_before>package testing

import (
	"fmt"
	"log"

	"github.com/awslabs/aws-sdk-go/gen/swf"
	"github.com/sclasen/swfsm/fsm"
	. "github.com/sclasen/swfsm/sugar"
)

const (
	StubWorkflow      = "stub"
	ShortStubWorkflow = "stub"
	StubVersion       = "1"
)

var (
	StubTaskList      = &swf.TaskList{Name: S(fmt.Sprintf("%s->%s", StubWorkflow, StubVersion))}
	ShortStubTaskList = &swf.TaskList{Name: S(fmt.Sprintf("%s->%s", ShortStubWorkflow, StubVersion))}
)

type DecisionOutcome struct {
	DecisionTask *swf.DecisionTask
	State        string
	Decisions    []swf.Decision
}

func StubFSM(domain string, client fsm.SWFOps, outcomes chan DecisionOutcome) *fsm.FSM {
	f := &fsm.FSM{
		SWF:                client,
		DataType:           make(map[string]interface{}),
		Domain:             domain,
		Name:               StubWorkflow,
		Serializer:         fsm.JSONStateSerializer{},
		TaskList:           *StubTaskList.Name,
		ReplicationHandler: TestReplicator(outcomes),
	}

	f.AddInitialState(&fsm.FSMState{Name: "Initial", Decider: StubState()})
	return f
}

func StubState() fsm.Decider {
	return func(ctx *fsm.FSMContext, h swf.HistoryEvent, data interface{}) fsm.Outcome {
		log.Printf("at=stub-event event=%+v", PrettyHistoryEvent(h))
		return ctx.Stay(data, ctx.EmptyDecisions())
	}
}

func ShortStubFSM(domain string, client fsm.SWFOps, outcomes chan DecisionOutcome) *fsm.FSM {
	f := &fsm.FSM{
		SWF:                client,
		DataType:           make(map[string]interface{}),
		Domain:             domain,
		Name:               ShortStubWorkflow,
		Serializer:         fsm.JSONStateSerializer{},
		TaskList:           *StubTaskList.Name,
		ReplicationHandler: TestReplicator(outcomes),
	}

	f.AddInitialState(&fsm.FSMState{Name: "Initial", Decider: ShortStubState()})
	return f
}

func ShortStubState() fsm.Decider {
	return func(ctx *fsm.FSMContext, h swf.HistoryEvent, data interface{}) fsm.Outcome {
		log.Printf("at=short-stub-event event=%+v", PrettyHistoryEvent(h))
		return ctx.CompleteWorkflow(data)
	}
}

//intercept any attempts to start a workflow and launch the stub workflow instead.
func TestInterceptor(testID string, stubbedWorkflows, stubbedShortWorkflows []string) *fsm.FuncInterceptor {
	stubbed := make(map[string]struct{})
	stubbedShort := make(map[string]struct{})
	v := struct{}{}
	for _, s := range stubbedWorkflows {
		stubbed[s] = v
	}
	for _, s := range stubbedShortWorkflows {
		stubbedShort[s] = v
	}
	return &fsm.FuncInterceptor{
		AfterDecisionFn: func(decision *swf.DecisionTask, ctx *fsm.FSMContext, outcome *fsm.Outcome) {
			for _, d := range outcome.Decisions {
				switch *d.DecisionType {
				case swf.DecisionTypeStartChildWorkflowExecution:
					if _, ok := stubbed[*d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name]; ok {
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name = S(StubWorkflow)
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Version = S(StubVersion)
						d.StartChildWorkflowExecutionDecisionAttributes.ExecutionStartToCloseTimeout = S("360")
						d.StartChildWorkflowExecutionDecisionAttributes.TaskList = StubTaskList
					}
					if _, ok := stubbedShort[*d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name]; ok {
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name = S(ShortStubWorkflow)
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Version = S(StubVersion)
						d.StartChildWorkflowExecutionDecisionAttributes.ExecutionStartToCloseTimeout = S("360")
						d.StartChildWorkflowExecutionDecisionAttributes.TaskList = ShortStubTaskList
					}
				case swf.DecisionTypeScheduleActivityTask:
					d.ScheduleActivityTaskDecisionAttributes.TaskList.Name = S(*d.ScheduleActivityTaskDecisionAttributes.TaskList.Name + testID)
				}
			}
		},
	}
}

func TestReplicator(decisionOutcomes chan DecisionOutcome) fsm.ReplicationHandler {
	return func(ctx *fsm.FSMContext, task *swf.DecisionTask, outcome *swf.RespondDecisionTaskCompletedInput, state *fsm.SerializedState) error {
		decisionOutcomes <- DecisionOutcome{State: state.StateName, DecisionTask: task, Decisions: outcome.Decisions}
		return nil
	}
}

func TestSWF(client fsm.ClientSWFOps, stubbedWorkflow ...string) fsm.ClientSWFOps {
	stubbed := make(map[string]struct{})
	v := struct{}{}
	for _, s := range stubbedWorkflow {
		stubbed[s] = v
	}
	return &StubSWFClient{
		ClientSWFOps:     client,
		stubbedWorkflows: stubbed,
	}
}

//intercept any attempts to start a workflow and launch the stub workflow instead.
type StubSWFClient struct {
	fsm.ClientSWFOps
	stubbedWorkflows map[string]struct{}
}

func (s *StubSWFClient) StartWorkflowExecution(req *swf.StartWorkflowExecutionInput) (resp *swf.Run, err error) {
	if _, ok := s.stubbedWorkflows[*req.WorkflowType.Name]; ok {
		req.WorkflowType.Name = S(StubWorkflow)
		req.WorkflowType.Version = S(StubVersion)
		req.ExecutionStartToCloseTimeout = S("360")
		req.TaskList = StubTaskList
	}
	return s.ClientSWFOps.StartWorkflowExecution(req)
}
<commit_msg>logging<commit_after>package testing

import (
	"fmt"
	"log"

	"github.com/awslabs/aws-sdk-go/gen/swf"
	"github.com/sclasen/swfsm/fsm"
	. "github.com/sclasen/swfsm/sugar"
)

const (
	StubWorkflow      = "stub"
	ShortStubWorkflow = "stub"
	StubVersion       = "1"
)

var (
	StubTaskList      = &swf.TaskList{Name: S(fmt.Sprintf("%s->%s", StubWorkflow, StubVersion))}
	ShortStubTaskList = &swf.TaskList{Name: S(fmt.Sprintf("%s->%s", ShortStubWorkflow, StubVersion))}
)

type DecisionOutcome struct {
	DecisionTask *swf.DecisionTask
	State        string
	Decisions    []swf.Decision
}

func StubFSM(domain string, client fsm.SWFOps, outcomes chan DecisionOutcome) *fsm.FSM {
	f := &fsm.FSM{
		SWF:                client,
		DataType:           make(map[string]interface{}),
		Domain:             domain,
		Name:               StubWorkflow,
		Serializer:         fsm.JSONStateSerializer{},
		TaskList:           *StubTaskList.Name,
		ReplicationHandler: TestReplicator(outcomes),
	}

	f.AddInitialState(&fsm.FSMState{Name: "Initial", Decider: StubState()})
	return f
}

func StubState() fsm.Decider {
	return func(ctx *fsm.FSMContext, h swf.HistoryEvent, data interface{}) fsm.Outcome {
		log.Printf("at=stub-event event=%+v", PrettyHistoryEvent(h))
		return ctx.Stay(data, ctx.EmptyDecisions())
	}
}

func ShortStubFSM(domain string, client fsm.SWFOps, outcomes chan DecisionOutcome) *fsm.FSM {
	f := &fsm.FSM{
		SWF:                client,
		DataType:           make(map[string]interface{}),
		Domain:             domain,
		Name:               ShortStubWorkflow,
		Serializer:         fsm.JSONStateSerializer{},
		TaskList:           *StubTaskList.Name,
		ReplicationHandler: TestReplicator(outcomes),
	}

	f.AddInitialState(&fsm.FSMState{Name: "Initial", Decider: ShortStubState()})
	return f
}

func ShortStubState() fsm.Decider {
	return func(ctx *fsm.FSMContext, h swf.HistoryEvent, data interface{}) fsm.Outcome {
		log.Printf("at=short-stub-event event=%+v", PrettyHistoryEvent(h))
		return ctx.CompleteWorkflow(data)
	}
}

//intercept any attempts to start a workflow and launch the stub workflow instead.
func TestInterceptor(testID string, stubbedWorkflows, stubbedShortWorkflows []string) *fsm.FuncInterceptor {
	stubbed := make(map[string]struct{})
	stubbedShort := make(map[string]struct{})
	v := struct{}{}
	for _, s := range stubbedWorkflows {
		stubbed[s] = v
	}
	for _, s := range stubbedShortWorkflows {
		stubbedShort[s] = v
	}
	return &fsm.FuncInterceptor{
		AfterDecisionFn: func(decision *swf.DecisionTask, ctx *fsm.FSMContext, outcome *fsm.Outcome) {
			for _, d := range outcome.Decisions {
				switch *d.DecisionType {
				case swf.DecisionTypeStartChildWorkflowExecution:
					if _, ok := stubbed[*d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name]; ok {
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name = S(StubWorkflow)
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Version = S(StubVersion)
						d.StartChildWorkflowExecutionDecisionAttributes.ExecutionStartToCloseTimeout = S("360")
						d.StartChildWorkflowExecutionDecisionAttributes.TaskList = StubTaskList
					}
					if _, ok := stubbedShort[*d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name]; ok {
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Name = S(ShortStubWorkflow)
						d.StartChildWorkflowExecutionDecisionAttributes.WorkflowType.Version = S(StubVersion)
						d.StartChildWorkflowExecutionDecisionAttributes.ExecutionStartToCloseTimeout = S("360")
						d.StartChildWorkflowExecutionDecisionAttributes.TaskList = ShortStubTaskList
					}
				case swf.DecisionTypeScheduleActivityTask:
				    log.Printf("%+v", d.ScheduleActivityTaskDecisionAttributes)
				    log.Printf("%+v", d.ScheduleActivityTaskDecisionAttributes.TaskList.Name)
					d.ScheduleActivityTaskDecisionAttributes.TaskList.Name = S(*d.ScheduleActivityTaskDecisionAttributes.TaskList.Name + testID)
				    log.Printf("%+v", d.ScheduleActivityTaskDecisionAttributes.TaskList.Name)

				}
			}
		},
	}
}

func TestReplicator(decisionOutcomes chan DecisionOutcome) fsm.ReplicationHandler {
	return func(ctx *fsm.FSMContext, task *swf.DecisionTask, outcome *swf.RespondDecisionTaskCompletedInput, state *fsm.SerializedState) error {
		decisionOutcomes <- DecisionOutcome{State: state.StateName, DecisionTask: task, Decisions: outcome.Decisions}
		return nil
	}
}

func TestSWF(client fsm.ClientSWFOps, stubbedWorkflow ...string) fsm.ClientSWFOps {
	stubbed := make(map[string]struct{})
	v := struct{}{}
	for _, s := range stubbedWorkflow {
		stubbed[s] = v
	}
	return &StubSWFClient{
		ClientSWFOps:     client,
		stubbedWorkflows: stubbed,
	}
}

//intercept any attempts to start a workflow and launch the stub workflow instead.
type StubSWFClient struct {
	fsm.ClientSWFOps
	stubbedWorkflows map[string]struct{}
}

func (s *StubSWFClient) StartWorkflowExecution(req *swf.StartWorkflowExecutionInput) (resp *swf.Run, err error) {
	if _, ok := s.stubbedWorkflows[*req.WorkflowType.Name]; ok {
		req.WorkflowType.Name = S(StubWorkflow)
		req.WorkflowType.Version = S(StubVersion)
		req.ExecutionStartToCloseTimeout = S("360")
		req.TaskList = StubTaskList
	}
	return s.ClientSWFOps.StartWorkflowExecution(req)
}
<|endoftext|>


<commit_before>package VK

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/feeds"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type VK struct{}

type VKPhoto struct {
	Album_id   int
	Owner_id   int
	Photo_75   string
	Photo_130  string
	Photo_604  string
	Photo_807  string
	Photo_1280 string
}

type VKAttachment struct {
	Type  string
	Photo VKPhoto
}

type VKItem struct {
	Id          int
	From_id     int
	Owner_id    int
	Date        int
	Post_type   string
	Text        string
	Attachments []VKAttachment
}

type VKProfile struct {
	Id          int
	First_name  string
	Last_name   string
	Screen_name string
	Photo_200   string
}

type VKGroup struct {
	Id          int
	Name        string
	Screen_name string
	Is_closed   int
	Type        string
	Photo_200   string
}

type VKResponseBody struct {
	Count    int
	Items    []VKItem
	Profiles []VKProfile
	Groups   []VKGroup
}

type VKResponse struct {
	Response VKResponseBody
}

func processAttachments(attachments []VKAttachment) string {
	if len(attachments) > 0 {
		var result, photo string = "", ""
		for _, attachment := range attachments {
			if attachment.Type == "photo" {

				if attachment.Photo.Photo_1280 != "" {
					photo = attachment.Photo.Photo_1280
				} else if attachment.Photo.Photo_807 != "" {
					photo = attachment.Photo.Photo_807
				} else if attachment.Photo.Photo_604 != "" {
					photo = attachment.Photo.Photo_604
				} else if attachment.Photo.Photo_130 != "" {
					photo = attachment.Photo.Photo_130
				} else if attachment.Photo.Photo_75 != "" {
					photo = attachment.Photo.Photo_75
				}
			}
			result += "
"
		}
		return result
	} else {
		return ""
	}
}

type ResolvedScreenName struct {
	Type      string
	Object_id float64
}

type ResolvedScreenNameResponse struct {
	Response ResolvedScreenName
}

func resolveScreenName(screenName string) ResolvedScreenName {
	var requestUrl = "https://api.vk.com/method/utils.resolveScreenName?v=5.12&screen_name=" + screenName
	resp, err := http.Get(requestUrl)

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		panic(err)
	}

	var encoded ResolvedScreenNameResponse

	err = json.Unmarshal(body, &encoded)

	if err != nil {
		panic(err)
	}

	return encoded.Response
}

type SourceInfo struct {
	Name        string
	Screen_name string
	First_name  string
	Last_name   string
}

type SourceInfoContainer struct {
	Response []SourceInfo
}

func getSourceInfo(feedId string) (string, string) {
	var isGroup bool = strings.Contains(feedId, "-")
	var groupUrl string = "https://api.vk.com/method/groups.getById?group_id="
	var profileUrl string = "https://api.vk.com/method/users.get?user_ids="
	var requestUrl string

	if isGroup {
		feedId = feedId[1:]
		requestUrl = groupUrl + feedId
	} else {
		requestUrl = profileUrl + feedId
	}

	resp, err := http.Get(requestUrl)

	if err != nil {

	}

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {

	}
	var encoded SourceInfoContainer

	err = json.Unmarshal(body, &encoded)

	if len(encoded.Response[0].Name) > 0 {
		return encoded.Response[0].Name, encoded.Response[0].Screen_name
	} else {
		return encoded.Response[0].First_name + " " + encoded.Response[0].Last_name, feedId
	}
}

func GetPosts(feedId string) (string, error) {
	var requestUrl string = "https://api.vk.com/method/wall.get?v=5.12&extended=1&owner_id=" + feedId

	fmt.Println(feedId)
	resp, err := http.Get(requestUrl)

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

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	var encoded VKResponse

	err = json.Unmarshal(body, &encoded)

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

	name, screenName := getSourceInfo(feedId)

	feed := &feeds.Feed{
		Title: name,
		Link:  &feeds.Link{Href: "https://vk.com/" + screenName},
	}

	for _, elem := range encoded.Response.Items {
		photo := processAttachments(elem.Attachments)
		feed.Add(&feeds.Item{
			Title:       strings.Split(elem.Text, ".")[0] + "...",
			Link:        &feeds.Link{Href: "http://vk.com/wall" + strconv.Itoa(elem.Owner_id) + "_" + strconv.Itoa(elem.Id)},
			Description: elem.Text + photo,
			Created:     time.Unix(int64(elem.Date), int64(0)),
		})
	}

	return feed.ToRss()
}

func GetPostsByUrl(feedUrl string) (string, error) {
	rp := regexp.MustCompile("vk.com/(\\w+)")
	result := rp.FindAllStringSubmatch(feedUrl, -1)
	screenName := resolveScreenName(result[0][1])
	var resolvedFeedId string

	if screenName.Type != "user" {
		resolvedFeedId = "-" + strconv.Itoa(int(screenName.Object_id))
	} else {
		resolvedFeedId = strconv.Itoa(int(screenName.Object_id))
	}

	return GetPosts(resolvedFeedId)
}
<commit_msg>process repost<commit_after>package VK

import (
	"encoding/json"
	"github.com/gorilla/feeds"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type VK struct{}

type VKPhoto struct {
	Album_id   int
	Owner_id   int
	Photo_75   string
	Photo_130  string
	Photo_604  string
	Photo_807  string
	Photo_1280 string
}

type VKAttachment struct {
	Type  string
	Photo VKPhoto
}

type VKItem struct {
	Id           int
	From_id      int
	Owner_id     int
	Date         int
	Post_type    string
	Text         string
	Copy_history []VKItem
	Attachments  []VKAttachment
}

type VKProfile struct {
	Id          int
	First_name  string
	Last_name   string
	Screen_name string
	Photo_200   string
}

type VKGroup struct {
	Id          int
	Name        string
	Screen_name string
	Is_closed   int
	Type        string
	Photo_200   string
}

type VKResponseBody struct {
	Count    int
	Items    []VKItem
	Profiles []VKProfile
	Groups   []VKGroup
}

type VKResponse struct {
	Response VKResponseBody
}

func processAttachments(attachments []VKAttachment) string {
	if len(attachments) > 0 {
		var result, photo string = "", ""
		for _, attachment := range attachments {
			if attachment.Type == "photo" {

				if attachment.Photo.Photo_1280 != "" {
					photo = attachment.Photo.Photo_1280
				} else if attachment.Photo.Photo_807 != "" {
					photo = attachment.Photo.Photo_807
				} else if attachment.Photo.Photo_604 != "" {
					photo = attachment.Photo.Photo_604
				} else if attachment.Photo.Photo_130 != "" {
					photo = attachment.Photo.Photo_130
				} else if attachment.Photo.Photo_75 != "" {
					photo = attachment.Photo.Photo_75
				}
			}
			result += "
"
		}
		return result
	} else {
		return ""
	}
}

type ResolvedScreenName struct {
	Type      string
	Object_id float64
}

type ResolvedScreenNameResponse struct {
	Response ResolvedScreenName
}

func resolveScreenName(screenName string) ResolvedScreenName {
	var requestUrl = "https://api.vk.com/method/utils.resolveScreenName?v=5.12&screen_name=" + screenName
	resp, err := http.Get(requestUrl)

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		panic(err)
	}

	var encoded ResolvedScreenNameResponse

	err = json.Unmarshal(body, &encoded)

	if err != nil {
		panic(err)
	}

	return encoded.Response
}

type SourceInfo struct {
	Name        string
	Screen_name string
	First_name  string
	Last_name   string
}

type SourceInfoContainer struct {
	Response []SourceInfo
}

func getSourceInfo(feedId string) (string, string) {
	var isGroup bool = strings.Contains(feedId, "-")
	var groupUrl string = "https://api.vk.com/method/groups.getById?group_id="
	var profileUrl string = "https://api.vk.com/method/users.get?user_ids="
	var requestUrl string

	if isGroup {
		feedId = feedId[1:]
		requestUrl = groupUrl + feedId
	} else {
		requestUrl = profileUrl + feedId
	}

	resp, err := http.Get(requestUrl)

	if err != nil {

	}

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {

	}
	var encoded SourceInfoContainer
	err = json.Unmarshal(body, &encoded)

	if len(encoded.Response[0].Name) > 0 {
		return encoded.Response[0].Name, encoded.Response[0].Screen_name
	} else {
		return encoded.Response[0].First_name + " " + encoded.Response[0].Last_name, feedId
	}
}

func GetPosts(feedId string) (string, error) {
	var requestUrl string = "https://api.vk.com/method/wall.get?v=5.12&extended=1&owner_id=" + feedId

	resp, err := http.Get(requestUrl)

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

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	var encoded VKResponse

	err = json.Unmarshal(body, &encoded)

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

	name, screenName := getSourceInfo(feedId)

	feed := &feeds.Feed{
		Title: name,
		Link:  &feeds.Link{Href: "https://vk.com/" + screenName},
	}

	for _, elem := range encoded.Response.Items {
		var description string = ""
		var screenName, name string = "", ""
		photo := processAttachments(elem.Attachments)
		description += elem.Text + photo

		if len(elem.Copy_history) > 0 {
			description += "
repost
" + elem.Copy_history[0].Text
			name, screenName = getSourceInfo(strconv.Itoa(elem.Copy_history[0].Owner_id))
		}
		feed.Add(&feeds.Item{
			Author:      &feeds.Author{Name: name, Email: "https://vk.com/" + screenName},
			Title:       strings.Split(elem.Text, ".")[0] + "...",
			Link:        &feeds.Link{Href: "http://vk.com/wall" + strconv.Itoa(elem.Owner_id) + "_" + strconv.Itoa(elem.Id)},
			Description: description,
			Created:     time.Unix(int64(elem.Date), int64(0)),
		})
	}

	return feed.ToRss()
}

func GetPostsByUrl(feedUrl string) (string, error) {
	rp := regexp.MustCompile("vk.com/(\\w+)")
	result := rp.FindAllStringSubmatch(feedUrl, -1)
	screenName := resolveScreenName(result[0][1])
	var resolvedFeedId string

	if screenName.Type != "user" {
		resolvedFeedId = "-" + strconv.Itoa(int(screenName.Object_id))
	} else {
		resolvedFeedId = strconv.Itoa(int(screenName.Object_id))
	}

	return GetPosts(resolvedFeedId)
}
<|endoftext|>


<commit_before>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 tff

import (
	"github.com/stretchr/testify/require"

	"bytes"
	"encoding/gob"
	"encoding/json"
	"reflect"
	"testing"
	"time"
)

func newLogRecord() *Record {
	return &Record{
		OriginId: 11,
		Method:   "POST",
	}
}

func newLogFFRecord() *FFRecord {
	return &FFRecord{
		OriginId: 11,
		Method:   "POST",
	}
}

func BenchmarkMarshalJSON(b *testing.B) {
	record := newLogRecord()

	buf, err := json.Marshal(&record)
	if err != nil {
		b.Fatalf("Marshal: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := json.Marshal(&record)
		if err != nil {
			b.Fatalf("Marshal: %v", err)
		}
	}
}

func BenchmarkMarshalJSONNative(b *testing.B) {
	record := newLogFFRecord()

	buf, err := json.Marshal(&record)
	if err != nil {
		b.Fatalf("Marshal: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := record.MarshalJSON()
		if err != nil {
			b.Fatalf("Marshal: %v", err)
		}
	}
}

func BenchmarkSimpleUnmarshal(b *testing.B) {
	record := newLogFFRecord()
	buf := []byte(`{"id": 123213, "OriginId": 22, "meth": "GET"}`)
	err := record.UnmarshalJSON(buf)
	if err != nil {
		b.Fatalf("UnmarshalJSON: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := record.UnmarshalJSON(buf)
		if err != nil {
			b.Fatalf("UnmarshalJSON: %v", err)
		}
	}
}

func BenchmarkSXimpleUnmarshalNative(b *testing.B) {
	record := newLogRecord()
	buf := []byte(`{"id": 123213, "OriginId": 22, "meth": "GET"}`)
	err := json.Unmarshal(buf, record)
	if err != nil {
		b.Fatalf("json.Unmarshal: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := json.Unmarshal(buf, record)
		if err != nil {
			b.Fatalf("json.Unmarshal: %v", err)
		}
	}
}

func TestSimpleUnmarshal(t *testing.T) {
	record := newLogFFRecord()

	err := record.UnmarshalJSON([]byte(`{"id": 123213, "OriginId": 22, "meth": "GET"}`))
	if err != nil {
		t.Fatalf("UnmarshalJSON: %v", err)
	}

	if record.Timestamp != 123213 {
		t.Fatalf("record.Timestamp: expected: 0 got: %v", record.Timestamp)
	}

	if record.OriginId != 22 {
		t.Fatalf("record.OriginId: expected: 22 got: %v", record.OriginId)
	}

	if record.Method != "GET" {
		t.Fatalf("record.Method: expected: GET got: %v", record.Method)
	}
}

func testType(t *testing.T, base interface{}, ff interface{}) {
	testSameMarshal(t, base, ff)
	testCycle(t, base, ff)
}

func testSameMarshal(t *testing.T, base interface{}, ff interface{}) {
	bufbase, err := json.Marshal(base)
	require.NoError(t, err, "base[%T] failed to Marshal", base)

	bufff, err := json.Marshal(ff)
	require.NoError(t, err, "ff[%T] failed to Marshal", ff)

	require.Equal(t, string(bufbase), string(bufff), "json.Marshal of base[%T] != ff[%T]", base, ff)
}

func testCycle(t *testing.T, base interface{}, ff interface{}) {
	setXValue(t, base)

	buf, err := json.Marshal(base)
	require.NoError(t, err, "base[%T] failed to Marshal", base)

	err = json.Unmarshal(buf, ff)
	require.NoError(t, err, "ff[%T] failed to Unmarshal", ff)

	require.Equal(t, getXValue(base), getXValue(ff), "json.Unmarshal of base[%T] into ff[%T]", base, ff)
}

func testExpectedX(t *testing.T, expected interface{}, base interface{}, ff interface{}) {
	buf, err := json.Marshal(base)
	require.NoError(t, err, "base[%T] failed to Marshal", base)

	err = json.Unmarshal(buf, ff)
	require.NoError(t, err, "ff[%T] failed to Unmarshal", ff)

	require.Equal(t, expected, getXValue(ff), "json.Unmarshal of base[%T] into ff[%T]", base, ff)
}

func testExpectedXValBare(t *testing.T, expected interface{}, xval string, ff interface{}) {
	buf := []byte(`{"X":` + xval + `}`)
	err := json.Unmarshal(buf, ff)
	require.NoError(t, err, "ff[%T] failed to Unmarshal", ff)

	require.Equal(t, expected, getXValue(ff), "json.Unmarshal of %T into ff[%T]", xval, ff)
}

func testExpectedXVal(t *testing.T, expected interface{}, xval string, ff interface{}) {
	testExpectedXValBare(t, expected, `"`+xval+`"`, ff)
}

func testExpectedError(t *testing.T, expected error, xval string, ff json.Unmarshaler) {
	buf := []byte(`{"X":` + xval + `}`)
	err := ff.UnmarshalJSON(buf)
	require.Error(t, err, "ff[%T] failed to Unmarshal", ff)
	require.IsType(t, expected, err)
}

func setXValue(t *testing.T, thing interface{}) {
	v := reflect.ValueOf(thing)
	v = reflect.Indirect(v)
	f := v.FieldByName("X")
	switch f.Kind() {
	case reflect.Bool:
		f.SetBool(true)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		f.SetInt(-42)
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		f.SetUint(42)
	case reflect.Float32, reflect.Float64:
		f.SetFloat(3.141592653)
	case reflect.String:
		f.SetString("hello world")
	}
}

func getXValue(thing interface{}) interface{} {
	v := reflect.ValueOf(thing)
	v = reflect.Indirect(v)
	f := v.FieldByName("X")
	switch f.Kind() {
	case reflect.Bool:
		return f.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return f.Int()
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return f.Uint()
	case reflect.Float32, reflect.Float64:
		return f.Float()
	case reflect.String:
		return f.String()
	}

	var buf bytes.Buffer
	enc := gob.NewEncoder(&buf)
	enc.Encode(f)
	return buf.String()
}

func TestArray(t *testing.T) {
	testType(t, &Tarray{X: []int{}}, &Xarray{X: []int{}})
	testCycle(t, &Tarray{X: []int{42, -42, 44}}, &Xarray{X: []int{}})

	x := Xarray{X: []int{222}}
	buf := []byte(`{"X": null}`)
	err := json.Unmarshal(buf, &x)
	require.NoError(t, err, "Unmarshal of null into array.")
	var eq []int = nil
	require.Equal(t, x.X, eq)
}

func TestArrayPtr(t *testing.T) {
	testType(t, &TarrayPtr{X: []*int{}}, &XarrayPtr{X: []*int{}})
	v := 33
	testCycle(t, &TarrayPtr{X: []*int{&v}}, &XarrayPtr{X: []*int{}})
}

func TestTimeDuration(t *testing.T) {
	testType(t, &Tduration{}, &Xduration{})
}

func TestTimeTimePtr(t *testing.T) {
	tm := time.Date(2014, 12, 13, 15, 16, 17, 18, time.UTC)
	testType(t, &TtimePtr{X: &tm}, &TtimePtr{X: &tm})
}

func TestBool(t *testing.T) {
	testType(t, &Tbool{}, &Xbool{})
	testExpectedXValBare(t,
		true,
		`null`,
		&Xbool{Tbool{X: true}})
}

func TestInt(t *testing.T) {
	testType(t, &Tint{}, &Xint{})
}

func TestInt8(t *testing.T) {
	testType(t, &Tint8{}, &Xint8{})
}

func TestInt16(t *testing.T) {
	testType(t, &Tint16{}, &Xint16{})
}

func TestInt32(t *testing.T) {
	testType(t, &Tint32{}, &Xint32{})
}

func TestInt64(t *testing.T) {
	testType(t, &Tint64{}, &Xint64{})
}

func TestUint(t *testing.T) {
	testType(t, &Tuint{}, &Xuint{})
}

func TestUint8(t *testing.T) {
	testType(t, &Tuint8{}, &Xuint8{})
}

func TestUint16(t *testing.T) {
	testType(t, &Tuint16{}, &Xuint16{})
}

func TestUint32(t *testing.T) {
	testType(t, &Tuint32{}, &Xuint32{})
}

func TestUint64(t *testing.T) {
	testType(t, &Tuint64{}, &Xuint64{})
}

func TestUintptr(t *testing.T) {
	testType(t, &Tuintptr{}, &Xuintptr{})
}

func TestFloat32(t *testing.T) {
	testType(t, &Tfloat32{}, &Xfloat32{})
}

func TestFloat64(t *testing.T) {
	testType(t, &Tfloat64{}, &Xfloat64{})
}

func TestForceStringTagged(t *testing.T) {
	// testSameMarshal is used instead of testType because
	// the string tag is a one way effect, Unmarshaling doesn't
	// work because the receiving type must be a string.
	testSameMarshal(t, &TstringTagged{}, &XstringTagged{})
	testSameMarshal(t, &TintTagged{}, &XintTagged{})
	testSameMarshal(t, &TboolTagged{}, &XboolTagged{})
}

func TestSortSame(t *testing.T) {
	testSameMarshal(t, &TsortName{C: "foo", B: 12}, &XsortName{C: "foo", B: 12})
}
<commit_msg>Assert that the FF object in tests implements all of our ffjson interfaces<commit_after>/**
 *  Copyright 2014 Paul Querna
 *
 *  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 tff

import (
	fflib "github.com/pquerna/ffjson/fflib/v1"
	"github.com/stretchr/testify/require"

	"bytes"
	"encoding/gob"
	"encoding/json"
	"reflect"
	"testing"
	"time"
)

func newLogRecord() *Record {
	return &Record{
		OriginId: 11,
		Method:   "POST",
	}
}

func newLogFFRecord() *FFRecord {
	return &FFRecord{
		OriginId: 11,
		Method:   "POST",
	}
}

func BenchmarkMarshalJSON(b *testing.B) {
	record := newLogRecord()

	buf, err := json.Marshal(&record)
	if err != nil {
		b.Fatalf("Marshal: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := json.Marshal(&record)
		if err != nil {
			b.Fatalf("Marshal: %v", err)
		}
	}
}

func BenchmarkMarshalJSONNative(b *testing.B) {
	record := newLogFFRecord()

	buf, err := json.Marshal(&record)
	if err != nil {
		b.Fatalf("Marshal: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := record.MarshalJSON()
		if err != nil {
			b.Fatalf("Marshal: %v", err)
		}
	}
}

func BenchmarkSimpleUnmarshal(b *testing.B) {
	record := newLogFFRecord()
	buf := []byte(`{"id": 123213, "OriginId": 22, "meth": "GET"}`)
	err := record.UnmarshalJSON(buf)
	if err != nil {
		b.Fatalf("UnmarshalJSON: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := record.UnmarshalJSON(buf)
		if err != nil {
			b.Fatalf("UnmarshalJSON: %v", err)
		}
	}
}

func BenchmarkSXimpleUnmarshalNative(b *testing.B) {
	record := newLogRecord()
	buf := []byte(`{"id": 123213, "OriginId": 22, "meth": "GET"}`)
	err := json.Unmarshal(buf, record)
	if err != nil {
		b.Fatalf("json.Unmarshal: %v", err)
	}
	b.SetBytes(int64(len(buf)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := json.Unmarshal(buf, record)
		if err != nil {
			b.Fatalf("json.Unmarshal: %v", err)
		}
	}
}

func TestSimpleUnmarshal(t *testing.T) {
	record := newLogFFRecord()

	err := record.UnmarshalJSON([]byte(`{"id": 123213, "OriginId": 22, "meth": "GET"}`))
	if err != nil {
		t.Fatalf("UnmarshalJSON: %v", err)
	}

	if record.Timestamp != 123213 {
		t.Fatalf("record.Timestamp: expected: 0 got: %v", record.Timestamp)
	}

	if record.OriginId != 22 {
		t.Fatalf("record.OriginId: expected: 22 got: %v", record.OriginId)
	}

	if record.Method != "GET" {
		t.Fatalf("record.Method: expected: GET got: %v", record.Method)
	}
}

type marshalerFaster interface {
	MarshalJSONBuf(buf fflib.EncodingBuffer) error
}

type unmarshalFaster interface {
	UnmarshalJSONFFLexer(l *fflib.FFLexer, state fflib.FFParseState) error
}

func testType(t *testing.T, base interface{}, ff interface{}) {
	require.Implements(t, (*json.Marshaler)(nil), ff)
	require.Implements(t, (*json.Unmarshaler)(nil), ff)
	require.Implements(t, (*marshalerFaster)(nil), ff)
	require.Implements(t, (*unmarshalFaster)(nil), ff)
	testSameMarshal(t, base, ff)
	testCycle(t, base, ff)
}

func testSameMarshal(t *testing.T, base interface{}, ff interface{}) {
	bufbase, err := json.Marshal(base)
	require.NoError(t, err, "base[%T] failed to Marshal", base)

	bufff, err := json.Marshal(ff)
	require.NoError(t, err, "ff[%T] failed to Marshal", ff)

	require.Equal(t, string(bufbase), string(bufff), "json.Marshal of base[%T] != ff[%T]", base, ff)
}

func testCycle(t *testing.T, base interface{}, ff interface{}) {
	setXValue(t, base)

	buf, err := json.Marshal(base)
	require.NoError(t, err, "base[%T] failed to Marshal", base)

	err = json.Unmarshal(buf, ff)
	require.NoError(t, err, "ff[%T] failed to Unmarshal", ff)

	require.Equal(t, getXValue(base), getXValue(ff), "json.Unmarshal of base[%T] into ff[%T]", base, ff)
}

func testExpectedX(t *testing.T, expected interface{}, base interface{}, ff interface{}) {
	buf, err := json.Marshal(base)
	require.NoError(t, err, "base[%T] failed to Marshal", base)

	err = json.Unmarshal(buf, ff)
	require.NoError(t, err, "ff[%T] failed to Unmarshal", ff)

	require.Equal(t, expected, getXValue(ff), "json.Unmarshal of base[%T] into ff[%T]", base, ff)
}

func testExpectedXValBare(t *testing.T, expected interface{}, xval string, ff interface{}) {
	buf := []byte(`{"X":` + xval + `}`)
	err := json.Unmarshal(buf, ff)
	require.NoError(t, err, "ff[%T] failed to Unmarshal", ff)

	require.Equal(t, expected, getXValue(ff), "json.Unmarshal of %T into ff[%T]", xval, ff)
}

func testExpectedXVal(t *testing.T, expected interface{}, xval string, ff interface{}) {
	testExpectedXValBare(t, expected, `"`+xval+`"`, ff)
}

func testExpectedError(t *testing.T, expected error, xval string, ff json.Unmarshaler) {
	buf := []byte(`{"X":` + xval + `}`)
	err := ff.UnmarshalJSON(buf)
	require.Error(t, err, "ff[%T] failed to Unmarshal", ff)
	require.IsType(t, expected, err)
}

func setXValue(t *testing.T, thing interface{}) {
	v := reflect.ValueOf(thing)
	v = reflect.Indirect(v)
	f := v.FieldByName("X")
	switch f.Kind() {
	case reflect.Bool:
		f.SetBool(true)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		f.SetInt(-42)
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		f.SetUint(42)
	case reflect.Float32, reflect.Float64:
		f.SetFloat(3.141592653)
	case reflect.String:
		f.SetString("hello world")
	}
}

func getXValue(thing interface{}) interface{} {
	v := reflect.ValueOf(thing)
	v = reflect.Indirect(v)
	f := v.FieldByName("X")
	switch f.Kind() {
	case reflect.Bool:
		return f.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return f.Int()
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return f.Uint()
	case reflect.Float32, reflect.Float64:
		return f.Float()
	case reflect.String:
		return f.String()
	}

	var buf bytes.Buffer
	enc := gob.NewEncoder(&buf)
	enc.Encode(f)
	return buf.String()
}

func TestArray(t *testing.T) {
	testType(t, &Tarray{X: []int{}}, &Xarray{X: []int{}})
	testCycle(t, &Tarray{X: []int{42, -42, 44}}, &Xarray{X: []int{}})

	x := Xarray{X: []int{222}}
	buf := []byte(`{"X": null}`)
	err := json.Unmarshal(buf, &x)
	require.NoError(t, err, "Unmarshal of null into array.")
	var eq []int = nil
	require.Equal(t, x.X, eq)
}

func TestArrayPtr(t *testing.T) {
	testType(t, &TarrayPtr{X: []*int{}}, &XarrayPtr{X: []*int{}})
	v := 33
	testCycle(t, &TarrayPtr{X: []*int{&v}}, &XarrayPtr{X: []*int{}})
}

func TestTimeDuration(t *testing.T) {
	testType(t, &Tduration{}, &Xduration{})
}

func TestTimeTimePtr(t *testing.T) {
	tm := time.Date(2014, 12, 13, 15, 16, 17, 18, time.UTC)
	testType(t, &TtimePtr{X: &tm}, &XtimePtr{X: &tm})
}

func TestBool(t *testing.T) {
	testType(t, &Tbool{}, &Xbool{})
	testExpectedXValBare(t,
		true,
		`null`,
		&Xbool{Tbool{X: true}})
}

func TestInt(t *testing.T) {
	testType(t, &Tint{}, &Xint{})
}

func TestInt8(t *testing.T) {
	testType(t, &Tint8{}, &Xint8{})
}

func TestInt16(t *testing.T) {
	testType(t, &Tint16{}, &Xint16{})
}

func TestInt32(t *testing.T) {
	testType(t, &Tint32{}, &Xint32{})
}

func TestInt64(t *testing.T) {
	testType(t, &Tint64{}, &Xint64{})
}

func TestUint(t *testing.T) {
	testType(t, &Tuint{}, &Xuint{})
}

func TestUint8(t *testing.T) {
	testType(t, &Tuint8{}, &Xuint8{})
}

func TestUint16(t *testing.T) {
	testType(t, &Tuint16{}, &Xuint16{})
}

func TestUint32(t *testing.T) {
	testType(t, &Tuint32{}, &Xuint32{})
}

func TestUint64(t *testing.T) {
	testType(t, &Tuint64{}, &Xuint64{})
}

func TestUintptr(t *testing.T) {
	testType(t, &Tuintptr{}, &Xuintptr{})
}

func TestFloat32(t *testing.T) {
	testType(t, &Tfloat32{}, &Xfloat32{})
}

func TestFloat64(t *testing.T) {
	testType(t, &Tfloat64{}, &Xfloat64{})
}

func TestForceStringTagged(t *testing.T) {
	// testSameMarshal is used instead of testType because
	// the string tag is a one way effect, Unmarshaling doesn't
	// work because the receiving type must be a string.
	testSameMarshal(t, &TstringTagged{}, &XstringTagged{})
	testSameMarshal(t, &TintTagged{}, &XintTagged{})
	testSameMarshal(t, &TboolTagged{}, &XboolTagged{})
}

func TestSortSame(t *testing.T) {
	testSameMarshal(t, &TsortName{C: "foo", B: 12}, &XsortName{C: "foo", B: 12})
}
<|endoftext|>


<commit_before>package appfile

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/hcl"
	hclobj "github.com/hashicorp/hcl/hcl"
	"github.com/mitchellh/mapstructure"
)

// Parse parses the Appfile from the given io.Reader.
//
// Due to current internal limitations, the entire contents of the
// io.Reader will be copied into memory first before parsing.
func Parse(r io.Reader) (*File, error) {
	// Copy the reader into an in-memory buffer first since HCL requires it.
	var buf bytes.Buffer
	if _, err := io.Copy(&buf, r); err != nil {
		return nil, err
	}

	// Parse the buffer
	obj, err := hcl.Parse(buf.String())
	if err != nil {
		return nil, fmt.Errorf("error parsing: %s", err)
	}
	buf.Reset()

	// Check for invalid keys
	valid := []string{
		"application",
		"customization",
		"import",
		"infrastructure",
		"project",
	}
	if err := checkHCLKeys(obj, valid); err != nil {
		return nil, err
	}

	var result File

	// Parse the imports
	if o := obj.Get("import", false); o != nil {
		if err := parseImport(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'import': %s", err)
		}
	}

	// Parse the application
	if o := obj.Get("application", false); o != nil {
		if err := parseApplication(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'application': %s", err)
		}
	}

	// Parse the project
	if o := obj.Get("project", false); o != nil {
		if err := parseProject(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'project': %s", err)
		}
	}

	// Parse the infrastructure
	if o := obj.Get("infrastructure", false); o != nil {
		if err := parseInfra(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'infrastructure': %s", err)
		}
	}

	// Parse the customizations
	if o := obj.Get("customization", false); o != nil {
		if err := parseCustomizations(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'customization': %s", err)
		}
	}

	return &result, nil
}

// ParseFile parses the given path as an Appfile.
func ParseFile(path string) (*File, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, err
	}

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	result, err := Parse(f)
	if result != nil {
		result.Path = path
		if err := result.loadID(); err != nil {
			return nil, err
		}
	}

	return result, err
}

func parseApplication(result *File, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'application' block allowed")
	}

	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, obj); err != nil {
		return err
	}

	var app Application
	result.Application = &app
	return mapstructure.WeakDecode(m, &app)
}

func parseCustomizations(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"customization '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Customization, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var c Customization
		c.Type = strings.ToLower(n)
		c.Config = m

		collection = append(collection, &c)
	}

	result.Customization = &CustomizationSet{Raw: collection}
	return nil
}

func parseImport(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make([]*hclobj.Object, 0, 3)
	set := make(map[string]struct{})
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := set[o2.Key]; ok {
				return fmt.Errorf(
					"imported '%s' more than once",
					o2.Key)
			}

			objects = append(objects, o2)
			set[o2.Key] = struct{}{}
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Import, 0, len(objects))
	for _, o := range objects {
		collection = append(collection, &Import{
			Source: o.Key,
		})
	}

	result.Imports = collection
	return nil
}

func parseInfra(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"infrastructure '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Infrastructure, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var infra Infrastructure
		if err := mapstructure.WeakDecode(m, &infra); err != nil {
			return fmt.Errorf(
				"error parsing infrastructure '%s': %s", n, err)
		}

		infra.Name = n
		if infra.Type == "" {
			infra.Type = infra.Name
		}

		// Parse the foundations if we have any
		if o2 := o.Get("foundation", false); o != nil {
			if err := parseFoundations(&infra, o2); err != nil {
				return fmt.Errorf("error parsing 'foundation': %s", err)
			}
		}

		collection = append(collection, &infra)
	}

	result.Infrastructure = collection
	return nil
}

func parseFoundations(result *Infrastructure, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"foundation '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Foundation, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var f Foundation
		f.Name = n
		f.Config = m

		collection = append(collection, &f)
	}

	// Set the results
	result.Foundations = collection
	return nil
}

func parseProject(result *File, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'project' block allowed")
	}

	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, obj); err != nil {
		return err
	}

	// Parse the project
	var proj Project
	result.Project = &proj
	if err := mapstructure.WeakDecode(m, &proj); err != nil {
		return err
	}

	return nil
}

func checkHCLKeys(obj *hclobj.Object, valid []string) error {
	validMap := make(map[string]struct{}, len(valid))
	for _, v := range valid {
		validMap[v] = struct{}{}
	}

	var result error
	for _, o := range obj.Elem(true) {
		if _, ok := validMap[o.Key]; !ok {
			result = multierror.Append(result, fmt.Errorf(
				"invald key: %s", o.Key))
		}
	}

	return result
}
<commit_msg>appfile: invalid key validation everywhere<commit_after>package appfile

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/hcl"
	hclobj "github.com/hashicorp/hcl/hcl"
	"github.com/mitchellh/mapstructure"
)

// Parse parses the Appfile from the given io.Reader.
//
// Due to current internal limitations, the entire contents of the
// io.Reader will be copied into memory first before parsing.
func Parse(r io.Reader) (*File, error) {
	// Copy the reader into an in-memory buffer first since HCL requires it.
	var buf bytes.Buffer
	if _, err := io.Copy(&buf, r); err != nil {
		return nil, err
	}

	// Parse the buffer
	obj, err := hcl.Parse(buf.String())
	if err != nil {
		return nil, fmt.Errorf("error parsing: %s", err)
	}
	buf.Reset()

	// Check for invalid keys
	valid := []string{
		"application",
		"customization",
		"import",
		"infrastructure",
		"project",
	}
	if err := checkHCLKeys(obj, valid); err != nil {
		return nil, err
	}

	var result File

	// Parse the imports
	if o := obj.Get("import", false); o != nil {
		if err := parseImport(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'import': %s", err)
		}
	}

	// Parse the application
	if o := obj.Get("application", false); o != nil {
		if err := parseApplication(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'application': %s", err)
		}
	}

	// Parse the project
	if o := obj.Get("project", false); o != nil {
		if err := parseProject(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'project': %s", err)
		}
	}

	// Parse the infrastructure
	if o := obj.Get("infrastructure", false); o != nil {
		if err := parseInfra(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'infrastructure': %s", err)
		}
	}

	// Parse the customizations
	if o := obj.Get("customization", false); o != nil {
		if err := parseCustomizations(&result, o); err != nil {
			return nil, fmt.Errorf("error parsing 'customization': %s", err)
		}
	}

	return &result, nil
}

// ParseFile parses the given path as an Appfile.
func ParseFile(path string) (*File, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return nil, err
	}

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	result, err := Parse(f)
	if result != nil {
		result.Path = path
		if err := result.loadID(); err != nil {
			return nil, err
		}
	}

	return result, err
}

func parseApplication(result *File, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'application' block allowed")
	}

	// Check for invalid keys
	valid := []string{"name", "type", "dependency"}
	if err := checkHCLKeys(obj, valid); err != nil {
		return multierror.Prefix(err, "application:")
	}

	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, obj); err != nil {
		return err
	}

	var app Application
	result.Application = &app
	return mapstructure.WeakDecode(m, &app)
}

func parseCustomizations(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"customization '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Customization, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var c Customization
		c.Type = strings.ToLower(n)
		c.Config = m

		collection = append(collection, &c)
	}

	result.Customization = &CustomizationSet{Raw: collection}
	return nil
}

func parseImport(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make([]*hclobj.Object, 0, 3)
	set := make(map[string]struct{})
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := set[o2.Key]; ok {
				return fmt.Errorf(
					"imported '%s' more than once",
					o2.Key)
			}

			objects = append(objects, o2)
			set[o2.Key] = struct{}{}
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Import, 0, len(objects))
	for _, o := range objects {
		// Check for invalid keys
		if err := checkHCLKeys(o, nil); err != nil {
			return multierror.Prefix(err, fmt.Sprintf(
				"import '%s':", o.Key))
		}

		collection = append(collection, &Import{
			Source: o.Key,
		})
	}

	result.Imports = collection
	return nil
}

func parseInfra(result *File, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"infrastructure '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Infrastructure, 0, len(objects))
	for n, o := range objects {
		// Check for invalid keys
		valid := []string{"name", "type", "flavor", "foundation"}
		if err := checkHCLKeys(o, valid); err != nil {
			return multierror.Prefix(err, fmt.Sprintf(
				"infrastructure '%s':", n))
		}

		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var infra Infrastructure
		if err := mapstructure.WeakDecode(m, &infra); err != nil {
			return fmt.Errorf(
				"error parsing infrastructure '%s': %s", n, err)
		}

		infra.Name = n
		if infra.Type == "" {
			infra.Type = infra.Name
		}

		// Parse the foundations if we have any
		if o2 := o.Get("foundation", false); o != nil {
			if err := parseFoundations(&infra, o2); err != nil {
				return fmt.Errorf("error parsing 'foundation': %s", err)
			}
		}

		collection = append(collection, &infra)
	}

	result.Infrastructure = collection
	return nil
}

func parseFoundations(result *Infrastructure, obj *hclobj.Object) error {
	// Get all the maps of keys to the actual object
	objects := make(map[string]*hclobj.Object)
	for _, o1 := range obj.Elem(false) {
		for _, o2 := range o1.Elem(true) {
			if _, ok := objects[o2.Key]; ok {
				return fmt.Errorf(
					"foundation '%s' defined more than once",
					o2.Key)
			}

			objects[o2.Key] = o2
		}
	}

	if len(objects) == 0 {
		return nil
	}

	// Go through each object and turn it into an actual result.
	collection := make([]*Foundation, 0, len(objects))
	for n, o := range objects {
		var m map[string]interface{}
		if err := hcl.DecodeObject(&m, o); err != nil {
			return err
		}

		var f Foundation
		f.Name = n
		f.Config = m

		collection = append(collection, &f)
	}

	// Set the results
	result.Foundations = collection
	return nil
}

func parseProject(result *File, obj *hclobj.Object) error {
	if obj.Len() > 1 {
		return fmt.Errorf("only one 'project' block allowed")
	}

	// Check for invalid keys
	valid := []string{"name", "infrastructure"}
	if err := checkHCLKeys(obj, valid); err != nil {
		return multierror.Prefix(err, "project:")
	}

	var m map[string]interface{}
	if err := hcl.DecodeObject(&m, obj); err != nil {
		return err
	}

	// Parse the project
	var proj Project
	result.Project = &proj
	if err := mapstructure.WeakDecode(m, &proj); err != nil {
		return err
	}

	return nil
}

func checkHCLKeys(obj *hclobj.Object, valid []string) error {
	validMap := make(map[string]struct{}, len(valid))
	for _, v := range valid {
		validMap[v] = struct{}{}
	}

	var result error
	for _, o := range obj.Elem(true) {
		if _, ok := validMap[o.Key]; !ok {
			result = multierror.Append(result, fmt.Errorf(
				"invald key: %s", o.Key))
		}
	}

	return result
}
<|endoftext|>