<commit_before>// Package allocation contains all CRUD operations for allocations
package allocation

import (
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/pion/logging"
	"github.com/pion/stun"
	"github.com/pion/turn/v2/internal/ipnet"
	"github.com/pion/turn/v2/internal/proto"
)

// Allocation is tied to a FiveTuple and relays traffic
// use CreateAllocation and GetAllocation to operate
type Allocation struct {
	RelayAddr           net.Addr
	Protocol            Protocol
	TurnSocket          net.PacketConn
	RelaySocket         net.PacketConn
	fiveTuple           *FiveTuple
	permissionsLock     sync.RWMutex
	permissions         map[string]*Permission
	channelBindingsLock sync.RWMutex
	channelBindings     []*ChannelBind
	lifetimeTimer       *time.Timer
	closed              chan interface{}
	log                 logging.LeveledLogger
}

func addr2IPFingerprint(addr net.Addr) string {
	switch a := addr.(type) {
	case *net.UDPAddr:
		return a.IP.String()
	case *net.TCPAddr: // Do we really need this case?
		return a.IP.String()
	}
	return "" // shoud never happen
}

// NewAllocation creates a new instance of NewAllocation.
func NewAllocation(turnSocket net.PacketConn, fiveTuple *FiveTuple, log logging.LeveledLogger) *Allocation {
	return &Allocation{
		TurnSocket:  turnSocket,
		fiveTuple:   fiveTuple,
		permissions: make(map[string]*Permission, 64),
		closed:      make(chan interface{}),
		log:         log,
	}
}

// GetPermission gets the Permission from the allocation
func (a *Allocation) GetPermission(addr net.Addr) *Permission {
	a.permissionsLock.RLock()
	defer a.permissionsLock.RUnlock()

	return a.permissions[addr2IPFingerprint(addr)]
}

// AddPermission adds a new permission to the allocation
func (a *Allocation) AddPermission(p *Permission) {
	fingerprint := addr2IPFingerprint(p.Addr)

	a.permissionsLock.RLock()
	existedPermission, ok := a.permissions[fingerprint]
	a.permissionsLock.RUnlock()

	if ok {
		existedPermission.refresh(permissionTimeout)
		return
	}

	p.allocation = a
	a.permissionsLock.Lock()
	a.permissions[fingerprint] = p
	a.permissionsLock.Unlock()

	p.start(permissionTimeout)
}

// RemovePermission removes the net.Addr's fingerprint from the allocation's permissions
func (a *Allocation) RemovePermission(addr net.Addr) {
	a.permissionsLock.Lock()
	defer a.permissionsLock.Unlock()
	delete(a.permissions, addr2IPFingerprint(addr))
}

// AddChannelBind adds a new ChannelBind to the allocation, it also updates the
// permissions needed for this ChannelBind
func (a *Allocation) AddChannelBind(c *ChannelBind, lifetime time.Duration) error {
	// Check that this channel id isn't bound to another transport address, and
	// that this transport address isn't bound to another channel number.
	channelByNumber := a.GetChannelByNumber(c.Number)

	if channelByNumber != a.GetChannelByAddr(c.Peer) {
		return fmt.Errorf("you cannot use the same channel number with different peer")
	}

	// Add or refresh this channel.
	if channelByNumber == nil {
		a.channelBindingsLock.Lock()
		defer a.channelBindingsLock.Unlock()

		c.allocation = a
		a.channelBindings = append(a.channelBindings, c)
		c.start(lifetime)

		// Channel binds also refresh permissions.
		a.AddPermission(NewPermission(c.Peer, a.log))
	} else {
		channelByNumber.refresh(lifetime)

		// Channel binds also refresh permissions.
		a.AddPermission(NewPermission(channelByNumber.Peer, a.log))
	}

	return nil
}

// RemoveChannelBind removes the ChannelBind from this allocation by id
func (a *Allocation) RemoveChannelBind(number proto.ChannelNumber) bool {
	a.channelBindingsLock.Lock()
	defer a.channelBindingsLock.Unlock()

	for i := len(a.channelBindings) - 1; i >= 0; i-- {
		if a.channelBindings[i].Number == number {
			a.channelBindings = append(a.channelBindings[:i], a.channelBindings[i+1:]...)
			return true
		}
	}

	return false
}

// GetChannelByNumber gets the ChannelBind from this allocation by id
func (a *Allocation) GetChannelByNumber(number proto.ChannelNumber) *ChannelBind {
	a.channelBindingsLock.RLock()
	defer a.channelBindingsLock.RUnlock()
	for _, cb := range a.channelBindings {
		if cb.Number == number {
			return cb
		}
	}
	return nil
}

// GetChannelByAddr gets the ChannelBind from this allocation by net.Addr
func (a *Allocation) GetChannelByAddr(addr net.Addr) *ChannelBind {
	a.channelBindingsLock.RLock()
	defer a.channelBindingsLock.RUnlock()
	for _, cb := range a.channelBindings {
		if ipnet.AddrEqual(cb.Peer, addr) {
			return cb
		}
	}
	return nil
}

// Refresh updates the allocations lifetime
func (a *Allocation) Refresh(lifetime time.Duration) {
	if !a.lifetimeTimer.Reset(lifetime) {
		a.log.Errorf("Failed to reset allocation timer for %v", a.fiveTuple)
	}
}

// Close closes the allocation
func (a *Allocation) Close() error {
	select {
	case <-a.closed:
		return nil
	default:
	}
	close(a.closed)

	a.lifetimeTimer.Stop()

	a.permissionsLock.RLock()
	for _, p := range a.permissions {
		p.lifetimeTimer.Stop()
	}
	a.permissionsLock.RUnlock()

	a.channelBindingsLock.RLock()
	for _, c := range a.channelBindings {
		c.lifetimeTimer.Stop()
	}
	a.channelBindingsLock.RUnlock()

	return a.RelaySocket.Close()
}

//  https://tools.ietf.org/html/rfc5766#section-10.3
//  When the server receives a UDP datagram at a currently allocated
//  relayed transport address, the server looks up the allocation
//  associated with the relayed transport address.  The server then
//  checks to see whether the set of permissions for the allocation allow
//  the relaying of the UDP datagram as described in Section 8.
//
//  If relaying is permitted, then the server checks if there is a
//  channel bound to the peer that sent the UDP datagram (see
//  Section 11).  If a channel is bound, then processing proceeds as
//  described in Section 11.7.
//
//  If relaying is permitted but no channel is bound to the peer, then
//  the server forms and sends a Data indication.  The Data indication
//  MUST contain both an XOR-PEER-ADDRESS and a DATA attribute.  The DATA
//  attribute is set to the value of the 'data octets' field from the
//  datagram, and the XOR-PEER-ADDRESS attribute is set to the source
//  transport address of the received UDP datagram.  The Data indication
//  is then sent on the 5-tuple associated with the allocation.

const rtpMTU = 1500

func (a *Allocation) packetHandler(m *Manager) {
	buffer := make([]byte, rtpMTU)

	for {
		n, srcAddr, err := a.RelaySocket.ReadFrom(buffer)
		if err != nil {
			m.DeleteAllocation(a.fiveTuple)
			return
		}

		a.log.Debugf("relay socket %s received %d bytes from %s",
			a.RelaySocket.LocalAddr().String(),
			n,
			srcAddr.String())

		if channel := a.GetChannelByAddr(srcAddr); channel != nil {
			channelData := &proto.ChannelData{
				Data:   buffer[:n],
				Number: channel.Number,
			}
			channelData.Encode()

			if _, err = a.TurnSocket.WriteTo(channelData.Raw, a.fiveTuple.SrcAddr); err != nil {
				a.log.Errorf("Failed to send ChannelData from allocation %v %v", srcAddr, err)
			}
		} else if p := a.GetPermission(srcAddr); p != nil {
			udpAddr := srcAddr.(*net.UDPAddr)
			peerAddressAttr := proto.PeerAddress{IP: udpAddr.IP, Port: udpAddr.Port}
			dataAttr := proto.Data(buffer[:n])

			msg, err := stun.Build(stun.TransactionID, stun.NewType(stun.MethodData, stun.ClassIndication), peerAddressAttr, dataAttr)
			if err != nil {
				a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
			}
			a.log.Debugf("relaying message from %s to client at %s",
				srcAddr.String(),
				a.fiveTuple.SrcAddr.String())
			if _, err = a.TurnSocket.WriteTo(msg.Raw, a.fiveTuple.SrcAddr); err != nil {
				a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
			}
		} else {
			a.log.Errorf("Packet unhandled in relay src %v", srcAddr)
		}
	}
}
<commit_msg>Update error message in Relay handler<commit_after>// Package allocation contains all CRUD operations for allocations
package allocation

import (
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/pion/logging"
	"github.com/pion/stun"
	"github.com/pion/turn/v2/internal/ipnet"
	"github.com/pion/turn/v2/internal/proto"
)

// Allocation is tied to a FiveTuple and relays traffic
// use CreateAllocation and GetAllocation to operate
type Allocation struct {
	RelayAddr           net.Addr
	Protocol            Protocol
	TurnSocket          net.PacketConn
	RelaySocket         net.PacketConn
	fiveTuple           *FiveTuple
	permissionsLock     sync.RWMutex
	permissions         map[string]*Permission
	channelBindingsLock sync.RWMutex
	channelBindings     []*ChannelBind
	lifetimeTimer       *time.Timer
	closed              chan interface{}
	log                 logging.LeveledLogger
}

func addr2IPFingerprint(addr net.Addr) string {
	switch a := addr.(type) {
	case *net.UDPAddr:
		return a.IP.String()
	case *net.TCPAddr: // Do we really need this case?
		return a.IP.String()
	}
	return "" // shoud never happen
}

// NewAllocation creates a new instance of NewAllocation.
func NewAllocation(turnSocket net.PacketConn, fiveTuple *FiveTuple, log logging.LeveledLogger) *Allocation {
	return &Allocation{
		TurnSocket:  turnSocket,
		fiveTuple:   fiveTuple,
		permissions: make(map[string]*Permission, 64),
		closed:      make(chan interface{}),
		log:         log,
	}
}

// GetPermission gets the Permission from the allocation
func (a *Allocation) GetPermission(addr net.Addr) *Permission {
	a.permissionsLock.RLock()
	defer a.permissionsLock.RUnlock()

	return a.permissions[addr2IPFingerprint(addr)]
}

// AddPermission adds a new permission to the allocation
func (a *Allocation) AddPermission(p *Permission) {
	fingerprint := addr2IPFingerprint(p.Addr)

	a.permissionsLock.RLock()
	existedPermission, ok := a.permissions[fingerprint]
	a.permissionsLock.RUnlock()

	if ok {
		existedPermission.refresh(permissionTimeout)
		return
	}

	p.allocation = a
	a.permissionsLock.Lock()
	a.permissions[fingerprint] = p
	a.permissionsLock.Unlock()

	p.start(permissionTimeout)
}

// RemovePermission removes the net.Addr's fingerprint from the allocation's permissions
func (a *Allocation) RemovePermission(addr net.Addr) {
	a.permissionsLock.Lock()
	defer a.permissionsLock.Unlock()
	delete(a.permissions, addr2IPFingerprint(addr))
}

