<commit_before>package lib

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"github.com/BytemarkHosting/bytemark-client/util/log"
)

// Request is the lower-level type that makes HTTP calls
type Request interface {
	// GetURL gets the URL this request will be / has been made to
	GetURL() url.URL
	// AllowInsecure allows the Request to be made over http instead of https
	AllowInsecure()
	// JSON-marshals the input and runs the request, unmarshalling the response to out if it's not nil
	MarshalAndRun(in interface{}, out interface{}) (statusCode int, responseBody []byte, err error)
	// Runs the request, reading the request body to reader and unmarshalling the response to responseObject (if not nil)
	Run(body io.Reader, responseObject interface{}) (statusCode int, responseBody []byte, err error)
}

// TokenType returns what kind of token is used for the given endpoint.
// token for endpoints which expect an authorization header like "Token token=blah"
// bearer for endpoints which expect one like "Bearer blah"
func TokenType(ep Endpoint) string {
	switch ep {
	case BillingEndpoint:
		return "token"
	}
	return "bearer"
}

// RequestAlreadyRunError is returned if the Run method was already called for this Request.
type RequestAlreadyRunError struct {
	Request Request
}

// InsecureConnectionError is returned if the endpoint isn't https but AllowInsecure was not called.
type InsecureConnectionError struct {
	Request Request
}

func (e RequestAlreadyRunError) Error() string {
	return "A Request was Run twice"
}

func (e InsecureConnectionError) Error() string {
	return "A Request to an insecure endpoint was attempted when AllowInsecureRequests had not been called."
}

// internalRequest is the workhorse of the bytemark-client/lib - it builds up a request, then Run can be called to get its results.
type internalRequest struct {
	authenticate  bool
	client        Client
	endpoint      Endpoint
	url           *url.URL
	method        string
	body          []byte
	allowInsecure bool
	hasRun        bool
}

// GetURL returns the URL that the Request is for.
func (r *internalRequest) GetURL() url.URL {
	if r.url == nil {
		return url.URL{}
	}
	return *r.url
}

