<commit_before>package pull

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"os"

	_ "github.com/docker/distribution"
	"github.com/setekhid/ketos/client"
)

func pull(name, tag string) error {
	// fetch manifest
	hub, err := client.NewRegitry("", "", "")
	if err != nil {
		return err
	}

	manifest, err := hub.ManifestV2(name, tag)
	if err != nil {
		return err
	}
	f, err := os.OpenFile("m.json", os.O_CREATE|os.O_WRONLY, os.ModePerm)
	if err != nil {
		return err
	}
	defer f.Close()
	err = json.NewEncoder(f).Encode(manifest)
	if err != nil {
		fmt.Println("encode json ", err)
		return err
	}

	maniDig, err := hub.ManifestDigest(name, tag)
	if err != nil {
		return err
	}

	fmt.Printf("%+v\n", manifest)
	fmt.Printf("%+v\n", maniDig)

	// fetch layers
	layers := manifest.Layers
	for _, l := range layers {
		fmt.Printf("layer %v\n", l.Digest.Encoded())

		contents, err := hub.DownloadLayer(name, l.Digest)
		if err != nil {
			return err
		}
		defer contents.Close()

		fd, err := os.OpenFile(l.Digest.Encoded()+".tar", os.O_CREATE|os.O_WRONLY, os.ModePerm)
		if err != nil {
			return err
		}
		defer fd.Close()
		buf := bytes.Buffer{}
		buf.ReadFrom(contents)
		tw := gzip.NewWriter(fd)
		tw.Write(buf.Bytes())
		//	fmt.Println(buf.String())
	}

	return nil
}
<commit_msg>complete pull command<commit_after>package pull

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	_ "github.com/docker/distribution"
	"github.com/setekhid/ketos/client"
)

var ()

func pull(name, tag string) error {
	// fetch manifest
	hub, err := client.NewRegitry("", "", "")
	if err != nil {
		return err
	}

	manifest, err := hub.ManifestV2(name, tag)
	if err != nil {
		return err
	}
	f, err := os.OpenFile("m.json", os.O_CREATE|os.O_WRONLY, os.ModePerm)
	if err != nil {
		return err
	}
	defer f.Close()
	err = json.NewEncoder(f).Encode(manifest)
	if err != nil {
		fmt.Println("encode json ", err)
		return err
	}

	fmt.Printf("%+v\n", manifest)

	// fetch layers
	layers := manifest.Layers
	for _, l := range layers {
		fmt.Printf("download layer %v\n", l.Digest.Encoded())

		contents, err := hub.DownloadLayer(name, l.Digest)
		if err != nil {
			return err
		}
		defer contents.Close()

		digest := l.Digest.Encoded()
		tmpDir, err := ioutil.TempDir(".", digest)
		if err != nil {
			return err
		}
		gz := filepath.Join(tmpDir, digest)
		fd, err := os.OpenFile(gz+".tar.gz", os.O_CREATE|os.O_WRONLY, 0600)
		if err != nil {
			return err
		}
		defer fd.Close()

		buf := bytes.Buffer{}
		buf.ReadFrom(contents)
		_, err = fd.Write(buf.Bytes())
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/bpicode/fritzctl/logger"
	"github.com/spf13/cobra"
)

var sessionIDCmd = &cobra.Command{
	Use:     "sessionid",
	Short:   "Obtain a session ID",
	Long:    `Obtain a session ID by solving the FRITZ!Box login challenge. The session ID can be used for subsequent requests until it gets invalidated.
Visit https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AVM_Technical_Note_-_Session_ID.pdf for more information.`,
	Example: "fritzctl sessionid",
	RunE:    sessionID,
}

func init() {
	RootCmd.AddCommand(sessionIDCmd)
}

func sessionID(cmd *cobra.Command, args []string) error {
	client := clientLogin()
	logger.Success("Successfully obtained session ID:", client.SessionInfo.SID)
	return nil
}
<commit_msg>gofmt<commit_after>package cmd

import (
	"github.com/bpicode/fritzctl/logger"
	"github.com/spf13/cobra"
)

var sessionIDCmd = &cobra.Command{
	Use:   "sessionid",
	Short: "Obtain a session ID",
	Long: `Obtain a session ID by solving the FRITZ!Box login challenge. The session ID can be used for subsequent requests until it gets invalidated.
Visit https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AVM_Technical_Note_-_Session_ID.pdf for more information.`,
	Example: "fritzctl sessionid",
	RunE:    sessionID,
}

func init() {
	RootCmd.AddCommand(sessionIDCmd)
}

func sessionID(cmd *cobra.Command, args []string) error {
	client := clientLogin()
	logger.Success("Successfully obtained session ID:", client.SessionInfo.SID)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

// The tika command provides a command line interface for Tika Server.
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/google/go-tika/tika"
)

func usage() {
	fmt.Printf("Usage: %s [OPTIONS] ACTION\n\n", os.Args[0])
	fmt.Printf("ACTIONS: parse, detect, language, meta, version, parsers, mimetypes, detectors\n\n")
	fmt.Println("OPTIONS:")
	flag.PrintDefaults()
}

// Flags requiring input.
const (
	parse    = "parse"
	detect   = "detect"
	language = "language"
	meta     = "meta"
)

// Informational flags which don't require input.
const (
	version   = "version"
	parsers   = "parsers"
	mimeTypes = "mimetypes"
	detectors = "detectors"
)

// Command line flags.
var (
	downloadVersion = flag.String("download_version", "", "Tika Server JAR version to download. If -serverJAR is specified, it will be downloaded to that location, otherwise it will be downloaded to your working directory. If the JAR has already been downloaded and has the correct MD5, this will do nothing. Valid versions: 1.14.")
	filename        = flag.String("filename", "", "Path to file to parse.")
	metaField       = flag.String("field", "", `Specific field to get when using the "meta" action. Undefined when using the -recursive flag.`)
	recursive       = flag.Bool("recursive", false, `Whether to run "parse" or "meta" recursively, returning a list with one element per embedded document. Undefined when using the -field flag.`)
	serverJAR       = flag.String("server_jar", "", "Absolute path to the Tika Server JAR. This will start a new server, ignoring -serverURL.")
	serverURL       = flag.String("server_url", "", "URL of Tika server.")
)

func main() {
	flag.Usage = usage
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
		os.Exit(1)
	}
	action := flag.Arg(0)

	if *downloadVersion != "" {
		v := tika.Version116
		switch *downloadVersion {
		case "1.14":
			v = tika.Version114
		case "1.15":
			v = tika.Version115
		case "1.16":
			v = tika.Version116
		}
		if *serverJAR == "" {
			*serverJAR = "tika-server-" + *downloadVersion + ".jar"
		}
		err := tika.DownloadServer(context.Background(), v, *serverJAR)
		if err != nil {
			log.Fatal(err)
		}
	}

	if *serverURL == "" && *serverJAR == "" {
		log.Fatal("no URL specified: set serverURL, serverJAR and/or downloadVersion")
	}

	var cancel func()
	if *serverJAR != "" {
		s, err := tika.NewServer(*serverJAR, "")
		if err != nil {
			log.Fatal(err)
		}

		cancel, err = s.Start(context.Background())
		if err != nil {
			log.Fatalf("could not start server: %v", err)
		}
		defer cancel()

		*serverURL = s.URL()
	}

	var file io.Reader

	// Check actions requiring input have an input and get it.
	switch action {
	case parse, detect, language, meta:
		if *filename == "" {
			cancel()
			log.Fatalf("error: you must provide an input filename")
		}
		var err error
		file, err = os.Open(*filename)
		if err != nil {
			cancel()
			log.Fatalf("error opening file: %v", err)
		}
	}

	c := tika.NewClient(nil, *serverURL)
	b, err := process(c, action, file)
	if err != nil {
		cancel()
		log.Fatalf("tika error: %v", err)
	}
	fmt.Println(b)
}