// AddChannelBind adds a new ChannelBind to the allocation, it also updates the
// permissions needed for this ChannelBind
func (a *Allocation) AddChannelBind(c *ChannelBind, lifetime time.Duration) error {
	// Check that this channel id isn't bound to another transport address, and
	// that this transport address isn't bound to another channel number.
	channelByNumber := a.GetChannelByNumber(c.Number)

	if channelByNumber != a.GetChannelByAddr(c.Peer) {
		return fmt.Errorf("you cannot use the same channel number with different peer")
	}

	// Add or refresh this channel.
	if channelByNumber == nil {
		a.channelBindingsLock.Lock()
		defer a.channelBindingsLock.Unlock()

		c.allocation = a
		a.channelBindings = append(a.channelBindings, c)
		c.start(lifetime)

		// Channel binds also refresh permissions.
		a.AddPermission(NewPermission(c.Peer, a.log))
	} else {
		channelByNumber.refresh(lifetime)

		// Channel binds also refresh permissions.
		a.AddPermission(NewPermission(channelByNumber.Peer, a.log))
	}

	return nil
}

// RemoveChannelBind removes the ChannelBind from this allocation by id
func (a *Allocation) RemoveChannelBind(number proto.ChannelNumber) bool {
	a.channelBindingsLock.Lock()
	defer a.channelBindingsLock.Unlock()

	for i := len(a.channelBindings) - 1; i >= 0; i-- {
		if a.channelBindings[i].Number == number {
			a.channelBindings = append(a.channelBindings[:i], a.channelBindings[i+1:]...)
			return true
		}
	}

	return false
}

// GetChannelByNumber gets the ChannelBind from this allocation by id
func (a *Allocation) GetChannelByNumber(number proto.ChannelNumber) *ChannelBind {
	a.channelBindingsLock.RLock()
	defer a.channelBindingsLock.RUnlock()
	for _, cb := range a.channelBindings {
		if cb.Number == number {
			return cb
		}
	}
	return nil
}

// GetChannelByAddr gets the ChannelBind from this allocation by net.Addr
func (a *Allocation) GetChannelByAddr(addr net.Addr) *ChannelBind {
	a.channelBindingsLock.RLock()
	defer a.channelBindingsLock.RUnlock()
	for _, cb := range a.channelBindings {
		if ipnet.AddrEqual(cb.Peer, addr) {
			return cb
		}
	}
	return nil
}

// Refresh updates the allocations lifetime
func (a *Allocation) Refresh(lifetime time.Duration) {
	if !a.lifetimeTimer.Reset(lifetime) {
		a.log.Errorf("Failed to reset allocation timer for %v", a.fiveTuple)
	}
}

// Close closes the allocation
func (a *Allocation) Close() error {
	select {
	case <-a.closed:
		return nil
	default:
	}
	close(a.closed)

	a.lifetimeTimer.Stop()

	a.permissionsLock.RLock()
	for _, p := range a.permissions {
		p.lifetimeTimer.Stop()
	}
	a.permissionsLock.RUnlock()

	a.channelBindingsLock.RLock()
	for _, c := range a.channelBindings {
		c.lifetimeTimer.Stop()
	}
	a.channelBindingsLock.RUnlock()

	return a.RelaySocket.Close()
}

//  https://tools.ietf.org/html/rfc5766#section-10.3
//  When the server receives a UDP datagram at a currently allocated
//  relayed transport address, the server looks up the allocation
//  associated with the relayed transport address.  The server then
//  checks to see whether the set of permissions for the allocation allow
//  the relaying of the UDP datagram as described in Section 8.
//
//  If relaying is permitted, then the server checks if there is a
//  channel bound to the peer that sent the UDP datagram (see
//  Section 11).  If a channel is bound, then processing proceeds as
//  described in Section 11.7.
//
//  If relaying is permitted but no channel is bound to the peer, then
//  the server forms and sends a Data indication.  The Data indication
//  MUST contain both an XOR-PEER-ADDRESS and a DATA attribute.  The DATA
//  attribute is set to the value of the 'data octets' field from the
//  datagram, and the XOR-PEER-ADDRESS attribute is set to the source
//  transport address of the received UDP datagram.  The Data indication
//  is then sent on the 5-tuple associated with the allocation.

const rtpMTU = 1500

func (a *Allocation) packetHandler(m *Manager) {
	buffer := make([]byte, rtpMTU)

	for {
		n, srcAddr, err := a.RelaySocket.ReadFrom(buffer)
		if err != nil {
			m.DeleteAllocation(a.fiveTuple)
			return
		}

		a.log.Debugf("relay socket %s received %d bytes from %s",
			a.RelaySocket.LocalAddr().String(),
			n,
			srcAddr.String())

		if channel := a.GetChannelByAddr(srcAddr); channel != nil {
			channelData := &proto.ChannelData{
				Data:   buffer[:n],
				Number: channel.Number,
			}
			channelData.Encode()

			if _, err = a.TurnSocket.WriteTo(channelData.Raw, a.fiveTuple.SrcAddr); err != nil {
				a.log.Errorf("Failed to send ChannelData from allocation %v %v", srcAddr, err)
			}
		} else if p := a.GetPermission(srcAddr); p != nil {
			udpAddr := srcAddr.(*net.UDPAddr)
			peerAddressAttr := proto.PeerAddress{IP: udpAddr.IP, Port: udpAddr.Port}
			dataAttr := proto.Data(buffer[:n])

			msg, err := stun.Build(stun.TransactionID, stun.NewType(stun.MethodData, stun.ClassIndication), peerAddressAttr, dataAttr)
			if err != nil {
				a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
			}
			a.log.Debugf("relaying message from %s to client at %s",
				srcAddr.String(),
				a.fiveTuple.SrcAddr.String())
			if _, err = a.TurnSocket.WriteTo(msg.Raw, a.fiveTuple.SrcAddr); err != nil {
				a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
			}
		} else {
			a.log.Infof("No Permission or Channel exists for %v on allocation %v", srcAddr, a.RelayAddr.String())
		}
	}
}
<|endoftext|>


<commit_before>package registry

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/registry/v2"
	"github.com/docker/docker/utils"
)

func getV2Builder(e *Endpoint) *v2.URLBuilder {
	if e.URLBuilder == nil {
		e.URLBuilder = v2.NewURLBuilder(e.URL)
	}
	return e.URLBuilder
}

// GetV2Authorization gets the authorization needed to the given image
// If readonly access is requested, then only the authorization may
// only be used for Get operations.
func (r *Session) GetV2Authorization(imageName string, readOnly bool) (auth *RequestAuthorization, err error) {
	scopes := []string{"pull"}
	if !readOnly {
		scopes = append(scopes, "push")
	}

	var registry *Endpoint
	if r.indexEndpoint.String() == IndexServerAddress() {
		registry, err = newEndpoint(REGISTRYSERVER, true)
		if err != nil {
			return
		}
		err = validateEndpoint(registry)
		if err != nil {
			return
		}
	} else {
		registry = r.indexEndpoint
	}
	registry.URLBuilder = v2.NewURLBuilder(registry.URL)
	r.indexEndpoint = registry

	log.Debugf("Getting authorization for %s %s", imageName, scopes)
	return NewRequestAuthorization(r.GetAuthConfig(true), registry, "repository", imageName, scopes), nil
}

//
// 1) Check if TarSum of each layer exists /v2/
//  1.a) if 200, continue
//  1.b) if 300, then push the
//  1.c) if anything else, err
// 2) PUT the created/signed manifest
//
func (r *Session) GetV2ImageManifest(imageName, tagName string, auth *RequestAuthorization) ([]byte, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildManifestURL(imageName, tagName)
	if err != nil {
		return nil, err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)

	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return nil, err
	}
	if err := auth.Authorize(req); err != nil {
		return nil, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return nil, errLoginRequired
		} else if res.StatusCode == 404 {
			return nil, ErrDoesNotExist
		}
		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res)
	}

	buf, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("Error while reading the http response: %s", err)
	}
	return buf, nil
}

// - Succeeded to mount for this image scope
// - Failed with no error (So continue to Push the Blob)
// - Failed with error
func (r *Session) PostV2ImageMountBlob(imageName, sumType, sum string, auth *RequestAuthorization) (bool, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobURL(imageName, sumType+":"+sum)
	if err != nil {
		return false, err
	}

	method := "HEAD"
	log.Debugf("[registry] Calling %q %s", method, routeURL)

	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return false, err
	}
	if err := auth.Authorize(req); err != nil {
		return false, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return false, err
	}
	res.Body.Close() // close early, since we're not needing a body on this call .. yet?
	switch res.StatusCode {
	case 200:
		// return something indicating no push needed
		return true, nil
	case 404:
		// return something indicating blob push needed
		return false, nil
	}
	return false, fmt.Errorf("Failed to mount %q - %s:%s : %d", imageName, sumType, sum, res.StatusCode)
}

func (r *Session) GetV2ImageBlob(imageName, sumType, sum string, blobWrtr io.Writer, auth *RequestAuthorization) error {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobURL(imageName, sumType+":"+sum)
	if err != nil {
		return err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)
	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return err
	}
	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return errLoginRequired
		}
		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
	}

	_, err = io.Copy(blobWrtr, res.Body)
	return err
}

func (r *Session) GetV2ImageBlobReader(imageName, sumType, sum string, auth *RequestAuthorization) (io.ReadCloser, int64, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobURL(imageName, sumType+":"+sum)
	if err != nil {
		return nil, 0, err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)
	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return nil, 0, err
	}
	if err := auth.Authorize(req); err != nil {
		return nil, 0, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return nil, 0, err
	}
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return nil, 0, errLoginRequired
		}
		return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
	}
	lenStr := res.Header.Get("Content-Length")
	l, err := strconv.ParseInt(lenStr, 10, 64)
	if err != nil {
		return nil, 0, err
	}

	return res.Body, l, err
}

// Push the image to the server for storage.
// 'layer' is an uncompressed reader of the blob to be pushed.
// The server will generate it's own checksum calculation.
func (r *Session) PutV2ImageBlob(imageName, sumType, sumStr string, blobRdr io.Reader, auth *RequestAuthorization) error {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobUploadURL(imageName)
	if err != nil {
		return err
	}

	log.Debugf("[registry] Calling %q %s", "POST", routeURL)
	req, err := r.reqFactory.NewRequest("POST", routeURL, nil)
	if err != nil {
		return err
	}

	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return err
	}
	location := res.Header.Get("Location")

	method := "PUT"
	log.Debugf("[registry] Calling %q %s", method, location)
	req, err = r.reqFactory.NewRequest(method, location, blobRdr)
	if err != nil {
		return err
	}
	queryParams := req.URL.Query()
	queryParams.Add("digest", sumType+":"+sumStr)
	req.URL.RawQuery = queryParams.Encode()
	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err = r.doRequest(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 201 {
		if res.StatusCode == 401 {
			return errLoginRequired
		}
		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob", res.StatusCode, imageName), res)
	}

	return nil
}

// Finally Push the (signed) manifest of the blobs we've just pushed
func (r *Session) PutV2ImageManifest(imageName, tagName string, manifestRdr io.Reader, auth *RequestAuthorization) error {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildManifestURL(imageName, tagName)
	if err != nil {
		return err
	}

	method := "PUT"
	log.Debugf("[registry] Calling %q %s", method, routeURL)
	req, err := r.reqFactory.NewRequest(method, routeURL, manifestRdr)
	if err != nil {
		return err
	}
	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return err
	}
	b, _ := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return errLoginRequired
		}
		log.Debugf("Unexpected response from server: %q %#v", b, res.Header)
		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
	}

	return nil
}

// Given a repository name, returns a json array of string tags
func (r *Session) GetV2RemoteTags(imageName string, auth *RequestAuthorization) ([]string, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildTagsURL(imageName)
	if err != nil {
		return nil, err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)

	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return nil, err
	}
	if err := auth.Authorize(req); err != nil {
		return nil, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return nil, errLoginRequired
		} else if res.StatusCode == 404 {
			return nil, ErrDoesNotExist
		}
		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res)
	}

	decoder := json.NewDecoder(res.Body)
	var tags []string
	err = decoder.Decode(&tags)
	if err != nil {
		return nil, fmt.Errorf("Error while decoding the http response: %s", err)
	}
	return tags, nil
}
<commit_msg>Fix list tags<commit_after>package registry

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/registry/v2"
	"github.com/docker/docker/utils"
)