// BuildRequestNoAuth creates a new Request with the intention of not authenticating.
func (c *bytemarkClient) BuildRequestNoAuth(method string, endpoint Endpoint, path string, parts ...string) (r Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &internalRequest{
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// BuildRequest builds a request that will be authenticated by the endpoint given.
func (c *bytemarkClient) BuildRequest(method string, endpoint Endpoint, path string, parts ...string) (r Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &internalRequest{
		authenticate:  true,
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// AllowInsecure tells the Request that it's ok if the endpoint isn't communicated with over HTTPS.
func (r *internalRequest) AllowInsecure() {
	r.allowInsecure = true
}

// mkHTTPClient creates an http.Client for this request. If the staging endpoint is used, InsecureSkipVerify is used because I guess we don't have a good cert for that brain.
func (r *internalRequest) mkHTTPClient() (c *http.Client) {
	c = new(http.Client)
	if r.url.Host == "staging.bigv.io" {
		c.Transport = &http.Transport{
			// disable gas lint for this line (gas looks for insecure TLS settings, among other things)
			/* #nosec */
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	}
	return c
}

// mkHTTPRequest assembles an http.Request for this Request, adding Authorization headers as needed, setting the Content-Type correctly for whichever endpoint it's talking to.
func (r *internalRequest) mkHTTPRequest(body io.Reader) (req *http.Request, err error) {
	req, err = http.NewRequest(r.method, r.url.String(), body)
	if err != nil {
		return nil, err
	}
	req.Close = true
	req.Header.Add("User-Agent", "bytemark-client-"+Version)

	if r.endpoint == SPPEndpoint {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	} else {
		req.Header.Add("Accept", "application/json")
		req.Header.Add("Content-Type", "application/json")
	}
	if r.authenticate {
		if r.client.GetSessionToken() == "" {
			return nil, NilAuthError{}
		}
		// if we could settle on a single standard
		// rather than two basically-identical ones that'd be cool
		switch TokenType(r.endpoint) {
		case "token":
			req.Header.Add("Authorization", "Token token="+r.client.GetSessionToken())
		case "bearer":
			req.Header.Add("Authorization", "Bearer "+r.client.GetSessionToken())
		}
	}
	return
}

// MarshalAndRun marshals the 'in' object and passes that and 'out' to Run as the body and responseObject, respectively.
func (r *internalRequest) MarshalAndRun(in interface{}, out interface{}) (statusCode int, responseBody []byte, err error) {
	var b bytes.Buffer
	err = json.NewEncoder(&b).Encode(in)
	if err != nil {
		return
	}

	return r.Run(&b, out)
}

// Run performs the request with the given body, and attempts to unmarshal a successful response into responseObject
func (r *internalRequest) Run(body io.Reader, responseObject interface{}) (statusCode int, responseBody []byte, err error) {
	if r.hasRun {
		err = RequestAlreadyRunError{r}
		return
	}
	r.hasRun = true

	if !r.allowInsecure && r.url.Scheme == "http" {
		err = InsecureConnectionError{r}
		return
	}
	var rb []byte
	if body != nil {

		rb, err = ioutil.ReadAll(body)
		if err != nil {
			return 0, nil, err
		}
		log.Debugf(log.LvlHTTPData, "request body: '%s'\r\n", string(rb))
	}

	cli := r.mkHTTPClient()

	req, err := r.mkHTTPRequest(bytes.NewBuffer(rb))
	if err != nil {
		return
	}
	if len(rb) > 0 {
		req.Header.Add("Content-Length", fmt.Sprintf("%d", len(rb)))
	}
	res, err := cli.Do(req)
	if err != nil {
		return
	}

	statusCode = res.StatusCode

	log.Debugf(log.LvlOutline, "%s %s: %d\r\n", r.method, req.URL, res.StatusCode)

	responseBody, err = r.handleResponse(req, rb, res, responseObject)
	return
}

// handleResponse deals with the response coming back from the request - creating an error if required, unmarshalling responseObject if necessary
func (r *internalRequest) handleResponse(req *http.Request, requestBody []byte, res *http.Response, responseObject interface{}) (body []byte, err error) {
	body, err = ioutil.ReadAll(res.Body)
	log.Debugf(log.LvlHTTPData, "response body: '%s'\r\n", body)
	if err != nil {
		return
	}

	baseErr := APIError{
		Method:      r.method,
		URL:         req.URL,
		StatusCode:  res.StatusCode,
		RequestBody: string(requestBody),
	}

	baseErr.ResponseBody = string(body)

	switch res.StatusCode {
	case http.StatusBadRequest:
		// because we need to reference fields specific to BadRequestError later
		err = newBadRequestError(baseErr, body)
	case http.StatusUnauthorized:
		err = UnauthorizedError{baseErr}
	case http.StatusForbidden:
		err = ForbiddenError{baseErr}
	case http.StatusNotFound:
		err = NotFoundError{baseErr}
	case http.StatusInternalServerError:
		err = InternalServerError{baseErr}
	case http.StatusServiceUnavailable:
		err = ServiceUnavailableError{baseErr}
	default:
		if 200 <= res.StatusCode && res.StatusCode <= 299 {
			if responseObject != nil {
				jsonErr := json.Unmarshal(body, responseObject)
				if jsonErr != nil {
					return body, jsonErr
				}
			}
		} else {
			err = UnknownStatusCodeError{baseErr}
		}
	}
	return
}

// BuildURL pieces together a URL from parts, escaping as necessary..
func (c *bytemarkClient) BuildURL(endpoint Endpoint, format string, args ...string) (*url.URL, error) {
	arr := make([]interface{}, len(args))
	for i, str := range args {
		arr[i] = url.QueryEscape(str)
	}
	endpointURL := ""
	switch endpoint {
	case APIEndpoint:
		endpointURL = c.urls.API
	case BrainEndpoint:
		endpointURL = c.urls.Brain
	case BillingEndpoint:
		endpointURL = c.urls.Billing
	case SPPEndpoint:
		endpointURL = c.urls.SPP
	default:
		return nil, UnsupportedEndpointError(endpoint)
	}
	if !strings.HasPrefix(format, "/") {
		return nil, UnsupportedEndpointError(-1)
	}
	return url.Parse(endpointURL + fmt.Sprintf(format, arr...))
}
<commit_msg>add comment to fix method that doesnt actually return an error<commit_after>package lib

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"github.com/BytemarkHosting/bytemark-client/util/log"
)

// Request is the lower-level type that makes HTTP calls
type Request interface {
	// GetURL gets the URL this request will be / has been made to
	GetURL() url.URL
	// AllowInsecure allows the Request to be made over http instead of https
	AllowInsecure()
	// JSON-marshals the input and runs the request, unmarshalling the response to out if it's not nil
	MarshalAndRun(in interface{}, out interface{}) (statusCode int, responseBody []byte, err error)
	// Runs the request, reading the request body to reader and unmarshalling the response to responseObject (if not nil)
	Run(body io.Reader, responseObject interface{}) (statusCode int, responseBody []byte, err error)
}

// TokenType returns what kind of token is used for the given endpoint.
// token for endpoints which expect an authorization header like "Token token=blah"
// bearer for endpoints which expect one like "Bearer blah"
func TokenType(ep Endpoint) string {
	switch ep {
	case BillingEndpoint:
		return "token"
	}
	return "bearer"
}

// RequestAlreadyRunError is returned if the Run method was already called for this Request.
type RequestAlreadyRunError struct {
	Request Request
}

// InsecureConnectionError is returned if the endpoint isn't https but AllowInsecure was not called.
type InsecureConnectionError struct {
	Request Request
}

func (e RequestAlreadyRunError) Error() string {
	return "A Request was Run twice"
}

func (e InsecureConnectionError) Error() string {
	return "A Request to an insecure endpoint was attempted when AllowInsecureRequests had not been called."
}

// internalRequest is the workhorse of the bytemark-client/lib - it builds up a request, then Run can be called to get its results.
type internalRequest struct {
	authenticate  bool
	client        Client
	endpoint      Endpoint
	url           *url.URL
	method        string
	body          []byte
	allowInsecure bool
	hasRun        bool
}

// GetURL returns the URL that the Request is for.
func (r *internalRequest) GetURL() url.URL {
	if r.url == nil {
		return url.URL{}
	}
	return *r.url
}

// BuildRequestNoAuth creates a new Request with the intention of not authenticating.
func (c *bytemarkClient) BuildRequestNoAuth(method string, endpoint Endpoint, path string, parts ...string) (r Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &internalRequest{
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// BuildRequest builds a request that will be authenticated by the endpoint given.
func (c *bytemarkClient) BuildRequest(method string, endpoint Endpoint, path string, parts ...string) (r Request, err error) {
	url, err := c.BuildURL(endpoint, path, parts...)
	if err != nil {
		return
	}
	return &internalRequest{
		authenticate:  true,
		client:        c,
		endpoint:      endpoint,
		url:           url,
		method:        method,
		allowInsecure: c.allowInsecure,
	}, nil
}

// AllowInsecure tells the Request that it's ok if the endpoint isn't communicated with over HTTPS.
func (r *internalRequest) AllowInsecure() {
	r.allowInsecure = true
}

// mkHTTPClient creates an http.Client for this request. If the staging endpoint is used, InsecureSkipVerify is used because I guess we don't have a good cert for that brain.
func (r *internalRequest) mkHTTPClient() (c *http.Client) {
	c = new(http.Client)
	if r.url.Host == "staging.bigv.io" {
		c.Transport = &http.Transport{
			// disable gas lint for this line (gas looks for insecure TLS settings, among other things)
			/* #nosec */
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	}
	return c
}

// mkHTTPRequest assembles an http.Request for this Request, adding Authorization headers as needed, setting the Content-Type correctly for whichever endpoint it's talking to.
func (r *internalRequest) mkHTTPRequest(body io.Reader) (req *http.Request, err error) {
	req, err = http.NewRequest(r.method, r.url.String(), body)
	if err != nil {
		return nil, err
	}
	req.Close = true
	req.Header.Add("User-Agent", "bytemark-client-"+Version)

	if r.endpoint == SPPEndpoint {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	} else {
		req.Header.Add("Accept", "application/json")
		req.Header.Add("Content-Type", "application/json")
	}
	if r.authenticate {
		if r.client.GetSessionToken() == "" {
			return nil, NilAuthError{}
		}
		// if we could settle on a single standard
		// rather than two basically-identical ones that'd be cool
		switch TokenType(r.endpoint) {
		case "token":
			req.Header.Add("Authorization", "Token token="+r.client.GetSessionToken())
		case "bearer":
			req.Header.Add("Authorization", "Bearer "+r.client.GetSessionToken())
		}
	}
	return
}

// MarshalAndRun marshals the 'in' object and passes that and 'out' to Run as the body and responseObject, respectively.
func (r *internalRequest) MarshalAndRun(in interface{}, out interface{}) (statusCode int, responseBody []byte, err error) {
	var b bytes.Buffer
	err = json.NewEncoder(&b).Encode(in)
	if err != nil {
		return
	}

	return r.Run(&b, out)
}

// Run performs the request with the given body, and attempts to unmarshal a successful response into responseObject
func (r *internalRequest) Run(body io.Reader, responseObject interface{}) (statusCode int, responseBody []byte, err error) {
	if r.hasRun {
		err = RequestAlreadyRunError{r}
		return
	}
	r.hasRun = true

	if !r.allowInsecure && r.url.Scheme == "http" {
		err = InsecureConnectionError{r}
		return
	}
	var rb []byte
	if body != nil {

		rb, err = ioutil.ReadAll(body)
		if err != nil {
			return 0, nil, err
		}
		log.Debugf(log.LvlHTTPData, "request body: '%s'\r\n", string(rb))
	}

	cli := r.mkHTTPClient()

	// This isnt actually returning errors if not authenticated. (when Auth or preflight has not been run, NilAuthError)
	req, err := r.mkHTTPRequest(bytes.NewBuffer(rb))
	if err != nil {
		return
	}
	if len(rb) > 0 {
		req.Header.Add("Content-Length", fmt.Sprintf("%d", len(rb)))
	}
	res, err := cli.Do(req)
	if err != nil {
		return
	}

	statusCode = res.StatusCode

	log.Debugf(log.LvlOutline, "%s %s: %d\r\n", r.method, req.URL, res.StatusCode)

	responseBody, err = r.handleResponse(req, rb, res, responseObject)
	return
}

// handleResponse deals with the response coming back from the request - creating an error if required, unmarshalling responseObject if necessary
func (r *internalRequest) handleResponse(req *http.Request, requestBody []byte, res *http.Response, responseObject interface{}) (body []byte, err error) {
	body, err = ioutil.ReadAll(res.Body)
	log.Debugf(log.LvlHTTPData, "response body: '%s'\r\n", body)
	if err != nil {
		return
	}

	baseErr := APIError{
		Method:      r.method,
		URL:         req.URL,
		StatusCode:  res.StatusCode,
		RequestBody: string(requestBody),
	}

	baseErr.ResponseBody = string(body)

	switch res.StatusCode {
	case http.StatusBadRequest:
		// because we need to reference fields specific to BadRequestError later
		err = newBadRequestError(baseErr, body)
	case http.StatusUnauthorized:
		err = UnauthorizedError{baseErr}
	case http.StatusForbidden:
		err = ForbiddenError{baseErr}
	case http.StatusNotFound:
		err = NotFoundError{baseErr}
	case http.StatusInternalServerError:
		err = InternalServerError{baseErr}
	case http.StatusServiceUnavailable:
		err = ServiceUnavailableError{baseErr}
	default:
		if 200 <= res.StatusCode && res.StatusCode <= 299 {
			if responseObject != nil {
				jsonErr := json.Unmarshal(body, responseObject)
				if jsonErr != nil {
					return body, jsonErr
				}
			}
		} else {
			err = UnknownStatusCodeError{baseErr}
		}
	}
	return
}

// BuildURL pieces together a URL from parts, escaping as necessary..
func (c *bytemarkClient) BuildURL(endpoint Endpoint, format string, args ...string) (*url.URL, error) {
	arr := make([]interface{}, len(args))
	for i, str := range args {
		arr[i] = url.QueryEscape(str)
	}
	endpointURL := ""
	switch endpoint {
	case APIEndpoint:
		endpointURL = c.urls.API
	case BrainEndpoint:
		endpointURL = c.urls.Brain
	case BillingEndpoint:
		endpointURL = c.urls.Billing
	case SPPEndpoint:
		endpointURL = c.urls.SPP
	default:
		return nil, UnsupportedEndpointError(endpoint)
	}
	if !strings.HasPrefix(format, "/") {
		return nil, UnsupportedEndpointError(-1)
	}
	return url.Parse(endpointURL + fmt.Sprintf(format, arr...))
}
<|endoftext|>


<commit_before>// Copyright 2014 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package plan9obj

import (
	"reflect"
	"testing"
)

type fileTest struct {
	file     string
	hdr      FileHeader
	sections []*SectionHeader
}

var fileTests = []fileTest{
	{
		"testdata/386-plan9-exec",
		FileHeader{Magic386, 0x324, 0x14, 4},
		[]*SectionHeader{
			{"text", 0x4c5f, 0x20},
			{"data", 0x94c, 0x4c7f},
			{"syms", 0x2c2b, 0x55cb},
			{"spsz", 0x0, 0x81f6},
			{"pcsz", 0xf7a, 0x81f6},
		},
	},
	{
		"testdata/amd64-plan9-exec",
		FileHeader{MagicAMD64, 0x618, 0x13, 8},
		[]*SectionHeader{
			{"text", 0x4213, 0x28},
			{"data", 0xa80, 0x423b},
			{"syms", 0x2c8c, 0x4cbb},
			{"spsz", 0x0, 0x7947},
			{"pcsz", 0xca0, 0x7947},
		},
	},
}

func TestOpen(t *testing.T) {
	for i := range fileTests {
		tt := &fileTests[i]

		f, err := Open(tt.file)
		if err != nil {
			t.Error(err)
			continue
		}
		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
			continue
		}

		for i, sh := range f.Sections {
			if i >= len(tt.sections) {
				break
			}
			have := &sh.SectionHeader
			want := tt.sections[i]
			if !reflect.DeepEqual(have, want) {
				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
			}
		}
		tn := len(tt.sections)
		fn := len(f.Sections)
		if tn != fn {
			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
		}
	}
}

func TestOpenFailure(t *testing.T) {
	filename := "file.go"    // not a Plan 9 a.out file
	_, err := Open(filename) // don't crash
	if err == nil {
		t.Errorf("open %s: succeeded unexpectedly", filename)
	}
}
<commit_msg>debug/plan9obj: fix test build<commit_after>// Copyright 2014 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package plan9obj

import (
	"reflect"
	"testing"
)

type fileTest struct {
	file     string
	hdr      FileHeader
	sections []*SectionHeader
}

var fileTests = []fileTest{
	{
		"testdata/386-plan9-exec",
		FileHeader{Magic386, 0x324, 0x14, 4, 0x1000, 32},
		[]*SectionHeader{
			{"text", 0x4c5f, 0x20},
			{"data", 0x94c, 0x4c7f},
			{"syms", 0x2c2b, 0x55cb},
			{"spsz", 0x0, 0x81f6},
			{"pcsz", 0xf7a, 0x81f6},
		},
	},
	{
		"testdata/amd64-plan9-exec",
		FileHeader{MagicAMD64, 0x618, 0x13, 8, 0x200000, 40},
		[]*SectionHeader{
			{"text", 0x4213, 0x28},
			{"data", 0xa80, 0x423b},
			{"syms", 0x2c8c, 0x4cbb},
			{"spsz", 0x0, 0x7947},
			{"pcsz", 0xca0, 0x7947},
		},
	},
}

func TestOpen(t *testing.T) {
	for i := range fileTests {
		tt := &fileTests[i]

		f, err := Open(tt.file)
		if err != nil {
			t.Error(err)
			continue
		}
		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
			continue
		}

		for i, sh := range f.Sections {
			if i >= len(tt.sections) {
				break
			}
			have := &sh.SectionHeader
			want := tt.sections[i]
			if !reflect.DeepEqual(have, want) {
				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
			}
		}
		tn := len(tt.sections)
		fn := len(f.Sections)
		if tn != fn {
			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
		}
	}
}

func TestOpenFailure(t *testing.T) {
	filename := "file.go"    // not a Plan 9 a.out file
	_, err := Open(filename) // don't crash
	if err == nil {
		t.Errorf("open %s: succeeded unexpectedly", filename)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// See issue 5659.
// +build !race

package pprof_test

import (
	"bytes"
	"hash/crc32"
	"os/exec"
	"runtime"
	. "runtime/pprof"
	"strings"
	"testing"
	"unsafe"
)

func TestCPUProfile(t *testing.T) {
	buf := make([]byte, 100000)
	testCPUProfile(t, []string{"crc32.ChecksumIEEE"}, func() {
		// This loop takes about a quarter second on a 2 GHz laptop.
		// We only need to get one 100 Hz clock tick, so we've got
		// a 25x safety buffer.
		for i := 0; i < 1000; i++ {
			crc32.ChecksumIEEE(buf)
		}
	})
}

func TestCPUProfileMultithreaded(t *testing.T) {
	buf := make([]byte, 100000)
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	testCPUProfile(t, []string{"crc32.ChecksumIEEE", "crc32.Update"}, func() {
		c := make(chan int)
		go func() {
			for i := 0; i < 2000; i++ {
				crc32.Update(0, crc32.IEEETable, buf)
			}
			c <- 1
		}()
		// This loop takes about a quarter second on a 2 GHz laptop.
		// We only need to get one 100 Hz clock tick, so we've got
		// a 25x safety buffer.
		for i := 0; i < 2000; i++ {
			crc32.ChecksumIEEE(buf)
		}
	})
}

func testCPUProfile(t *testing.T, need []string, f func()) {
	switch runtime.GOOS {
	case "darwin":
		out, err := exec.Command("uname", "-a").CombinedOutput()
		if err != nil {
			t.Fatal(err)
		}
		vers := string(out)
		t.Logf("uname -a: %v", vers)
	case "plan9":
		// unimplemented
		return
	}

	var prof bytes.Buffer
	if err := StartCPUProfile(&prof); err != nil {
		t.Fatal(err)
	}
	f()
	StopCPUProfile()

	// Convert []byte to []uintptr.
	bytes := prof.Bytes()
	l := len(bytes) / int(unsafe.Sizeof(uintptr(0)))
	val := *(*[]uintptr)(unsafe.Pointer(&bytes))
	val = val[:l]

	if l < 13 {
		t.Logf("profile too short: %#x", val)
		if badOS[runtime.GOOS] {
			t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
			return
		}
		t.FailNow()
	}

	hd, val, tl := val[:5], val[5:l-3], val[l-3:]
	if hd[0] != 0 || hd[1] != 3 || hd[2] != 0 || hd[3] != 1e6/100 || hd[4] != 0 {
		t.Fatalf("unexpected header %#x", hd)
	}

	if tl[0] != 0 || tl[1] != 1 || tl[2] != 0 {
		t.Fatalf("malformed end-of-data marker %#x", tl)
	}

	// Check that profile is well formed and contains ChecksumIEEE.
	have := make([]uintptr, len(need))
	for len(val) > 0 {
		if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
			t.Fatalf("malformed profile.  leftover: %#x", val)
		}
		for _, pc := range val[2 : 2+val[1]] {
			f := runtime.FuncForPC(pc)
			if f == nil {
				continue
			}
			for i, name := range need {
				if strings.Contains(f.Name(), name) {
					have[i] += val[0]
				}
			}
		}
		val = val[2+val[1]:]
	}

	var total uintptr
	for i, name := range need {
		total += have[i]
		t.Logf("%s: %d\n", name, have[i])
	}
	ok := true
	if total == 0 {
		t.Logf("no CPU profile samples collected")
		ok = false
	}
	min := total / uintptr(len(have)) / 3
	for i, name := range need {
		if have[i] < min {
			t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
			ok = false
		}
	}

	if !ok {
		if badOS[runtime.GOOS] {
			t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
			return
		}
		t.FailNow()
	}
}

// Operating systems that are expected to fail the tests. See issue 6047.
var badOS = map[string]bool{
	"darwin":  true,
	"netbsd":  true,
	"openbsd": true,
}
<commit_msg>runtime/pprof: add block profile test Fixes #5993.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// See issue 5659.
// +build !race

package pprof_test

import (
	"bytes"
	"hash/crc32"
	"os/exec"
	"regexp"
	"runtime"
	. "runtime/pprof"
	"strings"
	"sync"
	"testing"
	"time"
	"unsafe"
)

func TestCPUProfile(t *testing.T) {
	buf := make([]byte, 100000)
	testCPUProfile(t, []string{"crc32.ChecksumIEEE"}, func() {
		// This loop takes about a quarter second on a 2 GHz laptop.
		// We only need to get one 100 Hz clock tick, so we've got
		// a 25x safety buffer.
		for i := 0; i < 1000; i++ {
			crc32.ChecksumIEEE(buf)
		}
	})
}

func TestCPUProfileMultithreaded(t *testing.T) {
	buf := make([]byte, 100000)
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	testCPUProfile(t, []string{"crc32.ChecksumIEEE", "crc32.Update"}, func() {
		c := make(chan int)
		go func() {
			for i := 0; i < 2000; i++ {
				crc32.Update(0, crc32.IEEETable, buf)
			}
			c <- 1
		}()
		// This loop takes about a quarter second on a 2 GHz laptop.
		// We only need to get one 100 Hz clock tick, so we've got
		// a 25x safety buffer.
		for i := 0; i < 2000; i++ {
			crc32.ChecksumIEEE(buf)
		}
	})
}

func testCPUProfile(t *testing.T, need []string, f func()) {
	switch runtime.GOOS {
	case "darwin":
		out, err := exec.Command("uname", "-a").CombinedOutput()
		if err != nil {
			t.Fatal(err)
		}
		vers := string(out)
		t.Logf("uname -a: %v", vers)
	case "plan9":
		// unimplemented
		return
	}

	var prof bytes.Buffer
	if err := StartCPUProfile(&prof); err != nil {
		t.Fatal(err)
	}
	f()
	StopCPUProfile()

	// Convert []byte to []uintptr.
	bytes := prof.Bytes()
	l := len(bytes) / int(unsafe.Sizeof(uintptr(0)))
	val := *(*[]uintptr)(unsafe.Pointer(&bytes))
	val = val[:l]

	if l < 13 {
		t.Logf("profile too short: %#x", val)
		if badOS[runtime.GOOS] {
			t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
			return
		}
		t.FailNow()
	}

	hd, val, tl := val[:5], val[5:l-3], val[l-3:]
	if hd[0] != 0 || hd[1] != 3 || hd[2] != 0 || hd[3] != 1e6/100 || hd[4] != 0 {
		t.Fatalf("unexpected header %#x", hd)
	}

	if tl[0] != 0 || tl[1] != 1 || tl[2] != 0 {
		t.Fatalf("malformed end-of-data marker %#x", tl)
	}

	// Check that profile is well formed and contains ChecksumIEEE.
	have := make([]uintptr, len(need))
	for len(val) > 0 {
		if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
			t.Fatalf("malformed profile.  leftover: %#x", val)
		}
		for _, pc := range val[2 : 2+val[1]] {
			f := runtime.FuncForPC(pc)
			if f == nil {
				continue
			}
			for i, name := range need {
				if strings.Contains(f.Name(), name) {
					have[i] += val[0]
				}
			}
		}
		val = val[2+val[1]:]
	}

	var total uintptr
	for i, name := range need {
		total += have[i]
		t.Logf("%s: %d\n", name, have[i])
	}
	ok := true
	if total == 0 {
		t.Logf("no CPU profile samples collected")
		ok = false
	}
	min := total / uintptr(len(have)) / 3
	for i, name := range need {
		if have[i] < min {
			t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
			ok = false
		}
	}

	if !ok {
		if badOS[runtime.GOOS] {
			t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
			return
		}
		t.FailNow()
	}
}

// Operating systems that are expected to fail the tests. See issue 6047.
var badOS = map[string]bool{
	"darwin":  true,
	"netbsd":  true,
	"openbsd": true,
}

func TestBlockProfile(t *testing.T) {
	runtime.SetBlockProfileRate(1)
	defer runtime.SetBlockProfileRate(0)
	produceChanContention()
	produceMutexContention()
	var w bytes.Buffer
	Lookup("block").WriteTo(&w, 1)
	prof := w.String()

	if !strings.HasPrefix(prof, "--- contention:\ncycles/second=") {
		t.Fatalf("Bad profile header:\n%v", prof)
	}

	reChan := regexp.MustCompile(`
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
#	0x[0-9,a-f]+	runtime/pprof_test\.produceChanContention\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`)
	if !reChan.MatchString(prof) {
		t.Fatalf("Bad chan entry, expect:\n%v\ngot:\n%v", reChan, prof)
	}

	reMutex := regexp.MustCompile(`
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
#	0x[0-9,a-f]+	sync\.\(\*Mutex\)\.Lock\+0x[0-9,a-f]+	.*/src/pkg/sync/mutex\.go:[0-9]+
#	0x[0-9,a-f]+	runtime/pprof_test\.produceMutexContention\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
#	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`)
	if !reMutex.MatchString(prof) {
		t.Fatalf("Bad mutex entry, expect:\n%v\ngot:\n%v", reMutex, prof)
	}
}

func produceChanContention() {
	c := make(chan bool)
	go func() {
		time.Sleep(10 * time.Millisecond)
		c <- true
	}()
	<-c
}

func produceMutexContention() {
	var mu sync.Mutex
	mu.Lock()
	go func() {
		time.Sleep(10 * time.Millisecond)
		mu.Unlock()
	}()
	mu.Lock()
}
<|endoftext|>


<commit_before>// © 2014 Steve McCoy under the MIT license. See LICENSE for details.

package ogg

import (
	"bytes"
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"strconv"
)

// A Decoder decodes an ogg stream page-by-page with its Decode method.
type Decoder struct {
	r   io.Reader
	buf [maxPageSize]byte
}

// NewDecoder creates an ogg Decoder.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{r: r}
}

// A Page represents a logical ogg page.
type Page struct {
	// Type is a bitmask of COP, BOS, and/or EOS.
	Type byte
	// Serial is the bitstream serial number.
	Serial uint32
	// Granule is the granule position, whose meaning is dependent on the encapsulated codec.
	Granule int64
	// Packet is the raw packet data.
	// If Type & COP != 0, this is a continuation of the previous page's packet.
	Packet []byte
}

// ErrBadSegs is the error used when trying to decode a page with a segment table size less than 1.
var ErrBadSegs = errors.New("invalid segment table size")

// ErrBadCrc is the error used when an ogg page's CRC field does not match the CRC calculated by the Decoder.
type ErrBadCrc struct {
	Found    uint32
	Expected uint32
}

func (bc ErrBadCrc) Error() string {
	return "invalid crc in packet: got " + strconv.FormatInt(int64(bc.Found), 16) +
		", expected " + strconv.FormatInt(int64(bc.Found), 16)
}

var oggs = []byte{'O', 'g', 'g', 'S'}

// Decode reads from d's Reader to the next ogg page, then returns the decoded Page or an error.
// The error may be io.EOF if that's what the Reader returned.
//
// The buffer underlying the returned Page's Packet is owned by the Decoder.
// It may be overwritten by subsequent calls to Decode.
//
// It is safe to call Decode concurrently on distinct Decoders if their Readers are distinct.
// Otherwise, the behavior is undefined.
func (d *Decoder) Decode() (Page, error) {
	hbuf := d.buf[0:headsz]
	b := 0
	for {
		_, err := io.ReadFull(d.r, hbuf[b:])
		if err != nil {
			return Page{}, err
		}

		i := bytes.Index(hbuf, oggs)
		if i == 0 {
			break
		}

		if i < 0 {
			const n = headsz
			if hbuf[n-1] == 'O' {
				i = n - 1
			} else if hbuf[n-2] == 'O' && hbuf[n-1] == 'g' {
				i = n - 2
			} else if hbuf[n-3] == 'O' && hbuf[n-2] == 'g' && hbuf[n-1] == 'g' {
				i = n - 3
			}
		}

		if i > 0 {
			b = copy(hbuf, hbuf[i:])
		}
	}

	var h pageHeader
	err := binary.Read(bytes.NewBuffer(hbuf), byteOrder, &h)
	if err != nil {
		return Page{}, err
	}

	if h.Nsegs < 1 {
		return Page{}, ErrBadSegs
	}

	nsegs := int(h.Nsegs)
	segtbl := d.buf[headsz : headsz+nsegs]
	_, err = io.ReadFull(d.r, segtbl)
	if err != nil {
		return Page{}, err
	}

	packetlen := mss*(nsegs-1) + int(segtbl[nsegs-1])
	packet := d.buf[headsz+nsegs : headsz+nsegs+packetlen]
	_, err = io.ReadFull(d.r, packet)
	if err != nil {
		return Page{}, err
	}

	page := d.buf[0 : headsz+nsegs+packetlen]
	// Clear out existing crc before calculating it
	page[22] = 0
	page[23] = 0
	page[24] = 0
	page[25] = 0
	crc := crc32.Checksum(page, crcTable)
	if crc != h.Crc {
		return Page{}, ErrBadCrc{h.Crc, crc}
	}

	return Page{h.HeaderType, h.Serial, h.Granule, packet}, nil
}
<commit_msg>Bit by the copypasta bug<commit_after>// © 2014 Steve McCoy under the MIT license. See LICENSE for details.

package ogg

import (
	"bytes"
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"strconv"
)

// A Decoder decodes an ogg stream page-by-page with its Decode method.
type Decoder struct {
	r   io.Reader
	buf [maxPageSize]byte
}

// NewDecoder creates an ogg Decoder.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{r: r}
}

// A Page represents a logical ogg page.
type Page struct {
	// Type is a bitmask of COP, BOS, and/or EOS.
	Type byte
	// Serial is the bitstream serial number.
	Serial uint32
	// Granule is the granule position, whose meaning is dependent on the encapsulated codec.
	Granule int64
	// Packet is the raw packet data.
	// If Type & COP != 0, this is a continuation of the previous page's packet.
	Packet []byte
}

// ErrBadSegs is the error used when trying to decode a page with a segment table size less than 1.
var ErrBadSegs = errors.New("invalid segment table size")

// ErrBadCrc is the error used when an ogg page's CRC field does not match the CRC calculated by the Decoder.
type ErrBadCrc struct {
	Found    uint32
	Expected uint32
}

func (bc ErrBadCrc) Error() string {
	return "invalid crc in packet: got " + strconv.FormatInt(int64(bc.Found), 16) +
		", expected " + strconv.FormatInt(int64(bc.Expected), 16)
}

var oggs = []byte{'O', 'g', 'g', 'S'}

// Decode reads from d's Reader to the next ogg page, then returns the decoded Page or an error.
// The error may be io.EOF if that's what the Reader returned.
//
// The buffer underlying the returned Page's Packet is owned by the Decoder.
// It may be overwritten by subsequent calls to Decode.
//
// It is safe to call Decode concurrently on distinct Decoders if their Readers are distinct.
// Otherwise, the behavior is undefined.
func (d *Decoder) Decode() (Page, error) {
	hbuf := d.buf[0:headsz]
	b := 0
	for {
		_, err := io.ReadFull(d.r, hbuf[b:])
		if err != nil {
			return Page{}, err
		}

		i := bytes.Index(hbuf, oggs)
		if i == 0 {
			break
		}

		if i < 0 {
			const n = headsz
			if hbuf[n-1] == 'O' {
				i = n - 1
			} else if hbuf[n-2] == 'O' && hbuf[n-1] == 'g' {
				i = n - 2
			} else if hbuf[n-3] == 'O' && hbuf[n-2] == 'g' && hbuf[n-1] == 'g' {
				i = n - 3
			}
		}

		if i > 0 {
			b = copy(hbuf, hbuf[i:])
		}
	}

	var h pageHeader
	err := binary.Read(bytes.NewBuffer(hbuf), byteOrder, &h)
	if err != nil {
		return Page{}, err
	}

	if h.Nsegs < 1 {
		return Page{}, ErrBadSegs
	}

	nsegs := int(h.Nsegs)
	segtbl := d.buf[headsz : headsz+nsegs]
	_, err = io.ReadFull(d.r, segtbl)
	if err != nil {
		return Page{}, err
	}

	packetlen := mss*(nsegs-1) + int(segtbl[nsegs-1])
	packet := d.buf[headsz+nsegs : headsz+nsegs+packetlen]
	_, err = io.ReadFull(d.r, packet)
	if err != nil {
		return Page{}, err
	}

	page := d.buf[0 : headsz+nsegs+packetlen]
	// Clear out existing crc before calculating it
	page[22] = 0
	page[23] = 0
	page[24] = 0
	page[25] = 0
	crc := crc32.Checksum(page, crcTable)
	if crc != h.Crc {
		return Page{}, ErrBadCrc{h.Crc, crc}
	}

	return Page{h.HeaderType, h.Serial, h.Granule, packet}, nil
}
<|endoftext|>


<commit_before>package toml

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"strings"
	"time"
)

var e = fmt.Errorf

// Primitive is a TOML value that hasn't been decoded into a Go value.
// When using the various `Decode*` functions, the type `Primitive` may
// be given to any value, and its decoding will be delayed.
//
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
//
// The underlying representation of a `Primitive` value is subject to change.
// Do not rely on it.
//
// N.B. Primitive values are still parsed, so using them will only avoid
// the overhead of reflection. They can be useful when you don't know the
// exact type of TOML data until run time.
type Primitive interface{}

// PrimitiveDecode is just like the other `Decode*` functions, except it
// decodes a TOML value that has already been parsed. Valid primitive values
// can *only* be obtained from values filled by the decoder functions,
// including `PrimitiveDecode`. (i.e., `v` may contain more `Primitive`
// values.)
//
// Meta data for primitive values is included in the meta data returned by
// the `Decode*` functions.
func PrimitiveDecode(primValue Primitive, v interface{}) error {
	return unify(primValue, rvalue(v))
}

// Decode will decode the contents of `data` in TOML format into a pointer
// `v`.
//
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
// used interchangeably.)
//
// TOML datetimes correspond to Go `time.Time` values.
//
// All other TOML types (float, string, int, bool and array) correspond
// to the obvious Go types.
//
// TOML keys can map to either keys in a Go map or field names in a Go
// struct. The special `toml` struct tag may be used to map TOML keys to
// struct fields that don't match the key name exactly. (See the example.)
// A case insensitive match to struct names will be tried if an exact match
// can't be found.
//
// The mapping between TOML values and Go values is loose. That is, there
// may exist TOML values that cannot be placed into your representation, and
// there may be parts of your representation that do not correspond to
// TOML values.
//
// This decoder will not handle cyclic types. If a cyclic type is passed,
// `Decode` will not terminate.
func Decode(data string, v interface{}) (MetaData, error) {
	p, err := parse(data)
	if err != nil {
		return MetaData{}, err
	}
	return MetaData{p.mapping, p.types, p.ordered}, unify(p.mapping, rvalue(v))
}

// DecodeFile is just like Decode, except it will automatically read the
// contents of the file at `fpath` and decode it for you.
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadFile(fpath)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// DecodeReader is just like Decode, except it will consume all bytes
// from the reader and decode it for you.
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadAll(r)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
	// Special case. Look for a `Primitive` value.
	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
		return unifyAnything(data, rv)
	}

	// Special case. Go's `time.Time` is a struct, which we don't want
	// to confuse with a user struct.
	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
		return unifyDatetime(data, rv)
	}

	k := rv.Kind()

	// laziness
	if k >= reflect.Int && k <= reflect.Uint64 {
		return unifyInt(data, rv)
	}
	switch k {
	case reflect.Ptr:
		elem := reflect.New(rv.Type().Elem())
		err := unify(data, reflect.Indirect(elem))
		if err == nil {
			rv.Set(elem)
		}
		return err
	case reflect.Struct:
		return unifyStruct(data, rv)
	case reflect.Map:
		return unifyMap(data, rv)
	case reflect.Slice:
		return unifySlice(data, rv)
	case reflect.String:
		return unifyString(data, rv)
	case reflect.Bool:
		return unifyBool(data, rv)
	case reflect.Interface:
		// we only support empty interfaces.
		if rv.NumMethod() > 0 {
			return e("Unsupported type '%s'.", rv.Kind())
		}
		return unifyAnything(data, rv)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return unifyFloat64(data, rv)
	}
	return e("Unsupported type '%s'.", rv.Kind())
}