func process(c *tika.Client, action string, file io.Reader) (string, error) {
	switch action {
	default:
		flag.Usage()
		return "", fmt.Errorf("error: invalid action %q", action)
	case parse:
		if *recursive {
			bs, err := c.ParseRecursive(context.Background(), file)
			if err != nil {
				return "", err
			}
			return strings.Join(bs, "\n"), nil
		}
		return c.Parse(context.Background(), file)
	case detect:
		return c.Detect(context.Background(), file)
	case language:
		return c.Language(context.Background(), file)
	case meta:
		if *metaField != "" {
			return c.MetaField(context.Background(), file, *metaField)
		}
		if *recursive {
			mr, err := c.MetaRecursive(context.Background(), file)
			if err != nil {
				return "", err
			}
			bytes, err := json.MarshalIndent(mr, "", "  ")
			if err != nil {
				return "", err
			}
			return string(bytes), nil
		}
		return c.Meta(context.Background(), file)
	case version:
		return c.Version(context.Background())
	case parsers:
		p, err := c.Parsers(context.Background())
		if err != nil {
			return "", err
		}
		bytes, err := json.MarshalIndent(p, "", "  ")
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	case mimeTypes:
		mt, err := c.MIMETypes(context.Background())
		if err != nil {
			return "", err
		}
		bytes, err := json.MarshalIndent(mt, "", "  ")
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	case detectors:
		d, err := c.Detectors(context.Background())
		if err != nil {
			return "", err
		}
		bytes, err := json.MarshalIndent(d, "", "  ")
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	}
}
<commit_msg>main: log an error for unsupported server versions<commit_after>/*
Copyright 2017 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

// The tika command provides a command line interface for Tika Server.
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/google/go-tika/tika"
)

func usage() {
	fmt.Printf("Usage: %s [OPTIONS] ACTION\n\n", os.Args[0])
	fmt.Printf("ACTIONS: parse, detect, language, meta, version, parsers, mimetypes, detectors\n\n")
	fmt.Println("OPTIONS:")
	flag.PrintDefaults()
}

// Flags requiring input.
const (
	parse    = "parse"
	detect   = "detect"
	language = "language"
	meta     = "meta"
)

// Informational flags which don't require input.
const (
	version   = "version"
	parsers   = "parsers"
	mimeTypes = "mimetypes"
	detectors = "detectors"
)

// Command line flags.
var (
	downloadVersion = flag.String("download_version", "", "Tika Server JAR version to download. If -serverJAR is specified, it will be downloaded to that location, otherwise it will be downloaded to your working directory. If the JAR has already been downloaded and has the correct MD5, this will do nothing. Valid versions: 1.14.")
	filename        = flag.String("filename", "", "Path to file to parse.")
	metaField       = flag.String("field", "", `Specific field to get when using the "meta" action. Undefined when using the -recursive flag.`)
	recursive       = flag.Bool("recursive", false, `Whether to run "parse" or "meta" recursively, returning a list with one element per embedded document. Undefined when using the -field flag.`)
	serverJAR       = flag.String("server_jar", "", "Absolute path to the Tika Server JAR. This will start a new server, ignoring -serverURL.")
	serverURL       = flag.String("server_url", "", "URL of Tika server.")
)

func main() {
	flag.Usage = usage
	flag.Parse()
	if flag.NArg() != 1 {
		flag.Usage()
		os.Exit(1)
	}
	action := flag.Arg(0)

	if *downloadVersion != "" {
		v := tika.Version116
		switch *downloadVersion {
		case "1.14":
			v = tika.Version114
		case "1.15":
			v = tika.Version115
		case "1.16":
			v = tika.Version116
		default:
			log.Fatalf("unsupported server version: %q", *downloadVersion)
		}
		if *serverJAR == "" {
			*serverJAR = "tika-server-" + *downloadVersion + ".jar"
		}
		err := tika.DownloadServer(context.Background(), v, *serverJAR)
		if err != nil {
			log.Fatal(err)
		}
	}

	if *serverURL == "" && *serverJAR == "" {
		log.Fatal("no URL specified: set serverURL, serverJAR and/or downloadVersion")
	}

	var cancel func()
	if *serverJAR != "" {
		s, err := tika.NewServer(*serverJAR, "")
		if err != nil {
			log.Fatal(err)
		}

		cancel, err = s.Start(context.Background())
		if err != nil {
			log.Fatalf("could not start server: %v", err)
		}
		defer cancel()

		*serverURL = s.URL()
	}

	var file io.Reader

	// Check actions requiring input have an input and get it.
	switch action {
	case parse, detect, language, meta:
		if *filename == "" {
			cancel()
			log.Fatalf("error: you must provide an input filename")
		}
		var err error
		file, err = os.Open(*filename)
		if err != nil {
			cancel()
			log.Fatalf("error opening file: %v", err)
		}
	}

	c := tika.NewClient(nil, *serverURL)
	b, err := process(c, action, file)
	if err != nil {
		cancel()
		log.Fatalf("tika error: %v", err)
	}
	fmt.Println(b)
}

func process(c *tika.Client, action string, file io.Reader) (string, error) {
	switch action {
	default:
		flag.Usage()
		return "", fmt.Errorf("error: invalid action %q", action)
	case parse:
		if *recursive {
			bs, err := c.ParseRecursive(context.Background(), file)
			if err != nil {
				return "", err
			}
			return strings.Join(bs, "\n"), nil
		}
		return c.Parse(context.Background(), file)
	case detect:
		return c.Detect(context.Background(), file)
	case language:
		return c.Language(context.Background(), file)
	case meta:
		if *metaField != "" {
			return c.MetaField(context.Background(), file, *metaField)
		}
		if *recursive {
			mr, err := c.MetaRecursive(context.Background(), file)
			if err != nil {
				return "", err
			}
			bytes, err := json.MarshalIndent(mr, "", "  ")
			if err != nil {
				return "", err
			}
			return string(bytes), nil
		}
		return c.Meta(context.Background(), file)
	case version:
		return c.Version(context.Background())
	case parsers:
		p, err := c.Parsers(context.Background())
		if err != nil {
			return "", err
		}
		bytes, err := json.MarshalIndent(p, "", "  ")
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	case mimeTypes:
		mt, err := c.MIMETypes(context.Background())
		if err != nil {
			return "", err
		}
		bytes, err := json.MarshalIndent(mt, "", "  ")
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	case detectors:
		d, err := c.Detectors(context.Background())
		if err != nil {
			return "", err
		}
		bytes, err := json.MarshalIndent(d, "", "  ")
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/go-wire/expr"
)

func main() {
	input := ""
	if len(os.Args) > 2 {
		input = strings.Join(os.Args[1:], " ")
	} else if len(os.Args) == 2 {
		input = os.Args[1]
	} else {
		fmt.Println("Usage: wire 'u64:1 u64:2 <sig:Alice>'")
		return
	}

	fmt.Println(input)
	got, err := expr.ParseReader(input, strings.NewReader(input))
	if err != nil {
		Exit("Error parsing input: " + err.Error())
	}
	gotBytes, err := got.(expr.Byteful).Bytes()
	if err != nil {
		Exit("Error serializing parsed input: " + err.Error())
	}

	fmt.Println(Fmt("%X", gotBytes))
}
<commit_msg>wire command is more quiet<commit_after>package main

import (
	"fmt"
	"os"
	"strings"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/go-wire/expr"
)

func main() {
	input := ""
	if len(os.Args) > 2 {
		input = strings.Join(os.Args[1:], " ")
	} else if len(os.Args) == 2 {
		input = os.Args[1]
	} else {
		fmt.Println("Usage: wire 'u64:1 u64:2 <sig:Alice>'")
		return
	}

	// fmt.Println(input)
	got, err := expr.ParseReader(input, strings.NewReader(input))
	if err != nil {
		Exit("Error parsing input: " + err.Error())
	}
	gotBytes, err := got.(expr.Byteful).Bytes()
	if err != nil {
		Exit("Error serializing parsed input: " + err.Error())
	}

	fmt.Println(Fmt("%X", gotBytes))
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package worker

import (
	"github.com/Matir/gobuster/logging"
	"github.com/Matir/gobuster/util"
	"github.com/Matir/gobuster/workqueue"
	"golang.org/x/net/html"
	"io"
	"net/http"
	"net/url"
	"strings"
)

type HTMLWorker struct {
	// Function to add future work
	adder workqueue.QueueAddFunc
}

func NewHTMLWorker(adder workqueue.QueueAddFunc) *HTMLWorker {
	return &HTMLWorker{adder: adder}
}

func (w *HTMLWorker) Handle(URL *url.URL, body io.Reader) {
	links := w.GetLinks(body)
	foundURLs := make([]*url.URL, 0, len(links))
	for _, l := range links {
		u, err := url.Parse(l)
		if err != nil {
			logging.Logf(logging.LogInfo, "Error parsing URL (%s): %s", l, err.Error())
			continue
		}
		foundURLs = append(foundURLs, URL.ResolveReference(u))
	}
	w.adder(foundURLs...)
}

func (*HTMLWorker) Eligible(resp *http.Response) bool {
	ct := resp.Header.Get("Content-type")
	if strings.ToLower(ct) != "text/html" {
		return false
	}
	return resp.ContentLength > 0 && resp.ContentLength < 1024*1024
}

func (*HTMLWorker) GetLinks(body io.Reader) []string {
	tree, err := html.Parse(body)
	if err != nil {
		logging.Logf(logging.LogInfo, "Unable to parse HTML document: %s", err.Error())
		return nil
	}
	links := make([]string, 0)
	var handleNode func(*html.Node)
	handleNode = func(node *html.Node) {
		if node.Type == html.ElementNode {
			if strings.ToLower(node.Data) == "a" {
				for _, a := range node.Attr {
					if strings.ToLower(a.Key) == "href" {
						links = append(links, a.Val)
						break
					}
				}
			}
		}
		// Handle children
		for n := node.FirstChild; n != nil; n = n.NextSibling {
			handleNode(n)
		}
	}
	handleNode(tree)
	return util.DedupeStrings(links)
}
<commit_msg>Refactor HTML worker.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package worker

import (
	"github.com/Matir/gobuster/logging"
	"github.com/Matir/gobuster/util"
	"github.com/Matir/gobuster/workqueue"
	"golang.org/x/net/html"
	"io"
	"net/http"
	"net/url"
	"strings"
)

type HTMLWorker struct {
	// Function to add future work
	adder workqueue.QueueAddFunc
}

func NewHTMLWorker(adder workqueue.QueueAddFunc) *HTMLWorker {
	return &HTMLWorker{adder: adder}
}

func (w *HTMLWorker) Handle(URL *url.URL, body io.Reader) {
	links := w.GetLinks(body)
	foundURLs := make([]*url.URL, 0, len(links))
	for _, l := range links {
		u, err := url.Parse(l)
		if err != nil {
			logging.Logf(logging.LogInfo, "Error parsing URL (%s): %s", l, err.Error())
			continue
		}
		foundURLs = append(foundURLs, URL.ResolveReference(u))
	}
	w.adder(foundURLs...)
}

func (*HTMLWorker) Eligible(resp *http.Response) bool {
	ct := resp.Header.Get("Content-type")
	if strings.ToLower(ct) != "text/html" {
		return false
	}
	return resp.ContentLength > 0 && resp.ContentLength < 1024*1024
}

func getElementsByTagName(root *html.Node, name string) []*html.Node {
	results := make([]*html.Node, 0)
	var handleNode func(*html.Node)
	handleNode = func(node *html.Node) {
		if node.Type == html.ElementNode && strings.ToLower(node.Data) == name {
			results = append(results, node)
		}
		for n := node.FirstChild; n != nil; n = n.NextSibling {
			handleNode(n)
		}
	}
	handleNode(root)
	return results
}

func getElementAttribute(node *html.Node, attrName string) *string {
	for _, a := range node.Attr {
		if strings.ToLower(a.Key) == attrName {
			return &a.Val
		}
	}
	return nil
}

func collectElementAttributes(root *html.Node, tagName, attrName string) []string {
	results := make([]string, 0)
	for _, el := range getElementsByTagName(root, tagName) {
		if val := getElementAttribute(el, attrName); val != nil {
			results = append(results, *val)
		}
	}
	return results
}

func (*HTMLWorker) GetLinks(body io.Reader) []string {
	tree, err := html.Parse(body)
	if err != nil {
		logging.Logf(logging.LogInfo, "Unable to parse HTML document: %s", err.Error())
		return nil
	}
	links := collectElementAttributes(tree, "a", "href")
	return util.DedupeStrings(links)
}
<|endoftext|>


<commit_before>// package column implements an io.Writer which formats
// input lines into columns.
package column // import "sigint.ca/text/column"

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// A Writer is an io.Writer which filters text by arranging it into columns.
type Writer struct {
	buf      *bytes.Buffer
	w        io.Writer
	maxwidth int
	colwidth int
}

// NewWriter returns a new column.Writer. Text written to this writer will be
// arranged so that its combined width does not exceed the given width, and then
// written to w when flushed by calling Flush().
func NewWriter(w io.Writer, width int) *Writer {
	return &Writer{
		buf:      &bytes.Buffer{},
		w:        w,
		maxwidth: width,
	}
}

// Write writes p to an internal buffer. No writes are done to the backing io.Writer
// until Flush is called.
func (w *Writer) Write(p []byte) (n int, err error) {
	return w.buf.Write(p)
}

type column struct {
	words []string
}

// Flush performs the columnation and writes the results to the column.Writer's
// backing io.Writer.
func (w *Writer) Flush() error {
	words := strings.Fields(w.buf.String())
	w.colwidth = maxlen(words)
	cols := make([]column, 1)
	cols[0].words = words
	for w.split(words, &cols) {
	}
	return w.print(cols)
}

// maxlen returns the maximum length, in runes, of the strings in words
func maxlen(words []string) int {
	var max int
	for i := range words {
		l := len([]rune(words[i]))
		if l > max {
			max = l
		}
	}
	return max
}

// split returns true if the split was successful, or false if cols is already
// maximally columnated.
func (w *Writer) split(words []string, cols *[]column) bool {
	// try to become one column wider
	newcols := make([]column, len(*cols)+1)
	for colnum := range newcols {
		percol := (len(words) + len(newcols) - 1) / len(newcols)
		i, j := percol*colnum, percol*colnum+percol
		if i > len(words) {
			return false
		}
		if j > len(words) {
			j = len(words)
		}
		colwords := words[i:j]
		newcols[colnum] = column{words: colwords}
	}

	// if we're too wide now, revert
	if w.totalwidth(newcols) >= w.maxwidth {
		return false
	}
	*cols = newcols
	return true
}

// totalwidth returns the total width of cols.
func (w *Writer) totalwidth(cols []column) int {
	width := (w.colwidth + 1) * (len(cols) - 1)
	var lastwidth int
	for _, word := range cols[len(cols)-1].words {
		if len(word) > lastwidth {
			lastwidth = len(word)
		}
	}
	return width + lastwidth
}

// print writes the columns to the backing io.Writer.
func (w *Writer) print(cols []column) error {
	rowc := len(cols[0].words)
	for i := 0; i < rowc; i++ {
		for j := range cols {
			if i >= len(cols[j].words) {
				break // done this row
			}
			if j < len(cols)-1 {
				_, err := fmt.Fprintf(w.w, "%-*s", w.colwidth+1, cols[j].words[i])
				if err != nil {
					return err
				}
			} else {
				_, err := fmt.Fprintf(w.w, "%s", cols[j].words[i])
				if err != nil {
					return err
				}
			}
		}
		_, err := fmt.Fprintln(w.w)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>column: don't quit splitting early on empty column<commit_after>// package column implements an io.Writer which formats
// input lines into columns.
package column // import "sigint.ca/text/column"

import (
	"bytes"
	"fmt"
	"io"
	"strings"
)

// A Writer is an io.Writer which filters text by arranging it into columns.
type Writer struct {
	buf      *bytes.Buffer
	w        io.Writer
	maxwidth int
	colwidth int
}

// NewWriter returns a new column.Writer. Text written to this writer will be
// arranged so that its combined width does not exceed the given width, and then
// written to w when flushed by calling Flush().
func NewWriter(w io.Writer, width int) *Writer {
	return &Writer{
		buf:      &bytes.Buffer{},
		w:        w,
		maxwidth: width,
	}
}

// Write writes p to an internal buffer. No writes are done to the backing io.Writer
// until Flush is called.
func (w *Writer) Write(p []byte) (n int, err error) {
	return w.buf.Write(p)
}

type column struct {
	words []string
}

// Flush performs the columnation and writes the results to the column.Writer's
// backing io.Writer.
func (w *Writer) Flush() error {
	words := strings.Fields(w.buf.String())
	w.colwidth = maxlen(words)
	cols := make([]column, 1)
	cols[0].words = words
	for w.split(words, &cols) {
	}
	return w.print(cols)
}

// maxlen returns the maximum length, in runes, of the strings in words
func maxlen(words []string) int {
	var max int
	for i := range words {
		l := len([]rune(words[i]))
		if l > max {
			max = l
		}
	}
	return max
}

// split returns true if the split was successful, or false if cols is already
// maximally columnated.
func (w *Writer) split(words []string, cols *[]column) bool {
	// try to become one column wider
	newcols := make([]column, len(*cols)+1)
	percol := len(words) / len(newcols)
	if len(words)%len(newcols) != 0 {
		percol++
	}
	for colnum := range newcols {
		i, j := percol*colnum, percol*colnum+percol
		if j > len(words) {
			j = len(words)
		}

		// empty columns are possible, bail out if we've reached one.
		// otherwise, slice out some words for the column.
		if i < len(words) {
			colwords := words[i:j]
			newcols[colnum] = column{words: colwords}
		} else {
			break
		}
	}

	// if newcols is too wide, discard it and stop
	if w.totalwidth(newcols) >= w.maxwidth {
		return false
	}

	// otherwise, tell the caller to continue splitting
	*cols = newcols
	return true
}

// totalwidth returns the total width of cols.
func (w *Writer) totalwidth(cols []column) int {
	width := (w.colwidth + 1) * (len(cols) - 1)
	var lastwidth int
	for _, word := range cols[len(cols)-1].words {
		if len(word) > lastwidth {
			lastwidth = len(word)
		}
	}
	return width + lastwidth
}

// print writes the columns to the backing io.Writer.
func (w *Writer) print(cols []column) error {
	rowc := len(cols[0].words)
	for i := 0; i < rowc; i++ {
		for j := range cols {
			if i >= len(cols[j].words) {
				break // done this row
			}
			if j < len(cols)-1 {
				_, err := fmt.Fprintf(w.w, "%-*s", w.colwidth+1, cols[j].words[i])
				if err != nil {
					return err
				}
			} else {
				_, err := fmt.Fprintf(w.w, "%s", cols[j].words[i])
				if err != nil {
					return err
				}
			}
		}
		_, err := fmt.Fprintln(w.w)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/terraform"
)

// ApplyCommand is a Command implementation that applies a Terraform
// configuration and actually builds or changes infrastructure.
type ApplyCommand struct {
	Meta

	// If true, then this apply command will become the "destroy"
	// command. It is just like apply but only processes a destroy.
	Destroy bool

	// When this channel is closed, the apply will be cancelled.
	ShutdownCh <-chan struct{}
}

func (c *ApplyCommand) Run(args []string) int {
	var destroyForce, refresh bool
	args = c.Meta.process(args, true)

	cmdName := "apply"
	if c.Destroy {
		cmdName = "destroy"
	}

	cmdFlags := c.Meta.flagSet(cmdName)
	if c.Destroy {
		cmdFlags.BoolVar(&destroyForce, "force", false, "force")
	}
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	pwd, err := os.Getwd()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
		return 1
	}

	var configPath string
	maybeInit := true
	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error("The apply command expects at most one argument.")
		cmdFlags.Usage()
		return 1
	} else if len(args) == 1 {
		configPath = args[0]
	} else {
		configPath = pwd
		maybeInit = false
	}

	// Prepare the extra hooks to count resources
	countHook := new(CountHook)
	stateHook := new(StateHook)
	c.Meta.extraHooks = []terraform.Hook{countHook, stateHook}

	if !c.Destroy && maybeInit {
		// Do a detect to determine if we need to do an init + apply.
		if detected, err := module.Detect(configPath, pwd); err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Invalid path: %s", err))
			return 1
		} else if !strings.HasPrefix(detected, "file") {
			// If this isn't a file URL then we're doing an init +
			// apply.
			var init InitCommand
			init.Meta = c.Meta
			if code := init.Run([]string{detected}); code != 0 {
				return code
			}

			// Change the config path to be the cwd
			configPath = pwd
		}
	}

	// Build the context based on the arguments given
	ctx, planned, err := c.Context(contextOpts{
		Destroy:   c.Destroy,
		Path:      configPath,
		StatePath: c.Meta.statePath,
	})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if c.Destroy && planned {
		c.Ui.Error(fmt.Sprintf(
			"Destroy can't be called with a plan file."))
		return 1
	}
	if !destroyForce && c.Destroy {
		v, err := c.UIInput().Input(&terraform.InputOpts{
			Id:    "destroy",
			Query: "Do you really want to destroy?",
			Description: "Terraform will delete all your managed infrastructure.\n" +
				"There is no undo. Only 'yes' will be accepted to confirm.",
		})
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error asking for confirmation: %s", err))
			return 1
		}
		if v != "yes" {
			c.Ui.Output("Destroy cancelled.")
			return 1
		}
	}
	if !planned {
		if err := ctx.Input(c.InputMode()); err != nil {
			c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
			return 1
		}
	}
	if !validateContext(ctx, c.Ui) {
		return 1
	}

	// Plan if we haven't already
	if !planned {
		if refresh {
			if _, err := ctx.Refresh(); err != nil {
				c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
				return 1
			}
		}

		if _, err := ctx.Plan(); err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error creating plan: %s", err))
			return 1
		}
	}

	// Setup the state hook for continous state updates
	{
		state, err := c.State()
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error reading state: %s", err))
			return 1
		}

		stateHook.State = state
	}

	// Start the apply in a goroutine so that we can be interrupted.
	var state *terraform.State
	var applyErr error
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		state, applyErr = ctx.Apply()
	}()

	// Wait for the apply to finish or for us to be interrupted so
	// we can handle it properly.
	err = nil
	select {
	case <-c.ShutdownCh:
		c.Ui.Output("Interrupt received. Gracefully shutting down...")

		// Stop execution
		go ctx.Stop()

		// Still get the result, since there is still one
		select {
		case <-c.ShutdownCh:
			c.Ui.Error(
				"Two interrupts received. Exiting immediately. Note that data\n" +
					"loss may have occurred.")
			return 1
		case <-doneCh:
		}
	case <-doneCh:
	}

	// Persist the state
	if state != nil {
		if err := c.Meta.PersistState(state); err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to save state: %s", err))
			return 1
		}
	}

	if applyErr != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error applying plan:\n\n"+
				"%s\n\n"+
				"Terraform does not automatically rollback in the face of errors.\n"+
				"Instead, your Terraform state file has been partially updated with\n"+
				"any resources that successfully completed. Please address the error\n"+
				"above and apply again to incrementally change your infrastructure.",
			applyErr))
		return 1
	}

	c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
		"[reset][bold][green]\n"+
			"Apply complete! Resources: %d added, %d changed, %d destroyed.",
		countHook.Added,
		countHook.Changed,
		countHook.Removed)))

	if countHook.Added > 0 || countHook.Changed > 0 {
		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
			"[reset]\n"+
				"The state of your infrastructure has been saved to the path\n"+
				"below. This state is required to modify and destroy your\n"+
				"infrastructure, so keep it safe. To inspect the complete state\n"+
				"use the `terraform show` command.\n\n"+
				"State path: %s",
			c.Meta.StateOutPath())))
	}

	// If we have outputs, then output those at the end.
	var outputs map[string]string
	if !c.Destroy && state != nil {
		outputs = state.RootModule().Outputs
	}
	if len(outputs) > 0 {
		outputBuf := new(bytes.Buffer)
		outputBuf.WriteString("[reset][bold][green]\nOutputs:\n\n")

		// Output the outputs in alphabetical order
		keyLen := 0
		keys := make([]string, 0, len(outputs))
		for key, _ := range outputs {
			keys = append(keys, key)
			if len(key) > keyLen {
				keyLen = len(key)
			}
		}
		sort.Strings(keys)

		for _, k := range keys {
			v := outputs[k]

			outputBuf.WriteString(fmt.Sprintf(
				"  %s%s = %s\n",
				k,
				strings.Repeat(" ", keyLen-len(k)),
				v))
		}

		c.Ui.Output(c.Colorize().Color(
			strings.TrimSpace(outputBuf.String())))
	}

	return 0
}

func (c *ApplyCommand) Help() string {
	if c.Destroy {
		return c.helpDestroy()
	}

	return c.helpApply()
}

func (c *ApplyCommand) Synopsis() string {
	if c.Destroy {
		return "Destroy Terraform-managed infrastructure"
	}

	return "Builds or changes infrastructure"
}

func (c *ApplyCommand) helpApply() string {
	helpText := `
Usage: terraform apply [options] [DIR]

  Builds or changes infrastructure according to Terraform configuration
  files in DIR.

  DIR can also be a SOURCE as given to the "init" command. In this case,
  apply behaves as though "init" was called followed by "apply". This only
  works for sources that aren't files, and only if the current working
  directory is empty of Terraform files. This is a shortcut for getting
  started.

Options:

  -backup=path           Path to backup the existing state file before
                         modifying. Defaults to the "-state-out" path with
                         ".backup" extension. Set to "-" to disable backup.

  -input=true            Ask for input for variables if not directly set.

  -no-color              If specified, output won't contain any color.

  -refresh=true          Update state prior to checking for differences. This
                         has no effect if a plan file is given to apply.

  -state=path            Path to read and save state (unless state-out
                         is specified). Defaults to "terraform.tfstate".

  -state-out=path        Path to write state to that is different than
                         "-state". This can be used to preserve the old
                         state.

  -target=resource       Resource to target. Operation will be limited to this
                         resource and its dependencies. This flag can be used
                         multiple times.

  -var 'foo=bar'         Set a variable in the Terraform configuration. This
                         flag can be set multiple times.

  -var-file=foo          Set variables in the Terraform configuration from
                         a file. If "terraform.tfvars" is present, it will be
                         automatically loaded if this flag is not specified.

`
	return strings.TrimSpace(helpText)
}

func (c *ApplyCommand) helpDestroy() string {
	helpText := `
Usage: terraform destroy [options] [DIR]

  Destroy Terraform-managed infrastructure.

Options:

  -backup=path           Path to backup the existing state file before
                         modifying. Defaults to the "-state-out" path with
                         ".backup" extension. Set to "-" to disable backup.

  -force                 Don't ask for input for destroy confirmation.

  -no-color              If specified, output won't contain any color.

  -refresh=true          Update state prior to checking for differences. This
                         has no effect if a plan file is given to apply.

  -state=path            Path to read and save state (unless state-out
                         is specified). Defaults to "terraform.tfstate".

  -state-out=path        Path to write state to that is different than
                         "-state". This can be used to preserve the old
                         state.

  -target=resource       Resource to target. Operation will be limited to this
                         resource and its dependencies. This flag can be used
                         multiple times.

  -var 'foo=bar'         Set a variable in the Terraform configuration. This
                         flag can be set multiple times.

  -var-file=foo          Set variables in the Terraform configuration from
                         a file. If "terraform.tfvars" is present, it will be
                         automatically loaded if this flag is not specified.

`
	return strings.TrimSpace(helpText)
}
<commit_msg>command/apply: flatten multierrors<commit_after>package command

import (
	"bytes"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/terraform"
)

// ApplyCommand is a Command implementation that applies a Terraform
// configuration and actually builds or changes infrastructure.
type ApplyCommand struct {
	Meta

	// If true, then this apply command will become the "destroy"
	// command. It is just like apply but only processes a destroy.
	Destroy bool

	// When this channel is closed, the apply will be cancelled.
	ShutdownCh <-chan struct{}
}

func (c *ApplyCommand) Run(args []string) int {
	var destroyForce, refresh bool
	args = c.Meta.process(args, true)

	cmdName := "apply"
	if c.Destroy {
		cmdName = "destroy"
	}

	cmdFlags := c.Meta.flagSet(cmdName)
	if c.Destroy {
		cmdFlags.BoolVar(&destroyForce, "force", false, "force")
	}
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&c.Meta.stateOutPath, "state-out", "", "path")
	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	pwd, err := os.Getwd()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
		return 1
	}

	var configPath string
	maybeInit := true
	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error("The apply command expects at most one argument.")
		cmdFlags.Usage()
		return 1
	} else if len(args) == 1 {
		configPath = args[0]
	} else {
		configPath = pwd
		maybeInit = false
	}

	// Prepare the extra hooks to count resources
	countHook := new(CountHook)
	stateHook := new(StateHook)
	c.Meta.extraHooks = []terraform.Hook{countHook, stateHook}

	if !c.Destroy && maybeInit {
		// Do a detect to determine if we need to do an init + apply.
		if detected, err := module.Detect(configPath, pwd); err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Invalid path: %s", err))
			return 1
		} else if !strings.HasPrefix(detected, "file") {
			// If this isn't a file URL then we're doing an init +
			// apply.
			var init InitCommand
			init.Meta = c.Meta
			if code := init.Run([]string{detected}); code != 0 {
				return code
			}

			// Change the config path to be the cwd
			configPath = pwd
		}
	}

	// Build the context based on the arguments given
	ctx, planned, err := c.Context(contextOpts{
		Destroy:   c.Destroy,
		Path:      configPath,
		StatePath: c.Meta.statePath,
	})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if c.Destroy && planned {
		c.Ui.Error(fmt.Sprintf(
			"Destroy can't be called with a plan file."))
		return 1
	}
	if !destroyForce && c.Destroy {
		v, err := c.UIInput().Input(&terraform.InputOpts{
			Id:    "destroy",
			Query: "Do you really want to destroy?",
			Description: "Terraform will delete all your managed infrastructure.\n" +
				"There is no undo. Only 'yes' will be accepted to confirm.",
		})
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error asking for confirmation: %s", err))
			return 1
		}
		if v != "yes" {
			c.Ui.Output("Destroy cancelled.")
			return 1
		}
	}
	if !planned {
		if err := ctx.Input(c.InputMode()); err != nil {
			c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
			return 1
		}
	}
	if !validateContext(ctx, c.Ui) {
		return 1
	}

	// Plan if we haven't already
	if !planned {
		if refresh {
			if _, err := ctx.Refresh(); err != nil {
				c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
				return 1
			}
		}

		if _, err := ctx.Plan(); err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error creating plan: %s", err))
			return 1
		}
	}

	// Setup the state hook for continous state updates
	{
		state, err := c.State()
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Error reading state: %s", err))
			return 1
		}

		stateHook.State = state
	}

	// Start the apply in a goroutine so that we can be interrupted.
	var state *terraform.State
	var applyErr error
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		state, applyErr = ctx.Apply()
	}()

	// Wait for the apply to finish or for us to be interrupted so
	// we can handle it properly.
	err = nil
	select {
	case <-c.ShutdownCh:
		c.Ui.Output("Interrupt received. Gracefully shutting down...")

		// Stop execution
		go ctx.Stop()

		// Still get the result, since there is still one
		select {
		case <-c.ShutdownCh:
			c.Ui.Error(
				"Two interrupts received. Exiting immediately. Note that data\n" +
					"loss may have occurred.")
			return 1
		case <-doneCh:
		}
	case <-doneCh:
	}

	// Persist the state
	if state != nil {
		if err := c.Meta.PersistState(state); err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to save state: %s", err))
			return 1
		}
	}

	if applyErr != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error applying plan:\n\n"+
				"%s\n\n"+
				"Terraform does not automatically rollback in the face of errors.\n"+
				"Instead, your Terraform state file has been partially updated with\n"+
				"any resources that successfully completed. Please address the error\n"+
				"above and apply again to incrementally change your infrastructure.",
			multierror.Flatten(applyErr)))
		return 1
	}

	c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
		"[reset][bold][green]\n"+
			"Apply complete! Resources: %d added, %d changed, %d destroyed.",
		countHook.Added,
		countHook.Changed,
		countHook.Removed)))

	if countHook.Added > 0 || countHook.Changed > 0 {
		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
			"[reset]\n"+
				"The state of your infrastructure has been saved to the path\n"+
				"below. This state is required to modify and destroy your\n"+
				"infrastructure, so keep it safe. To inspect the complete state\n"+
				"use the `terraform show` command.\n\n"+
				"State path: %s",
			c.Meta.StateOutPath())))
	}

	// If we have outputs, then output those at the end.
	var outputs map[string]string
	if !c.Destroy && state != nil {
		outputs = state.RootModule().Outputs
	}
	if len(outputs) > 0 {
		outputBuf := new(bytes.Buffer)
		outputBuf.WriteString("[reset][bold][green]\nOutputs:\n\n")

		// Output the outputs in alphabetical order
		keyLen := 0
		keys := make([]string, 0, len(outputs))
		for key, _ := range outputs {
			keys = append(keys, key)
			if len(key) > keyLen {
				keyLen = len(key)
			}
		}
		sort.Strings(keys)

		for _, k := range keys {
			v := outputs[k]

			outputBuf.WriteString(fmt.Sprintf(
				"  %s%s = %s\n",
				k,
				strings.Repeat(" ", keyLen-len(k)),
				v))
		}

		c.Ui.Output(c.Colorize().Color(
			strings.TrimSpace(outputBuf.String())))
	}

	return 0
}

func (c *ApplyCommand) Help() string {
	if c.Destroy {
		return c.helpDestroy()
	}

	return c.helpApply()
}

func (c *ApplyCommand) Synopsis() string {
	if c.Destroy {
		return "Destroy Terraform-managed infrastructure"
	}

	return "Builds or changes infrastructure"
}

func (c *ApplyCommand) helpApply() string {
	helpText := `
Usage: terraform apply [options] [DIR]

  Builds or changes infrastructure according to Terraform configuration
  files in DIR.

  DIR can also be a SOURCE as given to the "init" command. In this case,
  apply behaves as though "init" was called followed by "apply". This only
  works for sources that aren't files, and only if the current working
  directory is empty of Terraform files. This is a shortcut for getting
  started.

Options:

  -backup=path           Path to backup the existing state file before
                         modifying. Defaults to the "-state-out" path with
                         ".backup" extension. Set to "-" to disable backup.

  -input=true            Ask for input for variables if not directly set.

  -no-color              If specified, output won't contain any color.

  -refresh=true          Update state prior to checking for differences. This
                         has no effect if a plan file is given to apply.

  -state=path            Path to read and save state (unless state-out
                         is specified). Defaults to "terraform.tfstate".

  -state-out=path        Path to write state to that is different than
                         "-state". This can be used to preserve the old
                         state.

  -target=resource       Resource to target. Operation will be limited to this
                         resource and its dependencies. This flag can be used
                         multiple times.

  -var 'foo=bar'         Set a variable in the Terraform configuration. This
                         flag can be set multiple times.

  -var-file=foo          Set variables in the Terraform configuration from
                         a file. If "terraform.tfvars" is present, it will be
                         automatically loaded if this flag is not specified.

`
	return strings.TrimSpace(helpText)
}

func (c *ApplyCommand) helpDestroy() string {
	helpText := `
Usage: terraform destroy [options] [DIR]

  Destroy Terraform-managed infrastructure.

Options:

  -backup=path           Path to backup the existing state file before
                         modifying. Defaults to the "-state-out" path with
                         ".backup" extension. Set to "-" to disable backup.

  -force                 Don't ask for input for destroy confirmation.

  -no-color              If specified, output won't contain any color.

  -refresh=true          Update state prior to checking for differences. This
                         has no effect if a plan file is given to apply.

  -state=path            Path to read and save state (unless state-out
                         is specified). Defaults to "terraform.tfstate".

  -state-out=path        Path to write state to that is different than
                         "-state". This can be used to preserve the old
                         state.

  -target=resource       Resource to target. Operation will be limited to this
                         resource and its dependencies. This flag can be used
                         multiple times.

  -var 'foo=bar'         Set a variable in the Terraform configuration. This
                         flag can be set multiple times.

  -var-file=foo          Set variables in the Terraform configuration from
                         a file. If "terraform.tfvars" is present, it will be
                         automatically loaded if this flag is not specified.

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"os"
	"path/filepath"
)

const flagSetFile = "iobeam file"

// NewFilesCommand returns the base 'device' command.
func NewFilesCommand(ctx *Context) *Command {
	cmd := &Command{
		Name:  "file",
		Usage: "Commands for managing files on iobeam (e.g. app JARs).",
		SubCommands: Mux{
			"delete": newDeleteFileCmd(ctx),
			"list":   newListFilesCmd(ctx),
			"upload": newUploadFileCmd(ctx),
		},
	}
	cmd.NewFlagSet(flagSetFile)

	return cmd
}

type uploadFileArgs struct {
	projectId uint64
	path      string
	checksum  string
}

func (a *uploadFileArgs) IsValid() bool {
	return len(a.path) > 0 && len(a.checksum) > 0 && a.projectId > 0
}

func newUploadFileCmd(ctx *Context) *Command {
	args := new(uploadFileArgs)

	cmd := &Command{
		Name:    "upload",
		ApiPath: "/v1/files",
		Usage:   "Upload a file to iobeam.",
		Data:    args,
		Action:  uploadFile,
	}
	flags := cmd.NewFlagSet(flagSetFile + " upload")
	flags.Uint64Var(&args.projectId, "projectId", ctx.Profile.ActiveProject, "The ID of the project to upload the file to (defaults to active project).")
	flags.StringVar(&args.path, "path", "", "Path to file to upload.")
	flags.StringVar(&args.checksum, "checksum", "", "SHA-256 checksum, as a hex digest, of the file.")

	return cmd
}

func uploadFile(c *Command, ctx *Context) error {
	args := c.Data.(*uploadFileArgs)
	f, err := os.Open(args.path)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = ctx.Client.
		Post(c.ApiPath+"/"+filepath.Base(args.path)).
		Expect(201).
		ProjectToken(ctx.Profile, args.projectId).
		Param("checksum", args.checksum).
		Param("checksum_alg", "SHA-256").
		BodyStream(f).
		Execute()

	if err == nil {
		fmt.Printf("File '%s' uploaded successfully.\n", args.path)
	}
	return err
}

type deleteFileArgs struct {
	projectId uint64
	filename  string
	checksum  string
}

func (a *deleteFileArgs) IsValid() bool {
	return len(a.filename) > 0 && a.projectId > 0
}

func newDeleteFileCmd(ctx *Context) *Command {
	args := new(deleteFileArgs)

	cmd := &Command{
		Name:    "delete",
		ApiPath: "/v1/files",
		Usage:   "Delete a file from iobeam.",
		Data:    args,
		Action:  deleteFile,
	}
	flags := cmd.NewFlagSet(flagSetFile + " delete")
	flags.Uint64Var(&args.projectId, "projectId", ctx.Profile.ActiveProject, "The ID of the project that contains the file (defaults to active project).")
	flags.StringVar(&args.filename, "name", "", "Name of the file to delete.")

	return cmd
}

func deleteFile(c *Command, ctx *Context) error {
	args := c.Data.(*deleteFileArgs)

	_, err := ctx.Client.
		Delete(c.ApiPath+"/"+args.filename).
		Expect(204).
		ProjectToken(ctx.Profile, args.projectId).
		Execute()

	if err == nil {
		fmt.Println("File successfully deleted")
	}

	return err
}

type listFilesArgs struct {
	projectId uint64
}

func (a *listFilesArgs) IsValid() bool {
	return a.projectId > 0
}

func newListFilesCmd(ctx *Context) *Command {
	args := new(listFilesArgs)

	cmd := &Command{
		Name:    "list",
		ApiPath: "/v1/files",
		Usage:   "List files for a project.",
		Data:    args,
		Action:  listFiles,
	}
	flags := cmd.NewFlagSet(flagSetFile + " list")
	flags.Uint64Var(&args.projectId, "projectId", ctx.Profile.ActiveProject, "The ID of the project to get list of files from (defaults to active project).")

	return cmd
}

type checksum struct {
	Algorithm string `json:"algorithm"`
	Sum       string `json:"sum"`
}

type fileInfo struct {
	Name     string   `json:"file_name"`
	Created  string   `json:"created"`
	Checksum checksum `json:"checksum"`
}

func (i *fileInfo) Print() {
	fmt.Printf("Name    : %s\n", i.Name)
	fmt.Printf("Created : %s\n", i.Created)
	fmt.Printf("Checksum: %s (%s)\n", i.Checksum.Sum, i.Checksum.Algorithm)
}

func listFiles(c *Command, ctx *Context) error {
	type listResult struct {
		Files []fileInfo `json:"files"`
	}
	args := c.Data.(*listFilesArgs)

	_, err := ctx.Client.
		Get(c.ApiPath).
		Expect(200).
		ProjectToken(ctx.Profile, args.projectId).
		ResponseBody(new(listResult)).
		ResponseBodyHandler(func(body interface{}) error {
		list := body.(*listResult)
		if len(list.Files) > 0 {
			for _, info := range list.Files {
				info.Print()
			}
		} else {
			fmt.Printf("No files found for project %d.\n", args.projectId)
		}

		return nil
	}).Execute()

	return err
}
<commit_msg>Calculates checksum om file upload<commit_after>package command

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"path/filepath"
)

const flagSetFile = "iobeam file"

// NewFilesCommand returns the base 'device' command.
func NewFilesCommand(ctx *Context) *Command {
	cmd := &Command{
		Name:  "file",
		Usage: "Commands for managing files on iobeam (e.g. app JARs).",
		SubCommands: Mux{
			"delete": newDeleteFileCmd(ctx),
			"list":   newListFilesCmd(ctx),
			"upload": newUploadFileCmd(ctx),
		},
	}
	cmd.NewFlagSet(flagSetFile)

	return cmd
}

type uploadFileArgs struct {
	projectId uint64
	path      string
}

func (a *uploadFileArgs) IsValid() bool {
	return len(a.path) > 0 && a.projectId > 0
}

func newUploadFileCmd(ctx *Context) *Command {
	args := new(uploadFileArgs)

	cmd := &Command{
		Name:    "upload",
		ApiPath: "/v1/files",
		Usage:   "Upload a file to iobeam.",
		Data:    args,
		Action:  uploadFile,
	}
	flags := cmd.NewFlagSet(flagSetFile + " upload")
	flags.Uint64Var(&args.projectId, "projectId", ctx.Profile.ActiveProject, "The ID of the project to upload the file to (defaults to active project).")
	flags.StringVar(&args.path, "path", "", "Path to file to upload.")

	return cmd
}

func getFileSha256HashString(path string) (string, error) {

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

	hash := sha256.New()

	if _, err := io.Copy(hash, f); err != nil {
		return "", err
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

func uploadFile(c *Command, ctx *Context) error {
	args := c.Data.(*uploadFileArgs)
	f, err := os.Open(args.path)
	if err != nil {
		return err
	}
	defer f.Close()
	calculatedChecksum, err := getFileSha256HashString(args.path)

	if err != nil {
		fmt.Printf("Error calculating checksum:\n")
		return err
	}

	_, err = ctx.Client.
		Post(c.ApiPath+"/"+filepath.Base(args.path)).
		Expect(201).
		ProjectToken(ctx.Profile, args.projectId).
		Param("checksum", calculatedChecksum).
		Param("checksum_alg", "SHA-256").
		BodyStream(f).
		Execute()

	if err == nil {
		fmt.Printf("File '%s' uploaded successfully.\n", args.path)
	}
	return err
}

type deleteFileArgs struct {
	projectId uint64
	filename  string
	checksum  string
}

func (a *deleteFileArgs) IsValid() bool {
	return len(a.filename) > 0 && a.projectId > 0
}

func newDeleteFileCmd(ctx *Context) *Command {
	args := new(deleteFileArgs)

	cmd := &Command{
		Name:    "delete",
		ApiPath: "/v1/files",
		Usage:   "Delete a file from iobeam.",
		Data:    args,
		Action:  deleteFile,
	}
	flags := cmd.NewFlagSet(flagSetFile + " delete")
	flags.Uint64Var(&args.projectId, "projectId", ctx.Profile.ActiveProject, "The ID of the project that contains the file (defaults to active project).")
	flags.StringVar(&args.filename, "name", "", "Name of the file to delete.")

	return cmd
}

func deleteFile(c *Command, ctx *Context) error {
	args := c.Data.(*deleteFileArgs)

	_, err := ctx.Client.
		Delete(c.ApiPath+"/"+args.filename).
		Expect(204).
		ProjectToken(ctx.Profile, args.projectId).
		Execute()

	if err == nil {
		fmt.Println("File successfully deleted")
	}

	return err
}

type listFilesArgs struct {
	projectId uint64
}

func (a *listFilesArgs) IsValid() bool {
	return a.projectId > 0
}

func newListFilesCmd(ctx *Context) *Command {
	args := new(listFilesArgs)

	cmd := &Command{
		Name:    "list",
		ApiPath: "/v1/files",
		Usage:   "List files for a project.",
		Data:    args,
		Action:  listFiles,
	}
	flags := cmd.NewFlagSet(flagSetFile + " list")
	flags.Uint64Var(&args.projectId, "projectId", ctx.Profile.ActiveProject, "The ID of the project to get list of files from (defaults to active project).")

	return cmd
}

type checksum struct {
	Algorithm string `json:"algorithm"`
	Sum       string `json:"sum"`
}

type fileInfo struct {
	Name     string   `json:"file_name"`
	Created  string   `json:"created"`
	Checksum checksum `json:"checksum"`
}

func (i *fileInfo) Print() {
	fmt.Printf("Name    : %s\n", i.Name)
	fmt.Printf("Created : %s\n", i.Created)
	fmt.Printf("Checksum: %s (%s)\n", i.Checksum.Sum, i.Checksum.Algorithm)
}

func listFiles(c *Command, ctx *Context) error {
	type listResult struct {
		Files []fileInfo `json:"files"`
	}
	args := c.Data.(*listFilesArgs)

	_, err := ctx.Client.
		Get(c.ApiPath).
		Expect(200).
		ProjectToken(ctx.Profile, args.projectId).
		ResponseBody(new(listResult)).
		ResponseBodyHandler(func(body interface{}) error {
		list := body.(*listResult)
		if len(list.Files) > 0 {
			for _, info := range list.Files {
				info.Print()
			}
		} else {
			fmt.Printf("No files found for project %d.\n", args.projectId)
		}

		return nil
	}).Execute()

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"regexp"
	"strings"
)

type CommandParser struct {
	commandRegexpMap map[string]*regexp.Regexp
}

func NewCommandParser() *CommandParser {
	return &CommandParser{}
}

func (p *CommandParser) Parse(entry string) (*Command, error) {
	bodyStart := strings.Index(entry, "{")
	//parts := strings.SplitN(entry, "{", 2)
	instr := ""
	body := ""
	if bodyStart == -1 {
		instr = entry
	} else {
		instr = entry[:bodyStart]
	}
	if bodyStart > -1 {
		body = entry[bodyStart:]
	}
	//if len(parts) > 0 {
	//instr = parts[0]
	//if len(parts) > 1 {
	//	body = parts[1]
	//}
	cmdTokens := strings.Split(instr, " ")
	cmdName := cmdTokens[0]
	//cmdArgs := tokens[1:]
	//if len(cmdArgs) == 0 {
	//	cmdArgs = append(cmdArgs, "")
	//}
	return NewCommand(instr, body, cmdName, cmdTokens), nil
}
<commit_msg>Cleaned.<commit_after>package main

import (
	"regexp"
	"strings"
)

type CommandParser struct {
	commandRegexpMap map[string]*regexp.Regexp
}

func NewCommandParser() *CommandParser {
	return &CommandParser{}
}

func (p *CommandParser) Parse(entry string) (*Command, error) {
	bodyStart := strings.Index(entry, "{")
	instr := ""
	body := ""
	if bodyStart == -1 {
		instr = entry
	} else {
		instr = entry[:bodyStart]
	}
	if bodyStart > -1 {
		body = entry[bodyStart:]
	}
	cmdTokens := strings.Split(instr, " ")
	cmdName := cmdTokens[0]
	return NewCommand(instr, body, cmdName, cmdTokens), nil
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/zetamatta/go-getch"

	"../dos"
)

func cmd_copy(cmd *exec.Cmd) (int, error) {
	return cmd_xxxx(cmd.Args,
		cmd.Stderr,
		func(src, dst string) error {
			return dos.Copy(src, dst, false)
		},
		false)
}

func cmd_move(cmd *exec.Cmd) (int, error) {
	return cmd_xxxx(cmd.Args,
		cmd.Stderr,
		func(src, dst string) error {
			return dos.Move(src, dst)
		},
		true)
}

func cmd_ln(cmd *exec.Cmd) (int, error) {
	if len(cmd.Args) >= 2 && cmd.Args[1] == "-s" {
		args := make([]string, 0, len(cmd.Args)-1)
		args = append(args, cmd.Args[0])
		args = append(args, cmd.Args[2:]...)
		return cmd_xxxx(
			args,
			cmd.Stderr,
			func(src, dst string) error {
				return os.Symlink(src, dst)
			},
			true)
	} else {
		return cmd_xxxx(
			cmd.Args,
			cmd.Stderr,
			func(src, dst string) error {
				return os.Link(src, dst)
			},
			false)
	}
}

func cmd_xxxx(args []string,
	out io.Writer,
	action func(src, dst string) error,
	isDirOk bool) (int, error) {
	if len(args) <= 2 {
		fmt.Fprintf(out,
			"Usage: %s [/y] SOURCE-FILENAME DESITINATE-FILENAME\n"+
				"       %s [/y] FILENAMES... DESINATE-DIRECTORY\n",
			args[0], args[0])
		return 0, nil
	}
	fi, err := os.Stat(args[len(args)-1])
	isDir := err == nil && fi.Mode().IsDir()
	all := false
	for i, n := 1, len(args)-1; i < n; i++ {
		if args[i] == "/y" {
			all = true
			continue
		}
		src := args[i]
		dst := args[n]
		if isDir {
			dst = filepath.Join(dst, filepath.Base(src))
		}
		if !isDirOk {
			fi, err := os.Stat(src)
			if err == nil && fi.Mode().IsDir() {
				fmt.Fprintf(out, "%s is directory and passed.\n", src)
				continue
			}
		}

		fmt.Fprintf(out, "%s -> %s\n", src, dst)
		if !all {
			fi, err := os.Stat(dst)
			if fi != nil && err == nil {
				fmt.Fprintf(out,
					"%s: override? [Yes/No/All/Quit] ",
					dst)
				ch := getch.Rune()
				fmt.Fprintf(out, "%c\n", ch)
				switch ch {
				case 'y', 'Y':

				case 'a', 'A':
					all = true
				case 'q', 'Q':
					return 0, nil
				default:
					continue
				}
			}
		}
		err := action(src, dst)
		if err != nil {
			if i == n-1 {
				return 1, err
			}
			fmt.Fprintf(out, "%s\nContinue? [Yes/No] ", err.Error())
			ch := getch.Rune()
			fmt.Fprintf(out, "%c\n", ch)
			switch ch {
			case 'y', 'Y':

			default:
				return 0, nil
			}
		}
	}
	return 0, nil
}
<commit_msg>Optimize copy,move<commit_after>package commands

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/zetamatta/go-getch"

	"../dos"
)

type copymove_t struct {
	*exec.Cmd
	Action  func(src, dst string) error
	IsDirOk bool
}

func cmd_copy(cmd *exec.Cmd) (int, error) {
	return copymove_t{
		Cmd: cmd,
		Action: func(src, dst string) error {
			return dos.Copy(src, dst, false)
		},
	}.Run()
}

func cmd_move(cmd *exec.Cmd) (int, error) {
	return copymove_t{
		Cmd:     cmd,
		Action:  dos.Move,
		IsDirOk: true,
	}.Run()
}

func cmd_ln(cmd *exec.Cmd) (int, error) {
	if len(cmd.Args) >= 2 && cmd.Args[1] == "-s" {
		args := make([]string, 0, len(cmd.Args)-1)
		args = append(args, cmd.Args[0])
		args = append(args, cmd.Args[2:]...)
		return copymove_t{
			Cmd:     cmd,
			Action:  os.Symlink,
			IsDirOk: true,
		}.Run()
	} else {
		return copymove_t{
			Cmd:    cmd,
			Action: os.Link,
		}.Run()
	}
}

func (this copymove_t) Run() (int, error) {
	if len(this.Args) <= 2 {
		fmt.Fprintf(this.Stderr,
			"Usage: %s [/y] SOURCE-FILENAME DESITINATE-FILENAME\n"+
				"       %s [/y] FILENAMES... DESINATE-DIRECTORY\n",
			this.Args[0], this.Args[0])
		return 0, nil
	}
	fi, err := os.Stat(this.Args[len(this.Args)-1])
	isDir := err == nil && fi.Mode().IsDir()
	all := false
	for i, src := range this.Args[1 : len(this.Args)-1] {
		if src == "/y" {
			all = true
			continue
		}
		dst := this.Args[len(this.Args)-1]
		if isDir {
			dst = filepath.Join(dst, filepath.Base(src))
		}
		if !this.IsDirOk {
			fi, err := os.Stat(src)
			if err == nil && fi.Mode().IsDir() {
				fmt.Fprintf(this.Stderr, "%s is directory and passed.\n", src)
				continue
			}
		}

		fmt.Fprintf(this.Stderr, "%s -> %s\n", src, dst)
		if !all {
			fi, err := os.Stat(dst)
			if fi != nil && err == nil {
				fmt.Fprintf(this.Stderr,
					"%s: override? [Yes/No/All/Quit] ",
					dst)
				ch := getch.Rune()
				fmt.Fprintf(this.Stderr, "%c\n", ch)
				switch ch {
				case 'y', 'Y':

				case 'a', 'A':
					all = true
				case 'q', 'Q':
					return 0, nil
				default:
					continue
				}
			}
		}
		err := this.Action(src, dst)
		if err != nil {
			if i == len(this.Args)-1 {
				return 1, err
			}
			fmt.Fprintf(this.Stderr, "%s\nContinue? [Yes/No] ", err.Error())
			ch := getch.Rune()
			fmt.Fprintf(this.Stderr, "%c\n", ch)
			if ch != 'y' && ch != 'Y' {
				return 0, nil
			}
		}
	}
	return 0, nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/connections"
)

const URLRouteCreateGame = "/games"

const MethodCreateGame = http.MethodPost

const (
	postFieldConnectionLimit = "limit"
	postFieldMapWidth        = "width"
	postFieldMapHeight       = "height"
)

type responseCreateGameHandler struct {
	ID     int   `json:"id"`
	Limit  int   `json:"limit"`
	Width  uint8 `json:"width"`
	Height uint8 `json:"height"`
}

type createGameHandler struct {
	logger       logrus.FieldLogger
	groupManager *connections.ConnectionGroupManager
}

type ErrCreateGameHandler string

func (e ErrCreateGameHandler) Error() string {
	return "create game handler error: " + string(e)
}

func NewCreateGameHandler(logger logrus.FieldLogger, groupManager *connections.ConnectionGroupManager) http.Handler {
	return &createGameHandler{
		logger:       logger,
		groupManager: groupManager,
	}
}

func (h *createGameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.logger.Info("create game handler start")
	defer h.logger.Info("create game handler end")

	connectionLimit, err := strconv.Atoi(r.PostFormValue(postFieldConnectionLimit))
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	if connectionLimit <= 0 {
		h.logger.Warnln(ErrCreateGameHandler("invalid connection limit"), connectionLimit)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	mapWidth, err := strconv.ParseUint(r.PostFormValue(postFieldMapWidth), 10, 8)
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	if mapWidth == 0 {
		h.logger.Warnln(ErrCreateGameHandler("invalid map width"), mapWidth)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	mapHeight, err := strconv.ParseUint(r.PostFormValue(postFieldMapHeight), 10, 8)
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	if mapHeight == 0 {
		h.logger.Warnln(ErrCreateGameHandler("invalid map height"), mapHeight)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	h.logger.WithFields(logrus.Fields{
		"width":            mapWidth,
		"height":           mapHeight,
		"connection_limit": connectionLimit,
	}).Debug("create game group")

	group, err := connections.NewConnectionGroup(h.logger, connectionLimit, uint8(mapWidth), uint8(mapHeight))
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	id, err := h.groupManager.Add(group)
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))

		switch err {
		case connections.ErrGroupLimitReached:
			http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
		case connections.ErrConnsLimitReached:
			http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
		default:
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		}
		return
	}

	h.logger.Info("start group")
	group.Start()

	h.logger.Infoln("created group with id:", id)

	w.WriteHeader(http.StatusCreated)
	w.Header().Add("Content-Type", "application/json; charset=utf-8")

	err = json.NewEncoder(w).Encode(responseCreateGameHandler{
		ID:     id,
		Limit:  group.GetLimit(),
		Width:  uint8(mapWidth),
		Height: uint8(mapHeight),
	})
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
}
<commit_msg>Fix handler create game group<commit_after>package handlers

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/connections"
)

const URLRouteCreateGame = "/games"

const MethodCreateGame = http.MethodPost

const (
	postFieldConnectionLimit = "limit"
	postFieldMapWidth        = "width"
	postFieldMapHeight       = "height"
)

type responseCreateGameHandler struct {
	ID     int   `json:"id"`
	Limit  int   `json:"limit"`
	Width  uint8 `json:"width"`
	Height uint8 `json:"height"`
}

type createGameHandler struct {
	logger       logrus.FieldLogger
	groupManager *connections.ConnectionGroupManager
}

type ErrCreateGameHandler string

func (e ErrCreateGameHandler) Error() string {
	return "create game handler error: " + string(e)
}

func NewCreateGameHandler(logger logrus.FieldLogger, groupManager *connections.ConnectionGroupManager) http.Handler {
	return &createGameHandler{
		logger:       logger,
		groupManager: groupManager,
	}
}

func (h *createGameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	connectionLimit, err := strconv.Atoi(r.PostFormValue(postFieldConnectionLimit))
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	if connectionLimit <= 0 {
		h.logger.Warnln(ErrCreateGameHandler("invalid connection limit"), connectionLimit)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	mapWidth, err := strconv.ParseUint(r.PostFormValue(postFieldMapWidth), 10, 8)
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	if mapWidth == 0 {
		h.logger.Warnln(ErrCreateGameHandler("invalid map width"), mapWidth)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	mapHeight, err := strconv.ParseUint(r.PostFormValue(postFieldMapHeight), 10, 8)
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}
	if mapHeight == 0 {
		h.logger.Warnln(ErrCreateGameHandler("invalid map height"), mapHeight)
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	h.logger.WithFields(logrus.Fields{
		"width":            mapWidth,
		"height":           mapHeight,
		"connection_limit": connectionLimit,
	}).Debug("create game group")

	group, err := connections.NewConnectionGroup(h.logger, connectionLimit, uint8(mapWidth), uint8(mapHeight))
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	id, err := h.groupManager.Add(group)
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))

		switch err {
		case connections.ErrGroupLimitReached:
			http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
		case connections.ErrConnsLimitReached:
			http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
		default:
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		}
		return
	}

	h.logger.Info("start group")
	group.Start()

	h.logger.WithField("group_id", id).Infoln("created group")

	w.WriteHeader(http.StatusCreated)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	err = json.NewEncoder(w).Encode(responseCreateGameHandler{
		ID:     id,
		Limit:  group.GetLimit(),
		Width:  uint8(mapWidth),
		Height: uint8(mapHeight),
	})
	if err != nil {
		h.logger.Error(ErrCreateGameHandler(err.Error()))
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Google LLC
//
// 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.

// TODO(jba): document in CONTRIBUTING.md that service account must be given "Logs Configuration Writer" IAM role for sink tests to pass.
// TODO(jba): [cont] (1) From top left menu, go to IAM & Admin. (2) In Roles dropdown for acct, select Logging > Logs Configuration Writer. (3) Save.
// TODO(jba): Also, cloud-logs@google.com must have Owner permission on the GCS bucket named for the test project.

package logadmin

import (
	"context"
	"log"
	"testing"
	"time"

	"cloud.google.com/go/internal/testutil"
	"cloud.google.com/go/internal/uid"
	ltest "cloud.google.com/go/logging/internal/testing"
	"cloud.google.com/go/storage"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

var sinkIDs = uid.NewSpace("GO-CLIENT-TEST-SINK", nil)

const testFilter = ""

var testSinkDestination string

// Called just before TestMain calls m.Run.
// Returns a cleanup function to be called after the tests finish.
func initSinks(ctx context.Context) func() {
	// Create a unique GCS bucket so concurrent tests don't interfere with each other.
	bucketIDs := uid.NewSpace(testProjectID+"-log-sink", nil)
	testBucket := bucketIDs.New()
	testSinkDestination = "storage.googleapis.com/" + testBucket
	var storageClient *storage.Client
	if integrationTest {
		// Create a unique bucket as a sink destination, and give the cloud logging account
		// owner right.
		ts := testutil.TokenSource(ctx, storage.ScopeFullControl)
		var err error
		storageClient, err = storage.NewClient(ctx, option.WithTokenSource(ts))
		if err != nil {
			log.Fatalf("new storage client: %v", err)
		}
		bucket := storageClient.Bucket(testBucket)
		if err := bucket.Create(ctx, testProjectID, nil); err != nil {
			log.Fatalf("creating storage bucket %q: %v", testBucket, err)
		}
		log.Printf("successfully created bucket %s", testBucket)
		if err := bucket.ACL().Set(ctx, "group-cloud-logs@google.com", storage.RoleOwner); err != nil {
			log.Fatalf("setting owner role: %v", err)
		}
	}
	// Clean up from aborted tests.
	it := client.Sinks(ctx)
	for {
		s, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Printf("listing sinks: %v", err)
			break
		}
		if sinkIDs.Older(s.ID, 24*time.Hour) {
			client.DeleteSink(ctx, s.ID) // ignore error
		}
	}
	if integrationTest {
		for _, bn := range bucketNames(ctx, storageClient) {
			if bucketIDs.Older(bn, 24*time.Hour) {
				storageClient.Bucket(bn).Delete(ctx) // ignore error
			}
		}
		return func() {
			if err := storageClient.Bucket(testBucket).Delete(ctx); err != nil {
				log.Printf("deleting %q: %v", testBucket, err)
			}
			storageClient.Close()
		}
	}
	return func() {}
}

// Collect the name of all buckets for the test project.
func bucketNames(ctx context.Context, client *storage.Client) []string {
	var names []string
	it := client.Buckets(ctx, testProjectID)
loop:
	for {
		b, err := it.Next()
		switch err {
		case nil:
			names = append(names, b.Name)
		case iterator.Done:
			break loop
		default:
			log.Printf("listing buckets: %v", err)
			break loop
		}
	}
	return names
}

func TestCreateSink(t *testing.T) {
	ctx := context.Background()
	sink := &Sink{
		ID:              sinkIDs.New(),
		Destination:     testSinkDestination,
		Filter:          testFilter,
		IncludeChildren: true,
	}
	got, err := client.CreateSink(ctx, sink)
	if err != nil {
		t.Fatal(err)
	}
	sink.WriterIdentity = ltest.SharedServiceAccount
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got %+v, want %+v", got, want)
	}
	got, err = client.Sink(ctx, sink.ID)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got %+v, want %+v", got, want)
	}

	// UniqueWriterIdentity
	sink.ID = sinkIDs.New()
	got, err = client.CreateSinkOpt(ctx, sink, SinkOptions{UniqueWriterIdentity: true})
	if err != nil {
		t.Fatal(err)
	}
	// The WriterIdentity should be different.
	if got.WriterIdentity == sink.WriterIdentity {
		t.Errorf("got %s, want something different", got.WriterIdentity)
	}
}

func TestUpdateSink(t *testing.T) {
	ctx := context.Background()
	sink := &Sink{
		ID:              sinkIDs.New(),
		Destination:     testSinkDestination,
		Filter:          testFilter,
		IncludeChildren: true,
		WriterIdentity:  ltest.SharedServiceAccount,
	}

	if _, err := client.CreateSink(ctx, sink); err != nil {
		t.Fatal(err)
	}
	got, err := client.UpdateSink(ctx, sink)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}
	got, err = client.Sink(ctx, sink.ID)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}

	// Updating an existing sink changes it.
	sink.Filter = ""
	sink.IncludeChildren = false
	if _, err := client.UpdateSink(ctx, sink); err != nil {
		t.Fatal(err)
	}
	got, err = client.Sink(ctx, sink.ID)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}
}

func TestUpdateSinkOpt(t *testing.T) {
	ctx := context.Background()
	id := sinkIDs.New()
	origSink := &Sink{
		ID:              id,
		Destination:     testSinkDestination,
		Filter:          testFilter,
		IncludeChildren: true,
		WriterIdentity:  ltest.SharedServiceAccount,
	}

	if _, err := client.CreateSink(ctx, origSink); err != nil {
		t.Fatal(err)
	}

	// Updating with empty options is an error.
	_, err := client.UpdateSinkOpt(ctx, &Sink{ID: id, Destination: testSinkDestination}, SinkOptions{})
	if err == nil {
		t.Errorf("got %v, want nil", err)
	}

	// Update selected fields.
	got, err := client.UpdateSinkOpt(ctx, &Sink{ID: id}, SinkOptions{
		UpdateFilter:          true,
		UpdateIncludeChildren: true,
	})
	if err != nil {
		t.Fatal(err)
	}
	want := *origSink
	want.Filter = ""
	want.IncludeChildren = false
	if !testutil.Equal(got, &want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}

	// Update writer identity.
	got, err = client.UpdateSinkOpt(ctx, &Sink{ID: id, Filter: "foo"},
		SinkOptions{UniqueWriterIdentity: true})
	if err != nil {
		t.Fatal(err)
	}
	if got.WriterIdentity == want.WriterIdentity {
		t.Errorf("got %s, want something different", got.WriterIdentity)
	}
	want.WriterIdentity = got.WriterIdentity
	if !testutil.Equal(got, &want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}
}

func TestListSinks(t *testing.T) {
	ctx := context.Background()
	var sinks []*Sink
	want := map[string]*Sink{}
	for i := 0; i < 4; i++ {
		s := &Sink{
			ID:             sinkIDs.New(),
			Destination:    testSinkDestination,
			Filter:         testFilter,
			WriterIdentity: "serviceAccount:cloud-logs@system.gserviceaccount.com",
		}
		sinks = append(sinks, s)
		want[s.ID] = s
	}
	for _, s := range sinks {
		if _, err := client.CreateSink(ctx, s); err != nil {
			t.Fatalf("Create(%q): %v", s.ID, err)
		}
	}

	got := map[string]*Sink{}
	it := client.Sinks(ctx)
	for {
		s, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		// If tests run simultaneously, we may have more sinks than we
		// created. So only check for our own.
		if _, ok := want[s.ID]; ok {
			got[s.ID] = s
		}
	}
	if !testutil.Equal(got, want) {
		t.Errorf("got %+v, want %+v", got, want)
	}
}
<commit_msg>logging: delete sinks after hour<commit_after>// Copyright 2016 Google LLC
//
// 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.

// TODO(jba): document in CONTRIBUTING.md that service account must be given "Logs Configuration Writer" IAM role for sink tests to pass.
// TODO(jba): [cont] (1) From top left menu, go to IAM & Admin. (2) In Roles dropdown for acct, select Logging > Logs Configuration Writer. (3) Save.
// TODO(jba): Also, cloud-logs@google.com must have Owner permission on the GCS bucket named for the test project.

package logadmin

import (
	"context"
	"log"
	"testing"
	"time"

	"cloud.google.com/go/internal/testutil"
	"cloud.google.com/go/internal/uid"
	ltest "cloud.google.com/go/logging/internal/testing"
	"cloud.google.com/go/storage"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

var sinkIDs = uid.NewSpace("GO-CLIENT-TEST-SINK", nil)

const testFilter = ""

var testSinkDestination string

// Called just before TestMain calls m.Run.
// Returns a cleanup function to be called after the tests finish.
func initSinks(ctx context.Context) func() {
	// Create a unique GCS bucket so concurrent tests don't interfere with each other.
	bucketIDs := uid.NewSpace(testProjectID+"-log-sink", nil)
	testBucket := bucketIDs.New()
	testSinkDestination = "storage.googleapis.com/" + testBucket
	var storageClient *storage.Client
	if integrationTest {
		// Create a unique bucket as a sink destination, and give the cloud logging account
		// owner right.
		ts := testutil.TokenSource(ctx, storage.ScopeFullControl)
		var err error
		storageClient, err = storage.NewClient(ctx, option.WithTokenSource(ts))
		if err != nil {
			log.Fatalf("new storage client: %v", err)
		}
		bucket := storageClient.Bucket(testBucket)
		if err := bucket.Create(ctx, testProjectID, nil); err != nil {
			log.Fatalf("creating storage bucket %q: %v", testBucket, err)
		}
		log.Printf("successfully created bucket %s", testBucket)
		if err := bucket.ACL().Set(ctx, "group-cloud-logs@google.com", storage.RoleOwner); err != nil {
			log.Fatalf("setting owner role: %v", err)
		}
	}
	// Clean up from aborted tests.
	it := client.Sinks(ctx)
	for {
		s, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Printf("listing sinks: %v", err)
			break
		}
		if sinkIDs.Older(s.ID, time.Hour) {
			client.DeleteSink(ctx, s.ID) // ignore error
		}
	}
	if integrationTest {
		for _, bn := range bucketNames(ctx, storageClient) {
			if bucketIDs.Older(bn, 24*time.Hour) {
				storageClient.Bucket(bn).Delete(ctx) // ignore error
			}
		}
		return func() {
			if err := storageClient.Bucket(testBucket).Delete(ctx); err != nil {
				log.Printf("deleting %q: %v", testBucket, err)
			}
			storageClient.Close()
		}
	}
	return func() {}
}

// Collect the name of all buckets for the test project.
func bucketNames(ctx context.Context, client *storage.Client) []string {
	var names []string
	it := client.Buckets(ctx, testProjectID)
loop:
	for {
		b, err := it.Next()
		switch err {
		case nil:
			names = append(names, b.Name)
		case iterator.Done:
			break loop
		default:
			log.Printf("listing buckets: %v", err)
			break loop
		}
	}
	return names
}

func TestCreateSink(t *testing.T) {
	ctx := context.Background()
	sink := &Sink{
		ID:              sinkIDs.New(),
		Destination:     testSinkDestination,
		Filter:          testFilter,
		IncludeChildren: true,
	}
	got, err := client.CreateSink(ctx, sink)
	if err != nil {
		t.Fatal(err)
	}
	sink.WriterIdentity = ltest.SharedServiceAccount
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got %+v, want %+v", got, want)
	}
	got, err = client.Sink(ctx, sink.ID)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got %+v, want %+v", got, want)
	}

	// UniqueWriterIdentity
	sink.ID = sinkIDs.New()
	got, err = client.CreateSinkOpt(ctx, sink, SinkOptions{UniqueWriterIdentity: true})
	if err != nil {
		t.Fatal(err)
	}
	// The WriterIdentity should be different.
	if got.WriterIdentity == sink.WriterIdentity {
		t.Errorf("got %s, want something different", got.WriterIdentity)
	}
}

func TestUpdateSink(t *testing.T) {
	ctx := context.Background()
	sink := &Sink{
		ID:              sinkIDs.New(),
		Destination:     testSinkDestination,
		Filter:          testFilter,
		IncludeChildren: true,
		WriterIdentity:  ltest.SharedServiceAccount,
	}

	if _, err := client.CreateSink(ctx, sink); err != nil {
		t.Fatal(err)
	}
	got, err := client.UpdateSink(ctx, sink)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}
	got, err = client.Sink(ctx, sink.ID)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}

	// Updating an existing sink changes it.
	sink.Filter = ""
	sink.IncludeChildren = false
	if _, err := client.UpdateSink(ctx, sink); err != nil {
		t.Fatal(err)
	}
	got, err = client.Sink(ctx, sink.ID)
	if err != nil {
		t.Fatal(err)
	}
	if want := sink; !testutil.Equal(got, want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}
}

func TestUpdateSinkOpt(t *testing.T) {
	ctx := context.Background()
	id := sinkIDs.New()
	origSink := &Sink{
		ID:              id,
		Destination:     testSinkDestination,
		Filter:          testFilter,
		IncludeChildren: true,
		WriterIdentity:  ltest.SharedServiceAccount,
	}

	if _, err := client.CreateSink(ctx, origSink); err != nil {
		t.Fatal(err)
	}

	// Updating with empty options is an error.
	_, err := client.UpdateSinkOpt(ctx, &Sink{ID: id, Destination: testSinkDestination}, SinkOptions{})
	if err == nil {
		t.Errorf("got %v, want nil", err)
	}

	// Update selected fields.
	got, err := client.UpdateSinkOpt(ctx, &Sink{ID: id}, SinkOptions{
		UpdateFilter:          true,
		UpdateIncludeChildren: true,
	})
	if err != nil {
		t.Fatal(err)
	}
	want := *origSink
	want.Filter = ""
	want.IncludeChildren = false
	if !testutil.Equal(got, &want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}

	// Update writer identity.
	got, err = client.UpdateSinkOpt(ctx, &Sink{ID: id, Filter: "foo"},
		SinkOptions{UniqueWriterIdentity: true})
	if err != nil {
		t.Fatal(err)
	}
	if got.WriterIdentity == want.WriterIdentity {
		t.Errorf("got %s, want something different", got.WriterIdentity)
	}
	want.WriterIdentity = got.WriterIdentity
	if !testutil.Equal(got, &want) {
		t.Errorf("got\n%+v\nwant\n%+v", got, want)
	}
}

func TestListSinks(t *testing.T) {
	ctx := context.Background()
	var sinks []*Sink
	want := map[string]*Sink{}
	for i := 0; i < 4; i++ {
		s := &Sink{
			ID:             sinkIDs.New(),
			Destination:    testSinkDestination,
			Filter:         testFilter,
			WriterIdentity: "serviceAccount:cloud-logs@system.gserviceaccount.com",
		}
		sinks = append(sinks, s)
		want[s.ID] = s
	}
	for _, s := range sinks {
		if _, err := client.CreateSink(ctx, s); err != nil {
			t.Fatalf("Create(%q): %v", s.ID, err)
		}
	}

	got := map[string]*Sink{}
	it := client.Sinks(ctx)
	for {
		s, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		// If tests run simultaneously, we may have more sinks than we
		// created. So only check for our own.
		if _, ok := want[s.ID]; ok {
			got[s.ID] = s
		}
	}
	if !testutil.Equal(got, want) {
		t.Errorf("got %+v, want %+v", got, want)
	}
}
<|endoftext|>


<commit_before>package drone

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

type Client struct {
	token      string
	url        string
	isServer04 bool

	Commits    *CommitService
	Repos      *RepoService
	Users      *UserService
	HttpClient *http.Client
}

func NewClient(token, url string, client *http.Client) *Client {
	c := Client{
		token: token,
		url:   url,
	}

	c.Commits = &CommitService{&c}
	c.Repos = &RepoService{&c}
	c.Users = &UserService{&c}
	if client == nil {
		client = http.DefaultClient
	}
	c.HttpClient = client
	return &c
}

func NewClient04(token string, url string, client *http.Client) *Client {
	c := NewClient(token, url, client)
	c.isServer04 = true
	return c
}

var (
	ErrNotFound       = errors.New("Not Found")
	ErrForbidden      = errors.New("Forbidden")
	ErrBadRequest     = errors.New("Bad Request")
	ErrNotAuthorized  = errors.New("Unauthorized")
	ErrInternalServer = errors.New("Internal Server Error")
)

// runs an http.Request and parses the JSON-encoded http.Response,
// storing the result in the value pointed to by v.
func (c *Client) run(method, path string, in, out interface{}) error {

	// create the URI
	uri, err := url.Parse(c.url + path)
	if err != nil {
		return err
	}

	if len(uri.Scheme) == 0 {
		uri.Scheme = "http"
	}

	if len(c.token) > 0 {
		params := uri.Query()
		params.Add("access_token", c.token)
		uri.RawQuery = params.Encode()
	}

	// create the request
	req, err := http.NewRequest(method, uri.String(), nil)
	if err != nil {
		return err
	}
	req.ProtoAtLeast(1, 1)
	req.Close = true
	req.ContentLength = 0

	// if data input is provided, serialize to JSON
	if in != nil {
		formIn, ok := in.(map[string]string)
		var buf *bytes.Buffer
		var contentType string
		if c.isServer04 && ok {
			contentType = "application/x-www-form-urlencoded"
			data := url.Values{}
			for key, val := range formIn {
				data.Set(key, val)
			}
			buf = bytes.NewBufferString(data.Encode())
		} else if bytesIn, ok := in.([]byte); c.isServer04 && ok {
			contentType = "text/plain"
			buf = bytes.NewBufferString(string(bytesIn[:]))
		} else {
			contentType = "application/json"
			inJson, err := json.Marshal(in)
			if err != nil {
				return err
			}
			buf = bytes.NewBuffer(inJson)
		}

		req.Body = ioutil.NopCloser(buf)
		req.ContentLength = int64(buf.Len())
		req.Header.Set("Content-Length", strconv.Itoa(buf.Len()))
		req.Header.Set("Content-Type", contentType)
	}

	// make the request using the default http client
	resp, err := c.HttpClient.Do(req)

	if err != nil {
		return err
	}

	// make sure we defer close the body
	defer resp.Body.Close()

	// Check for an http error status (ie not 200 StatusOK)
	switch resp.StatusCode {
	case 404:
		return ErrNotFound
	case 403:
		return ErrForbidden
	case 401:
		return ErrNotAuthorized
	case 400:
		return ErrBadRequest
	case 500:
		return ErrInternalServer
	}

	// Decode the JSON response
	if out != nil {
		err = json.NewDecoder(resp.Body).Decode(out)
		if err != nil {
			if outStr, ok := out.(*string); ok {
				defer resp.Body.Close()
				contents, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					return err
				} else {
					*outStr = string(contents[:])
				}
			} else {
				return err
			}
		}
	}

	return nil
}

// do makes an http.Request and returns the response
func (c *Client) do(method, path string) (*http.Response, error) {

	// create the URI
	uri, err := url.Parse(c.url + path)
	if err != nil {
		return nil, err
	}

	if len(uri.Scheme) == 0 {
		uri.Scheme = "http"
	}

	if len(c.token) > 0 {
		params := uri.Query()
		params.Add("access_token", c.token)
		uri.RawQuery = params.Encode()
	}

	// create the request
	req, err := http.NewRequest(method, uri.String(), nil)
	if err != nil {
		return nil, err
	}
	req.ProtoAtLeast(1, 1)
	req.Close = true
	req.ContentLength = 0

	// make the request using the default http client
	resp, err := c.HttpClient.Do(req)

	return resp, err
}
<commit_msg>Read response body only once when trying to read it as either json or a string<commit_after>package drone

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

type Client struct {
	token      string
	url        string
	isServer04 bool

	Commits    *CommitService
	Repos      *RepoService
	Users      *UserService
	HttpClient *http.Client
}

func NewClient(token, url string, client *http.Client) *Client {
	c := Client{
		token: token,
		url:   url,
	}

	c.Commits = &CommitService{&c}
	c.Repos = &RepoService{&c}
	c.Users = &UserService{&c}
	if client == nil {
		client = http.DefaultClient
	}
	c.HttpClient = client
	return &c
}

func NewClient04(token string, url string, client *http.Client) *Client {
	c := NewClient(token, url, client)
	c.isServer04 = true
	return c
}

var (
	ErrNotFound       = errors.New("Not Found")
	ErrForbidden      = errors.New("Forbidden")
	ErrBadRequest     = errors.New("Bad Request")
	ErrNotAuthorized  = errors.New("Unauthorized")
	ErrInternalServer = errors.New("Internal Server Error")
)

// runs an http.Request and parses the JSON-encoded http.Response,
// storing the result in the value pointed to by v.
func (c *Client) run(method, path string, in, out interface{}) error {

	// create the URI
	uri, err := url.Parse(c.url + path)
	if err != nil {
		return err
	}

	if len(uri.Scheme) == 0 {
		uri.Scheme = "http"
	}

	if len(c.token) > 0 {
		params := uri.Query()
		params.Add("access_token", c.token)
		uri.RawQuery = params.Encode()
	}

	// create the request
	req, err := http.NewRequest(method, uri.String(), nil)
	if err != nil {
		return err
	}
	req.ProtoAtLeast(1, 1)
	req.Close = true
	req.ContentLength = 0

	// if data input is provided, serialize to JSON
	if in != nil {
		formIn, ok := in.(map[string]string)
		var buf *bytes.Buffer
		var contentType string
		if c.isServer04 && ok {
			contentType = "application/x-www-form-urlencoded"
			data := url.Values{}
			for key, val := range formIn {
				data.Set(key, val)
			}
			buf = bytes.NewBufferString(data.Encode())
		} else if bytesIn, ok := in.([]byte); c.isServer04 && ok {
			contentType = "text/plain"
			buf = bytes.NewBufferString(string(bytesIn[:]))
		} else {
			contentType = "application/json"
			inJson, err := json.Marshal(in)
			if err != nil {
				return err
			}
			buf = bytes.NewBuffer(inJson)
		}

		req.Body = ioutil.NopCloser(buf)
		req.ContentLength = int64(buf.Len())
		req.Header.Set("Content-Length", strconv.Itoa(buf.Len()))
		req.Header.Set("Content-Type", contentType)
	}

	// make the request using the default http client
	resp, err := c.HttpClient.Do(req)

	if err != nil {
		return err
	}

	// make sure we defer close the body
	defer resp.Body.Close()

	// Check for an http error status (ie not 200 StatusOK)
	switch resp.StatusCode {
	case 404:
		return ErrNotFound
	case 403:
		return ErrForbidden
	case 401:
		return ErrNotAuthorized
	case 400:
		return ErrBadRequest
	case 500:
		return ErrInternalServer
	}

	// Decode the JSON response
	if out != nil {
		respBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return errors.New(fmt.Sprintf("Error reading response body: %s", err))
		}
		err = json.Marshal(respBody, out)
		if err != nil {
			if outStr, ok := out.(*string); ok {
				*outStr = string(contents[:])
			} else {
				return err
			}
		}
	}

	return nil
}

// do makes an http.Request and returns the response
func (c *Client) do(method, path string) (*http.Response, error) {

	// create the URI
	uri, err := url.Parse(c.url + path)
	if err != nil {
		return nil, err
	}

	if len(uri.Scheme) == 0 {
		uri.Scheme = "http"
	}

	if len(c.token) > 0 {
		params := uri.Query()
		params.Add("access_token", c.token)
		uri.RawQuery = params.Encode()
	}

	// create the request
	req, err := http.NewRequest(method, uri.String(), nil)
	if err != nil {
		return nil, err
	}
	req.ProtoAtLeast(1, 1)
	req.Close = true
	req.ContentLength = 0

	// make the request using the default http client
	resp, err := c.HttpClient.Do(req)

	return resp, err
}
<|endoftext|>