func getV2Builder(e *Endpoint) *v2.URLBuilder {
	if e.URLBuilder == nil {
		e.URLBuilder = v2.NewURLBuilder(e.URL)
	}
	return e.URLBuilder
}

// GetV2Authorization gets the authorization needed to the given image
// If readonly access is requested, then only the authorization may
// only be used for Get operations.
func (r *Session) GetV2Authorization(imageName string, readOnly bool) (auth *RequestAuthorization, err error) {
	scopes := []string{"pull"}
	if !readOnly {
		scopes = append(scopes, "push")
	}

	var registry *Endpoint
	if r.indexEndpoint.String() == IndexServerAddress() {
		registry, err = newEndpoint(REGISTRYSERVER, true)
		if err != nil {
			return
		}
		err = validateEndpoint(registry)
		if err != nil {
			return
		}
	} else {
		registry = r.indexEndpoint
	}
	registry.URLBuilder = v2.NewURLBuilder(registry.URL)
	r.indexEndpoint = registry

	log.Debugf("Getting authorization for %s %s", imageName, scopes)
	return NewRequestAuthorization(r.GetAuthConfig(true), registry, "repository", imageName, scopes), nil
}

//
// 1) Check if TarSum of each layer exists /v2/
//  1.a) if 200, continue
//  1.b) if 300, then push the
//  1.c) if anything else, err
// 2) PUT the created/signed manifest
//
func (r *Session) GetV2ImageManifest(imageName, tagName string, auth *RequestAuthorization) ([]byte, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildManifestURL(imageName, tagName)
	if err != nil {
		return nil, err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)

	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return nil, err
	}
	if err := auth.Authorize(req); err != nil {
		return nil, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return nil, errLoginRequired
		} else if res.StatusCode == 404 {
			return nil, ErrDoesNotExist
		}
		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s:%s", res.StatusCode, imageName, tagName), res)
	}

	buf, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("Error while reading the http response: %s", err)
	}
	return buf, nil
}

// - Succeeded to mount for this image scope
// - Failed with no error (So continue to Push the Blob)
// - Failed with error
func (r *Session) PostV2ImageMountBlob(imageName, sumType, sum string, auth *RequestAuthorization) (bool, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobURL(imageName, sumType+":"+sum)
	if err != nil {
		return false, err
	}

	method := "HEAD"
	log.Debugf("[registry] Calling %q %s", method, routeURL)

	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return false, err
	}
	if err := auth.Authorize(req); err != nil {
		return false, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return false, err
	}
	res.Body.Close() // close early, since we're not needing a body on this call .. yet?
	switch res.StatusCode {
	case 200:
		// return something indicating no push needed
		return true, nil
	case 404:
		// return something indicating blob push needed
		return false, nil
	}
	return false, fmt.Errorf("Failed to mount %q - %s:%s : %d", imageName, sumType, sum, res.StatusCode)
}

func (r *Session) GetV2ImageBlob(imageName, sumType, sum string, blobWrtr io.Writer, auth *RequestAuthorization) error {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobURL(imageName, sumType+":"+sum)
	if err != nil {
		return err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)
	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return err
	}
	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return errLoginRequired
		}
		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
	}

	_, err = io.Copy(blobWrtr, res.Body)
	return err
}

func (r *Session) GetV2ImageBlobReader(imageName, sumType, sum string, auth *RequestAuthorization) (io.ReadCloser, int64, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobURL(imageName, sumType+":"+sum)
	if err != nil {
		return nil, 0, err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)
	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return nil, 0, err
	}
	if err := auth.Authorize(req); err != nil {
		return nil, 0, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return nil, 0, err
	}
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return nil, 0, errLoginRequired
		}
		return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
	}
	lenStr := res.Header.Get("Content-Length")
	l, err := strconv.ParseInt(lenStr, 10, 64)
	if err != nil {
		return nil, 0, err
	}

	return res.Body, l, err
}

// Push the image to the server for storage.
// 'layer' is an uncompressed reader of the blob to be pushed.
// The server will generate it's own checksum calculation.
func (r *Session) PutV2ImageBlob(imageName, sumType, sumStr string, blobRdr io.Reader, auth *RequestAuthorization) error {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildBlobUploadURL(imageName)
	if err != nil {
		return err
	}

	log.Debugf("[registry] Calling %q %s", "POST", routeURL)
	req, err := r.reqFactory.NewRequest("POST", routeURL, nil)
	if err != nil {
		return err
	}

	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return err
	}
	location := res.Header.Get("Location")

	method := "PUT"
	log.Debugf("[registry] Calling %q %s", method, location)
	req, err = r.reqFactory.NewRequest(method, location, blobRdr)
	if err != nil {
		return err
	}
	queryParams := req.URL.Query()
	queryParams.Add("digest", sumType+":"+sumStr)
	req.URL.RawQuery = queryParams.Encode()
	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err = r.doRequest(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 201 {
		if res.StatusCode == 401 {
			return errLoginRequired
		}
		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob", res.StatusCode, imageName), res)
	}

	return nil
}

// Finally Push the (signed) manifest of the blobs we've just pushed
func (r *Session) PutV2ImageManifest(imageName, tagName string, manifestRdr io.Reader, auth *RequestAuthorization) error {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildManifestURL(imageName, tagName)
	if err != nil {
		return err
	}

	method := "PUT"
	log.Debugf("[registry] Calling %q %s", method, routeURL)
	req, err := r.reqFactory.NewRequest(method, routeURL, manifestRdr)
	if err != nil {
		return err
	}
	if err := auth.Authorize(req); err != nil {
		return err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return err
	}
	b, _ := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return errLoginRequired
		}
		log.Debugf("Unexpected response from server: %q %#v", b, res.Header)
		return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
	}

	return nil
}

type remoteTags struct {
	name string
	tags []string
}

// Given a repository name, returns a json array of string tags
func (r *Session) GetV2RemoteTags(imageName string, auth *RequestAuthorization) ([]string, error) {
	routeURL, err := getV2Builder(r.indexEndpoint).BuildTagsURL(imageName)
	if err != nil {
		return nil, err
	}

	method := "GET"
	log.Debugf("[registry] Calling %q %s", method, routeURL)

	req, err := r.reqFactory.NewRequest(method, routeURL, nil)
	if err != nil {
		return nil, err
	}
	if err := auth.Authorize(req); err != nil {
		return nil, err
	}
	res, _, err := r.doRequest(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		if res.StatusCode == 401 {
			return nil, errLoginRequired
		} else if res.StatusCode == 404 {
			return nil, ErrDoesNotExist
		}
		return nil, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch for %s", res.StatusCode, imageName), res)
	}

	decoder := json.NewDecoder(res.Body)
	var remote remoteTags
	err = decoder.Decode(&remote)
	if err != nil {
		return nil, fmt.Errorf("Error while decoding the http response: %s", err)
	}
	return remote.tags, nil
}
<|endoftext|>


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

package graphicscommand

import (
	"fmt"
	"image"
	"os"
	"strings"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/png"
)

type lastCommand int

const (
	lastCommandNone lastCommand = iota
	lastCommandClear
	lastCommandDrawTriangles
	lastCommandReplacePixels
)

// Image represents an image that is implemented with OpenGL.
type Image struct {
	image          driver.Image
	width          int
	height         int
	internalWidth  int
	internalHeight int
	screen         bool

	// id is an indentifier for the image. This is used only when dummping the information.
	//
	// This is duplicated with driver.Image's ID, but this id is still necessary because this image might not
	// have its driver.Image.
	id int

	bufferedRP []*driver.ReplacePixelsArgs

	lastCommand lastCommand
}

var nextID = 1

func genNextID() int {
	id := nextID
	nextID++
	return id
}

// NewImage returns a new image.
//
// Note that the image is not initialized yet.
func NewImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		id:     genNextID(),
	}
	c := &newImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func NewScreenFramebufferImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		screen: true,
		id:     genNextID(),
	}
	c := &newScreenFramebufferImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func (i *Image) resolveBufferedReplacePixels() {
	if len(i.bufferedRP) == 0 {
		return
	}
	c := &replacePixelsCommand{
		dst:  i,
		args: i.bufferedRP,
	}
	theCommandQueue.Enqueue(c)
	i.bufferedRP = nil
}

func (i *Image) Dispose() {
	c := &disposeImageCommand{
		target: i,
	}
	theCommandQueue.Enqueue(c)
}

func (i *Image) InternalSize() (int, int) {
	if i.internalWidth == 0 {
		i.internalWidth = graphics.InternalImageSize(i.width)
	}
	if i.internalHeight == 0 {
		i.internalHeight = graphics.InternalImageSize(i.height)
	}
	return i.internalWidth, i.internalHeight
}

// DrawTriangles draws triangles with the given image.
//
// The vertex floats are:
//
//   0:  Destination X in pixels
//   1:  Destination Y in pixels
//   2:  Source X in pixels (not texels!)
//   3:  Source Y in pixels
//   4:  Bounds of the source min X in pixels
//   5:  Bounds of the source min Y in pixels
//   6:  Bounds of the source max X in pixels
//   7:  Bounds of the source max Y in pixels
//   8:  Color R [0.0-1.0]
//   9:  Color G
//   10: Color B
//   11: Color Y
//
// src and shader are exclusive and only either is non-nil.
func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms map[int]interface{}) {
	if src.screen {
		panic("graphicscommand: the screen image cannot be the rendering source")
	}

	if i.lastCommand == lastCommandNone {
		if !i.screen && mode != driver.CompositeModeClear {
			panic("graphicscommand: the image must be cleared first")
		}
	}

	var us map[int]interface{}
	if src != nil {
		src.resolveBufferedReplacePixels()
	} else {
		us = map[int]interface{}{}
		for k, v := range uniforms {
			switch v := v.(type) {
			case *Image:
				v.resolveBufferedReplacePixels()
				us[k] = v.image
			default:
				us[k] = v
			}
		}
	}
	i.resolveBufferedReplacePixels()

	theCommandQueue.EnqueueDrawTrianglesCommand(i, src, vertices, indices, clr, mode, filter, address, shader, us)

	if i.lastCommand == lastCommandNone && !i.screen {
		i.lastCommand = lastCommandClear
	} else {
		i.lastCommand = lastCommandDrawTriangles
	}
}

// Pixels returns the image's pixels.
// Pixels might return nil when OpenGL error happens.
func (i *Image) Pixels() ([]byte, error) {
	i.resolveBufferedReplacePixels()
	c := &pixelsCommand{
		result: nil,
		img:    i,
	}
	theCommandQueue.Enqueue(c)
	if err := theCommandQueue.Flush(); err != nil {
		return nil, err
	}
	return c.result, nil
}

func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
	// ReplacePixels for a part might invalidate the current image that are drawn by DrawTriangles (#593, #738).
	if i.lastCommand == lastCommandDrawTriangles {
		if x != 0 || y != 0 || i.width != width || i.height != height {
			panic("graphicscommand: ReplacePixels for a part after DrawTriangles is forbidden")
		}
	}
	i.bufferedRP = append(i.bufferedRP, &driver.ReplacePixelsArgs{
		Pixels: pixels,
		X:      x,
		Y:      y,
		Width:  width,
		Height: height,
	})
	i.lastCommand = lastCommandReplacePixels
}