func unifyStruct(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return mismatch(rv, "map", mapping)
	}

	rt := rv.Type()
	for i := 0; i < rt.NumField(); i++ {
		// A little tricky. We want to use the special `toml` name in the
		// struct tag if it exists. In particular, we need to make sure that
		// this struct field is in the current map before trying to unify it.
		sft := rt.Field(i)
		kname := sft.Tag.Get("toml")
		if len(kname) == 0 {
			kname = sft.Name
		}
		if datum, ok := insensitiveGet(tmap, kname); ok {
			sf := indirect(rv.Field(i))

			// Don't try to mess with unexported types and other such things.
			if sf.CanSet() {
				if err := unify(datum, sf); err != nil {
					return e("Type mismatch for '%s.%s': %s",
						rt.String(), sft.Name, err)
				}
			} else if len(sft.Tag.Get("toml")) > 0 {
				// Bad user! No soup for you!
				return e("Field '%s.%s' is unexported, and therefore cannot "+
					"be loaded with reflection.", rt.String(), sft.Name)
			}
		}
	}
	return nil
}

func unifyMap(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return badtype("map", mapping)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeMap(rv.Type()))
	}
	for k, v := range tmap {
		rvkey := indirect(reflect.New(rv.Type().Key()))
		rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
		if err := unify(v, rvval); err != nil {
			return err
		}

		rvkey.SetString(k)
		rv.SetMapIndex(rvkey, rvval)
	}
	return nil
}

func unifySlice(data interface{}, rv reflect.Value) error {
	slice, ok := data.([]interface{})
	if !ok {
		return badtype("slice", data)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeSlice(rv.Type(), len(slice), len(slice)))
	}
	for i, v := range slice {
		sliceval := indirect(rv.Index(i))
		if err := unify(v, sliceval); err != nil {
			return err
		}
	}
	return nil
}

func unifyDatetime(data interface{}, rv reflect.Value) error {
	if _, ok := data.(time.Time); ok {
		rv.Set(reflect.ValueOf(data))
		return nil
	}
	return badtype("time.Time", data)
}

func unifyString(data interface{}, rv reflect.Value) error {
	if s, ok := data.(string); ok {
		rv.SetString(s)
		return nil
	}
	return badtype("string", data)
}

func unifyFloat64(data interface{}, rv reflect.Value) error {
	if num, ok := data.(float64); ok {
		switch rv.Kind() {
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			rv.SetFloat(num)
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("float", data)
}

func unifyInt(data interface{}, rv reflect.Value) error {
	if num, ok := data.(int64); ok {
		switch rv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			rv.SetInt(int64(num))
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			rv.SetUint(uint64(num))
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("integer", data)
}

func unifyBool(data interface{}, rv reflect.Value) error {
	if b, ok := data.(bool); ok {
		rv.SetBool(b)
		return nil
	}
	return badtype("integer", data)
}

func unifyAnything(data interface{}, rv reflect.Value) error {
	// too awesome to fail
	rv.Set(reflect.ValueOf(data))
	return nil
}

// rvalue returns a reflect.Value of `v`. All pointers are resolved.
func rvalue(v interface{}) reflect.Value {
	return indirect(reflect.ValueOf(v))
}

// indirect returns the value pointed to by a pointer.
// Pointers are followed until the value is not a pointer.
// New values are allocated for each nil pointer.
func indirect(v reflect.Value) reflect.Value {
	if v.Kind() != reflect.Ptr {
		return v
	}
	if v.IsNil() {
		v.Set(reflect.New(v.Type().Elem()))
	}
	return indirect(reflect.Indirect(v))
}

func tstring(rv reflect.Value) string {
	return rv.Type().String()
}

func badtype(expected string, data interface{}) error {
	return e("Expected %s but found '%T'.", expected, data)
}

func mismatch(user reflect.Value, expected string, data interface{}) error {
	return e("Type mismatch for %s. Expected %s but found '%T'.",
		tstring(user), expected, data)
}

func insensitiveGet(
	tmap map[string]interface{}, kname string) (interface{}, bool) {

	if datum, ok := tmap[kname]; ok {
		return datum, true
	}
	for k, v := range tmap {
		if strings.EqualFold(kname, k) {
			return v, true
		}
	}
	return nil, false
}

// MetaData allows access to meta information about TOML data that may not
// be inferrable via reflection. In particular, whether a key has been defined
// and the TOML type of a key.
//
// (XXX: If TOML gets NULL values, that information will be added here too.)
type MetaData struct {
	mapping map[string]interface{}
	types   map[string]tomlType
	keys    []Key
}

// IsDefined returns true if the key given exists in the TOML data. The key
// should be specified hierarchially. e.g.,
//
//	// access the TOML key 'a.b.c'
//	IsDefined("a", "b", "c")
//
// IsDefined will return false if an empty key given. Keys are case sensitive.
func (md MetaData) IsDefined(key ...string) bool {
	var hashOrVal interface{}
	var hash map[string]interface{}
	var ok bool

	if len(key) == 0 {
		return false
	}

	hashOrVal = md.mapping
	for _, k := range key {
		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
			return false
		}
		if hashOrVal, ok = hash[k]; !ok {
			return false
		}
	}
	return true
}

// Type returns a string representation of the type of the key specified.
//
// Type will return the empty string if given an empty key or a key that
// does not exist. Keys are case sensitive.
func (md MetaData) Type(key ...string) string {
	fullkey := strings.Join(key, ".")
	if typ, ok := md.types[fullkey]; ok {
		return typ.typeString()
	}
	return ""
}

// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
// to get values of this type.
type Key []string

func (k Key) String() string {
	return strings.Join(k, ".")
}

func (k Key) add(piece string) Key {
	newKey := make(Key, len(k))
	copy(newKey, k)
	return append(newKey, piece)
}

// Keys returns a slice of every key in the TOML data, including key groups.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific.
//
// The list will have the same order as the keys appeared in the TOML data.
//
// All keys returned are non-empty.
func (md MetaData) Keys() []Key {
	return md.keys
}

func allKeys(m map[string]interface{}, context Key) []Key {
	keys := make([]Key, 0, len(m))
	for k, v := range m {
		keys = append(keys, context.add(k))
		if t, ok := v.(map[string]interface{}); ok {
			keys = append(keys, allKeys(t, context.add(k))...)
		}
	}
	return keys
}
<commit_msg>Be idiomatic, even if it does use one more SLOC.<commit_after>package toml

import (
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"strings"
	"time"
)

var e = fmt.Errorf

// Primitive is a TOML value that hasn't been decoded into a Go value.
// When using the various `Decode*` functions, the type `Primitive` may
// be given to any value, and its decoding will be delayed.
//
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
//
// The underlying representation of a `Primitive` value is subject to change.
// Do not rely on it.
//
// N.B. Primitive values are still parsed, so using them will only avoid
// the overhead of reflection. They can be useful when you don't know the
// exact type of TOML data until run time.
type Primitive interface{}

// PrimitiveDecode is just like the other `Decode*` functions, except it
// decodes a TOML value that has already been parsed. Valid primitive values
// can *only* be obtained from values filled by the decoder functions,
// including `PrimitiveDecode`. (i.e., `v` may contain more `Primitive`
// values.)
//
// Meta data for primitive values is included in the meta data returned by
// the `Decode*` functions.
func PrimitiveDecode(primValue Primitive, v interface{}) error {
	return unify(primValue, rvalue(v))
}

// Decode will decode the contents of `data` in TOML format into a pointer
// `v`.
//
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
// used interchangeably.)
//
// TOML datetimes correspond to Go `time.Time` values.
//
// All other TOML types (float, string, int, bool and array) correspond
// to the obvious Go types.
//
// TOML keys can map to either keys in a Go map or field names in a Go
// struct. The special `toml` struct tag may be used to map TOML keys to
// struct fields that don't match the key name exactly. (See the example.)
// A case insensitive match to struct names will be tried if an exact match
// can't be found.
//
// The mapping between TOML values and Go values is loose. That is, there
// may exist TOML values that cannot be placed into your representation, and
// there may be parts of your representation that do not correspond to
// TOML values.
//
// This decoder will not handle cyclic types. If a cyclic type is passed,
// `Decode` will not terminate.
func Decode(data string, v interface{}) (MetaData, error) {
	p, err := parse(data)
	if err != nil {
		return MetaData{}, err
	}
	return MetaData{p.mapping, p.types, p.ordered}, unify(p.mapping, rvalue(v))
}

// DecodeFile is just like Decode, except it will automatically read the
// contents of the file at `fpath` and decode it for you.
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadFile(fpath)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// DecodeReader is just like Decode, except it will consume all bytes
// from the reader and decode it for you.
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
	bs, err := ioutil.ReadAll(r)
	if err != nil {
		return MetaData{}, err
	}
	return Decode(string(bs), v)
}

// unify performs a sort of type unification based on the structure of `rv`,
// which is the client representation.
//
// Any type mismatch produces an error. Finding a type that we don't know
// how to handle produces an unsupported type error.
func unify(data interface{}, rv reflect.Value) error {
	// Special case. Look for a `Primitive` value.
	if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
		return unifyAnything(data, rv)
	}

	// Special case. Go's `time.Time` is a struct, which we don't want
	// to confuse with a user struct.
	if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
		return unifyDatetime(data, rv)
	}

	k := rv.Kind()

	// laziness
	if k >= reflect.Int && k <= reflect.Uint64 {
		return unifyInt(data, rv)
	}
	switch k {
	case reflect.Ptr:
		elem := reflect.New(rv.Type().Elem())
		err := unify(data, reflect.Indirect(elem))
		if err != nil {
			return err
		}
		rv.Set(elem)
		return nil
	case reflect.Struct:
		return unifyStruct(data, rv)
	case reflect.Map:
		return unifyMap(data, rv)
	case reflect.Slice:
		return unifySlice(data, rv)
	case reflect.String:
		return unifyString(data, rv)
	case reflect.Bool:
		return unifyBool(data, rv)
	case reflect.Interface:
		// we only support empty interfaces.
		if rv.NumMethod() > 0 {
			return e("Unsupported type '%s'.", rv.Kind())
		}
		return unifyAnything(data, rv)
	case reflect.Float32:
		fallthrough
	case reflect.Float64:
		return unifyFloat64(data, rv)
	}
	return e("Unsupported type '%s'.", rv.Kind())
}