func (i *Image) IsInvalidated() bool {
	if i.screen {
		// The screen image might not have a texture, and in this case it is impossible to detect whether
		// the image is invalidated or not.
		panic("graphicscommand: IsInvalidated cannot be called on the screen image")
	}

	// i.image can be nil before initializing.
	if i.image == nil {
		return false
	}
	return i.image.IsInvalidated()
}

// Dump dumps the image to the specified path.
// In the path, '*' is replaced with the image's ID.
//
// If blackbg is true, any alpha values in the dumped image will be 255.
//
// This is for testing usage.
func (i *Image) Dump(path string, blackbg bool) error {
	// Screen image cannot be dumped.
	if i.screen {
		return nil
	}

	path = strings.ReplaceAll(path, "*", fmt.Sprintf("%d", i.id))
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()

	pix, err := i.Pixels()
	if err != nil {
		return err
	}

	if blackbg {
		for i := 0; i < len(pix)/4; i++ {
			pix[4*i+3] = 0xff
		}
	}

	if err := png.Encode(f, &image.RGBA{
		Pix:    pix,
		Stride: 4 * i.width,
		Rect:   image.Rect(0, 0, i.width, i.height),
	}); err != nil {
		return err
	}
	return nil
}
<commit_msg>graphicscommand: Bug fix: test failures<commit_after>// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package graphicscommand

import (
	"fmt"
	"image"
	"os"
	"strings"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/png"
)

type lastCommand int

const (
	lastCommandNone lastCommand = iota
	lastCommandClear
	lastCommandDrawTriangles
	lastCommandReplacePixels
)

// Image represents an image that is implemented with OpenGL.
type Image struct {
	image          driver.Image
	width          int
	height         int
	internalWidth  int
	internalHeight int
	screen         bool

	// id is an indentifier for the image. This is used only when dummping the information.
	//
	// This is duplicated with driver.Image's ID, but this id is still necessary because this image might not
	// have its driver.Image.
	id int

	bufferedRP []*driver.ReplacePixelsArgs

	lastCommand lastCommand
}

var nextID = 1

func genNextID() int {
	id := nextID
	nextID++
	return id
}

// NewImage returns a new image.
//
// Note that the image is not initialized yet.
func NewImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		id:     genNextID(),
	}
	c := &newImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func NewScreenFramebufferImage(width, height int) *Image {
	i := &Image{
		width:  width,
		height: height,
		screen: true,
		id:     genNextID(),
	}
	c := &newScreenFramebufferImageCommand{
		result: i,
		width:  width,
		height: height,
	}
	theCommandQueue.Enqueue(c)
	return i
}

func (i *Image) resolveBufferedReplacePixels() {
	if len(i.bufferedRP) == 0 {
		return
	}
	c := &replacePixelsCommand{
		dst:  i,
		args: i.bufferedRP,
	}
	theCommandQueue.Enqueue(c)
	i.bufferedRP = nil
}

func (i *Image) Dispose() {
	c := &disposeImageCommand{
		target: i,
	}
	theCommandQueue.Enqueue(c)
}

func (i *Image) InternalSize() (int, int) {
	if i.internalWidth == 0 {
		i.internalWidth = graphics.InternalImageSize(i.width)
	}
	if i.internalHeight == 0 {
		i.internalHeight = graphics.InternalImageSize(i.height)
	}
	return i.internalWidth, i.internalHeight
}

// DrawTriangles draws triangles with the given image.
//
// The vertex floats are:
//
//   0:  Destination X in pixels
//   1:  Destination Y in pixels
//   2:  Source X in pixels (not texels!)
//   3:  Source Y in pixels
//   4:  Bounds of the source min X in pixels
//   5:  Bounds of the source min Y in pixels
//   6:  Bounds of the source max X in pixels
//   7:  Bounds of the source max Y in pixels
//   8:  Color R [0.0-1.0]
//   9:  Color G
//   10: Color B
//   11: Color Y
//
// src and shader are exclusive and only either is non-nil.
func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms map[int]interface{}) {
	if src != nil && src.screen {
		panic("graphicscommand: the screen image cannot be the rendering source")
	}

	if i.lastCommand == lastCommandNone {
		if !i.screen && mode != driver.CompositeModeClear {
			panic("graphicscommand: the image must be cleared first")
		}
	}

	var us map[int]interface{}
	if src != nil {
		src.resolveBufferedReplacePixels()
	} else {
		us = map[int]interface{}{}
		for k, v := range uniforms {
			switch v := v.(type) {
			case *Image:
				v.resolveBufferedReplacePixels()
				us[k] = v.image
			default:
				us[k] = v
			}
		}
	}
	i.resolveBufferedReplacePixels()

	theCommandQueue.EnqueueDrawTrianglesCommand(i, src, vertices, indices, clr, mode, filter, address, shader, us)

	if i.lastCommand == lastCommandNone && !i.screen {
		i.lastCommand = lastCommandClear
	} else {
		i.lastCommand = lastCommandDrawTriangles
	}
}

// Pixels returns the image's pixels.
// Pixels might return nil when OpenGL error happens.
func (i *Image) Pixels() ([]byte, error) {
	i.resolveBufferedReplacePixels()
	c := &pixelsCommand{
		result: nil,
		img:    i,
	}
	theCommandQueue.Enqueue(c)
	if err := theCommandQueue.Flush(); err != nil {
		return nil, err
	}
	return c.result, nil
}

func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
	// ReplacePixels for a part might invalidate the current image that are drawn by DrawTriangles (#593, #738).
	if i.lastCommand == lastCommandDrawTriangles {
		if x != 0 || y != 0 || i.width != width || i.height != height {
			panic("graphicscommand: ReplacePixels for a part after DrawTriangles is forbidden")
		}
	}
	i.bufferedRP = append(i.bufferedRP, &driver.ReplacePixelsArgs{
		Pixels: pixels,
		X:      x,
		Y:      y,
		Width:  width,
		Height: height,
	})
	i.lastCommand = lastCommandReplacePixels
}

func (i *Image) IsInvalidated() bool {
	if i.screen {
		// The screen image might not have a texture, and in this case it is impossible to detect whether
		// the image is invalidated or not.
		panic("graphicscommand: IsInvalidated cannot be called on the screen image")
	}

	// i.image can be nil before initializing.
	if i.image == nil {
		return false
	}
	return i.image.IsInvalidated()
}

// Dump dumps the image to the specified path.
// In the path, '*' is replaced with the image's ID.
//
// If blackbg is true, any alpha values in the dumped image will be 255.
//
// This is for testing usage.
func (i *Image) Dump(path string, blackbg bool) error {
	// Screen image cannot be dumped.
	if i.screen {
		return nil
	}

	path = strings.ReplaceAll(path, "*", fmt.Sprintf("%d", i.id))
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()

	pix, err := i.Pixels()
	if err != nil {
		return err
	}

	if blackbg {
		for i := 0; i < len(pix)/4; i++ {
			pix[4*i+3] = 0xff
		}
	}

	if err := png.Encode(f, &image.RGBA{
		Pix:    pix,
		Stride: 4 * i.width,
		Rect:   image.Rect(0, 0, i.width, i.height),
	}); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package release

import (
	"testing"

	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
	"github.com/stretchr/testify/require"
)

func TestSetupGitLab(t *testing.T) {
	t.Run("no repo", func(t *testing.T) {
		ctx := context.New(config.Project{})

		require.NoError(t, setupGitLab(ctx))
		require.Equal(t, "goreleaser", ctx.Config.Release.GitLab.Owner)
		require.Equal(t, "goreleaser", ctx.Config.Release.GitLab.Name)
	})

	t.Run("with templates", func(t *testing.T) {
		ctx := context.New(config.Project{
			Env: []string{"NAME=foo", "OWNER=bar"},
			GitLabURLs: config.GitLabURLs{
				Download: "https://{{ .Env.OWNER }}/download",
			},
			Release: config.Release{
				GitLab: config.Repo{
					Owner: "{{.Env.OWNER}}",
					Name:  "{{.Env.NAME}}",
				},
			},
		})

		require.NoError(t, setupGitLab(ctx))
		require.Equal(t, "bar", ctx.Config.Release.GitLab.Owner)
		require.Equal(t, "foo", ctx.Config.Release.GitLab.Name)
		require.Equal(t, "https://bar/download/bar/foo/-/releases/", ctx.ReleaseURL)
	})

	t.Run("with invalid templates", func(t *testing.T) {
		t.Run("owner", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitLab: config.Repo{
						Name:  "foo",
						Owner: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitLab(ctx))
		})

		t.Run("name", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitLab: config.Repo{
						Name: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitLab(ctx))
		})
	})
}

func TestSetupGitea(t *testing.T) {
	t.Run("no repo", func(t *testing.T) {
		ctx := context.New(config.Project{})

		require.NoError(t, setupGitea(ctx))
		require.Equal(t, "goreleaser", ctx.Config.Release.Gitea.Owner)
		require.Equal(t, "goreleaser", ctx.Config.Release.Gitea.Name)
	})

	t.Run("with templates", func(t *testing.T) {
		ctx := context.New(config.Project{
			Env: []string{"NAME=foo", "OWNER=bar"},
			GiteaURLs: config.GiteaURLs{
				Download: "https://{{ .Env.OWNER }}/download",
			},
			Release: config.Release{
				Gitea: config.Repo{
					Owner: "{{.Env.OWNER}}",
					Name:  "{{.Env.NAME}}",
				},
			},
		})

		require.NoError(t, setupGitea(ctx))
		require.Equal(t, "bar", ctx.Config.Release.Gitea.Owner)
		require.Equal(t, "foo", ctx.Config.Release.Gitea.Name)
		require.Equal(t, "https://bar/download/bar/foo/releases/tag/", ctx.ReleaseURL)
	})

	t.Run("with invalid templates", func(t *testing.T) {
		t.Run("owner", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					Gitea: config.Repo{
						Name:  "foo",
						Owner: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitea(ctx))
		})

		t.Run("name", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					Gitea: config.Repo{
						Name: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitea(ctx))
		})
	})
}

func TestSetupGitHub(t *testing.T) {
	t.Run("no repo", func(t *testing.T) {
		ctx := context.New(config.Project{})

		require.NoError(t, setupGitHub(ctx))
		require.Equal(t, "goreleaser", ctx.Config.Release.GitHub.Owner)
		require.Equal(t, "goreleaser", ctx.Config.Release.GitHub.Name)
	})

	t.Run("with templates", func(t *testing.T) {
		ctx := context.New(config.Project{
			Env: []string{"NAME=foo", "OWNER=bar"},
			GitHubURLs: config.GitHubURLs{
				Download: "https://{{ .Env.OWNER }}/download",
			},
			Release: config.Release{
				GitHub: config.Repo{
					Owner: "{{.Env.OWNER}}",
					Name:  "{{.Env.NAME}}",
				},
			},
		})

		require.NoError(t, setupGitHub(ctx))
		require.Equal(t, "bar", ctx.Config.Release.GitHub.Owner)
		require.Equal(t, "foo", ctx.Config.Release.GitHub.Name)
		require.Equal(t, "https://bar/download/bar/foo/releases/tag/", ctx.ReleaseURL)
	})

	t.Run("with invalid templates", func(t *testing.T) {
		t.Run("owner", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitHub: config.Repo{
						Name:  "foo",
						Owner: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitHub(ctx))
		})

		t.Run("name", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitHub: config.Repo{
						Name: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitHub(ctx))
		})
	})
}
<commit_msg>test: fix scm test on forks<commit_after>package release

import (
	"testing"

	"github.com/goreleaser/goreleaser/internal/git"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
	"github.com/stretchr/testify/require"
)