func unifyStruct(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return mismatch(rv, "map", mapping)
	}

	rt := rv.Type()
	for i := 0; i < rt.NumField(); i++ {
		// A little tricky. We want to use the special `toml` name in the
		// struct tag if it exists. In particular, we need to make sure that
		// this struct field is in the current map before trying to unify it.
		sft := rt.Field(i)
		kname := sft.Tag.Get("toml")
		if len(kname) == 0 {
			kname = sft.Name
		}
		if datum, ok := insensitiveGet(tmap, kname); ok {
			sf := indirect(rv.Field(i))

			// Don't try to mess with unexported types and other such things.
			if sf.CanSet() {
				if err := unify(datum, sf); err != nil {
					return e("Type mismatch for '%s.%s': %s",
						rt.String(), sft.Name, err)
				}
			} else if len(sft.Tag.Get("toml")) > 0 {
				// Bad user! No soup for you!
				return e("Field '%s.%s' is unexported, and therefore cannot "+
					"be loaded with reflection.", rt.String(), sft.Name)
			}
		}
	}
	return nil
}

func unifyMap(mapping interface{}, rv reflect.Value) error {
	tmap, ok := mapping.(map[string]interface{})
	if !ok {
		return badtype("map", mapping)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeMap(rv.Type()))
	}
	for k, v := range tmap {
		rvkey := indirect(reflect.New(rv.Type().Key()))
		rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
		if err := unify(v, rvval); err != nil {
			return err
		}

		rvkey.SetString(k)
		rv.SetMapIndex(rvkey, rvval)
	}
	return nil
}

func unifySlice(data interface{}, rv reflect.Value) error {
	slice, ok := data.([]interface{})
	if !ok {
		return badtype("slice", data)
	}
	if rv.IsNil() {
		rv.Set(reflect.MakeSlice(rv.Type(), len(slice), len(slice)))
	}
	for i, v := range slice {
		sliceval := indirect(rv.Index(i))
		if err := unify(v, sliceval); err != nil {
			return err
		}
	}
	return nil
}

func unifyDatetime(data interface{}, rv reflect.Value) error {
	if _, ok := data.(time.Time); ok {
		rv.Set(reflect.ValueOf(data))
		return nil
	}
	return badtype("time.Time", data)
}

func unifyString(data interface{}, rv reflect.Value) error {
	if s, ok := data.(string); ok {
		rv.SetString(s)
		return nil
	}
	return badtype("string", data)
}

func unifyFloat64(data interface{}, rv reflect.Value) error {
	if num, ok := data.(float64); ok {
		switch rv.Kind() {
		case reflect.Float32:
			fallthrough
		case reflect.Float64:
			rv.SetFloat(num)
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("float", data)
}

func unifyInt(data interface{}, rv reflect.Value) error {
	if num, ok := data.(int64); ok {
		switch rv.Kind() {
		case reflect.Int:
			fallthrough
		case reflect.Int8:
			fallthrough
		case reflect.Int16:
			fallthrough
		case reflect.Int32:
			fallthrough
		case reflect.Int64:
			rv.SetInt(int64(num))
		case reflect.Uint:
			fallthrough
		case reflect.Uint8:
			fallthrough
		case reflect.Uint16:
			fallthrough
		case reflect.Uint32:
			fallthrough
		case reflect.Uint64:
			rv.SetUint(uint64(num))
		default:
			panic("bug")
		}
		return nil
	}
	return badtype("integer", data)
}

func unifyBool(data interface{}, rv reflect.Value) error {
	if b, ok := data.(bool); ok {
		rv.SetBool(b)
		return nil
	}
	return badtype("integer", data)
}

func unifyAnything(data interface{}, rv reflect.Value) error {
	// too awesome to fail
	rv.Set(reflect.ValueOf(data))
	return nil
}

// rvalue returns a reflect.Value of `v`. All pointers are resolved.
func rvalue(v interface{}) reflect.Value {
	return indirect(reflect.ValueOf(v))
}

// indirect returns the value pointed to by a pointer.
// Pointers are followed until the value is not a pointer.
// New values are allocated for each nil pointer.
func indirect(v reflect.Value) reflect.Value {
	if v.Kind() != reflect.Ptr {
		return v
	}
	if v.IsNil() {
		v.Set(reflect.New(v.Type().Elem()))
	}
	return indirect(reflect.Indirect(v))
}

func tstring(rv reflect.Value) string {
	return rv.Type().String()
}

func badtype(expected string, data interface{}) error {
	return e("Expected %s but found '%T'.", expected, data)
}

func mismatch(user reflect.Value, expected string, data interface{}) error {
	return e("Type mismatch for %s. Expected %s but found '%T'.",
		tstring(user), expected, data)
}

func insensitiveGet(
	tmap map[string]interface{}, kname string) (interface{}, bool) {

	if datum, ok := tmap[kname]; ok {
		return datum, true
	}
	for k, v := range tmap {
		if strings.EqualFold(kname, k) {
			return v, true
		}
	}
	return nil, false
}

// MetaData allows access to meta information about TOML data that may not
// be inferrable via reflection. In particular, whether a key has been defined
// and the TOML type of a key.
//
// (XXX: If TOML gets NULL values, that information will be added here too.)
type MetaData struct {
	mapping map[string]interface{}
	types   map[string]tomlType
	keys    []Key
}

// IsDefined returns true if the key given exists in the TOML data. The key
// should be specified hierarchially. e.g.,
//
//	// access the TOML key 'a.b.c'
//	IsDefined("a", "b", "c")
//
// IsDefined will return false if an empty key given. Keys are case sensitive.
func (md MetaData) IsDefined(key ...string) bool {
	var hashOrVal interface{}
	var hash map[string]interface{}
	var ok bool

	if len(key) == 0 {
		return false
	}

	hashOrVal = md.mapping
	for _, k := range key {
		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
			return false
		}
		if hashOrVal, ok = hash[k]; !ok {
			return false
		}
	}
	return true
}

// Type returns a string representation of the type of the key specified.
//
// Type will return the empty string if given an empty key or a key that
// does not exist. Keys are case sensitive.
func (md MetaData) Type(key ...string) string {
	fullkey := strings.Join(key, ".")
	if typ, ok := md.types[fullkey]; ok {
		return typ.typeString()
	}
	return ""
}

// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
// to get values of this type.
type Key []string

func (k Key) String() string {
	return strings.Join(k, ".")
}

func (k Key) add(piece string) Key {
	newKey := make(Key, len(k))
	copy(newKey, k)
	return append(newKey, piece)
}

// Keys returns a slice of every key in the TOML data, including key groups.
// Each key is itself a slice, where the first element is the top of the
// hierarchy and the last is the most specific.
//
// The list will have the same order as the keys appeared in the TOML data.
//
// All keys returned are non-empty.
func (md MetaData) Keys() []Key {
	return md.keys
}

func allKeys(m map[string]interface{}, context Key) []Key {
	keys := make([]Key, 0, len(m))
	for k, v := range m {
		keys = append(keys, context.add(k))
		if t, ok := v.(map[string]interface{}); ok {
			keys = append(keys, allKeys(t, context.add(k))...)
		}
	}
	return keys
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 IBM Corp. All rights reserved.
// Use of this source code is governed by the Apache License,
// Version 2.0, a copy of which can be found in the LICENSE file.

// Delete our room

package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"time"
)

// Deletes our room with the GameOn! server, with retries on connection failure.
func deleteWithRetries() (e error) {
	locus := "DELETE_W_RETRIES"
	checkpoint(locus, fmt.Sprintf("retries=%d secondsBetween=%d", config.retries, config.secondsBetween))
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	for i := 0; i < config.retries; i++ {
		checkpoint(locus, fmt.Sprintf("Begin attempt %d of %d",
			i+1, config.retries))
		var stopTrying bool
		stopTrying, e = deleteRoom(client)
		if e == nil {
			if stopTrying {
				checkpoint(locus, "Room deletion failed")
			} else {
				checkpoint(locus, "Room deletion was successful.")
			}
			return
		}
		checkpoint(locus, fmt.Sprintf("sleeping %d seconds.", config.secondsBetween))
		if i+1 < config.retries {
			time.Sleep(time.Duration(config.secondsBetween) * time.Second)
		}
	}
	checkpoint(locus, "Room deletion failed.")
	e = RegError{fmt.Sprintf("Timed out. Last error: %s", e.Error())}
	return
}

func deleteRoom(client *http.Client) (stopTrying bool, err error) {
	locus := "DELETE.ROOM"
	checkpoint(locus, "Begin")
	ts := makeTimestamp()
	bodyHash := hash("")
	tokens := []string{config.id, ts}
	sig := buildHmac(tokens, config.secret)
	var u string
	if config.localServer {
		u = fmt.Sprintf("http://%s/map/v1/sites/%s", config.gameonAddr, config.roomToDelete)
	} else {
		u = fmt.Sprintf("https://%s/map/v1/sites/%s", config.gameonAddr, config.roomToDelete)
	}

	checkpoint(locus, fmt.Sprintf("URL %s", u))

	req, err := http.NewRequest("DELETE", u, nil)
	if err != nil {
		checkpoint(locus, fmt.Sprintf("NewRequest.Error err=%s", err.Error()))
		return
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json,text/plain")
	req.Header.Set("gameon-id", config.id)
	req.Header.Set("gameon-date", ts)
	req.Header.Set("gameon-sig-body", bodyHash)
	req.Header.Set("gameon-signature", sig)
	if config.debug {
		for _, k := range []string{"gameon-id", "gameon-date", "gameon-sig-body", "gameon-signature"} {
			fmt.Printf("%s=%s\n", k, req.Header.Get(k))
		}
	}
	resp, err := client.Do(req)
	if err != nil {
		checkpoint(locus, fmt.Sprintf("DELETE.Error err=%s", err.Error()))
		return
	}
	body, err := extractBody(resp)
	if err != nil {
		checkpoint(locus, fmt.Sprintf("Body.Error err=%s", err.Error()))
		return
	}
	checkpoint(locus, fmt.Sprintf("Status=%s", resp.Status))
	switch resp.StatusCode {
	case http.StatusNoContent:
		checkpoint(locus, "Deleted")
		return
	case http.StatusOK:
	case http.StatusForbidden:
	case http.StatusNotFound:
		checkpoint(locus, "Sigh. There is no use trying any more.")
		printResponseBody(locus, resp, body)
		stopTrying = true
		return
	default:
		err = RegError{fmt.Sprintf("Unhandled Status: %s", resp.Status)}
		checkpoint(locus, fmt.Sprintf("Unhandled Status=%s", resp.Status))
		printResponseBody(locus, resp, body)
		return
	}
	return
}
<commit_msg>fix bad switch statement in delete<commit_after>// Copyright (c) 2016 IBM Corp. All rights reserved.
// Use of this source code is governed by the Apache License,
// Version 2.0, a copy of which can be found in the LICENSE file.

// Delete our room

package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"time"
)

// Deletes our room with the GameOn! server, with retries on connection failure.
func deleteWithRetries() (e error) {
	locus := "DELETE_W_RETRIES"
	checkpoint(locus, fmt.Sprintf("retries=%d secondsBetween=%d", config.retries, config.secondsBetween))
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	for i := 0; i < config.retries; i++ {
		checkpoint(locus, fmt.Sprintf("Begin attempt %d of %d",
			i+1, config.retries))
		var stopTrying bool
		stopTrying, e = deleteRoom(client)
		if e == nil {
			if stopTrying {
				checkpoint(locus, "Room deletion failed")
			} else {
				checkpoint(locus, "Room deletion was successful.")
			}
			return
		}
		checkpoint(locus, fmt.Sprintf("sleeping %d seconds.", config.secondsBetween))
		if i+1 < config.retries {
			time.Sleep(time.Duration(config.secondsBetween) * time.Second)
		}
	}
	checkpoint(locus, "Room deletion failed.")
	e = RegError{fmt.Sprintf("Timed out. Last error: %s", e.Error())}
	return
}

func deleteRoom(client *http.Client) (stopTrying bool, err error) {
	locus := "DELETE.ROOM"
	checkpoint(locus, "Begin")
	ts := makeTimestamp()
	bodyHash := hash("")
	tokens := []string{config.id, ts}
	sig := buildHmac(tokens, config.secret)
	var u string
	if config.localServer {
		u = fmt.Sprintf("http://%s/map/v1/sites/%s", config.gameonAddr, config.roomToDelete)
	} else {
		u = fmt.Sprintf("https://%s/map/v1/sites/%s", config.gameonAddr, config.roomToDelete)
	}

	checkpoint(locus, fmt.Sprintf("URL %s", u))

	req, err := http.NewRequest("DELETE", u, nil)
	if err != nil {
		checkpoint(locus, fmt.Sprintf("NewRequest.Error err=%s", err.Error()))
		return
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json,text/plain")
	req.Header.Set("gameon-id", config.id)
	req.Header.Set("gameon-date", ts)
	req.Header.Set("gameon-sig-body", bodyHash)
	req.Header.Set("gameon-signature", sig)
	if config.debug {
		for _, k := range []string{"gameon-id", "gameon-date", "gameon-sig-body", "gameon-signature"} {
			fmt.Printf("%s=%s\n", k, req.Header.Get(k))
		}
	}
	resp, err := client.Do(req)
	if err != nil {
		checkpoint(locus, fmt.Sprintf("DELETE.Error err=%s", err.Error()))
		return
	}
	body, err := extractBody(resp)
	if err != nil {
		checkpoint(locus, fmt.Sprintf("Body.Error err=%s", err.Error()))
		return
	}
	checkpoint(locus, fmt.Sprintf("Status=%s", resp.Status))
	switch resp.StatusCode {
	case http.StatusNoContent:
		checkpoint(locus, "Deleted")
		return
	case http.StatusOK, http.StatusForbidden, http.StatusNotFound:
		checkpoint(locus, "Sigh. There is no use trying any more.")
		printResponseBody(locus, resp, body)
		stopTrying = true
		return
	default:
		err = RegError{fmt.Sprintf("Unhandled Status: %s", resp.Status)}
		checkpoint(locus, fmt.Sprintf("Unhandled Status=%s", resp.Status))
		printResponseBody(locus, resp, body)
		return
	}
	return
}
<|endoftext|>


<commit_before>package main

import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/lambda"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awserr"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/tj/go-debug"
import "os"
import "io"
import "io/ioutil"
import "fmt"
import "bytes"

//import "github.com/aws/aws-sdk-go/aws"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/spf13/cobra"

type wtflog struct{}

func (w wtflog) Log(s ...interface{}) {
	fmt.Println(s...)
}

func init() {
	dCmd := &cobra.Command{
		Use:   "deploy",
		Short: "deploys your lambda function according to your config file or options provided",
		RunE:  deploy,
	}

	flg := dCmd.Flags()

	flg.BoolP("verbose", "v", false, "verbosity")
	cmds = append(cmds, dCmd)
}

func deploy(c *cobra.Command, args []string) error {
	debug := debug.Debug("cmd.deploy")
	// must package first, so:
	var err error
	err = pkg(c, args)

	if err != nil {
		return err
	}

	// should have written data to this file
	binName := getArchiveName(c)

	var iamRole *string
	iamRole, err = cfg.getRoleArn()
	if err != nil {
		return err
	}

	code := &lambda.FunctionCode{}
	// try getting s3 information
	bucket, key := cfg.getS3Info(binName)

	if bucket == nil || key == nil {
		// if we couldn't get bucket or
		// key info, let's upload the data
		// ...soon
		b, err := ioutil.ReadFile(binName)
		if err != nil {
			return err
		}

		code.ZipFile = b
	} else {
		code.S3Bucket = bucket
		code.S3Key = key
		err = uploadS3(binName, bucket, key)
		if err != nil {
			return err
		}
	}

	debug("preparing for lambda API")
	for _, region := range cfg.Regions {
		debug("using lambda API for region %s", *region)
		l := lambda.New(
			aws.NewConfig().
				WithRegion(*region),
		)
		//just try creating the function now
		_, err := l.CreateFunction(
			&lambda.CreateFunctionInput{
				Code:         code,
				FunctionName: cfg.Name,
				Description:  cfg.Description,
				Handler:      cfg.EntryPoint,
				MemorySize:   cfg.MemorySize,
				Runtime:      cfg.Runtime,
				Timeout:      cfg.Timeout,
				Role:         iamRole,
				Publish:      aws.Bool(true),
			},
		)

		if err != nil {
			if awe, ok := err.(awserr.Error); ok {
				if awe.Code() == "ResourceConflictException" {
					debug("function already exists, calling update")
					return updateLambda(l, code, iamRole)
				} else {
					return err
				}
			} else {
				return err
			}
		} else {
			// if the create function succeeded,
			// we need to figure out the mapping
			// info, etc
			debug("function creation succeeded! ...we think")
		}
	}

	return nil
}

// updates function code, settings in AWS lambda
func updateLambda(
	l *lambda.Lambda,
	code *lambda.FunctionCode,
	iamRole *string,
) error {
	_, err := l.UpdateFunctionConfiguration(
		&lambda.UpdateFunctionConfigurationInput{
			FunctionName: cfg.Name,
			Description:  cfg.Description,
			Handler:      cfg.EntryPoint,
			MemorySize:   cfg.MemorySize,
			Role:         iamRole,
			Timeout:      cfg.Timeout,
		},
	)
	if err != nil {
		return err
	}

	_, err = l.UpdateFunctionCode(
		&lambda.UpdateFunctionCodeInput{
			FunctionName:    cfg.Name,
			S3Bucket:        code.S3Bucket,
			S3Key:           code.S3Key,
			S3ObjectVersion: code.S3ObjectVersion,
			ZipFile:         code.ZipFile,
			Publish:         aws.Bool(true),
		},
	)

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

// should probably handle this in memory,
// but this fn will upload your file to s3
func uploadS3(fName string, bucket, key *string) error {
	debug := debug.Debug("uploadS3")
	awscfg := aws.NewConfig().WithRegion(*cfg.Location.S3Region)
	s := s3.New(awscfg)

	f, err := os.Open(fName)
	if err != nil {
		return err
	}
	debug("opened file, beginning read")

	st, err := f.Stat()
	if err != nil {
		return err
	}

	if st.Size() >= (1024 * 1024 * 5) {
		// multipart if bigger than 5MiB
		return uploadS3MPU(s, f, bucket, key)
	} else {
		_, err = s.PutObject(&s3.PutObjectInput{
			Bucket: bucket,
			Key:    key,
			Body:   f,
		})
		if err != nil {
			return err
		}
	}

	return nil
}

// multipart upload
func uploadS3MPU(
	s *s3.S3,
	f *os.File,
	bucket, key *string,
) error {
	debug := debug.Debug("uploadS3MPU")
	mpu := &s3.CreateMultipartUploadInput{
		Bucket: bucket,
		Key:    key,
	}

	canceler := func(uploadId *string) {
		debug("canceling upload")
		_, err := s.AbortMultipartUpload(
			&s3.AbortMultipartUploadInput{
				Bucket:   bucket,
				Key:      key,
				UploadId: uploadId,
			},
		)
		if err != nil {
			fmt.Printf(
				"WARNING: upload abort failed for upload ID %s",
				*uploadId,
			)
		}
	}

	cr, err := s.CreateMultipartUpload(mpu)
	if err != nil {
		return err
	}

	debug("created multipart upload")

	buf := new(bytes.Buffer)
	bslice := make([]byte, 8096)
	var pNum int64 = 1

	parts := make([]*s3.CompletedPart, 0)

	for {
		n, err := f.Read(bslice)

		isEOF := err != nil && err == io.EOF

		if err != nil && !isEOF {
			f.Close()
			canceler(cr.UploadId)
			return err
		}

		if isEOF {
			debug("reached end of file")
			// trim final content
			bslice = bslice[:n]
		}

		buf.Write(bslice)

		// drain buf on 1MiB of data
		if buf.Len() >= (1024*1024*5) || isEOF {
			debug("have file data, uploading chunk")
			var err error
			if buf.Len() > 0 {
				var p *s3.UploadPartOutput
				p, err = s.UploadPart(
					&s3.UploadPartInput{
						Bucket:     bucket,
						Key:        key,
						PartNumber: aws.Int64(pNum),
						UploadId:   cr.UploadId,
						Body:       bytes.NewReader(buf.Bytes()),
					},
				)

				if err != nil {
					// if uploading a part failed,
					// cancel the whole upload...
					f.Close()
					canceler(cr.UploadId)
					return err
				}

				parts = append(parts,
					&s3.CompletedPart{
						ETag:       p.ETag,
						PartNumber: aws.Int64(pNum),
					},
				)
			}

			pNum += 1
			buf.Reset()

			if isEOF {
				f.Close()
				debug("completing upload")
				iput := &s3.CompleteMultipartUploadInput{
					Bucket:   bucket,
					Key:      key,
					UploadId: cr.UploadId,
					MultipartUpload: &s3.CompletedMultipartUpload{
						Parts: parts,
					},
				}
				_, err := s.CompleteMultipartUpload(
					iput,
				)

				if err != nil {
					canceler(cr.UploadId)
					return err
				}

				break
			}
		}
	}
	return nil
}
<commit_msg>print information messages during deploy<commit_after>package main

import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/lambda"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awserr"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/tj/go-debug"
import "os"
import "io"
import "io/ioutil"
import "fmt"
import "bytes"

//import "github.com/aws/aws-sdk-go/aws"
import "github.com/hopkinsth/lambda-phage/Godeps/_workspace/src/github.com/spf13/cobra"

type wtflog struct{}

func (w wtflog) Log(s ...interface{}) {
	fmt.Println(s...)
}

func init() {
	dCmd := &cobra.Command{
		Use:   "deploy",
		Short: "deploys your lambda function according to your config file or options provided",
		RunE:  deploy,
	}

	cmds = append(cmds, dCmd)
}

func deploy(c *cobra.Command, args []string) error {
	debug := debug.Debug("cmd.deploy")
	// must package first, so:
	var err error
	err = pkg(c, args)

	if err != nil {
		return err
	}

	// should have written data to this file
	binName := getArchiveName(c)

	var iamRole *string
	iamRole, err = cfg.getRoleArn()
	if err != nil {
		return err
	}

	code := &lambda.FunctionCode{}
	// try getting s3 information
	bucket, key := cfg.getS3Info(binName)

	if bucket == nil || key == nil {
		fmt.Println("Uploading function to Lambda")
		// if we couldn't get bucket or
		// key info, let's upload the data
		// ...soon
		b, err := ioutil.ReadFile(binName)
		if err != nil {
			return err
		}

		code.ZipFile = b
	} else {
		fmt.Println("Uploading function to s3")
		code.S3Bucket = bucket
		code.S3Key = key
		err = uploadS3(binName, bucket, key)
		if err != nil {
			return err
		}
	}

	debug("preparing for lambda API")
	for _, region := range cfg.Regions {
		fmt.Printf("Deploying lambda function for %s\n", *region)

		l := lambda.New(
			aws.NewConfig().
				WithRegion(*region),
		)
		//just try creating the function now
		_, err := l.CreateFunction(
			&lambda.CreateFunctionInput{
				Code:         code,
				FunctionName: cfg.Name,
				Description:  cfg.Description,
				Handler:      cfg.EntryPoint,
				MemorySize:   cfg.MemorySize,
				Runtime:      cfg.Runtime,
				Timeout:      cfg.Timeout,
				Role:         iamRole,
				Publish:      aws.Bool(true),
			},
		)

		if err != nil {
			if awe, ok := err.(awserr.Error); ok {
				if awe.Code() == "ResourceConflictException" {
					debug("function already exists, calling update")
					err = updateLambda(l, code, iamRole)
				} else {
					return err
				}
			} else {
				return err
			}
		} else {
			// if the create function succeeded,
			// we need to figure out the mapping
			// info, etc
			debug("function creation succeeded! ...we think")
		}

		if err != nil {
			return err
		}

		fmt.Printf("Function %s deployed to region %s!\n", *cfg.Name, *region)
	}

	return nil
}

// updates function code, settings in AWS lambda
func updateLambda(
	l *lambda.Lambda,
	code *lambda.FunctionCode,
	iamRole *string,
) error {
	_, err := l.UpdateFunctionConfiguration(
		&lambda.UpdateFunctionConfigurationInput{
			FunctionName: cfg.Name,
			Description:  cfg.Description,
			Handler:      cfg.EntryPoint,
			MemorySize:   cfg.MemorySize,
			Role:         iamRole,
			Timeout:      cfg.Timeout,
		},
	)
	if err != nil {
		return err
	}

	_, err = l.UpdateFunctionCode(
		&lambda.UpdateFunctionCodeInput{
			FunctionName:    cfg.Name,
			S3Bucket:        code.S3Bucket,
			S3Key:           code.S3Key,
			S3ObjectVersion: code.S3ObjectVersion,
			ZipFile:         code.ZipFile,
			Publish:         aws.Bool(true),
		},
	)

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

// should probably handle this in memory,
// but this fn will upload your file to s3
func uploadS3(fName string, bucket, key *string) error {
	debug := debug.Debug("uploadS3")
	awscfg := aws.NewConfig().WithRegion(*cfg.Location.S3Region)
	s := s3.New(awscfg)

	f, err := os.Open(fName)
	if err != nil {
		return err
	}
	debug("opened file, beginning read")

	st, err := f.Stat()
	if err != nil {
		return err
	}

	if st.Size() >= (1024 * 1024 * 5) {
		// multipart if bigger than 5MiB
		return uploadS3MPU(s, f, bucket, key)
	} else {
		_, err = s.PutObject(&s3.PutObjectInput{
			Bucket: bucket,
			Key:    key,
			Body:   f,
		})
		if err != nil {
			return err
		}
	}

	return nil
}

// multipart upload
func uploadS3MPU(
	s *s3.S3,
	f *os.File,
	bucket, key *string,
) error {
	debug := debug.Debug("uploadS3MPU")
	mpu := &s3.CreateMultipartUploadInput{
		Bucket: bucket,
		Key:    key,
	}

	canceler := func(uploadId *string) {
		debug("canceling upload")
		_, err := s.AbortMultipartUpload(
			&s3.AbortMultipartUploadInput{
				Bucket:   bucket,
				Key:      key,
				UploadId: uploadId,
			},
		)
		if err != nil {
			fmt.Printf(
				"WARNING: upload abort failed for upload ID %s",
				*uploadId,
			)
		}
	}

	cr, err := s.CreateMultipartUpload(mpu)
	if err != nil {
		return err
	}

	debug("created multipart upload")

	buf := new(bytes.Buffer)
	bslice := make([]byte, 8096)
	var pNum int64 = 1

	parts := make([]*s3.CompletedPart, 0)

	for {
		n, err := f.Read(bslice)

		isEOF := err != nil && err == io.EOF

		if err != nil && !isEOF {
			f.Close()
			canceler(cr.UploadId)
			return err
		}

		if isEOF {
			debug("reached end of file")
			// trim final content
			bslice = bslice[:n]
		}

		buf.Write(bslice)

		// drain buf on 1MiB of data
		if buf.Len() >= (1024*1024*5) || isEOF {
			debug("have file data, uploading chunk")
			var err error
			if buf.Len() > 0 {
				var p *s3.UploadPartOutput
				p, err = s.UploadPart(
					&s3.UploadPartInput{
						Bucket:     bucket,
						Key:        key,
						PartNumber: aws.Int64(pNum),
						UploadId:   cr.UploadId,
						Body:       bytes.NewReader(buf.Bytes()),
					},
				)

				if err != nil {
					// if uploading a part failed,
					// cancel the whole upload...
					f.Close()
					canceler(cr.UploadId)
					return err
				}

				parts = append(parts,
					&s3.CompletedPart{
						ETag:       p.ETag,
						PartNumber: aws.Int64(pNum),
					},
				)
			}

			pNum += 1
			buf.Reset()

			if isEOF {
				f.Close()
				debug("completing upload")
				iput := &s3.CompleteMultipartUploadInput{
					Bucket:   bucket,
					Key:      key,
					UploadId: cr.UploadId,
					MultipartUpload: &s3.CompletedMultipartUpload{
						Parts: parts,
					},
				}
				_, err := s.CompleteMultipartUpload(
					iput,
				)

				if err != nil {
					canceler(cr.UploadId)
					return err
				}

				break
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/template/interpolate"
)

// BlockDevice
type BlockDevice struct {
	DeleteOnTermination bool           `mapstructure:"delete_on_termination"`
	DeviceName          string         `mapstructure:"device_name"`
	RawEncrypted        config.Trilean `mapstructure:"encrypted"`
	IOPS                int64          `mapstructure:"iops"`
	NoDevice            bool           `mapstructure:"no_device"`
	SnapshotId          string         `mapstructure:"snapshot_id"`
	VirtualName         string         `mapstructure:"virtual_name"`
	VolumeType          string         `mapstructure:"volume_type"`
	VolumeSize          int64          `mapstructure:"volume_size"`
	KmsKeyId            string         `mapstructure:"kms_key_id"`
	// ebssurrogate only
	OmitFromArtifact bool `mapstructure:"omit_from_artifact"`

	Encrypted *bool
}

type BlockDevices struct {
	AMIBlockDevices    `mapstructure:",squash"`
	LaunchBlockDevices `mapstructure:",squash"`
}

type AMIBlockDevices struct {
	AMIMappings []BlockDevice `mapstructure:"ami_block_device_mappings"`
}

type LaunchBlockDevices struct {
	LaunchMappings []BlockDevice `mapstructure:"launch_block_device_mappings"`
}

func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
	var blockDevices []*ec2.BlockDeviceMapping

	for _, blockDevice := range b {
		mapping := &ec2.BlockDeviceMapping{
			DeviceName: aws.String(blockDevice.DeviceName),
		}

		if blockDevice.NoDevice {
			mapping.NoDevice = aws.String("")
		} else if blockDevice.VirtualName != "" {
			if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
				mapping.VirtualName = aws.String(blockDevice.VirtualName)
			}
		} else {
			ebsBlockDevice := &ec2.EbsBlockDevice{
				DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination),
			}

			if blockDevice.VolumeType != "" {
				ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType)
			}

			if blockDevice.VolumeSize > 0 {
				ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize)
			}

			// IOPS is only valid for io1 type
			if blockDevice.VolumeType == "io1" {
				ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS)
			}

			// You cannot specify Encrypted if you specify a Snapshot ID
			if blockDevice.SnapshotId != "" {
				ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
			}
			ebsBlockDevice.Encrypted = blockDevice.Encrypted

			if blockDevice.KmsKeyId != "" {
				ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
			}

			mapping.Ebs = ebsBlockDevice
		}

		blockDevices = append(blockDevices, mapping)
	}
	return blockDevices
}

func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
	if b.DeviceName == "" {
		return fmt.Errorf("The `device_name` must be specified " +
			"for every device in the block device mapping.")
	}
	b.Encrypted = b.RawEncrypted.ToBoolPointer()
	// Warn that encrypted must be true or nil when setting kms_key_id
	if b.KmsKeyId != "" && b.Encrypted != nil && *b.Encrypted == false {
		return fmt.Errorf("The device %v, must also have `encrypted: "+
			"true` when setting a kms_key_id.", b.DeviceName)
	}

	return nil
}