func TestSetupGitLab(t *testing.T) {
	t.Run("no repo", func(t *testing.T) {
		ctx := context.New(config.Project{})

		require.NoError(t, setupGitLab(ctx))

		repo, err := git.ExtractRepoFromConfig(ctx)
		require.NoError(t, err)
		require.Equal(t, repo.Owner, ctx.Config.Release.GitLab.Owner)
		require.Equal(t, repo.Name, ctx.Config.Release.GitLab.Name)
	})

	t.Run("with templates", func(t *testing.T) {
		ctx := context.New(config.Project{
			Env: []string{"NAME=foo", "OWNER=bar"},
			GitLabURLs: config.GitLabURLs{
				Download: "https://{{ .Env.OWNER }}/download",
			},
			Release: config.Release{
				GitLab: config.Repo{
					Owner: "{{.Env.OWNER}}",
					Name:  "{{.Env.NAME}}",
				},
			},
		})

		require.NoError(t, setupGitLab(ctx))
		require.Equal(t, "bar", ctx.Config.Release.GitLab.Owner)
		require.Equal(t, "foo", ctx.Config.Release.GitLab.Name)
		require.Equal(t, "https://bar/download/bar/foo/-/releases/", ctx.ReleaseURL)
	})

	t.Run("with invalid templates", func(t *testing.T) {
		t.Run("owner", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitLab: config.Repo{
						Name:  "foo",
						Owner: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitLab(ctx))
		})

		t.Run("name", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitLab: config.Repo{
						Name: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitLab(ctx))
		})
	})
}

func TestSetupGitea(t *testing.T) {
	t.Run("no repo", func(t *testing.T) {
		ctx := context.New(config.Project{})

		require.NoError(t, setupGitea(ctx))
		require.Equal(t, "goreleaser", ctx.Config.Release.Gitea.Owner)
		require.Equal(t, "goreleaser", ctx.Config.Release.Gitea.Name)
	})

	t.Run("with templates", func(t *testing.T) {
		ctx := context.New(config.Project{
			Env: []string{"NAME=foo", "OWNER=bar"},
			GiteaURLs: config.GiteaURLs{
				Download: "https://{{ .Env.OWNER }}/download",
			},
			Release: config.Release{
				Gitea: config.Repo{
					Owner: "{{.Env.OWNER}}",
					Name:  "{{.Env.NAME}}",
				},
			},
		})

		require.NoError(t, setupGitea(ctx))
		require.Equal(t, "bar", ctx.Config.Release.Gitea.Owner)
		require.Equal(t, "foo", ctx.Config.Release.Gitea.Name)
		require.Equal(t, "https://bar/download/bar/foo/releases/tag/", ctx.ReleaseURL)
	})

	t.Run("with invalid templates", func(t *testing.T) {
		t.Run("owner", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					Gitea: config.Repo{
						Name:  "foo",
						Owner: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitea(ctx))
		})

		t.Run("name", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					Gitea: config.Repo{
						Name: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitea(ctx))
		})
	})
}

func TestSetupGitHub(t *testing.T) {
	t.Run("no repo", func(t *testing.T) {
		ctx := context.New(config.Project{})

		require.NoError(t, setupGitHub(ctx))
		require.Equal(t, "goreleaser", ctx.Config.Release.GitHub.Owner)
		require.Equal(t, "goreleaser", ctx.Config.Release.GitHub.Name)
	})

	t.Run("with templates", func(t *testing.T) {
		ctx := context.New(config.Project{
			Env: []string{"NAME=foo", "OWNER=bar"},
			GitHubURLs: config.GitHubURLs{
				Download: "https://{{ .Env.OWNER }}/download",
			},
			Release: config.Release{
				GitHub: config.Repo{
					Owner: "{{.Env.OWNER}}",
					Name:  "{{.Env.NAME}}",
				},
			},
		})

		require.NoError(t, setupGitHub(ctx))
		require.Equal(t, "bar", ctx.Config.Release.GitHub.Owner)
		require.Equal(t, "foo", ctx.Config.Release.GitHub.Name)
		require.Equal(t, "https://bar/download/bar/foo/releases/tag/", ctx.ReleaseURL)
	})

	t.Run("with invalid templates", func(t *testing.T) {
		t.Run("owner", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitHub: config.Repo{
						Name:  "foo",
						Owner: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitHub(ctx))
		})

		t.Run("name", func(t *testing.T) {
			ctx := context.New(config.Project{
				Release: config.Release{
					GitHub: config.Repo{
						Name: "{{.Env.NOPE}}",
					},
				},
			})

			require.Error(t, setupGitHub(ctx))
		})
	})
}
<|endoftext|>


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

package util_test

import (
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/prometheus/procfs/internal/util"
)

func TestValueParser(t *testing.T) {
	tests := []struct {
		name string
		v    string
		ok   bool
		fn   func(t *testing.T, vp *util.ValueParser)
	}{
		{
			name: "bad PInt64",
			v:    "hello",
			fn: func(_ *testing.T, vp *util.ValueParser) {
				_ = vp.PInt64()
			},
		},
		{
			name: "bad hex PInt64",
			v:    "0xhello",
			fn: func(_ *testing.T, vp *util.ValueParser) {
				_ = vp.PInt64()
			},
		},
		{
			name: "ok PInt64",
			v:    "1",
			ok:   true,
			fn: func(t *testing.T, vp *util.ValueParser) {
				want := int64(1)
				got := vp.PInt64()

				if diff := cmp.Diff(&want, got); diff != "" {
					t.Fatalf("unexpected integer (-want +got):\n%s", diff)
				}
			},
		},
		{
			name: "ok hex PInt64",
			v:    "0xff",
			ok:   true,
			fn: func(t *testing.T, vp *util.ValueParser) {
				want := int64(255)
				got := vp.PInt64()

				if diff := cmp.Diff(&want, got); diff != "" {
					t.Fatalf("unexpected integer (-want +got):\n%s", diff)
				}
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			vp := util.NewValueParser(tt.v)
			tt.fn(t, vp)

			err := vp.Err()
			if err != nil {
				if tt.ok {
					t.Fatalf("unexpected error: %v", err)
				}

				t.Logf("OK err: %v", err)
				return
			}

			if err == nil && !tt.ok {
				t.Fatal("expected an error, but none occurred")
			}
		})
	}
}
<commit_msg>internal/util: remove redundant error check<commit_after>// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package util_test

import (
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/prometheus/procfs/internal/util"
)