func (b *BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
	for _, d := range b.AMIMappings {
		if err := d.Prepare(ctx); err != nil {
			errs = append(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
		}
	}
	for _, d := range b.LaunchMappings {
		if err := d.Prepare(ctx); err != nil {
			errs = append(errs, fmt.Errorf("LaunchMapping: %s", err.Error()))
		}
	}
	return errs
}

func (b *AMIBlockDevices) BuildAMIDevices() []*ec2.BlockDeviceMapping {
	return buildBlockDevices(b.AMIMappings)
}

func (b *LaunchBlockDevices) BuildLaunchDevices() []*ec2.BlockDeviceMapping {
	return buildBlockDevices(b.LaunchMappings)
}

func (b *LaunchBlockDevices) GetOmissions() map[string]bool {
	omitMap := make(map[string]bool)

	for _, blockDevice := range b.LaunchMappings {
		omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact
	}

	return omitMap
}
<commit_msg>converte block device encryption to trilean<commit_after>package common

import (
	"fmt"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/template/interpolate"
)

// BlockDevice
type BlockDevice struct {
	DeleteOnTermination bool           `mapstructure:"delete_on_termination"`
	DeviceName          string         `mapstructure:"device_name"`
	Encrypted           config.Trilean `mapstructure:"encrypted"`
	IOPS                int64          `mapstructure:"iops"`
	NoDevice            bool           `mapstructure:"no_device"`
	SnapshotId          string         `mapstructure:"snapshot_id"`
	VirtualName         string         `mapstructure:"virtual_name"`
	VolumeType          string         `mapstructure:"volume_type"`
	VolumeSize          int64          `mapstructure:"volume_size"`
	KmsKeyId            string         `mapstructure:"kms_key_id"`
	// ebssurrogate only
	OmitFromArtifact bool `mapstructure:"omit_from_artifact"`
}

type BlockDevices struct {
	AMIBlockDevices    `mapstructure:",squash"`
	LaunchBlockDevices `mapstructure:",squash"`
}

type AMIBlockDevices struct {
	AMIMappings []BlockDevice `mapstructure:"ami_block_device_mappings"`
}

type LaunchBlockDevices struct {
	LaunchMappings []BlockDevice `mapstructure:"launch_block_device_mappings"`
}

func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
	var blockDevices []*ec2.BlockDeviceMapping

	for _, blockDevice := range b {
		mapping := &ec2.BlockDeviceMapping{
			DeviceName: aws.String(blockDevice.DeviceName),
		}

		if blockDevice.NoDevice {
			mapping.NoDevice = aws.String("")
		} else if blockDevice.VirtualName != "" {
			if strings.HasPrefix(blockDevice.VirtualName, "ephemeral") {
				mapping.VirtualName = aws.String(blockDevice.VirtualName)
			}
		} else {
			ebsBlockDevice := &ec2.EbsBlockDevice{
				DeleteOnTermination: aws.Bool(blockDevice.DeleteOnTermination),
			}

			if blockDevice.VolumeType != "" {
				ebsBlockDevice.VolumeType = aws.String(blockDevice.VolumeType)
			}

			if blockDevice.VolumeSize > 0 {
				ebsBlockDevice.VolumeSize = aws.Int64(blockDevice.VolumeSize)
			}

			// IOPS is only valid for io1 type
			if blockDevice.VolumeType == "io1" {
				ebsBlockDevice.Iops = aws.Int64(blockDevice.IOPS)
			}

			// You cannot specify Encrypted if you specify a Snapshot ID
			if blockDevice.SnapshotId != "" {
				ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
			}

			ebsBlockDevice.Encrypted = blockDevice.Encrypted.ToBoolPointer()

			if blockDevice.KmsKeyId != "" {
				ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
			}

			mapping.Ebs = ebsBlockDevice
		}

		blockDevices = append(blockDevices, mapping)
	}
	return blockDevices
}