func TestValueParser(t *testing.T) {
	tests := []struct {
		name string
		v    string
		ok   bool
		fn   func(t *testing.T, vp *util.ValueParser)
	}{
		{
			name: "bad PInt64",
			v:    "hello",
			fn: func(_ *testing.T, vp *util.ValueParser) {
				_ = vp.PInt64()
			},
		},
		{
			name: "bad hex PInt64",
			v:    "0xhello",
			fn: func(_ *testing.T, vp *util.ValueParser) {
				_ = vp.PInt64()
			},
		},
		{
			name: "ok PInt64",
			v:    "1",
			ok:   true,
			fn: func(t *testing.T, vp *util.ValueParser) {
				want := int64(1)
				got := vp.PInt64()

				if diff := cmp.Diff(&want, got); diff != "" {
					t.Fatalf("unexpected integer (-want +got):\n%s", diff)
				}
			},
		},
		{
			name: "ok hex PInt64",
			v:    "0xff",
			ok:   true,
			fn: func(t *testing.T, vp *util.ValueParser) {
				want := int64(255)
				got := vp.PInt64()

				if diff := cmp.Diff(&want, got); diff != "" {
					t.Fatalf("unexpected integer (-want +got):\n%s", diff)
				}
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			vp := util.NewValueParser(tt.v)
			tt.fn(t, vp)

			err := vp.Err()
			if err != nil {
				if tt.ok {
					t.Fatalf("unexpected error: %v", err)
				}

				t.Logf("OK err: %v", err)
				return
			}

			if !tt.ok {
				t.Fatal("expected an error, but none occurred")
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"

	"sourcegraph.com/sourcegraph/appdash"
	"sourcegraph.com/sourcegraph/appdash/examples/cmd/webapp"
	"sourcegraph.com/sourcegraph/appdash/httptrace"
	"sourcegraph.com/sourcegraph/appdash/traceapp"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"
	influxdb "github.com/influxdb/influxdb/cmd/influxd/run"
)

const CtxSpanID = 0

var collector appdash.Collector

func main() {
	conf, err := influxdb.NewDemoConfig()
	if err != nil {
		log.Fatalf("failed to create influxdb config, error: %v", err)
	}
	store, err := appdash.NewInfluxDBStore(conf, &influxdb.BuildInfo{})
	if err != nil {
		log.Fatalf("failed to create influxdb store, error: %v", err)
	}
	tapp := traceapp.New(nil)
	tapp.Store = store
	tapp.Queryer = store
	log.Println("Appdash web UI running on HTTP :8700")
	go func() {
		log.Fatal(http.ListenAndServe(":8700", tapp))
	}()
	collector = appdash.NewLocalCollector(store)
	tracemw := httptrace.Middleware(collector, &httptrace.MiddlewareConfig{
		RouteName: func(r *http.Request) string { return r.URL.Path },
		SetContextSpan: func(r *http.Request, spanID appdash.SpanID) {
			context.Set(r, CtxSpanID, spanID)
		},
	})
	router := mux.NewRouter()
	router.HandleFunc("/", webapp.Home)
	router.HandleFunc("/endpoint", webapp.Endpoint)
	n := negroni.Classic()
	n.Use(negroni.HandlerFunc(tracemw)) // Register appdash's HTTP middleware.
	n.UseHandler(router)
	n.Run(":8699")
}
<commit_msg>cleans up influxdb example<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"sourcegraph.com/sourcegraph/appdash"
	"sourcegraph.com/sourcegraph/appdash/httptrace"
	"sourcegraph.com/sourcegraph/appdash/traceapp"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"

	influxDBServer "github.com/influxdb/influxdb/cmd/influxd/run"
)

const CtxSpanID = 0

var collector appdash.Collector

func main() {
	conf, err := influxDBServer.NewDemoConfig()
	if err != nil {
		log.Fatalf("failed to create influxdb config, error: %v", err)
	}
	store, err := appdash.NewInfluxDBStore(conf, &influxDBServer.BuildInfo{})
	if err != nil {
		log.Fatalf("failed to create influxdb store, error: %v", err)
	}
	defer store.Close()
	tapp := traceapp.New(nil)
	tapp.Store = store
	tapp.Queryer = store
	log.Println("Appdash web UI running on HTTP :8700")
	go func() {
		log.Fatal(http.ListenAndServe(":8700", tapp))
	}()
	collector = appdash.NewLocalCollector(store)
	tracemw := httptrace.Middleware(collector, &httptrace.MiddlewareConfig{
		RouteName: func(r *http.Request) string { return r.URL.Path },
		SetContextSpan: func(r *http.Request, spanID appdash.SpanID) {
			context.Set(r, CtxSpanID, spanID)
		},
	})
	router := mux.NewRouter()
	router.HandleFunc("/", Home)
	router.HandleFunc("/endpoint", Endpoint)
	n := negroni.Classic()
	n.Use(negroni.HandlerFunc(tracemw))
	n.UseHandler(router)
	n.Run(":8699")
}

func Home(w http.ResponseWriter, r *http.Request) {
	span := context.Get(r, CtxSpanID).(appdash.SpanID)
	httpClient := &http.Client{
		Transport: &httptrace.Transport{
			Recorder: appdash.NewRecorder(span, collector),
			SetName:  true,
		},
	}
	for i := 0; i < 3; i++ {
		resp, err := httpClient.Get("http://localhost:8699/endpoint")
		if err != nil {
			log.Println("/endpoint:", err)
			continue
		}
		resp.Body.Close()
	}
	fmt.Fprintf(w, `<p>Three API requests have been made!</p>`)
	fmt.Fprintf(w, `<p><a href="http://localhost:8700/traces/%s" target="_">View the trace (ID:%s)</a></p>`, span.Trace, span.Trace)
}

func Endpoint(w http.ResponseWriter, r *http.Request) {
	time.Sleep(200 * time.Millisecond)
	fmt.Fprintf(w, "Slept for 200ms!")
}
<|endoftext|>


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

package elastigo

import (
	"bytes"
	"encoding/json"
	"fmt"
	hostpool "github.com/bitly/go-hostpool"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type Request struct {
	*http.Request
	hostResponse hostpool.HostPoolResponse
}

func (r *Request) SetBodyJson(data interface{}) error {
	body, err := json.Marshal(data)
	if err != nil {
		return err
	}
	r.SetBodyBytes(body)
	r.Header.Set("Content-Type", "application/json")
	return nil
}

func (r *Request) SetBodyString(body string) {
	r.SetBody(strings.NewReader(body))
}

func (r *Request) SetBodyBytes(body []byte) {
	r.SetBody(bytes.NewReader(body))
}

func (r *Request) SetBody(body io.Reader) {
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	r.Body = rc
	if body != nil {
		switch v := body.(type) {
		case *strings.Reader:
			r.ContentLength = int64(v.Len())
		case *bytes.Reader:
			r.ContentLength = int64(v.Len())
		}
	}
}

func (r *Request) Do(v interface{}) (int, []byte, error) {
	response, bodyBytes, err := r.DoResponse(v)
	if err != nil {
		return -1, nil, err
	}
	return response.StatusCode, bodyBytes, err
}

func (r *Request) DoResponse(v interface{}) (*http.Response, []byte, error) {
	res, err := http.DefaultClient.Do(r.Request)
	// Inform the HostPool of what happened to the request and allow it to update
	r.hostResponse.Mark(err)
	if err != nil {
		return nil, nil, err
	}

	defer res.Body.Close()
	bodyBytes, err := ioutil.ReadAll(res.Body)

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

	if res.StatusCode == 404 {
		return nil, bodyBytes, RecordNotFound
	}

	if res.StatusCode > 304 && v != nil {
		jsonErr := json.Unmarshal(bodyBytes, v)
		if jsonErr != nil {
			return nil, nil, jsonErr
		}
	}
	return res, bodyBytes, err
}

func Escape(args map[string]interface{}) (s string, err error) {
	vals := url.Values{}
	for key, val := range args {
		switch v := val.(type) {
		case string:
			vals.Add(key, v)
		case bool:
			vals.Add(key, strconv.FormatBool(v))
		case int, int32, int64:
			vals.Add(key, strconv.Itoa(v.(int)))
		case float32, float64:
			vals.Add(key, strconv.FormatFloat(v.(float64), 'f', -1, 64))
		case []string:
			vals.Add(key, strings.Join(v, ","))
		default:
			err = fmt.Errorf("Could not format URL argument: %s", key)
			return
		}
	}
	s = vals.Encode()
	return
}
<commit_msg>Don't use chunked for byte buffers.<commit_after>// Copyright 2013 Matthew Baird
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package elastigo

import (
	"bytes"
	"encoding/json"
	"fmt"
	hostpool "github.com/bitly/go-hostpool"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type Request struct {
	*http.Request
	hostResponse hostpool.HostPoolResponse
}

func (r *Request) SetBodyJson(data interface{}) error {
	body, err := json.Marshal(data)
	if err != nil {
		return err
	}
	r.SetBodyBytes(body)
	r.Header.Set("Content-Type", "application/json")
	return nil
}

func (r *Request) SetBodyString(body string) {
	r.SetBody(strings.NewReader(body))
}

func (r *Request) SetBodyBytes(body []byte) {
	r.SetBody(bytes.NewReader(body))
}

func (r *Request) SetBody(body io.Reader) {
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	r.Body = rc
	if body != nil {
		switch v := body.(type) {
		case *strings.Reader:
			r.ContentLength = int64(v.Len())
		case *bytes.Reader:
			r.ContentLength = int64(v.Len())
		case *bytes.Buffer:
			r.ContentLength = int64(v.Len())
		}
	}
}

func (r *Request) Do(v interface{}) (int, []byte, error) {
	response, bodyBytes, err := r.DoResponse(v)
	if err != nil {
		return -1, nil, err
	}
	return response.StatusCode, bodyBytes, err
}

func (r *Request) DoResponse(v interface{}) (*http.Response, []byte, error) {
	res, err := http.DefaultClient.Do(r.Request)
	// Inform the HostPool of what happened to the request and allow it to update
	r.hostResponse.Mark(err)
	if err != nil {
		return nil, nil, err
	}

	defer res.Body.Close()
	bodyBytes, err := ioutil.ReadAll(res.Body)

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

	if res.StatusCode == 404 {
		return nil, bodyBytes, RecordNotFound
	}

	if res.StatusCode > 304 && v != nil {
		jsonErr := json.Unmarshal(bodyBytes, v)
		if jsonErr != nil {
			return nil, nil, jsonErr
		}
	}
	return res, bodyBytes, err
}

func Escape(args map[string]interface{}) (s string, err error) {
	vals := url.Values{}
	for key, val := range args {
		switch v := val.(type) {
		case string:
			vals.Add(key, v)
		case bool:
			vals.Add(key, strconv.FormatBool(v))
		case int, int32, int64:
			vals.Add(key, strconv.Itoa(v.(int)))
		case float32, float64:
			vals.Add(key, strconv.FormatFloat(v.(float64), 'f', -1, 64))
		case []string:
			vals.Add(key, strings.Join(v, ","))
		default:
			err = fmt.Errorf("Could not format URL argument: %s", key)
			return
		}
	}
	s = vals.Encode()
	return
}
<|endoftext|>


<commit_before>package splitbox

import (
	"math/rand"

	. "github.com/peterstace/grayt/examples/cornellbox"
	. "github.com/peterstace/grayt/grayt"
)

var SkyFn func(Vector) Colour = nil

func CameraFn() CameraBlueprint {
	c := Cam(1.3)
	return c.With(
		LookingAt(Vect(0.5, initialBoxRadius.Y+0.03, -0.5)),
		ScaleFieldOfView(0.5),
		AspectRatioWidthAndHeight(16, 9),
	)
}

func ObjectsFn() ObjectList {
	return Group(
		Floor,
		Ceiling,
		BackWall,
		LeftWall.With(ColourRGB(Red)),
		RightWall.With(ColourRGB(Green)),
		CeilingLight().With(Emittance(1)),
		splitBox(),
	)
}

const (
	numMovements = 100
)

var initialBoxRadius = Vect(0.22, 0.1, 0.1)

type box struct {
	min, max Vector
}

func splitBox() ObjectList {

	v1 := Vect(0.5-initialBoxRadius.X, 0, -0.5+initialBoxRadius.Z)
	v2 := Vect(0.5+initialBoxRadius.X, 2*initialBoxRadius.Y, -0.5-initialBoxRadius.Z)
	v1, v2 = v1.Min(v2), v1.Max(v2)
	boxes := []box{{v1, v2}}

	rnd := rand.New(rand.NewSource(0))
	for i := 0; i < numMovements; i++ {
		var newBoxes []box
		for _, box := range boxes {

			kind := rnd.Intn(6)
			fn := movements[kind]

			var splitLocation float64
			switch kind {
			case 0, 4:
				splitLocation = v1.X + (v2.X-v1.X)*rnd.Float64()
			case 2, 3:
				splitLocation = v1.Y + (v2.Y-v1.Y)*rnd.Float64()
			case 1, 5:
				splitLocation = v1.Z + (v2.Z-v1.Z)*rnd.Float64()
			default:
				panic(false)
			}

			splitAmount := (rnd.Float64() - 0.5) * 0.05
			splitBoxes := fn(splitLocation, splitAmount, box)
			newBoxes = append(newBoxes, splitBoxes...)
		}
		boxes = newBoxes
	}

	var objList ObjectList
	for _, box := range boxes {
		objList = Group(objList, AlignedBox(box.min, box.max))
	}
	return objList
}

func splitLeftRight(x float64, b box) (box, box) {
	b1 := box{b.min, Vect(x, b.max.Y, b.max.Z)}
	b2 := box{Vect(x, b.min.Y, b.min.Z), b.max}
	return b1, b2
}

func splitUpDown(y float64, b box) (box, box) {
	b1 := box{b.min, Vect(b.max.X, y, b.max.Z)}
	b2 := box{Vect(b.min.X, y, b.min.Z), b.max}
	return b1, b2
}

func splitFwdBack(z float64, b box) (box, box) {
	b1 := box{b.min, Vect(b.max.X, b.max.Y, z)}
	b2 := box{Vect(b.min.X, b.min.Y, z), b.max}
	return b1, b2
}

func heightMovementLeftRight(x float64, amount float64, input box) []box {
	if x < input.min.X || x > input.max.X {
		return []box{input}
	}
	b1, b2 := splitLeftRight(x, input)
	scale := amount / (2 * initialBoxRadius.Y)
	b1.min.Y *= 1 + scale
	b1.max.Y *= 1 + scale
	b2.min.Y *= 1 - scale
	b2.max.Y *= 1 - scale
	return []box{b1, b2}
}

func heightMovementFwdBack(z float64, amount float64, input box) []box {
	if z < input.min.Z || z > input.max.Z {
		return []box{input}
	}
	b1, b2 := splitFwdBack(z, input)
	scale := amount / (2 * initialBoxRadius.Y)
	b1.min.Y *= 1 + scale
	b1.max.Y *= 1 + scale
	b2.min.Y *= 1 - scale
	b2.max.Y *= 1 - scale
	return []box{b1, b2}
}

func layerMovementLeftRight(y float64, amount float64, input box) []box {
	if y < input.min.Y || y > input.max.Y {
		return []box{input}
	}
	b1, b2 := splitUpDown(y, input)
	b1.min.X += amount
	b1.max.X += amount
	b2.min.X -= amount
	b2.max.X -= amount
	return []box{b1, b2}
}

func layerMovementFwdBack(y float64, amount float64, input box) []box {
	if y < input.min.Y || y > input.max.Y {
		return []box{input}
	}
	b1, b2 := splitUpDown(y, input)
	b1.min.Z += amount
	b1.max.Z += amount
	b2.min.Z -= amount
	b2.max.Z -= amount
	return []box{b1, b2}
}

func shearFwdBack(x float64, amount float64, input box) []box {
	if x < input.min.X || x > input.max.X {
		return []box{input}
	}
	b1, b2 := splitLeftRight(x, input)
	b1.min.Z += amount
	b1.max.Z += amount
	b2.min.Z -= amount
	b2.max.Z -= amount
	return []box{b1, b2}
}

func shearLeftRight(z float64, amount float64, input box) []box {
	if z < input.min.Z || z > input.max.Z {
		return []box{input}
	}
	b1, b2 := splitFwdBack(z, input)
	b1.min.X += amount
	b1.max.X += amount
	b2.min.X -= amount
	b2.max.X -= amount
	return []box{b1, b2}
}

var movements = [...]func(float64, float64, box) []box{
	heightMovementLeftRight,
	heightMovementFwdBack,
	layerMovementLeftRight,
	layerMovementFwdBack,
	shearFwdBack,
	shearLeftRight,
}
<commit_msg>16:10 for splitbox<commit_after>package splitbox

import (
	"math/rand"

	. "github.com/peterstace/grayt/examples/cornellbox"
	. "github.com/peterstace/grayt/grayt"
)

var SkyFn func(Vector) Colour = nil

func CameraFn() CameraBlueprint {
	c := Cam(1.3)
	return c.With(
		LookingAt(Vect(0.5, initialBoxRadius.Y+0.03, -0.5)),
		ScaleFieldOfView(0.5),
		AspectRatioWidthAndHeight(16, 10),
	)
}

func ObjectsFn() ObjectList {
	return Group(
		Floor,
		Ceiling,
		BackWall,
		LeftWall.With(ColourRGB(Red)),
		RightWall.With(ColourRGB(Green)),
		CeilingLight().With(Emittance(1)),
		splitBox(),
	)
}

const (
	numMovements = 100
)

var initialBoxRadius = Vect(0.22, 0.1, 0.1)

type box struct {
	min, max Vector
}

func splitBox() ObjectList {

	v1 := Vect(0.5-initialBoxRadius.X, 0, -0.5+initialBoxRadius.Z)
	v2 := Vect(0.5+initialBoxRadius.X, 2*initialBoxRadius.Y, -0.5-initialBoxRadius.Z)
	v1, v2 = v1.Min(v2), v1.Max(v2)
	boxes := []box{{v1, v2}}

	rnd := rand.New(rand.NewSource(0))
	for i := 0; i < numMovements; i++ {
		var newBoxes []box
		for _, box := range boxes {

			kind := rnd.Intn(6)
			fn := movements[kind]

			var splitLocation float64
			switch kind {
			case 0, 4:
				splitLocation = v1.X + (v2.X-v1.X)*rnd.Float64()
			case 2, 3:
				splitLocation = v1.Y + (v2.Y-v1.Y)*rnd.Float64()
			case 1, 5:
				splitLocation = v1.Z + (v2.Z-v1.Z)*rnd.Float64()
			default:
				panic(false)
			}

			splitAmount := (rnd.Float64() - 0.5) * 0.05
			splitBoxes := fn(splitLocation, splitAmount, box)
			newBoxes = append(newBoxes, splitBoxes...)
		}
		boxes = newBoxes
	}

	var objList ObjectList
	for _, box := range boxes {
		objList = Group(objList, AlignedBox(box.min, box.max))
	}
	return objList
}

func splitLeftRight(x float64, b box) (box, box) {
	b1 := box{b.min, Vect(x, b.max.Y, b.max.Z)}
	b2 := box{Vect(x, b.min.Y, b.min.Z), b.max}
	return b1, b2
}

func splitUpDown(y float64, b box) (box, box) {
	b1 := box{b.min, Vect(b.max.X, y, b.max.Z)}
	b2 := box{Vect(b.min.X, y, b.min.Z), b.max}
	return b1, b2
}

func splitFwdBack(z float64, b box) (box, box) {
	b1 := box{b.min, Vect(b.max.X, b.max.Y, z)}
	b2 := box{Vect(b.min.X, b.min.Y, z), b.max}
	return b1, b2
}

func heightMovementLeftRight(x float64, amount float64, input box) []box {
	if x < input.min.X || x > input.max.X {
		return []box{input}
	}
	b1, b2 := splitLeftRight(x, input)
	scale := amount / (2 * initialBoxRadius.Y)
	b1.min.Y *= 1 + scale
	b1.max.Y *= 1 + scale
	b2.min.Y *= 1 - scale
	b2.max.Y *= 1 - scale
	return []box{b1, b2}
}

func heightMovementFwdBack(z float64, amount float64, input box) []box {
	if z < input.min.Z || z > input.max.Z {
		return []box{input}
	}
	b1, b2 := splitFwdBack(z, input)
	scale := amount / (2 * initialBoxRadius.Y)
	b1.min.Y *= 1 + scale
	b1.max.Y *= 1 + scale
	b2.min.Y *= 1 - scale
	b2.max.Y *= 1 - scale
	return []box{b1, b2}
}

func layerMovementLeftRight(y float64, amount float64, input box) []box {
	if y < input.min.Y || y > input.max.Y {
		return []box{input}
	}
	b1, b2 := splitUpDown(y, input)
	b1.min.X += amount
	b1.max.X += amount
	b2.min.X -= amount
	b2.max.X -= amount
	return []box{b1, b2}
}

func layerMovementFwdBack(y float64, amount float64, input box) []box {
	if y < input.min.Y || y > input.max.Y {
		return []box{input}
	}
	b1, b2 := splitUpDown(y, input)
	b1.min.Z += amount
	b1.max.Z += amount
	b2.min.Z -= amount
	b2.max.Z -= amount
	return []box{b1, b2}
}

func shearFwdBack(x float64, amount float64, input box) []box {
	if x < input.min.X || x > input.max.X {
		return []box{input}
	}
	b1, b2 := splitLeftRight(x, input)
	b1.min.Z += amount
	b1.max.Z += amount
	b2.min.Z -= amount
	b2.max.Z -= amount
	return []box{b1, b2}
}

func shearLeftRight(z float64, amount float64, input box) []box {
	if z < input.min.Z || z > input.max.Z {
		return []box{input}
	}
	b1, b2 := splitFwdBack(z, input)
	b1.min.X += amount
	b1.max.X += amount
	b2.min.X -= amount
	b2.max.X -= amount
	return []box{b1, b2}
}

var movements = [...]func(float64, float64, box) []box{
	heightMovementLeftRight,
	heightMovementFwdBack,
	layerMovementLeftRight,
	layerMovementFwdBack,
	shearFwdBack,
	shearLeftRight,
}
<|endoftext|>


<commit_before>package tricorder

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

const (
	browseMetricsUrl = "/tricorder"
	htmlTemplateStr  = `

	  <link rel="stylesheet" type="text/css" href="/tricorderstatic/theme.css">

	{{with $top := .}}
	  {{range .List}}
	    {{if .Directory}}
	      {{.Directory.AbsPath}}

            {{else}}
	      {{if $top.IsDistribution .Metric.Value.Type}}
	        {{.Metric.AbsPath}} (distribution: {{.Metric.Description}})

	        {{with .Metric.Value.AsDistribution.Snapshot}}

	          {{range .Breakdown}}
		  {{if .Count}}

  	            {{if .First}}
	              <{{.End}}:	{{.Count}}
	            {{else if .Last}}
	              >={{.Start}}:	 {{.Count}}
	            {{else}}
		    {{.Start}}-{{.End}}:	 {{.Count}}
	            {{end}}

		  {{end}}
		  {{end}}

	          {{if .Count}}
		   min: {{.Min}} max: {{.Max}} avg: {{.Average}} ~median: {{$top.ToFloat32 .Median}} count: {{.Count}}

	          {{end}}
		{{end}}
	      {{else}}
	        {{.Metric.AbsPath}} {{.Metric.Value.AsHtmlString}} ({{.Metric.Value.Type}}: {{.Metric.Description}})

	      {{end}}
	    {{end}}
	  {{end}}
	{{end}}

	  `

	themeCss = `
	.summary {color:#999999; font-style: italic;}
	  `
)

var (
	htmlTemplate = template.Must(template.New("browser").Parse(htmlTemplateStr))
	errLog       *log.Logger
	appStartTime time.Time
)

type view struct {
	*directory
}

func (v *view) Link(d *directory) string {
	return browseMetricsUrl + d.AbsPath()
}

func (v *view) IsDistribution(t valueType) bool {
	return t == Dist
}

func (v *view) ToFloat32(f float64) float32 {
	return float32(f)
}

func emitDirectoryAsHtml(d *directory, w io.Writer) error {
	v := &view{d}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func browseFunc(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	d := root.GetDirectory(path)
	if d == nil {
		fmt.Fprintf(w, "Path does not exist.")
		return
	}
	if err := emitDirectoryAsHtml(d, w); err != nil {
		fmt.Fprintln(w, "Error in template.")
		errLog.Printf("Error in template: %v\n", err)
	}
}

func newStatic() http.Handler {
	result := http.NewServeMux()
	addStatic(result, "/theme.css", themeCss)
	return result
}

func addStatic(mux *http.ServeMux, path, content string) {
	addStaticBinary(mux, path, []byte(content))
}

func addStaticBinary(mux *http.ServeMux, path string, content []byte) {
	mux.Handle(
		path,
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			http.ServeContent(
				w,
				r,
				path,
				appStartTime,
				bytes.NewReader(content))
		}))
}

func getProgramArgs() string {
	return strings.Join(os.Args[1:], " ")
}

func registerDefaultMetrics() {
	RegisterMetric("/name", &os.Args[0], None, "Program name")
	RegisterMetric("/args", getProgramArgs, None, "Program args")
}

func initHttpFramework() {
	appStartTime = time.Now()
	errLog = log.New(os.Stderr, "", log.LstdFlags|log.Lmicroseconds)
}

func registerBrowserHandlers() {
	http.Handle(browseMetricsUrl+"/", http.StripPrefix(browseMetricsUrl, http.HandlerFunc(browseFunc)))
	http.Handle("/tricorderstatic/", http.StripPrefix("/tricorderstatic", newStatic()))
}

func init() {
	registerDefaultMetrics()
	initHttpFramework()
	registerBrowserHandlers()

}
<commit_msg>show units<commit_after>package tricorder

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

const (
	browseMetricsUrl = "/tricorder"
	htmlTemplateStr  = `

	  <link rel="stylesheet" type="text/css" href="/tricorderstatic/theme.css">

	{{with $top := .}}
	  {{range .List}}
	    {{if .Directory}}
	      {{.Directory.AbsPath}}

            {{else}}
	      {{if $top.IsDistribution .Metric.Value.Type}}
	      {{.Metric.AbsPath}} (distribution: {{.Metric.Description}}{{if $top.HasUnit .Metric.Unit}}; unit: {{.Metric.Unit}}{{end}})

	        {{with .Metric.Value.AsDistribution.Snapshot}}

	          {{range .Breakdown}}
		  {{if .Count}}

  	            {{if .First}}
	              <{{.End}}:	{{.Count}}
	            {{else if .Last}}
	              >={{.Start}}:	 {{.Count}}
	            {{else}}
		    {{.Start}}-{{.End}}:	 {{.Count}}
	            {{end}}

		  {{end}}
		  {{end}}

	          {{if .Count}}
		   min: {{.Min}} max: {{.Max}} avg: {{.Average}} ~median: {{$top.ToFloat32 .Median}} count: {{.Count}}

	          {{end}}
		{{end}}
	      {{else}}
	      {{.Metric.AbsPath}} {{.Metric.Value.AsHtmlString}} ({{.Metric.Value.Type}}: {{.Metric.Description}}{{if $top.HasUnit .Metric.Unit}}; unit: {{.Metric.Unit}}{{end}})

	      {{end}}
	    {{end}}
	  {{end}}
	{{end}}

	  `

	themeCss = `
	.summary {color:#999999; font-style: italic;}
	  `
)

var (
	htmlTemplate = template.Must(template.New("browser").Parse(htmlTemplateStr))
	errLog       *log.Logger
	appStartTime time.Time
)

type view struct {
	*directory
}

func (v *view) Link(d *directory) string {
	return browseMetricsUrl + d.AbsPath()
}

func (v *view) IsDistribution(t valueType) bool {
	return t == Dist
}

func (v *view) HasUnit(u Unit) bool {
	return u != None
}

func (v *view) ToFloat32(f float64) float32 {
	return float32(f)
}

func emitDirectoryAsHtml(d *directory, w io.Writer) error {
	v := &view{d}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func browseFunc(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	d := root.GetDirectory(path)
	if d == nil {
		fmt.Fprintf(w, "Path does not exist.")
		return
	}
	if err := emitDirectoryAsHtml(d, w); err != nil {
		fmt.Fprintln(w, "Error in template.")
		errLog.Printf("Error in template: %v\n", err)
	}
}

func newStatic() http.Handler {
	result := http.NewServeMux()
	addStatic(result, "/theme.css", themeCss)
	return result
}

func addStatic(mux *http.ServeMux, path, content string) {
	addStaticBinary(mux, path, []byte(content))
}

func addStaticBinary(mux *http.ServeMux, path string, content []byte) {
	mux.Handle(
		path,
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			http.ServeContent(
				w,
				r,
				path,
				appStartTime,
				bytes.NewReader(content))
		}))
}

func getProgramArgs() string {
	return strings.Join(os.Args[1:], " ")
}

func registerDefaultMetrics() {
	RegisterMetric("/name", &os.Args[0], None, "Program name")
	RegisterMetric("/args", getProgramArgs, None, "Program args")
}

func initHttpFramework() {
	appStartTime = time.Now()
	errLog = log.New(os.Stderr, "", log.LstdFlags|log.Lmicroseconds)
}

func registerBrowserHandlers() {
	http.Handle(browseMetricsUrl+"/", http.StripPrefix(browseMetricsUrl, http.HandlerFunc(browseFunc)))
	http.Handle("/tricorderstatic/", http.StripPrefix("/tricorderstatic", newStatic()))
}

func init() {
	registerDefaultMetrics()
	initHttpFramework()
	registerBrowserHandlers()

}
<|endoftext|>


<commit_before>// Copyright 2013 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.

// This file tests types.Check by using it to
// typecheck the standard library and tests.

package types_test

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/scanner"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	_ "code.google.com/p/go.tools/go/gcimporter"
	. "code.google.com/p/go.tools/go/types"
)

var (
	pkgCount int // number of packages processed
	start    = time.Now()
)

func TestStdlib(t *testing.T) {
	walkDirs(t, filepath.Join(runtime.GOROOT(), "src/pkg"))
	if testing.Verbose() {
		fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
	}
}

// firstComment returns the contents of the first comment in
// the given file, assuming there's one within the first KB.
func firstComment(filename string) string {
	f, err := os.Open(filename)
	if err != nil {
		return ""
	}
	defer f.Close()

	var src [1 << 10]byte // read at most 1KB
	n, _ := f.Read(src[:])

	var s scanner.Scanner
	s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments)
	for {
		_, tok, lit := s.Scan()
		switch tok {
		case token.COMMENT:
			// remove trailing */ of multi-line comment
			if lit[1] == '*' {
				lit = lit[:len(lit)-2]
			}
			return strings.TrimSpace(lit[2:])
		case token.EOF:
			return ""
		}
	}
}

func testTestDir(t *testing.T, path string, ignore ...string) {
	files, err := ioutil.ReadDir(path)
	if err != nil {
		t.Fatal(err)
	}

	excluded := make(map[string]bool)
	for _, filename := range ignore {
		excluded[filename] = true
	}

	fset := token.NewFileSet()
	for _, f := range files {
		// filter directory contents
		if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
			continue
		}

		// get per-file instructions
		expectErrors := false
		filename := filepath.Join(path, f.Name())
		if cmd := firstComment(filename); cmd != "" {
			switch cmd {
			case "skip", "compiledir":
				continue // ignore this file
			case "errorcheck":
				expectErrors = true
			}
		}

		// parse and type-check file
		file, err := parser.ParseFile(fset, filename, nil, 0)
		if err == nil {
			_, err = Check(filename, fset, []*ast.File{file})
		}

		if expectErrors {
			if err == nil {
				t.Errorf("expected errors but found none in %s", filename)
			}
		} else {
			if err != nil {
				t.Error(err)
			}
		}
	}
}

func TestStdTest(t *testing.T) {
	testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
		"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
		"sigchld.go",     // don't work on Windows; testTestDir should consult build tags
		"float_lit2.go",  // TODO(gri) 340282356779733661637539395458142568447 not representable as float32
	)
}

func TestStdFixed(t *testing.T) {
	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
		"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
		"bug459.go",    // possibly incorrect test - see issue 6703 (pending spec clarification)
		"issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification)
		"issue6889.go", // gc-specific test
	)
}

func TestStdKen(t *testing.T) {
	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
}

// Package paths of excluded packages.
var excluded = map[string]bool{
	"builtin": true,
}

// typecheck typechecks the given package files.
func typecheck(t *testing.T, path string, filenames []string) {
	fset := token.NewFileSet()

	// parse package files
	var files []*ast.File
	for _, filename := range filenames {
		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
		if err != nil {
			// the parser error may be a list of individual errors; report them all
			if list, ok := err.(scanner.ErrorList); ok {
				for _, err := range list {
					t.Error(err)
				}
				return
			}
			t.Error(err)
			return
		}

		if testing.Verbose() {
			if len(files) == 0 {
				fmt.Println("package", file.Name.Name)
			}
			fmt.Println("\t", filename)
		}

		files = append(files, file)
	}

	// typecheck package files
	var conf Config
	conf.Error = func(err error) { t.Error(err) }
	conf.Check(path, fset, files, nil)
	pkgCount++
}