func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
	if b.DeviceName == "" {
		return fmt.Errorf("The `device_name` must be specified " +
			"for every device in the block device mapping.")
	}

	// Warn that encrypted must be true or nil when setting kms_key_id
	if b.KmsKeyId != "" && b.Encrypted.False() {
		return fmt.Errorf("The device %v, must also have `encrypted: "+
			"true` when setting a kms_key_id.", b.DeviceName)
	}

	return nil
}

func (b *BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
	for _, d := range b.AMIMappings {
		if err := d.Prepare(ctx); err != nil {
			errs = append(errs, fmt.Errorf("AMIMapping: %s", err.Error()))
		}
	}
	for _, d := range b.LaunchMappings {
		if err := d.Prepare(ctx); err != nil {
			errs = append(errs, fmt.Errorf("LaunchMapping: %s", err.Error()))
		}
	}
	return errs
}

func (b *AMIBlockDevices) BuildAMIDevices() []*ec2.BlockDeviceMapping {
	return buildBlockDevices(b.AMIMappings)
}

func (b *LaunchBlockDevices) BuildLaunchDevices() []*ec2.BlockDeviceMapping {
	return buildBlockDevices(b.LaunchMappings)
}

func (b *LaunchBlockDevices) GetOmissions() map[string]bool {
	omitMap := make(map[string]bool)

	for _, blockDevice := range b.LaunchMappings {
		omitMap[blockDevice.DeviceName] = blockDevice.OmitFromArtifact
	}

	return omitMap
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ioutil implements some I/O utility functions.
package ioutil

import (
	"bytes"
	"io"
	"os"
	"sort"
	"sync"
)

// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
	var buf bytes.Buffer
	// If the buffer overflows, we will get bytes.ErrTooLarge.
	// Return that as an error. Any other panic remains.
	defer func() {
		e := recover()
		if e == nil {
			return
		}
		if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
			err = panicErr
		} else {
			panic(e)
		}
	}()
	if int64(int(capacity)) == capacity {
		buf.Grow(int(capacity))
	}
	_, err = buf.ReadFrom(r)
	return buf.Bytes(), err
}

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
func ReadAll(r io.Reader) ([]byte, error) {
	return readAll(r, bytes.MinRead)
}

// ReadFile reads the file named by filename and returns the contents.
// A successful call returns err == nil, not err == EOF. Because ReadFile
// reads the whole file, it does not treat an EOF from Read as an error
// to be reported.
func ReadFile(filename string) ([]byte, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// It's a good but not certain bet that FileInfo will tell us exactly how much to
	// read, so let's try it but be prepared for the answer to be wrong.
	var n int64 = bytes.MinRead

	if fi, err := f.Stat(); err == nil {
		// As initial capacity for readAll, use Size + a little extra in case Size
		// is zero, and to avoid another allocation after Read has filled the
		// buffer. The readAll call will read into its allocated internal buffer
		// cheaply. If the size was wrong, we'll either waste some space off the end
		// or reallocate as needed, but in the overwhelmingly common case we'll get
		// it just right.
		if size := fi.Size() + bytes.MinRead; size > n {
			n = size
		}
	}
	return readAll(f, n)
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm
// (before umask); otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm os.FileMode) error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	_, err = f.Write(data)
	if err1 := f.Close(); err == nil {
		err = err1
	}
	return err
}

// ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename.
func ReadDir(dirname string) ([]os.FileInfo, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
	return list, nil
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
	return nopCloser{r}
}

type devNull int

// devNull implements ReaderFrom as an optimization so io.Copy to
// ioutil.Discard can avoid doing unnecessary work.
var _ io.ReaderFrom = devNull(0)

func (devNull) Write(p []byte) (int, error) {
	return len(p), nil
}

func (devNull) WriteString(s string) (int, error) {
	return len(s), nil
}

var blackHolePool = sync.Pool{
	New: func() interface{} {
		b := make([]byte, 8192)
		return &b
	},
}

func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
	bufp := blackHolePool.Get().(*[]byte)
	readSize := 0
	for {
		readSize, err = r.Read(*bufp)
		n += int64(readSize)
		if err != nil {
			blackHolePool.Put(bufp)
			if err == io.EOF {
				return n, nil
			}
			return
		}
	}
}

// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
<commit_msg>io/ioutil: update WriteFile to clarify it does not change permissions if the file exists.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ioutil implements some I/O utility functions.
package ioutil

import (
	"bytes"
	"io"
	"os"
	"sort"
	"sync"
)

// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
	var buf bytes.Buffer
	// If the buffer overflows, we will get bytes.ErrTooLarge.
	// Return that as an error. Any other panic remains.
	defer func() {
		e := recover()
		if e == nil {
			return
		}
		if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
			err = panicErr
		} else {
			panic(e)
		}
	}()
	if int64(int(capacity)) == capacity {
		buf.Grow(int(capacity))
	}
	_, err = buf.ReadFrom(r)
	return buf.Bytes(), err
}

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
func ReadAll(r io.Reader) ([]byte, error) {
	return readAll(r, bytes.MinRead)
}

// ReadFile reads the file named by filename and returns the contents.
// A successful call returns err == nil, not err == EOF. Because ReadFile
// reads the whole file, it does not treat an EOF from Read as an error
// to be reported.
func ReadFile(filename string) ([]byte, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// It's a good but not certain bet that FileInfo will tell us exactly how much to
	// read, so let's try it but be prepared for the answer to be wrong.
	var n int64 = bytes.MinRead

	if fi, err := f.Stat(); err == nil {
		// As initial capacity for readAll, use Size + a little extra in case Size
		// is zero, and to avoid another allocation after Read has filled the
		// buffer. The readAll call will read into its allocated internal buffer
		// cheaply. If the size was wrong, we'll either waste some space off the end
		// or reallocate as needed, but in the overwhelmingly common case we'll get
		// it just right.
		if size := fi.Size() + bytes.MinRead; size > n {
			n = size
		}
	}
	return readAll(f, n)
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm
// (before umask); otherwise WriteFile truncates it before writing, without changing permissions.
func WriteFile(filename string, data []byte, perm os.FileMode) error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	_, err = f.Write(data)
	if err1 := f.Close(); err == nil {
		err = err1
	}
	return err
}

// ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename.
func ReadDir(dirname string) ([]os.FileInfo, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
	return list, nil
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
	return nopCloser{r}
}

type devNull int

// devNull implements ReaderFrom as an optimization so io.Copy to
// ioutil.Discard can avoid doing unnecessary work.
var _ io.ReaderFrom = devNull(0)

func (devNull) Write(p []byte) (int, error) {
	return len(p), nil
}

func (devNull) WriteString(s string) (int, error) {
	return len(s), nil
}

var blackHolePool = sync.Pool{
	New: func() interface{} {
		b := make([]byte, 8192)
		return &b
	},
}

func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
	bufp := blackHolePool.Get().(*[]byte)
	readSize := 0
	for {
		readSize, err = r.Read(*bufp)
		n += int64(readSize)
		if err != nil {
			blackHolePool.Put(bufp)
			if err == io.EOF {
				return n, nil
			}
			return
		}
	}
}

// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
<|endoftext|>