// pkgFilenames returns the list of package filenames for the given directory.
func pkgFilenames(dir string) ([]string, error) {
	ctxt := build.Default
	ctxt.CgoEnabled = false
	pkg, err := ctxt.ImportDir(dir, 0)
	if err != nil {
		if _, nogo := err.(*build.NoGoError); nogo {
			return nil, nil // no *.go files, not an error
		}
		return nil, err
	}
	if excluded[pkg.ImportPath] {
		return nil, nil
	}
	var filenames []string
	for _, name := range pkg.GoFiles {
		filenames = append(filenames, filepath.Join(pkg.Dir, name))
	}
	for _, name := range pkg.TestGoFiles {
		filenames = append(filenames, filepath.Join(pkg.Dir, name))
	}
	return filenames, nil
}

// Note: Could use filepath.Walk instead of walkDirs but that wouldn't
//       necessarily be shorter or clearer after adding the code to
//       terminate early for -short tests.

func walkDirs(t *testing.T, dir string) {
	// limit run time for short tests
	if testing.Short() && time.Since(start) >= 750*time.Millisecond {
		return
	}

	fis, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Error(err)
		return
	}

	// typecheck package in directory
	files, err := pkgFilenames(dir)
	if err != nil {
		t.Error(err)
		return
	}
	if files != nil {
		typecheck(t, dir, files)
	}

	// traverse subdirectories, but don't walk into testdata
	for _, fi := range fis {
		if fi.IsDir() && fi.Name() != "testdata" {
			walkDirs(t, filepath.Join(dir, fi.Name()))
		}
	}
}
<commit_msg>go.tools/go/types: enable float_lit2.go test<commit_after>// Copyright 2013 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.

// This file tests types.Check by using it to
// typecheck the standard library and tests.

package types_test

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/scanner"
	"go/token"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	_ "code.google.com/p/go.tools/go/gcimporter"
	. "code.google.com/p/go.tools/go/types"
)

var (
	pkgCount int // number of packages processed
	start    = time.Now()
)

func TestStdlib(t *testing.T) {
	walkDirs(t, filepath.Join(runtime.GOROOT(), "src/pkg"))
	if testing.Verbose() {
		fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
	}
}

// firstComment returns the contents of the first comment in
// the given file, assuming there's one within the first KB.
func firstComment(filename string) string {
	f, err := os.Open(filename)
	if err != nil {
		return ""
	}
	defer f.Close()

	var src [1 << 10]byte // read at most 1KB
	n, _ := f.Read(src[:])

	var s scanner.Scanner
	s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments)
	for {
		_, tok, lit := s.Scan()
		switch tok {
		case token.COMMENT:
			// remove trailing */ of multi-line comment
			if lit[1] == '*' {
				lit = lit[:len(lit)-2]
			}
			return strings.TrimSpace(lit[2:])
		case token.EOF:
			return ""
		}
	}
}

func testTestDir(t *testing.T, path string, ignore ...string) {
	files, err := ioutil.ReadDir(path)
	if err != nil {
		t.Fatal(err)
	}

	excluded := make(map[string]bool)
	for _, filename := range ignore {
		excluded[filename] = true
	}

	fset := token.NewFileSet()
	for _, f := range files {
		// filter directory contents
		if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
			continue
		}

		// get per-file instructions
		expectErrors := false
		filename := filepath.Join(path, f.Name())
		if cmd := firstComment(filename); cmd != "" {
			switch cmd {
			case "skip", "compiledir":
				continue // ignore this file
			case "errorcheck":
				expectErrors = true
			}
		}

		// parse and type-check file
		file, err := parser.ParseFile(fset, filename, nil, 0)
		if err == nil {
			_, err = Check(filename, fset, []*ast.File{file})
		}

		if expectErrors {
			if err == nil {
				t.Errorf("expected errors but found none in %s", filename)
			}
		} else {
			if err != nil {
				t.Error(err)
			}
		}
	}
}

func TestStdTest(t *testing.T) {
	testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
		"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
		"sigchld.go",     // don't work on Windows; testTestDir should consult build tags
	)
}

func TestStdFixed(t *testing.T) {
	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
		"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
		"bug459.go",    // possibly incorrect test - see issue 6703 (pending spec clarification)
		"issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification)
		"issue6889.go", // gc-specific test
	)
}

func TestStdKen(t *testing.T) {
	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
}

// Package paths of excluded packages.
var excluded = map[string]bool{
	"builtin": true,
}

// typecheck typechecks the given package files.
func typecheck(t *testing.T, path string, filenames []string) {
	fset := token.NewFileSet()

	// parse package files
	var files []*ast.File
	for _, filename := range filenames {
		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
		if err != nil {
			// the parser error may be a list of individual errors; report them all
			if list, ok := err.(scanner.ErrorList); ok {
				for _, err := range list {
					t.Error(err)
				}
				return
			}
			t.Error(err)
			return
		}

		if testing.Verbose() {
			if len(files) == 0 {
				fmt.Println("package", file.Name.Name)
			}
			fmt.Println("\t", filename)
		}

		files = append(files, file)
	}

	// typecheck package files
	var conf Config
	conf.Error = func(err error) { t.Error(err) }
	conf.Check(path, fset, files, nil)
	pkgCount++
}

// pkgFilenames returns the list of package filenames for the given directory.
func pkgFilenames(dir string) ([]string, error) {
	ctxt := build.Default
	ctxt.CgoEnabled = false
	pkg, err := ctxt.ImportDir(dir, 0)
	if err != nil {
		if _, nogo := err.(*build.NoGoError); nogo {
			return nil, nil // no *.go files, not an error
		}
		return nil, err
	}
	if excluded[pkg.ImportPath] {
		return nil, nil
	}
	var filenames []string
	for _, name := range pkg.GoFiles {
		filenames = append(filenames, filepath.Join(pkg.Dir, name))
	}
	for _, name := range pkg.TestGoFiles {
		filenames = append(filenames, filepath.Join(pkg.Dir, name))
	}
	return filenames, nil
}

// Note: Could use filepath.Walk instead of walkDirs but that wouldn't
//       necessarily be shorter or clearer after adding the code to
//       terminate early for -short tests.

func walkDirs(t *testing.T, dir string) {
	// limit run time for short tests
	if testing.Short() && time.Since(start) >= 750*time.Millisecond {
		return
	}

	fis, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Error(err)
		return
	}

	// typecheck package in directory
	files, err := pkgFilenames(dir)
	if err != nil {
		t.Error(err)
		return
	}
	if files != nil {
		typecheck(t, dir, files)
	}

	// traverse subdirectories, but don't walk into testdata
	for _, fi := range fis {
		if fi.IsDir() && fi.Name() != "testdata" {
			walkDirs(t, filepath.Join(dir, fi.Name()))
		}
	}
}
<|endoftext|>