<commit_before>package peer

import (
	"bufio"
	"bytes"
	"crypto/sha1"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"sync"
	"time"

	"github.com/zeebo/bencode"

	"github.com/cenkalti/rain/internal/bitfield"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/piece"
	"github.com/cenkalti/rain/internal/protocol"
)

const connReadTimeout = 3 * time.Minute

const (
	Outgoing = iota
	Incoming
)

type Peer struct {
	conn net.Conn

	// Will be closed when peer disconnects
	Disconnected chan struct{}

	transfer   Transfer
	downloader Downloader
	uploader   Uploader

	amChoking      bool // this client is choking the peer
	amInterested   bool // this client is interested in the peer
	peerChoking    bool // peer is choking this client
	peerInterested bool // peer is interested in this client

	onceInterested sync.Once // for sending "interested" message only once

	// Protects "peerChoking" and broadcasts when an "unchoke" message is received.
	unchokeCond sync.Cond

	log logger.Logger
}

type Transfer interface {
	BitField() bitfield.BitField
	Pieces() []*piece.Piece
	Downloader() Downloader
	Uploader() Uploader
}

type Downloader interface {
	HaveC() chan *Have
	BlockC() chan *Block
}

type Uploader interface {
	RequestC() chan *Request
}

func New(conn net.Conn, direction int, t Transfer) *Peer {
	var arrow string
	switch direction {
	case Outgoing:
		arrow = "-> "
	case Incoming:
		arrow = "<- "
	}
	var m sync.Mutex
	return &Peer{
		conn:         conn,
		Disconnected: make(chan struct{}),
		transfer:     t,
		downloader:   t.Downloader(),
		uploader:     t.Uploader(),
		amChoking:    true,
		peerChoking:  true,
		unchokeCond:  sync.Cond{L: &m},
		log:          logger.New("peer " + arrow + conn.RemoteAddr().String()),
	}
}

// Serve processes incoming messages after handshake.
func (p *Peer) Serve() {
	defer close(p.Disconnected)
	p.log.Debugln("Communicating peer", p.conn.RemoteAddr())

	first := true
	for {
		err := p.conn.SetReadDeadline(time.Now().Add(connReadTimeout))
		if err != nil {
			p.log.Error(err)
			return
		}

		var length uint32
		p.log.Debug("Reading message...")
		err = binary.Read(p.conn, binary.BigEndian, &length)
		if err != nil {
			if err == io.EOF {
				p.log.Warning("Remote peer has closed the connection")
				return
			}
			p.log.Error(err)
			return
		}
		p.log.Debugf("Received message of length: %d", length)

		if length == 0 { // keep-alive message
			p.log.Debug("Received message of type \"keep alive\"")
			continue
		}

		var msgType protocol.MessageType
		err = binary.Read(p.conn, binary.BigEndian, &msgType)
		if err != nil {
			p.log.Error(err)
			return
		}
		length--

		p.log.Debugf("Received message of type %q", msgType)

		switch msgType {
		case protocol.Choke:
			p.unchokeCond.L.Lock()
			p.peerChoking = true
			p.unchokeCond.L.Unlock()
		case protocol.Unchoke:
			p.unchokeCond.L.Lock()
			p.peerChoking = false
			p.unchokeCond.Broadcast()
			p.unchokeCond.L.Unlock()
		case protocol.Interested:
			p.peerInterested = true
			if err := p.SendMessage(protocol.Unchoke); err != nil {
				p.log.Error(err)
				return
			}
		case protocol.NotInterested:
			p.peerInterested = false
		case protocol.Have:
			var i uint32
			err = binary.Read(p.conn, binary.BigEndian, &i)
			if err != nil {
				p.log.Error(err)
				return
			}
			if i >= uint32(len(p.transfer.Pieces())) {
				p.log.Error("unexpected piece index")
				return
			}
			p.log.Debug("Peer ", p.conn.RemoteAddr(), " has piece #", i)
			p.downloader.HaveC() <- &Have{p, p.transfer.Pieces()[i]}
		case protocol.Bitfield:
			if !first {
				p.log.Error("bitfield can only be sent after handshake")
				return
			}

			if int64(length) != int64(len(p.transfer.BitField().Bytes())) {
				p.log.Error("invalid bitfield length")
				return
			}

			bf := bitfield.New(p.transfer.BitField().Len())
			_, err = p.conn.Read(bf.Bytes())
			if err != nil {
				p.log.Error(err)
				return
			}
			p.log.Debugln("Received bitfield:", bf.Hex())

			for i := uint32(0); i < bf.Len(); i++ {
				if bf.Test(i) {
					p.downloader.HaveC() <- &Have{p, p.transfer.Pieces()[i]}
				}
			}
		case protocol.Request:
			var req requestMessage
			err = binary.Read(p.conn, binary.BigEndian, &req)
			if err != nil {
				p.log.Error(err)
				return
			}
			p.log.Debugf("Request: %#v", req)

			if req.Index >= uint32(len(p.transfer.Pieces())) {
				p.log.Error("invalid request: index")
				return
			}
			requestedPiece := p.transfer.Pieces()[req.Index]
			if req.Begin >= requestedPiece.Length() {
				p.log.Error("invalid request: begin")
				return
			}
			if req.Length > protocol.MaxAllowedBlockSize {
				p.log.Error("received a request with block size larger than allowed")
				return
			}
			if req.Begin+req.Length > requestedPiece.Length() {
				p.log.Error("invalid request: length")
			}

			p.uploader.RequestC() <- &Request{p, requestedPiece, req.Begin, req.Length}
		case protocol.Piece:
			var msg pieceMessage
			err = binary.Read(p.conn, binary.BigEndian, &msg)
			if err != nil {
				p.log.Error(err)
				return
			}
			if msg.Index >= uint32(len(p.transfer.Pieces())) {
				p.log.Error("unexpected piece index")
				return
			}
			receivedPiece := p.transfer.Pieces()[msg.Index]
			if msg.Begin%protocol.BlockSize != 0 {
				p.log.Error("unexpected piece offset")
				return
			}
			blockIndex := msg.Begin / protocol.BlockSize
			if blockIndex >= uint32(len(receivedPiece.Blocks())) {
				p.log.Error("unexpected piece offset")
				return
			}
			block := &receivedPiece.Blocks()[blockIndex]
			length -= 8
			if length != block.Length() {
				p.log.Error("unexpected block size")
				return
			}
			data := make([]byte, length)
			_, err = io.ReadFull(p.conn, data)
			if err != nil {
				p.log.Error(err)
				return
			}
			p.downloader.BlockC() <- &Block{p, receivedPiece, block, data}
		case protocol.Cancel:
		case protocol.Port:
		default:
			p.log.Debugf("Unknown message type: %d", msgType)
			p.log.Debugln("Discarding", length, "bytes...")
			io.CopyN(ioutil.Discard, p.conn, int64(length))
			p.log.Debug("Discarding finished.")
		}

		first = false
	}
}

func (p *Peer) SendBitField() error {
	// Do not send a bitfield message if we don't have any pieces.
	if p.transfer.BitField().Count() == 0 {
		return nil
	}

	buf := bytes.NewBuffer(make([]byte, 0, 5+len(p.transfer.BitField().Bytes())))

	err := binary.Write(buf, binary.BigEndian, uint32(1+len(p.transfer.BitField().Bytes())))
	if err != nil {
		return err
	}
	if err = buf.WriteByte(byte(protocol.Bitfield)); err != nil {
		return err
	}
	if _, err = buf.Write(p.transfer.BitField().Bytes()); err != nil {
		return err
	}
	p.log.Debugf("Sending message: \"bitfield\" %#v", buf.Bytes())
	_, err = buf.WriteTo(p.conn)
	return err
}

// beInterested sends "interested" message to peer (once) and
// returns a channel that will be closed when an "unchoke" message is received.
func (p *Peer) beInterested() error {
	p.log.Debug("beInterested")

	var err error
	p.onceInterested.Do(func() { err = p.SendMessage(protocol.Interested) })
	if err != nil {
		return err
	}

	var disconnected bool
	checkDisconnect := func() {
		select {
		case <-p.Disconnected:
			disconnected = true
		default:
		}
	}

	p.unchokeCond.L.Lock()
	for checkDisconnect(); p.peerChoking && !disconnected; {
		p.unchokeCond.Wait()
	}
	p.unchokeCond.L.Unlock()

	if disconnected {
		return errors.New("peer disconnected while waiting for unchoke message")
	}

	return nil
}

func (p *Peer) SendMessage(msgType protocol.MessageType) error {
	var msg = struct {
		Length      uint32
		MessageType protocol.MessageType
	}{1, msgType}
	p.log.Debugf("Sending message: %q", msgType)
	return binary.Write(p.conn, binary.BigEndian, &msg)
}

func (p *Peer) sendExtensionMessage(id byte, payload []byte) error {
	msg := struct {
		Length      uint32
		BTID        byte
		ExtensionID byte
	}{
		Length:      uint32(len(payload)) + 2,
		BTID:        protocol.Extension,
		ExtensionID: id,
	}

	buf := bytes.NewBuffer(make([]byte, 0, 6+len(payload)))
	err := binary.Write(buf, binary.BigEndian, msg)
	if err != nil {
		return err
	}

	_, err = buf.Write(payload)
	if err != nil {
		return err
	}

	return binary.Write(p.conn, binary.BigEndian, buf.Bytes())
}

type ExtensionHandshakeMessage struct {
	M            map[string]uint8 `bencode:"m"`
	MetadataSize uint32           `bencode:"metadata_size,omitempty"`
}

func (p *Peer) SendExtensionHandshake(m *ExtensionHandshakeMessage) error {
	const extensionHandshakeID = 0
	var buf bytes.Buffer
	e := bencode.NewEncoder(&buf)
	err := e.Encode(m)
	if err != nil {
		return err
	}
	return p.sendExtensionMessage(extensionHandshakeID, buf.Bytes())
}

type peerRequestMessage struct {
	ID                   protocol.MessageType
	Index, Begin, Length uint32
}

func newRequestMessage(index, begin, length uint32) *peerRequestMessage {
	return &peerRequestMessage{protocol.Request, index, begin, length}
}

func (p *Peer) sendRequest(m *peerRequestMessage) error {
	var msg = struct {
		Length  uint32
		Message peerRequestMessage
	}{13, *m}
	p.log.Debugf("Sending message: %q %#v", "request", msg)
	return binary.Write(p.conn, binary.BigEndian, &msg)
}

func (p *Peer) DownloadPiece(piece *piece.Piece) error {
	p.log.Debugf("downloading piece #%d", piece.Index())

	err := p.beInterested()
	if err != nil {
		return err
	}

	for _, b := range piece.Blocks() {
		if err := p.sendRequest(newRequestMessage(piece.Index(), b.Index()*protocol.BlockSize, b.Length())); err != nil {
			return err
		}
	}

	pieceData := make([]byte, piece.Length())
	for _ = range piece.Blocks() {
		select {
		case peerBlock := <-p.downloader.BlockC():
			p.log.Debugln("received block of length", len(peerBlock.Data))
			copy(pieceData[peerBlock.Block.Index()*protocol.BlockSize:], peerBlock.Data)
			if _, err = peerBlock.Block.Write(peerBlock.Data); err != nil {
				return err
			}
			piece.BitField().Set(peerBlock.Block.Index())
		case <-time.After(time.Minute):
			return fmt.Errorf("peer did not send piece #%d completely", piece.Index())
		}
	}

	// Verify piece hash
	hash := sha1.New()
	hash.Write(pieceData)
	if !bytes.Equal(hash.Sum(nil), piece.Hash()) {
		return errors.New("received corrupt piece")
	}
	return nil
}

func (p *Peer) SendPiece(index, begin uint32, block []byte) error {

	// TODO not here
	if err := p.SendMessage(protocol.Unchoke); err != nil {
		return err
	}

	buf := bufio.NewWriterSize(p.conn, int(13+len(block)))
	msgLen := 9 + uint32(len(block))
	if err := binary.Write(buf, binary.BigEndian, msgLen); err != nil {
		return err
	}
	buf.WriteByte(byte(protocol.Piece))
	if err := binary.Write(buf, binary.BigEndian, index); err != nil {
		return err
	}
	if err := binary.Write(buf, binary.BigEndian, begin); err != nil {
		return err
	}
	buf.Write(block)
	return buf.Flush()
}

type Have struct {
	Peer  *Peer
	Piece *piece.Piece
}

type Block struct {
	Peer  *Peer
	Piece *piece.Piece
	Block *piece.Block
	Data  []byte
}

type Request struct {
	Peer   *Peer
	Piece  *piece.Piece
	Begin  uint32
	Length uint32
}

type requestMessage struct {
	Index, Begin, Length uint32
}

type pieceMessage struct {
	Index, Begin uint32
}
<commit_msg>refactor<commit_after>package peer

import (
	"bufio"
	"bytes"
	"crypto/sha1"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"sync"
	"time"

	"github.com/zeebo/bencode"

	"github.com/cenkalti/rain/internal/bitfield"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/piece"
	"github.com/cenkalti/rain/internal/protocol"
)

const connReadTimeout = 3 * time.Minute

const (
	Outgoing = iota
	Incoming
)

type Peer struct {
	conn net.Conn

	// Will be closed when peer disconnects
	Disconnected chan struct{}

	transfer   Transfer
	downloader Downloader
	uploader   Uploader

	amChoking      bool // this client is choking the peer
	amInterested   bool // this client is interested in the peer
	peerChoking    bool // peer is choking this client
	peerInterested bool // peer is interested in this client

	onceInterested sync.Once // for sending "interested" message only once

	// Protects "peerChoking" and broadcasts when an "unchoke" message is received.
	unchokeCond sync.Cond

	log logger.Logger
}

type Transfer interface {
	BitField() bitfield.BitField
	Pieces() []*piece.Piece
	Downloader() Downloader
	Uploader() Uploader
}

type Downloader interface {
	HaveC() chan *Have
	BlockC() chan *Block
}

type Uploader interface {
	RequestC() chan *Request
}

type Have struct {
	Peer  *Peer
	Piece *piece.Piece
}

type Block struct {
	Peer  *Peer
	Piece *piece.Piece
	Block *piece.Block
	Data  []byte
}

type Request struct {
	Peer   *Peer
	Piece  *piece.Piece
	Begin  uint32
	Length uint32
}

func New(conn net.Conn, direction int, t Transfer) *Peer {
	var arrow string
	switch direction {
	case Outgoing:
		arrow = "-> "
	case Incoming:
		arrow = "<- "
	}
	var m sync.Mutex
	return &Peer{
		conn:         conn,
		Disconnected: make(chan struct{}),
		transfer:     t,
		downloader:   t.Downloader(),
		uploader:     t.Uploader(),
		amChoking:    true,
		peerChoking:  true,
		unchokeCond:  sync.Cond{L: &m},
		log:          logger.New("peer " + arrow + conn.RemoteAddr().String()),
	}
}

// Serve processes incoming messages after handshake.
func (p *Peer) Serve() {
	defer close(p.Disconnected)
	p.log.Debugln("Communicating peer", p.conn.RemoteAddr())

	first := true
	for {
		err := p.conn.SetReadDeadline(time.Now().Add(connReadTimeout))
		if err != nil {
			p.log.Error(err)
			return
		}

		var length uint32
		p.log.Debug("Reading message...")
		err = binary.Read(p.conn, binary.BigEndian, &length)
		if err != nil {
			if err == io.EOF {
				p.log.Warning("Remote peer has closed the connection")
				return
			}
			p.log.Error(err)
			return
		}
		p.log.Debugf("Received message of length: %d", length)

		if length == 0 { // keep-alive message
			p.log.Debug("Received message of type \"keep alive\"")
			continue
		}

		var msgType protocol.MessageType
		err = binary.Read(p.conn, binary.BigEndian, &msgType)
		if err != nil {
			p.log.Error(err)
			return
		}
		length--

		p.log.Debugf("Received message of type %q", msgType)

		switch msgType {
		case protocol.Choke:
			p.unchokeCond.L.Lock()
			p.peerChoking = true
			p.unchokeCond.L.Unlock()
		case protocol.Unchoke:
			p.unchokeCond.L.Lock()
			p.peerChoking = false
			p.unchokeCond.Broadcast()
			p.unchokeCond.L.Unlock()
		case protocol.Interested:
			p.peerInterested = true
			if err := p.SendMessage(protocol.Unchoke); err != nil {
				p.log.Error(err)
				return
			}
		case protocol.NotInterested:
			p.peerInterested = false
		case protocol.Have:
			var i uint32
			err = binary.Read(p.conn, binary.BigEndian, &i)
			if err != nil {
				p.log.Error(err)
				return
			}
			if i >= uint32(len(p.transfer.Pieces())) {
				p.log.Error("unexpected piece index")
				return
			}
			p.log.Debug("Peer ", p.conn.RemoteAddr(), " has piece #", i)
			p.downloader.HaveC() <- &Have{p, p.transfer.Pieces()[i]}
		case protocol.Bitfield:
			if !first {
				p.log.Error("bitfield can only be sent after handshake")
				return
			}

			if int64(length) != int64(len(p.transfer.BitField().Bytes())) {
				p.log.Error("invalid bitfield length")
				return
			}

			bf := bitfield.New(p.transfer.BitField().Len())
			_, err = p.conn.Read(bf.Bytes())
			if err != nil {
				p.log.Error(err)
				return
			}
			p.log.Debugln("Received bitfield:", bf.Hex())

			for i := uint32(0); i < bf.Len(); i++ {
				if bf.Test(i) {
					p.downloader.HaveC() <- &Have{p, p.transfer.Pieces()[i]}
				}
			}
		case protocol.Request:
			var req requestMessage
			err = binary.Read(p.conn, binary.BigEndian, &req)
			if err != nil {
				p.log.Error(err)
				return
			}
			p.log.Debugf("Request: %#v", req)

			if req.Index >= uint32(len(p.transfer.Pieces())) {
				p.log.Error("invalid request: index")
				return
			}
			requestedPiece := p.transfer.Pieces()[req.Index]
			if req.Begin >= requestedPiece.Length() {
				p.log.Error("invalid request: begin")
				return
			}
			if req.Length > protocol.MaxAllowedBlockSize {
				p.log.Error("received a request with block size larger than allowed")
				return
			}
			if req.Begin+req.Length > requestedPiece.Length() {
				p.log.Error("invalid request: length")
			}

			p.uploader.RequestC() <- &Request{p, requestedPiece, req.Begin, req.Length}
		case protocol.Piece:
			var msg pieceMessage
			err = binary.Read(p.conn, binary.BigEndian, &msg)
			if err != nil {
				p.log.Error(err)
				return
			}
			if msg.Index >= uint32(len(p.transfer.Pieces())) {
				p.log.Error("unexpected piece index")
				return
			}
			receivedPiece := p.transfer.Pieces()[msg.Index]
			if msg.Begin%protocol.BlockSize != 0 {
				p.log.Error("unexpected piece offset")
				return
			}
			blockIndex := msg.Begin / protocol.BlockSize
			if blockIndex >= uint32(len(receivedPiece.Blocks())) {
				p.log.Error("unexpected piece offset")
				return
			}
			block := &receivedPiece.Blocks()[blockIndex]
			length -= 8
			if length != block.Length() {
				p.log.Error("unexpected block size")
				return
			}
			data := make([]byte, length)
			_, err = io.ReadFull(p.conn, data)
			if err != nil {
				p.log.Error(err)
				return
			}
			p.downloader.BlockC() <- &Block{p, receivedPiece, block, data}
		case protocol.Cancel:
		case protocol.Port:
		default:
			p.log.Debugf("Unknown message type: %d", msgType)
			p.log.Debugln("Discarding", length, "bytes...")
			io.CopyN(ioutil.Discard, p.conn, int64(length))
			p.log.Debug("Discarding finished.")
		}

		first = false
	}
}

func (p *Peer) SendBitField() error {
	// Do not send a bitfield message if we don't have any pieces.
	if p.transfer.BitField().Count() == 0 {
		return nil
	}

	buf := bytes.NewBuffer(make([]byte, 0, 5+len(p.transfer.BitField().Bytes())))

	err := binary.Write(buf, binary.BigEndian, uint32(1+len(p.transfer.BitField().Bytes())))
	if err != nil {
		return err
	}
	if err = buf.WriteByte(byte(protocol.Bitfield)); err != nil {
		return err
	}
	if _, err = buf.Write(p.transfer.BitField().Bytes()); err != nil {
		return err
	}
	p.log.Debugf("Sending message: \"bitfield\" %#v", buf.Bytes())
	_, err = buf.WriteTo(p.conn)
	return err
}

// beInterested sends "interested" message to peer (once) and
// returns a channel that will be closed when an "unchoke" message is received.
func (p *Peer) beInterested() error {
	p.log.Debug("beInterested")

	var err error
	p.onceInterested.Do(func() { err = p.SendMessage(protocol.Interested) })
	if err != nil {
		return err
	}

	var disconnected bool
	checkDisconnect := func() {
		select {
		case <-p.Disconnected:
			disconnected = true
		default:
		}
	}

	p.unchokeCond.L.Lock()
	for checkDisconnect(); p.peerChoking && !disconnected; {
		p.unchokeCond.Wait()
	}
	p.unchokeCond.L.Unlock()

	if disconnected {
		return errors.New("peer disconnected while waiting for unchoke message")
	}

	return nil
}

func (p *Peer) SendMessage(msgType protocol.MessageType) error {
	var msg = struct {
		Length      uint32
		MessageType protocol.MessageType
	}{1, msgType}
	p.log.Debugf("Sending message: %q", msgType)
	return binary.Write(p.conn, binary.BigEndian, &msg)
}

func (p *Peer) sendExtensionMessage(id byte, payload []byte) error {
	msg := struct {
		Length      uint32
		BTID        byte
		ExtensionID byte
	}{
		Length:      uint32(len(payload)) + 2,
		BTID:        protocol.Extension,
		ExtensionID: id,
	}

	buf := bytes.NewBuffer(make([]byte, 0, 6+len(payload)))
	err := binary.Write(buf, binary.BigEndian, msg)
	if err != nil {
		return err
	}

	_, err = buf.Write(payload)
	if err != nil {
		return err
	}

	return binary.Write(p.conn, binary.BigEndian, buf.Bytes())
}

type ExtensionHandshakeMessage struct {
	M            map[string]uint8 `bencode:"m"`
	MetadataSize uint32           `bencode:"metadata_size,omitempty"`
}

func (p *Peer) SendExtensionHandshake(m *ExtensionHandshakeMessage) error {
	const extensionHandshakeID = 0
	var buf bytes.Buffer
	e := bencode.NewEncoder(&buf)
	err := e.Encode(m)
	if err != nil {
		return err
	}
	return p.sendExtensionMessage(extensionHandshakeID, buf.Bytes())
}

type peerRequestMessage struct {
	ID                   protocol.MessageType
	Index, Begin, Length uint32
}

func newRequestMessage(index, begin, length uint32) *peerRequestMessage {
	return &peerRequestMessage{protocol.Request, index, begin, length}
}

func (p *Peer) sendRequest(m *peerRequestMessage) error {
	var msg = struct {
		Length  uint32
		Message peerRequestMessage
	}{13, *m}
	p.log.Debugf("Sending message: %q %#v", "request", msg)
	return binary.Write(p.conn, binary.BigEndian, &msg)
}

func (p *Peer) DownloadPiece(piece *piece.Piece) error {
	p.log.Debugf("downloading piece #%d", piece.Index())

	err := p.beInterested()
	if err != nil {
		return err
	}

	for _, b := range piece.Blocks() {
		if err := p.sendRequest(newRequestMessage(piece.Index(), b.Index()*protocol.BlockSize, b.Length())); err != nil {
			return err
		}
	}

	pieceData := make([]byte, piece.Length())
	for _ = range piece.Blocks() {
		select {
		case peerBlock := <-p.downloader.BlockC():
			p.log.Debugln("received block of length", len(peerBlock.Data))
			copy(pieceData[peerBlock.Block.Index()*protocol.BlockSize:], peerBlock.Data)
			if _, err = peerBlock.Block.Write(peerBlock.Data); err != nil {
				return err
			}
			piece.BitField().Set(peerBlock.Block.Index())
		case <-time.After(time.Minute):
			return fmt.Errorf("peer did not send piece #%d completely", piece.Index())
		}
	}

	// Verify piece hash
	hash := sha1.Sum(pieceData)
	if !bytes.Equal(hash[:], piece.Hash()) {
		return errors.New("received corrupt piece")
	}
	return nil
}

func (p *Peer) SendPiece(index, begin uint32, block []byte) error {

	// TODO not here
	if err := p.SendMessage(protocol.Unchoke); err != nil {
		return err
	}

	buf := bufio.NewWriterSize(p.conn, int(13+len(block)))
	msgLen := 9 + uint32(len(block))
	if err := binary.Write(buf, binary.BigEndian, msgLen); err != nil {
		return err
	}
	buf.WriteByte(byte(protocol.Piece))
	if err := binary.Write(buf, binary.BigEndian, index); err != nil {
		return err
	}
	if err := binary.Write(buf, binary.BigEndian, begin); err != nil {
		return err
	}
	buf.Write(block)
	return buf.Flush()
}

type requestMessage struct {
	Index, Begin, Length uint32
}

type pieceMessage struct {
	Index, Begin uint32
}
<|endoftext|>


<commit_before>package pool

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"gopkg.in/bsm/ratelimit.v1"

	"gopkg.in/pg.v4/internal"
)

var (
	ErrClosed      = errors.New("pg: database is closed")
	ErrPoolTimeout = errors.New("pg: connection pool timeout")
	errConnStale   = errors.New("connection is stale")
)

var timers = sync.Pool{
	New: func() interface{} {
		return time.NewTimer(0)
	},
}

// PoolStats contains pool state information and accumulated stats.
type PoolStats struct {
	Requests uint32 // number of times a connection was requested by the pool
	Hits     uint32 // number of times free connection was found in the pool
	Timeouts uint32 // number of times a wait timeout occurred

	TotalConns uint32 // the number of total connections in the pool
	FreeConns  uint32 // the number of free connections in the pool
}

type Pooler interface {
	Get() (*Conn, error)
	Put(*Conn) error
	Remove(*Conn, error) error
	Len() int
	FreeLen() int
	Stats() *PoolStats
	Close() error
	Closed() bool
}

type dialer func() (net.Conn, error)

type ConnPool struct {
	_dial       dialer
	DialLimiter *ratelimit.RateLimiter
	OnClose     func(*Conn) error

	poolTimeout time.Duration
	idleTimeout time.Duration

	queue chan struct{}

	connsMu sync.Mutex
	conns   []*Conn

	freeConnsMu sync.Mutex
	freeConns   []*Conn

	stats PoolStats

	_closed int32 // atomic
	lastErr atomic.Value
}

var _ Pooler = (*ConnPool)(nil)

func NewConnPool(dial dialer, poolSize int, poolTimeout, idleTimeout, idleCheckFrequency time.Duration) *ConnPool {
	p := &ConnPool{
		_dial:       dial,
		DialLimiter: ratelimit.New(3*poolSize, time.Second),

		poolTimeout: poolTimeout,
		idleTimeout: idleTimeout,

		queue:     make(chan struct{}, poolSize),
		conns:     make([]*Conn, 0, poolSize),
		freeConns: make([]*Conn, 0, poolSize),
	}
	for i := 0; i < poolSize; i++ {
		p.queue <- struct{}{}
	}
	if idleTimeout > 0 && idleCheckFrequency > 0 {
		go p.reaper(idleCheckFrequency)
	}
	return p
}

func (p *ConnPool) dial() (net.Conn, error) {
	if p.DialLimiter != nil && p.DialLimiter.Limit() {
		err := fmt.Errorf(
			"pg: you open connections too fast (last_error=%q)",
			p.loadLastErr(),
		)
		return nil, err
	}

	cn, err := p._dial()
	if err != nil {
		p.storeLastErr(err.Error())
		return nil, err
	}
	return cn, nil
}

func (p *ConnPool) NewConn() (*Conn, error) {
	netConn, err := p.dial()
	if err != nil {
		return nil, err
	}
	return NewConn(netConn), nil
}

func (p *ConnPool) PopFree() *Conn {
	timer := timers.Get().(*time.Timer)
	if !timer.Reset(p.poolTimeout) {
		<-timer.C
	}

	select {
	case <-p.queue:
		timers.Put(timer)
	case <-timer.C:
		timers.Put(timer)
		atomic.AddUint32(&p.stats.Timeouts, 1)
		return nil
	}

	p.freeConnsMu.Lock()
	cn := p.popFree()
	p.freeConnsMu.Unlock()

	if cn == nil {
		p.queue <- struct{}{}
	}
	return cn
}

func (p *ConnPool) popFree() *Conn {
	if len(p.freeConns) == 0 {
		return nil
	}

	idx := len(p.freeConns) - 1
	cn := p.freeConns[idx]
	p.freeConns = p.freeConns[:idx]
	return cn
}

// Get returns existed connection from the pool or creates a new one.
func (p *ConnPool) Get() (*Conn, error) {
	if p.Closed() {
		return nil, ErrClosed
	}

	atomic.AddUint32(&p.stats.Requests, 1)

	timer := timers.Get().(*time.Timer)
	if !timer.Reset(p.poolTimeout) {
		<-timer.C
	}

	select {
	case <-p.queue:
		timers.Put(timer)
	case <-timer.C:
		timers.Put(timer)
		atomic.AddUint32(&p.stats.Timeouts, 1)
		return nil, ErrPoolTimeout
	}

	p.freeConnsMu.Lock()
	cn := p.popFree()
	p.freeConnsMu.Unlock()

	if cn != nil {
		atomic.AddUint32(&p.stats.Hits, 1)
		if !cn.IsStale(p.idleTimeout) {
			return cn, nil
		}
		_ = p.closeConn(cn, errConnStale)
	}

	newcn, err := p.NewConn()
	if err != nil {
		p.queue <- struct{}{}
		return nil, err
	}

	p.connsMu.Lock()
	if cn != nil {
		p.removeConn(cn)
	}
	p.conns = append(p.conns, newcn)
	p.connsMu.Unlock()

	return newcn, nil
}

func (p *ConnPool) Put(cn *Conn) error {
	if e := cn.CheckHealth(); e != nil {
		internal.Logf(e.Error())
		return p.Remove(cn, e)
	}
	p.freeConnsMu.Lock()
	p.freeConns = append(p.freeConns, cn)
	p.freeConnsMu.Unlock()
	p.queue <- struct{}{}
	return nil
}

func (p *ConnPool) Remove(cn *Conn, reason error) error {
	p.remove(cn, reason)
	p.queue <- struct{}{}
	return nil
}

func (p *ConnPool) remove(cn *Conn, reason error) {
	_ = p.closeConn(cn, reason)

	p.connsMu.Lock()
	p.removeConn(cn)
	p.connsMu.Unlock()
}

func (p *ConnPool) removeConn(cn *Conn) {
	for i, c := range p.conns {
		if c == cn {
			p.conns = append(p.conns[:i], p.conns[i+1:]...)
			break
		}
	}
}

// Len returns total number of connections.
func (p *ConnPool) Len() int {
	p.connsMu.Lock()
	l := len(p.conns)
	p.connsMu.Unlock()
	return l
}

// FreeLen returns number of free connections.
func (p *ConnPool) FreeLen() int {
	p.freeConnsMu.Lock()
	l := len(p.freeConns)
	p.freeConnsMu.Unlock()
	return l
}

func (p *ConnPool) Stats() *PoolStats {
	stats := PoolStats{}
	stats.Requests = atomic.LoadUint32(&p.stats.Requests)
	stats.Hits = atomic.LoadUint32(&p.stats.Hits)
	stats.Timeouts = atomic.LoadUint32(&p.stats.Timeouts)
	stats.TotalConns = uint32(p.Len())
	stats.FreeConns = uint32(p.FreeLen())
	return &stats
}

func (p *ConnPool) Closed() bool {
	return atomic.LoadInt32(&p._closed) == 1
}

func (p *ConnPool) Close() (retErr error) {
	if !atomic.CompareAndSwapInt32(&p._closed, 0, 1) {
		return ErrClosed
	}

	p.connsMu.Lock()
	// Close all connections.
	for _, cn := range p.conns {
		if cn == nil {
			continue
		}
		if err := p.closeConn(cn, ErrClosed); err != nil && retErr == nil {
			retErr = err
		}
	}
	p.conns = nil
	p.connsMu.Unlock()

	p.freeConnsMu.Lock()
	p.freeConns = nil
	p.freeConnsMu.Unlock()

	return retErr
}

func (p *ConnPool) closeConn(cn *Conn, reason error) error {
	p.storeLastErr(reason.Error())
	if p.OnClose != nil {
		_ = p.OnClose(cn)
	}
	return cn.Close()
}

func (p *ConnPool) reapStaleConn() bool {
	if len(p.freeConns) == 0 {
		return false
	}

	cn := p.freeConns[0]
	if !cn.IsStale(p.idleTimeout) {
		return false
	}

	p.remove(cn, errConnStale)
	p.freeConns = append(p.freeConns[:0], p.freeConns[1:]...)

	return true
}

func (p *ConnPool) ReapStaleConns() (int, error) {
	var n int
	for {
		<-p.queue
		p.freeConnsMu.Lock()

		reaped := p.reapStaleConn()

		p.freeConnsMu.Unlock()
		p.queue <- struct{}{}

		if reaped {
			n++
		} else {
			break
		}
	}
	return n, nil
}

func (p *ConnPool) reaper(frequency time.Duration) {
	ticker := time.NewTicker(frequency)
	defer ticker.Stop()

	for _ = range ticker.C {
		if p.Closed() {
			break
		}
		n, err := p.ReapStaleConns()
		if err != nil {
			internal.Logf("ReapStaleConns failed: %s", err)
			continue
		}
		s := p.Stats()
		internal.Logf(
			"reaper: removed %d stale conns (TotalConns=%d FreeConns=%d Requests=%d Hits=%d Timeouts=%d)",
			n, s.TotalConns, s.FreeConns, s.Requests, s.Hits, s.Timeouts,
		)
	}
}

func (p *ConnPool) storeLastErr(err string) {
	p.lastErr.Store(err)
}

func (p *ConnPool) loadLastErr() string {
	if v := p.lastErr.Load(); v != nil {
		return v.(string)
	}
	return ""
}

//------------------------------------------------------------------------------

var idleCheckFrequency atomic.Value

func SetIdleCheckFrequency(d time.Duration) {
	idleCheckFrequency.Store(d)
}

func getIdleCheckFrequency() time.Duration {
	v := idleCheckFrequency.Load()
	if v == nil {
		return time.Minute
	}
	return v.(time.Duration)
}
<commit_msg>internal/pool: more idiomatic work with channels.<commit_after>package pool

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"sync/atomic"
	"time"

	"gopkg.in/bsm/ratelimit.v1"

	"gopkg.in/pg.v4/internal"
)

var (
	ErrClosed      = errors.New("pg: database is closed")
	ErrPoolTimeout = errors.New("pg: connection pool timeout")
	errConnStale   = errors.New("connection is stale")
)

var timers = sync.Pool{
	New: func() interface{} {
		return time.NewTimer(0)
	},
}

// PoolStats contains pool state information and accumulated stats.
type PoolStats struct {
	Requests uint32 // number of times a connection was requested by the pool
	Hits     uint32 // number of times free connection was found in the pool
	Timeouts uint32 // number of times a wait timeout occurred

	TotalConns uint32 // the number of total connections in the pool
	FreeConns  uint32 // the number of free connections in the pool
}

type Pooler interface {
	Get() (*Conn, error)
	Put(*Conn) error
	Remove(*Conn, error) error
	Len() int
	FreeLen() int
	Stats() *PoolStats
	Close() error
	Closed() bool
}

type dialer func() (net.Conn, error)

type ConnPool struct {
	_dial       dialer
	DialLimiter *ratelimit.RateLimiter
	OnClose     func(*Conn) error

	poolTimeout time.Duration
	idleTimeout time.Duration

	queue chan struct{}

	connsMu sync.Mutex
	conns   []*Conn

	freeConnsMu sync.Mutex
	freeConns   []*Conn

	stats PoolStats

	_closed int32 // atomic
	lastErr atomic.Value
}

var _ Pooler = (*ConnPool)(nil)

func NewConnPool(dial dialer, poolSize int, poolTimeout, idleTimeout, idleCheckFrequency time.Duration) *ConnPool {
	p := &ConnPool{
		_dial:       dial,
		DialLimiter: ratelimit.New(3*poolSize, time.Second),

		poolTimeout: poolTimeout,
		idleTimeout: idleTimeout,

		queue:     make(chan struct{}, poolSize),
		conns:     make([]*Conn, 0, poolSize),
		freeConns: make([]*Conn, 0, poolSize),
	}
	if idleTimeout > 0 && idleCheckFrequency > 0 {
		go p.reaper(idleCheckFrequency)
	}
	return p
}

func (p *ConnPool) dial() (net.Conn, error) {
	if p.DialLimiter != nil && p.DialLimiter.Limit() {
		err := fmt.Errorf(
			"pg: you open connections too fast (last_error=%q)",
			p.loadLastErr(),
		)
		return nil, err
	}

	cn, err := p._dial()
	if err != nil {
		p.storeLastErr(err.Error())
		return nil, err
	}
	return cn, nil
}

func (p *ConnPool) NewConn() (*Conn, error) {
	netConn, err := p.dial()
	if err != nil {
		return nil, err
	}
	return NewConn(netConn), nil
}

func (p *ConnPool) PopFree() *Conn {
	timer := timers.Get().(*time.Timer)
	if !timer.Reset(p.poolTimeout) {
		<-timer.C
	}

	select {
	case p.queue <- struct{}{}:
		timers.Put(timer)
	case <-timer.C:
		timers.Put(timer)
		atomic.AddUint32(&p.stats.Timeouts, 1)
		return nil
	}

	p.freeConnsMu.Lock()
	cn := p.popFree()
	p.freeConnsMu.Unlock()

	if cn == nil {
		<-p.queue
	}
	return cn
}

func (p *ConnPool) popFree() *Conn {
	if len(p.freeConns) == 0 {
		return nil
	}

	idx := len(p.freeConns) - 1
	cn := p.freeConns[idx]
	p.freeConns = p.freeConns[:idx]
	return cn
}

// Get returns existed connection from the pool or creates a new one.
func (p *ConnPool) Get() (*Conn, error) {
	if p.Closed() {
		return nil, ErrClosed
	}

	atomic.AddUint32(&p.stats.Requests, 1)

	timer := timers.Get().(*time.Timer)
	if !timer.Reset(p.poolTimeout) {
		<-timer.C
	}

	select {
	case p.queue <- struct{}{}:
		timers.Put(timer)
	case <-timer.C:
		timers.Put(timer)
		atomic.AddUint32(&p.stats.Timeouts, 1)
		return nil, ErrPoolTimeout
	}

	p.freeConnsMu.Lock()
	cn := p.popFree()
	p.freeConnsMu.Unlock()

	if cn != nil {
		atomic.AddUint32(&p.stats.Hits, 1)
		if !cn.IsStale(p.idleTimeout) {
			return cn, nil
		}
		_ = p.closeConn(cn, errConnStale)
	}

	newcn, err := p.NewConn()
	if err != nil {
		<-p.queue
		return nil, err
	}

	p.connsMu.Lock()
	if cn != nil {
		p.removeConn(cn)
	}
	p.conns = append(p.conns, newcn)
	p.connsMu.Unlock()

	return newcn, nil
}

func (p *ConnPool) Put(cn *Conn) error {
	if e := cn.CheckHealth(); e != nil {
		internal.Logf(e.Error())
		return p.Remove(cn, e)
	}
	p.freeConnsMu.Lock()
	p.freeConns = append(p.freeConns, cn)
	p.freeConnsMu.Unlock()
	<-p.queue
	return nil
}

func (p *ConnPool) Remove(cn *Conn, reason error) error {
	p.remove(cn, reason)
	<-p.queue
	return nil
}

func (p *ConnPool) remove(cn *Conn, reason error) {
	_ = p.closeConn(cn, reason)

	p.connsMu.Lock()
	p.removeConn(cn)
	p.connsMu.Unlock()
}

func (p *ConnPool) removeConn(cn *Conn) {
	for i, c := range p.conns {
		if c == cn {
			p.conns = append(p.conns[:i], p.conns[i+1:]...)
			break
		}
	}
}

// Len returns total number of connections.
func (p *ConnPool) Len() int {
	p.connsMu.Lock()
	l := len(p.conns)
	p.connsMu.Unlock()
	return l
}

// FreeLen returns number of free connections.
func (p *ConnPool) FreeLen() int {
	p.freeConnsMu.Lock()
	l := len(p.freeConns)
	p.freeConnsMu.Unlock()
	return l
}

func (p *ConnPool) Stats() *PoolStats {
	stats := PoolStats{}
	stats.Requests = atomic.LoadUint32(&p.stats.Requests)
	stats.Hits = atomic.LoadUint32(&p.stats.Hits)
	stats.Timeouts = atomic.LoadUint32(&p.stats.Timeouts)
	stats.TotalConns = uint32(p.Len())
	stats.FreeConns = uint32(p.FreeLen())
	return &stats
}

func (p *ConnPool) Closed() bool {
	return atomic.LoadInt32(&p._closed) == 1
}

func (p *ConnPool) Close() (retErr error) {
	if !atomic.CompareAndSwapInt32(&p._closed, 0, 1) {
		return ErrClosed
	}

	p.connsMu.Lock()
	// Close all connections.
	for _, cn := range p.conns {
		if cn == nil {
			continue
		}
		if err := p.closeConn(cn, ErrClosed); err != nil && retErr == nil {
			retErr = err
		}
	}
	p.conns = nil
	p.connsMu.Unlock()

	p.freeConnsMu.Lock()
	p.freeConns = nil
	p.freeConnsMu.Unlock()

	return retErr
}

func (p *ConnPool) closeConn(cn *Conn, reason error) error {
	p.storeLastErr(reason.Error())
	if p.OnClose != nil {
		_ = p.OnClose(cn)
	}
	return cn.Close()
}

func (p *ConnPool) reapStaleConn() bool {
	if len(p.freeConns) == 0 {
		return false
	}

	cn := p.freeConns[0]
	if !cn.IsStale(p.idleTimeout) {
		return false
	}

	p.remove(cn, errConnStale)
	p.freeConns = append(p.freeConns[:0], p.freeConns[1:]...)

	return true
}

func (p *ConnPool) ReapStaleConns() (int, error) {
	var n int
	for {
		p.queue <- struct{}{}
		p.freeConnsMu.Lock()

		reaped := p.reapStaleConn()

		p.freeConnsMu.Unlock()
		<-p.queue

		if reaped {
			n++
		} else {
			break
		}
	}
	return n, nil
}

func (p *ConnPool) reaper(frequency time.Duration) {
	ticker := time.NewTicker(frequency)
	defer ticker.Stop()

	for _ = range ticker.C {
		if p.Closed() {
			break
		}
		n, err := p.ReapStaleConns()
		if err != nil {
			internal.Logf("ReapStaleConns failed: %s", err)
			continue
		}
		s := p.Stats()
		internal.Logf(
			"reaper: removed %d stale conns (TotalConns=%d FreeConns=%d Requests=%d Hits=%d Timeouts=%d)",
			n, s.TotalConns, s.FreeConns, s.Requests, s.Hits, s.Timeouts,
		)
	}
}

func (p *ConnPool) storeLastErr(err string) {
	p.lastErr.Store(err)
}

func (p *ConnPool) loadLastErr() string {
	if v := p.lastErr.Load(); v != nil {
		return v.(string)
	}
	return ""
}

//------------------------------------------------------------------------------

var idleCheckFrequency atomic.Value

func SetIdleCheckFrequency(d time.Duration) {
	idleCheckFrequency.Store(d)
}

func getIdleCheckFrequency() time.Duration {
	v := idleCheckFrequency.Load()
	if v == nil {
		return time.Minute
	}
	return v.(time.Duration)
}
<|endoftext|>


<commit_before>package v7

import (
	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v7action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v7/shared"
)

//go:generate counterfeiter . DeleteRouteActor

type DeleteRouteActor interface {
	DeleteRoute(domainName, hostname, path string) (v7action.Warnings, error)
}

type DeleteRouteCommand struct {
	RequiredArgs    flag.Domain `positional-args:"yes"`
	usage           interface{} `usage:"CF_NAME delete-route DOMAIN [--hostname HOSTNAME] [--path PATH] [-f]"`
	Force           bool        `short:"f" description:"Force deletion without confirmation"`
	Hostname        string      `long:"hostname" short:"n" description:"Hostname used to identify the HTTP route (required for shared domains)"`
	Path            string      `long:"path" description:"Path used to identify the HTTP route"`
	relatedCommands interface{} `related_commands:"delete-orphaned-routes, routes, unmap-route"`

	UI          command.UI
	Config      command.Config
	Actor       DeleteRouteActor
	SharedActor command.SharedActor
}

func (cmd *DeleteRouteCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	sharedActor := sharedaction.NewActor(config)
	cmd.SharedActor = sharedActor

	ccClient, uaaClient, err := shared.NewClients(config, ui, true, "")
	if err != nil {
		return err
	}
	cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient)
	return nil
}

func (cmd DeleteRouteCommand) Execute(args []string) error {
	err := cmd.SharedActor.CheckTarget(true, false)
	if err != nil {
		return err
	}

	_, err = cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	domain := cmd.RequiredArgs.Domain
	hostname := cmd.Hostname
	pathName := cmd.Path
	fqdn := desiredFQDN(domain, hostname, pathName)

	cmd.UI.DisplayText("This action impacts all apps using this route.")
	cmd.UI.DisplayText("Deleting the route will remove associated apps which will make apps with this route unreachable.")

	if !cmd.Force {
		response, promptErr := cmd.UI.DisplayBoolPrompt(false, "Really delete the route {{.FQDN}}?", map[string]interface{}{
			"FQDN": fqdn,
		})

		if promptErr != nil {
			return promptErr
		}

		if !response {
			cmd.UI.DisplayText("'{{.FQDN}}' has not been deleted.", map[string]interface{}{
				"FQDN": fqdn,
			})
			return nil
		}
	}

	cmd.UI.DisplayTextWithFlavor("Deleting route {{.FQDN}}...",
		map[string]interface{}{
			"FQDN": fqdn,
		})

	warnings, err := cmd.Actor.DeleteRoute(domain, hostname, pathName)

	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		if _, ok := err.(actionerror.RouteNotFoundError); ok {
			cmd.UI.DisplayText(`Unable to delete. ` + err.Error())
			cmd.UI.DisplayOK()
			return nil
		}
		return err
	}

	cmd.UI.DisplayOK()
	return nil
}
<commit_msg>Fix help text error delete route command<commit_after>package v7

import (
	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v7action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v7/shared"
)

//go:generate counterfeiter . DeleteRouteActor

type DeleteRouteActor interface {
	DeleteRoute(domainName, hostname, path string) (v7action.Warnings, error)
}

type DeleteRouteCommand struct {
	RequiredArgs    flag.Domain `positional-args:"yes"`
	usage           interface{} `usage:"CF_NAME delete-route DOMAIN [--hostname HOSTNAME] [--path PATH] [-f]\n\nEXAMPLES:\n   CF_NAME delete-route example.com                             # example.com\n   CF_NAME delete-route example.com --hostname myhost            # myhost.example.com\n   CF_NAME delete-route example.com --hostname myhost --path foo # myhost.example.com/foo"`
	Force           bool        `short:"f" description:"Force deletion without confirmation"`
	Hostname        string      `long:"hostname" short:"n" description:"Hostname used to identify the HTTP route (required for shared domains)"`
	Path            string      `long:"path" description:"Path used to identify the HTTP route"`
	relatedCommands interface{} `related_commands:"delete-orphaned-routes, routes, unmap-route"`

	UI          command.UI
	Config      command.Config
	Actor       DeleteRouteActor
	SharedActor command.SharedActor
}

func (cmd *DeleteRouteCommand) Setup(config command.Config, ui command.UI) error {
	cmd.UI = ui
	cmd.Config = config
	sharedActor := sharedaction.NewActor(config)
	cmd.SharedActor = sharedActor

	ccClient, uaaClient, err := shared.NewClients(config, ui, true, "")
	if err != nil {
		return err
	}
	cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient)
	return nil
}

func (cmd DeleteRouteCommand) Execute(args []string) error {
	err := cmd.SharedActor.CheckTarget(true, false)
	if err != nil {
		return err
	}

	_, err = cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	domain := cmd.RequiredArgs.Domain
	hostname := cmd.Hostname
	pathName := cmd.Path
	fqdn := desiredFQDN(domain, hostname, pathName)

	cmd.UI.DisplayText("This action impacts all apps using this route.")
	cmd.UI.DisplayText("Deleting the route will remove associated apps which will make apps with this route unreachable.")

	if !cmd.Force {
		response, promptErr := cmd.UI.DisplayBoolPrompt(false, "Really delete the route {{.FQDN}}?", map[string]interface{}{
			"FQDN": fqdn,
		})

		if promptErr != nil {
			return promptErr
		}

		if !response {
			cmd.UI.DisplayText("'{{.FQDN}}' has not been deleted.", map[string]interface{}{
				"FQDN": fqdn,
			})
			return nil
		}
	}

	cmd.UI.DisplayTextWithFlavor("Deleting route {{.FQDN}}...",
		map[string]interface{}{
			"FQDN": fqdn,
		})

	warnings, err := cmd.Actor.DeleteRoute(domain, hostname, pathName)

	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		if _, ok := err.(actionerror.RouteNotFoundError); ok {
			cmd.UI.DisplayText(`Unable to delete. ` + err.Error())
			cmd.UI.DisplayOK()
			return nil
		}
		return err
	}

	cmd.UI.DisplayOK()
	return nil
}
<|endoftext|>


<commit_before>package ldap

import (
	"fmt"

	"github.com/go-ldap/ldap"
	"github.com/hashicorp/vault/helper/mfa"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
	"strings"
)

func Factory(conf *logical.BackendConfig) (logical.Backend, error) {
	return Backend().Setup(conf)
}

func Backend() *framework.Backend {
	var b backend
	b.Backend = &framework.Backend{
		Help: backendHelp,

		PathsSpecial: &logical.Paths{
			Root: append([]string{
				"config",
				"groups/*",
				"users/*",
			},
				mfa.MFARootPaths()...,
			),

			Unauthenticated: []string{
				"login/*",
			},
		},

		Paths: append([]*framework.Path{
			pathConfig(&b),
			pathGroups(&b),
			pathUsers(&b),
		},
			mfa.MFAPaths(b.Backend, pathLogin(&b))...,
		),

		AuthRenew: b.pathLoginRenew,
	}

	return b.Backend
}

type backend struct {
	*framework.Backend
}

func EscapeLDAPValue(input string) string {
	// RFC4514 forbids un-escaped:
	// - leading space or hash
	// - trailing space
	// - special characters '"', '+', ',', ';', '<', '>', '\\'
	// - null
	for i := 0; i < len(input); i++ {
		escaped := false
		if input[i] == '\\' {
			i++
			escaped = true
		}
		switch input[i] {
		case '"', '+', ',', ';', '<', '>', '\\':
			if !escaped {
				input = input[0:i] + "\\" + input[i:]
				i++
			}
			continue
		}
		if escaped {
			input = input[0:i] + "\\" + input[i:]
			i++
		}
	}
	if input[0] == ' ' || input[0] == '#' {
		input = "\\" + input
	}
	if input[len(input)-1] == ' ' {
		input = input[0:len(input)-1] + "\\ "
	}
	return input
}

func (b *backend) Login(req *logical.Request, username string, password string) ([]string, *logical.Response, error) {

	cfg, err := b.Config(req)
	if err != nil {
		return nil, nil, err
	}
	if cfg == nil {
		return nil, logical.ErrorResponse("ldap backend not configured"), nil
	}

	c, err := cfg.DialLDAP()
	if err != nil {
		return nil, logical.ErrorResponse(err.Error()), nil
	}
	if c == nil {
		return nil, logical.ErrorResponse("invalid connection returned from LDAP dial"), nil
	}

	// Format binddn
	binddn := ""
	if cfg.DiscoverDN || (cfg.BindDN != "" && cfg.BindPassword != "") {
		if err = c.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP bind (service) failed: %v", err)), nil
		}
		sresult, err := c.Search(&ldap.SearchRequest{
			BaseDN: cfg.UserDN,
			Scope:  2, // subtree
			Filter: fmt.Sprintf("(%s=%s)", cfg.UserAttr, ldap.EscapeFilter(username)),
		})
		if err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP search for binddn failed: %v", err)), nil
		}
		if len(sresult.Entries) != 1 {
			return nil, logical.ErrorResponse("LDAP search for binddn 0 or not unique"), nil
		}
		binddn = sresult.Entries[0].DN
	} else {
		if cfg.UPNDomain != "" {
			binddn = fmt.Sprintf("%s@%s", EscapeLDAPValue(username), cfg.UPNDomain)
		} else {
			binddn = fmt.Sprintf("%s=%s,%s", cfg.UserAttr, EscapeLDAPValue(username), cfg.UserDN)
		}
	}
	if err = c.Bind(binddn, password); err != nil {
		return nil, logical.ErrorResponse(fmt.Sprintf("LDAP bind failed: %v", err)), nil
	}

	userdn := ""
	ldapGroups := make(map[string]bool)
	if cfg.UPNDomain != "" {
		// Find the distinguished name for the user if userPrincipalName used for login
		// and the groups from memberOf attributes
		sresult, err := c.Search(&ldap.SearchRequest{
			BaseDN: cfg.UserDN,
			Scope:  2, // subtree
			Filter: fmt.Sprintf("(userPrincipalName=%s)", ldap.EscapeFilter(binddn)),
		})
		if err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP search failed: %v", err)), nil
		}
		for _, e := range sresult.Entries {
			userdn = e.DN
			// Find the groups the user is member of from the 'memberOf' attribute extracting the CN
			for _,dnAttr := range e.Attributes {
				if dnAttr.Name == "memberOf" {
					for _,value := range dnAttr.Values {
						memberOfDN, err := ldap.ParseDN(value)
						if err != nil {
							return nil, nil, err
						}

						for _, rdn := range memberOfDN.RDNs {
							for _, rdnTypeAndValue := range rdn.Attributes {
								if strings.EqualFold(rdnTypeAndValue.Type, "CN") {
									ldapGroups[rdnTypeAndValue.Value] = true
								}
							}
						}
					}
				}
			}
		}
	} else {
		userdn = binddn
	}

	resp := &logical.Response{
		Data: map[string]interface{}{},
	}
	// Find groups by searching in groupDN for any of the memberUid, member or uniqueMember attributes
	// and retrieving the CN in the DN result
	if cfg.GroupDN != "" {
		sresult, err := c.Search(&ldap.SearchRequest{
			BaseDN: cfg.GroupDN,
			Scope:  2, // subtree
			Filter: fmt.Sprintf("(|(memberUid=%s)(member=%s)(uniqueMember=%s))", ldap.EscapeFilter(username), ldap.EscapeFilter(userdn), ldap.EscapeFilter(userdn)),
		})
		if err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP search failed: %v", err)), nil
		}

		for _, e := range sresult.Entries {
			dn, err := ldap.ParseDN(e.DN)
			if err != nil {
				return nil, nil, err
			}
			for _, rdn := range dn.RDNs {
				for _, rdnTypeAndValue := range rdn.Attributes {
					if strings.EqualFold(rdnTypeAndValue.Type, "CN" ) {
						ldapGroups[rdnTypeAndValue.Value] = true
					}
				}
			}
		}
	}

	if len(ldapGroups) == 0 {
		resp.AddWarning(
			fmt.Sprintf(
				"no LDAP groups found in user DN '%s' or group DN '%s';only policies from locally-defined groups available",
				cfg.UserDN,
				cfg.GroupDN
			)
		)
	}
	var allgroups []string
	// Import the custom added groups from ldap backend
	user, err := b.User(req.Storage, username)
	if err == nil && user != nil {
		allgroups = append(allgroups, user.Groups...)
	}
	// add the LDAP groups
	for key, _ := range ldapGroups {
		allgroups = append(allgroups, key)
	}

	// Retrieve policies
	var policies []string
	for _, gname := range allgroups {
		group, err := b.Group(req.Storage, gname)
		if err == nil && group != nil {
			policies = append(policies, group.Policies...)
		}
	}

	if len(policies) == 0 {
		errStr := "user is not a member of any authorized group"
		if len(resp.Warnings()) > 0 {
			errStr = fmt.Sprintf("%s; additionally, %s", errStr, resp.Warnings()[0])
		}

		resp.Data["error"] = errStr
		return nil, resp, nil
	}

	return policies, resp, nil
}

const backendHelp = `
The "ldap" credential provider allows authentication querying
a LDAP server, checking username and password, and associating groups
to set of policies.

Configuration of the server is done through the "config" and "groups"
endpoints by a user with root access. Authentication is then done
by suppying the two fields for "login".
`
<commit_msg>- fixed merge with upstream master<commit_after>package ldap

import (
	"fmt"

	"github.com/go-ldap/ldap"
	"github.com/hashicorp/vault/helper/mfa"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
	"strings"
)

func Factory(conf *logical.BackendConfig) (logical.Backend, error) {
	return Backend().Setup(conf)
}

func Backend() *framework.Backend {
	var b backend
	b.Backend = &framework.Backend{
		Help: backendHelp,

		PathsSpecial: &logical.Paths{
			Root: append([]string{
				"config",
				"groups/*",
				"users/*",
			},
				mfa.MFARootPaths()...,
			),

			Unauthenticated: []string{
				"login/*",
			},
		},

		Paths: append([]*framework.Path{
			pathConfig(&b),
			pathGroups(&b),
			pathUsers(&b),
		},
			mfa.MFAPaths(b.Backend, pathLogin(&b))...,
		),

		AuthRenew: b.pathLoginRenew,
	}

	return b.Backend
}

type backend struct {
	*framework.Backend
}

func EscapeLDAPValue(input string) string {
	// RFC4514 forbids un-escaped:
	// - leading space or hash
	// - trailing space
	// - special characters '"', '+', ',', ';', '<', '>', '\\'
	// - null
	for i := 0; i < len(input); i++ {
		escaped := false
		if input[i] == '\\' {
			i++
			escaped = true
		}
		switch input[i] {
		case '"', '+', ',', ';', '<', '>', '\\':
			if !escaped {
				input = input[0:i] + "\\" + input[i:]
				i++
			}
			continue
		}
		if escaped {
			input = input[0:i] + "\\" + input[i:]
			i++
		}
	}
	if input[0] == ' ' || input[0] == '#' {
		input = "\\" + input
	}
	if input[len(input)-1] == ' ' {
		input = input[0:len(input)-1] + "\\ "
	}
	return input
}

func (b *backend) Login(req *logical.Request, username string, password string) ([]string, *logical.Response, error) {

	cfg, err := b.Config(req)
	if err != nil {
		return nil, nil, err
	}
	if cfg == nil {
		return nil, logical.ErrorResponse("ldap backend not configured"), nil
	}

	c, err := cfg.DialLDAP()
	if err != nil {
		return nil, logical.ErrorResponse(err.Error()), nil
	}
	if c == nil {
		return nil, logical.ErrorResponse("invalid connection returned from LDAP dial"), nil
	}

	// Format binddn
	binddn := ""
	if cfg.DiscoverDN || (cfg.BindDN != "" && cfg.BindPassword != "") {
		if err = c.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP bind (service) failed: %v", err)), nil
		}
		sresult, err := c.Search(&ldap.SearchRequest{
			BaseDN: cfg.UserDN,
			Scope:  2, // subtree
			Filter: fmt.Sprintf("(%s=%s)", cfg.UserAttr, ldap.EscapeFilter(username)),
		})
		if err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP search for binddn failed: %v", err)), nil
		}
		if len(sresult.Entries) != 1 {
			return nil, logical.ErrorResponse("LDAP search for binddn 0 or not unique"), nil
		}
		binddn = sresult.Entries[0].DN
	} else {
		if cfg.UPNDomain != "" {
			binddn = fmt.Sprintf("%s@%s", EscapeLDAPValue(username), cfg.UPNDomain)
		} else {
			binddn = fmt.Sprintf("%s=%s,%s", cfg.UserAttr, EscapeLDAPValue(username), cfg.UserDN)
		}
	}
	if err = c.Bind(binddn, password); err != nil {
		return nil, logical.ErrorResponse(fmt.Sprintf("LDAP bind failed: %v", err)), nil
	}

	userdn := ""
	ldapGroups := make(map[string]bool)
	if cfg.UPNDomain != "" {
		// Find the distinguished name for the user if userPrincipalName used for login
		// and the groups from memberOf attributes
		sresult, err := c.Search(&ldap.SearchRequest{
			BaseDN: cfg.UserDN,
			Scope:  2, // subtree
			Filter: fmt.Sprintf("(userPrincipalName=%s)", ldap.EscapeFilter(binddn)),
		})
		if err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP search failed: %v", err)), nil
		}
		for _, e := range sresult.Entries {
			userdn = e.DN
			// Find the groups the user is member of from the 'memberOf' attribute extracting the CN
			for _,dnAttr := range e.Attributes {
				if dnAttr.Name == "memberOf" {
					for _,value := range dnAttr.Values {
						memberOfDN, err := ldap.ParseDN(value)
						if err != nil {
							return nil, nil, err
						}

						for _, rdn := range memberOfDN.RDNs {
							for _, rdnTypeAndValue := range rdn.Attributes {
								if strings.EqualFold(rdnTypeAndValue.Type, "CN") {
									ldapGroups[rdnTypeAndValue.Value] = true
								}
							}
						}
					}
				}
			}
		}
	} else {
		userdn = binddn
	}

	resp := &logical.Response{
		Data: map[string]interface{}{},
	}
	// Find groups by searching in groupDN for any of the memberUid, member or uniqueMember attributes
	// and retrieving the CN in the DN result
	if cfg.GroupDN != "" {
		sresult, err := c.Search(&ldap.SearchRequest{
			BaseDN: cfg.GroupDN,
			Scope:  2, // subtree
			Filter: fmt.Sprintf("(|(memberUid=%s)(member=%s)(uniqueMember=%s))", ldap.EscapeFilter(username), ldap.EscapeFilter(userdn), ldap.EscapeFilter(userdn)),
		})
		if err != nil {
			return nil, logical.ErrorResponse(fmt.Sprintf("LDAP search failed: %v", err)), nil
		}

		for _, e := range sresult.Entries {
			dn, err := ldap.ParseDN(e.DN)
			if err != nil {
				return nil, nil, err
			}
			for _, rdn := range dn.RDNs {
				for _, rdnTypeAndValue := range rdn.Attributes {
					if strings.EqualFold(rdnTypeAndValue.Type, "CN" ) {
						ldapGroups[rdnTypeAndValue.Value] = true
					}
				}
			}
		}
	}

	if len(ldapGroups) == 0 {
		errString := fmt.Sprintf(
			"no LDAP groups found in user DN '%s' or group DN '%s';only policies from locally-defined groups available",
			cfg.UserDN,
			cfg.GroupDN)
		resp.AddWarning(errString)
	}

	var allgroups []string
	// Import the custom added groups from ldap backend
	user, err := b.User(req.Storage, username)
	if err == nil && user != nil {
		allgroups = append(allgroups, user.Groups...)
	}
	// add the LDAP groups
	for key, _ := range ldapGroups {
		allgroups = append(allgroups, key)
	}

	// Retrieve policies
	var policies []string
	for _, gname := range allgroups {
		group, err := b.Group(req.Storage, gname)
		if err == nil && group != nil {
			policies = append(policies, group.Policies...)
		}
	}

	if len(policies) == 0 {
		errStr := "user is not a member of any authorized group"
		if len(resp.Warnings()) > 0 {
			errStr = fmt.Sprintf("%s; additionally, %s", errStr, resp.Warnings()[0])
		}

		resp.Data["error"] = errStr
		return nil, resp, nil
	}

	return policies, resp, nil
}

const backendHelp = `
The "ldap" credential provider allows authentication querying
a LDAP server, checking username and password, and associating groups
to set of policies.

Configuration of the server is done through the "config" and "groups"
endpoints by a user with root access. Authentication is then done
by suppying the two fields for "login".
`
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"fmt"

	"github.com/pingcap/tidb/util/types"
)

// IDriver opens IContext.
type IDriver interface {
	// OpenCtx opens an IContext with connection id, client capability, collation and dbname.
	OpenCtx(connID uint64, capability uint32, collation uint8, dbname string) (IContext, error)
}

// IContext is the interface to execute commant.
type IContext interface {
	// Status returns server status code.
	Status() uint16

	// LastInsertID returns last inserted ID.
	LastInsertID() uint64

	// AffectedRows returns affected rows of last executed command.
	AffectedRows() uint64

	// Value returns the value associated with this context for key.
	Value(key fmt.Stringer) interface{}

	// SetValue saves a value associated with this context for key.
	SetValue(key fmt.Stringer, value interface{})

	// CommitTxn commits the transaction operations.
	CommitTxn() error

	// RollbackTxn undoes the transaction operations.
	RollbackTxn() error

	// WarningCount returns warning count of last executed command.
	WarningCount() uint16

	// CurrentDB returns current DB.
	CurrentDB() string

	// Execute executes a SQL statement.
	Execute(sql string) ([]ResultSet, error)

	// SetClientCapability sets client capability flags
	SetClientCapability(uint32)

	// Prepare prepares a statement.
	Prepare(sql string) (statement IStatement, columns, params []*ColumnInfo, err error)

	// GetStatement gets IStatement by statement ID.
	GetStatement(stmtID int) IStatement

	// FieldList returns columns of a table.
	FieldList(tableName string) (columns []*ColumnInfo, err error)

	// Close closes the IContext.
	Close() error

	// Auth verifies user's authentication.
	Auth(user string, auth []byte, salt []byte) bool
}

// IStatement is the interface to use a prepared statement.
type IStatement interface {
	// ID returns statement ID
	ID() int

	// Execute executes the statement.
	Execute(args ...interface{}) (ResultSet, error)

	// AppendParam appends parameter to the statement.
	AppendParam(paramID int, data []byte) error

	// NumParams returns number of parameters.
	NumParams() int

	// BoundParams returns bound parameters.
	BoundParams() [][]byte

	// Reset removes all bound parameters.
	Reset()

	// Close closes the statement.
	Close() error
}

// ResultSet is the result set of an query.
type ResultSet interface {
	Columns() ([]*ColumnInfo, error)
	Next() ([]types.Datum, error)
	Close() error
}
<commit_msg>server/driver.go: fix typo<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"fmt"

	"github.com/pingcap/tidb/util/types"
)

// IDriver opens IContext.
type IDriver interface {
	// OpenCtx opens an IContext with connection id, client capability, collation and dbname.
	OpenCtx(connID uint64, capability uint32, collation uint8, dbname string) (IContext, error)
}

// IContext is the interface to execute command.
type IContext interface {
	// Status returns server status code.
	Status() uint16

	// LastInsertID returns last inserted ID.
	LastInsertID() uint64

	// AffectedRows returns affected rows of last executed command.
	AffectedRows() uint64

	// Value returns the value associated with this context for key.
	Value(key fmt.Stringer) interface{}

	// SetValue saves a value associated with this context for key.
	SetValue(key fmt.Stringer, value interface{})

	// CommitTxn commits the transaction operations.
	CommitTxn() error

	// RollbackTxn undoes the transaction operations.
	RollbackTxn() error

	// WarningCount returns warning count of last executed command.
	WarningCount() uint16

	// CurrentDB returns current DB.
	CurrentDB() string

	// Execute executes a SQL statement.
	Execute(sql string) ([]ResultSet, error)

	// SetClientCapability sets client capability flags
	SetClientCapability(uint32)

	// Prepare prepares a statement.
	Prepare(sql string) (statement IStatement, columns, params []*ColumnInfo, err error)

	// GetStatement gets IStatement by statement ID.
	GetStatement(stmtID int) IStatement

	// FieldList returns columns of a table.
	FieldList(tableName string) (columns []*ColumnInfo, err error)

	// Close closes the IContext.
	Close() error

	// Auth verifies user's authentication.
	Auth(user string, auth []byte, salt []byte) bool
}

// IStatement is the interface to use a prepared statement.
type IStatement interface {
	// ID returns statement ID
	ID() int

	// Execute executes the statement.
	Execute(args ...interface{}) (ResultSet, error)

	// AppendParam appends parameter to the statement.
	AppendParam(paramID int, data []byte) error

	// NumParams returns number of parameters.
	NumParams() int

	// BoundParams returns bound parameters.
	BoundParams() [][]byte

	// Reset removes all bound parameters.
	Reset()

	// Close closes the statement.
	Close() error
}

// ResultSet is the result set of an query.
type ResultSet interface {
	Columns() ([]*ColumnInfo, error)
	Next() ([]types.Datum, error)
	Close() error
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"

	"github.com/git-lfs/git-lfs/errors"
	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/git-lfs/git-lfs/tq"
	"github.com/spf13/cobra"
)

const (
	// cleanFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "clean" command. 512 bytes is (in most cases) enough to
	// hold an entire LFS pointer in memory.
	cleanFilterBufferCapacity = 512

	// smudgeFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "smudge" command.
	smudgeFilterBufferCapacity = git.MaxPacketLength
)

// filterSmudgeSkip is a command-line flag owned by the `filter-process` command
// dictating whether or not to skip the smudging process, leaving pointers as-is
// in the working tree.
var filterSmudgeSkip bool

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewFilterProcessScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}

	caps, err := s.NegotiateCapabilities()
	if err != nil {
		ExitWithError(err)
	}

	var supportsDelay bool
	for _, cap := range caps {
		if cap == "capability=delay" {
			supportsDelay = true
			break
		}
	}

	skip := filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false)
	filter := filepathfilter.New(cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	ptrs := make(map[string]*lfs.Pointer)

	var q *tq.TransferQueue
	closeOnce := new(sync.Once)
	available := make(chan *tq.Transfer)

	if supportsDelay {
		q = tq.NewTransferQueue(tq.Download, getTransferManifest(), cfg.CurrentRemote)
		go infiniteTransferBuffer(q, available)
	}

	var malformed []string
	var malformedOnWindows []string
	for s.Scan() {
		var n int64
		var err error
		var delayed bool
		var w *git.PktlineWriter

		req := s.Request()

		if !(req.Header["command"] == "smudge" && req.Header["can-delay"] == "1") && !(req.Header["command"] == "list_available_blobs") {
			s.WriteStatus(statusFromErr(nil))
		}

		switch req.Header["command"] {
		case "clean":
			w = git.NewPktlineWriter(os.Stdout, cleanFilterBufferCapacity)

			var ptr *lfs.Pointer
			ptr, err = clean(w, req.Payload, req.Header["pathname"], -1)

			if ptr != nil {
				n = ptr.Size
			}
		case "smudge":
			w = git.NewPktlineWriter(os.Stdout, smudgeFilterBufferCapacity)
			if req.Header["can-delay"] == "1" {
				var ptr *lfs.Pointer

				n, delayed, ptr, err = delayedSmudge(s, w, req.Payload, q, req.Header["pathname"], skip, filter)

				if delayed {
					ptrs[req.Header["pathname"]] = ptr
				}
			} else {
				from, ferr := incomingOrCached(req.Payload, ptrs[req.Header["pathname"]])
				if ferr != nil {
					break
				}

				n, err = smudge(w, from, req.Header["pathname"], skip, filter)
				if err == nil {
					delete(ptrs, req.Header["pathname"])
				}
			}
		case "list_available_blobs":
			closeOnce.Do(func() {
				// The first time that Git sends us the
				// 'list_available_blobs' command, it is given
				// that no more smudge commands will be issued
				// with _new_ checkout entries.
				//
				// This means that, by the time that we're here,
				// we have seen all entries in the checkout, and
				// should therefore instruct the transfer queue
				// to make a batch out of whatever remaining
				// items it has, and then close itself.
				//
				// This function call is wrapped in a
				// `sync.(*Once).Do()` call so we only call
				// `q.Wait()` once, and is called via a
				// goroutine since `q.Wait()` is blocking.
				go q.Wait()
			})

			// The first, and all subsequent calls to
			// list_available_blobs, we read items from `tq.Watch()`
			// until a read from that channel becomes blocking (in
			// other words, we read until there are no more items
			// immediately ready to be sent back to Git).
			paths := pathnames(readAvailable(available))
			if len(paths) == 0 {
				// If `len(paths) == 0`, `tq.Watch()` has
				// closed, indicating that all items have been
				// completely processed, and therefore, sent
				// back to Git for checkout.
				for path, _ := range ptrs {
					// If we sent a path to Git but it
					// didn't ask for the smudge contents,
					// that path is available and Git should
					// accept it later.
					paths = append(paths, fmt.Sprintf("pathname=%s", path))
				}
			}
			err = s.WriteList(paths)
		default:
			ExitWithError(fmt.Errorf("Unknown command %q", req.Header["command"]))
		}

		if errors.IsNotAPointerError(err) {
			malformed = append(malformed, req.Header["pathname"])
			err = nil
		} else if possiblyMalformedObjectSize(n) {
			malformedOnWindows = append(malformedOnWindows, req.Header["pathname"])
		}

		var status string
		if delayed {
			// If we delayed, there is no need to write a flush
			// packet since no content was written.
			status = delayedStatusFromErr(err)
		} else if ferr := w.Flush(); ferr != nil {
			// Otherwise, assume that content was written and
			// perform a flush operation.
			status = statusFromErr(ferr)
		} else {
			// If the flush operation succeeded, write the status of
			// the checkout operation.
			status = statusFromErr(err)
		}

		s.WriteStatus(status)
	}

	if len(malformed) > 0 {
		fmt.Fprintf(os.Stderr, "Encountered %d file(s) that should have been pointers, but weren't:\n", len(malformed))
		for _, m := range malformed {
			fmt.Fprintf(os.Stderr, "\t%s\n", m)
		}
	}

	if len(malformedOnWindows) > 0 {
		fmt.Fprintf(os.Stderr, "Encountered %d file(s) that may not have been copied correctly on Windows:\n")

		for _, m := range malformedOnWindows {
			fmt.Fprintf(os.Stderr, "\t%s\n", m)
		}

		fmt.Fprintf(os.Stderr, "\nSee: `git lfs help smudge` for more details.\n")
	}

	if err := s.Err(); err != nil && err != io.EOF {
		ExitWithError(err)
	}
}

// infiniteTransferBuffer streams the results of q.Watch() into "available" as
// if available had an infinite channel buffer.
func infiniteTransferBuffer(q *tq.TransferQueue, available chan<- *tq.Transfer) {
	// Stream results from q.Watch() into chan "available" via an infinite
	// buffer.

	watch := q.Watch()

	// pending is used to keep track of an ordered list of available
	// `*tq.Transfer`'s that cannot be written to "available" without
	// blocking.
	var pending []*tq.Transfer

	for {
		if len(pending) > 0 {
			select {
			case t, ok := <-watch:
				if !ok {
					// If the list of pending elements is
					// non-empty, stream them out (even if
					// they block), and then close().
					for _, t = range pending {
						available <- t
					}
					close(available)
					return
				}
				pending = append(pending, t)
			case available <- pending[0]:
				// Otherwise, dequeue and shift the first
				// element from pending onto available.
				pending = pending[1:]
			}
		} else {
			t, ok := <-watch
			if !ok {
				// If watch is closed, the "tq" is done, and
				// there are no items on the buffer.  Return
				// immediately.
				close(available)
				return
			}

			select {
			case available <- t:
			// Copy an item directly from <-watch onto available<-.
			default:
				// Otherwise, if that would have blocked, make
				// the new read pending.
				pending = append(pending, t)
			}
		}
	}
}

// incomingOrCached returns an io.Reader that is either the contents of the
// given io.Reader "r", or the encoded contents of "ptr". It returns an error if
// there was an error reading from "r".
//
// This is done because when a `command=smudge` with `can-delay=0` is issued,
// the entry's contents are not sent, and must be re-encoded from the stored
// pointer corresponding to the request's filepath.
func incomingOrCached(r io.Reader, ptr *lfs.Pointer) (io.Reader, error) {
	var buf bytes.Buffer
	if _, err := io.CopyN(&buf, r, 1024); err != nil {
		if err != io.EOF {
			return nil, err
		}
	}

	if buf.Len() < 1024 && ptr != nil {
		return strings.NewReader(ptr.Encoded()), nil
	}
	return io.MultiReader(&buf, r), nil
}

// readAvailable satisfies the accumulation semantics for the
// 'list_available_blobs' command. It accumulates items until:
//
// 1. Reading from the channel of available items blocks, or ...
// 2. There is one item available, or ...
// 3. The 'tq.TransferQueue' is completed.
func readAvailable(ch <-chan *tq.Transfer) []*tq.Transfer {
	ts := make([]*tq.Transfer, 0, 100)

	for {
		select {
		case t, ok := <-ch:
			if !ok {
				return ts
			}
			ts = append(ts, t)
		default:
			if len(ts) > 0 {
				return ts
			}

			t, ok := <-ch
			if !ok {
				return ts
			}
			return append(ts, t)
		}
	}

	return ts
}

// pathnames formats a list of *tq.Transfers as a valid response to the
// 'list_available_blobs' command.
func pathnames(ts []*tq.Transfer) []string {
	pathnames := make([]string, 0, len(ts))
	for _, t := range ts {
		pathnames = append(pathnames, fmt.Sprintf("pathname=%s", t.Name))
	}

	return pathnames
}

// statusFromErr returns the status code that should be sent over the filter
// protocol based on a given error, "err".
func statusFromErr(err error) string {
	if err != nil && err != io.EOF {
		return "error"
	}
	return "success"
}

// delayedStatusFromErr returns the status code that should be sent over the
// filter protocol based on a given error, "err" when the blob smudge operation
// was delayed.
func delayedStatusFromErr(err error) string {
	if err != nil && err != io.EOF {
		return "error"
	}
	return "delayed"
}

func init() {
	RegisterCommand("filter-process", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<commit_msg>commands: clarify err to status conversion<commit_after>package commands

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"

	"github.com/git-lfs/git-lfs/errors"
	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/git-lfs/git-lfs/tq"
	"github.com/spf13/cobra"
)

const (
	// cleanFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "clean" command. 512 bytes is (in most cases) enough to
	// hold an entire LFS pointer in memory.
	cleanFilterBufferCapacity = 512

	// smudgeFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "smudge" command.
	smudgeFilterBufferCapacity = git.MaxPacketLength
)

// filterSmudgeSkip is a command-line flag owned by the `filter-process` command
// dictating whether or not to skip the smudging process, leaving pointers as-is
// in the working tree.
var filterSmudgeSkip bool

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewFilterProcessScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}

	caps, err := s.NegotiateCapabilities()
	if err != nil {
		ExitWithError(err)
	}

	var supportsDelay bool
	for _, cap := range caps {
		if cap == "capability=delay" {
			supportsDelay = true
			break
		}
	}

	skip := filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false)
	filter := filepathfilter.New(cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	ptrs := make(map[string]*lfs.Pointer)

	var q *tq.TransferQueue
	closeOnce := new(sync.Once)
	available := make(chan *tq.Transfer)

	if supportsDelay {
		q = tq.NewTransferQueue(tq.Download, getTransferManifest(), cfg.CurrentRemote)
		go infiniteTransferBuffer(q, available)
	}

	var malformed []string
	var malformedOnWindows []string
	for s.Scan() {
		var n int64
		var err error
		var delayed bool
		var w *git.PktlineWriter

		req := s.Request()

		if !(req.Header["command"] == "smudge" && req.Header["can-delay"] == "1") && !(req.Header["command"] == "list_available_blobs") {
			s.WriteStatus(statusFromErr(nil))
		}

		switch req.Header["command"] {
		case "clean":
			w = git.NewPktlineWriter(os.Stdout, cleanFilterBufferCapacity)

			var ptr *lfs.Pointer
			ptr, err = clean(w, req.Payload, req.Header["pathname"], -1)

			if ptr != nil {
				n = ptr.Size
			}
		case "smudge":
			w = git.NewPktlineWriter(os.Stdout, smudgeFilterBufferCapacity)
			if req.Header["can-delay"] == "1" {
				var ptr *lfs.Pointer

				n, delayed, ptr, err = delayedSmudge(s, w, req.Payload, q, req.Header["pathname"], skip, filter)

				if delayed {
					ptrs[req.Header["pathname"]] = ptr
				}
			} else {
				from, ferr := incomingOrCached(req.Payload, ptrs[req.Header["pathname"]])
				if ferr != nil {
					break
				}

				n, err = smudge(w, from, req.Header["pathname"], skip, filter)
				if err == nil {
					delete(ptrs, req.Header["pathname"])
				}
			}
		case "list_available_blobs":
			closeOnce.Do(func() {
				// The first time that Git sends us the
				// 'list_available_blobs' command, it is given
				// that no more smudge commands will be issued
				// with _new_ checkout entries.
				//
				// This means that, by the time that we're here,
				// we have seen all entries in the checkout, and
				// should therefore instruct the transfer queue
				// to make a batch out of whatever remaining
				// items it has, and then close itself.
				//
				// This function call is wrapped in a
				// `sync.(*Once).Do()` call so we only call
				// `q.Wait()` once, and is called via a
				// goroutine since `q.Wait()` is blocking.
				go q.Wait()
			})

			// The first, and all subsequent calls to
			// list_available_blobs, we read items from `tq.Watch()`
			// until a read from that channel becomes blocking (in
			// other words, we read until there are no more items
			// immediately ready to be sent back to Git).
			paths := pathnames(readAvailable(available))
			if len(paths) == 0 {
				// If `len(paths) == 0`, `tq.Watch()` has
				// closed, indicating that all items have been
				// completely processed, and therefore, sent
				// back to Git for checkout.
				for path, _ := range ptrs {
					// If we sent a path to Git but it
					// didn't ask for the smudge contents,
					// that path is available and Git should
					// accept it later.
					paths = append(paths, fmt.Sprintf("pathname=%s", path))
				}
			}
			err = s.WriteList(paths)
		default:
			ExitWithError(fmt.Errorf("Unknown command %q", req.Header["command"]))
		}

		if errors.IsNotAPointerError(err) {
			malformed = append(malformed, req.Header["pathname"])
			err = nil
		} else if possiblyMalformedObjectSize(n) {
			malformedOnWindows = append(malformedOnWindows, req.Header["pathname"])
		}

		if delayed {
			// If we delayed, there is no need to write a flush
			// packet since no content was written.
			w = nil
		}

		var status string
		if ferr := w.Flush(); ferr != nil {
			status = statusFromErr(ferr)
		} else {
			if delayed {
				// If the flush operation succeeded, write that
				// we were delayed, or encountered an error.
				// the checkout operation.
				status = delayedStatusFromErr(err)
			} else {
				// If we responded with content, report the
				// status of that operation instead.
				status = statusFromErr(err)
			}
		}

		s.WriteStatus(status)
	}

	if len(malformed) > 0 {
		fmt.Fprintf(os.Stderr, "Encountered %d file(s) that should have been pointers, but weren't:\n", len(malformed))
		for _, m := range malformed {
			fmt.Fprintf(os.Stderr, "\t%s\n", m)
		}
	}

	if len(malformedOnWindows) > 0 {
		fmt.Fprintf(os.Stderr, "Encountered %d file(s) that may not have been copied correctly on Windows:\n")

		for _, m := range malformedOnWindows {
			fmt.Fprintf(os.Stderr, "\t%s\n", m)
		}

		fmt.Fprintf(os.Stderr, "\nSee: `git lfs help smudge` for more details.\n")
	}

	if err := s.Err(); err != nil && err != io.EOF {
		ExitWithError(err)
	}
}

// infiniteTransferBuffer streams the results of q.Watch() into "available" as
// if available had an infinite channel buffer.
func infiniteTransferBuffer(q *tq.TransferQueue, available chan<- *tq.Transfer) {
	// Stream results from q.Watch() into chan "available" via an infinite
	// buffer.

	watch := q.Watch()

	// pending is used to keep track of an ordered list of available
	// `*tq.Transfer`'s that cannot be written to "available" without
	// blocking.
	var pending []*tq.Transfer

	for {
		if len(pending) > 0 {
			select {
			case t, ok := <-watch:
				if !ok {
					// If the list of pending elements is
					// non-empty, stream them out (even if
					// they block), and then close().
					for _, t = range pending {
						available <- t
					}
					close(available)
					return
				}
				pending = append(pending, t)
			case available <- pending[0]:
				// Otherwise, dequeue and shift the first
				// element from pending onto available.
				pending = pending[1:]
			}
		} else {
			t, ok := <-watch
			if !ok {
				// If watch is closed, the "tq" is done, and
				// there are no items on the buffer.  Return
				// immediately.
				close(available)
				return
			}

			select {
			case available <- t:
			// Copy an item directly from <-watch onto available<-.
			default:
				// Otherwise, if that would have blocked, make
				// the new read pending.
				pending = append(pending, t)
			}
		}
	}
}

// incomingOrCached returns an io.Reader that is either the contents of the
// given io.Reader "r", or the encoded contents of "ptr". It returns an error if
// there was an error reading from "r".
//
// This is done because when a `command=smudge` with `can-delay=0` is issued,
// the entry's contents are not sent, and must be re-encoded from the stored
// pointer corresponding to the request's filepath.
func incomingOrCached(r io.Reader, ptr *lfs.Pointer) (io.Reader, error) {
	var buf bytes.Buffer
	if _, err := io.CopyN(&buf, r, 1024); err != nil {
		if err != io.EOF {
			return nil, err
		}
	}

	if buf.Len() < 1024 && ptr != nil {
		return strings.NewReader(ptr.Encoded()), nil
	}
	return io.MultiReader(&buf, r), nil
}

// readAvailable satisfies the accumulation semantics for the
// 'list_available_blobs' command. It accumulates items until:
//
// 1. Reading from the channel of available items blocks, or ...
// 2. There is one item available, or ...
// 3. The 'tq.TransferQueue' is completed.
func readAvailable(ch <-chan *tq.Transfer) []*tq.Transfer {
	ts := make([]*tq.Transfer, 0, 100)

	for {
		select {
		case t, ok := <-ch:
			if !ok {
				return ts
			}
			ts = append(ts, t)
		default:
			if len(ts) > 0 {
				return ts
			}

			t, ok := <-ch
			if !ok {
				return ts
			}
			return append(ts, t)
		}
	}

	return ts
}

// pathnames formats a list of *tq.Transfers as a valid response to the
// 'list_available_blobs' command.
func pathnames(ts []*tq.Transfer) []string {
	pathnames := make([]string, 0, len(ts))
	for _, t := range ts {
		pathnames = append(pathnames, fmt.Sprintf("pathname=%s", t.Name))
	}

	return pathnames
}

// statusFromErr returns the status code that should be sent over the filter
// protocol based on a given error, "err".
func statusFromErr(err error) string {
	if err != nil && err != io.EOF {
		return "error"
	}
	return "success"
}

// delayedStatusFromErr returns the status code that should be sent over the
// filter protocol based on a given error, "err" when the blob smudge operation
// was delayed.
func delayedStatusFromErr(err error) string {
	if err != nil && err != io.EOF {
		return "error"
	}
	return "delayed"
}

func init() {
	RegisterCommand("filter-process", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://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.
*/

// This file contains an object which encapsulates k8s clients which are useful for e2e tests.

package test

import (
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/operator/pkg/client/clientset/versioned"
	operatorv1alpha1 "knative.dev/operator/pkg/client/clientset/versioned/typed/operator/v1alpha1"
	"knative.dev/pkg/test"
)

// Clients holds instances of interfaces for making requests to Knative Serving.
type Clients struct {
	KubeClient *test.KubeClient
	Dynamic    dynamic.Interface
	Operator   operatorv1alpha1.OperatorV1alpha1Interface
	Config     *rest.Config
}

// NewClients instantiates and returns several clientsets required for making request to the
// Knative Serving cluster specified by the combination of clusterName and configPath.
func NewClients(configPath string, clusterName string) (*Clients, error) {
	clients := &Clients{}
	cfg, err := buildClientConfig(configPath, clusterName)
	if err != nil {
		return nil, err
	}

	// We poll, so set our limits high.
	cfg.QPS = 100
	cfg.Burst = 200

	clients.KubeClient, err = test.NewKubeClient(configPath, clusterName)
	if err != nil {
		return nil, err
	}

	clients.Dynamic, err = dynamic.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	clients.Operator, err = newKnativeOperatorAlphaClients(cfg)
	if err != nil {
		return nil, err
	}

	clients.Config = cfg
	return clients, nil
}

func buildClientConfig(kubeConfigPath string, clusterName string) (*rest.Config, error) {
	overrides := clientcmd.ConfigOverrides{}
	// Override the cluster name if provided.
	if clusterName != "" {
		overrides.Context.Cluster = clusterName
	}
	return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeConfigPath},
		&overrides).ClientConfig()
}

func newKnativeOperatorAlphaClients(cfg *rest.Config) (operatorv1alpha1.OperatorV1alpha1Interface, error) {
	cs, err := versioned.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}
	return cs.OperatorV1alpha1(), nil
}

func (c *Clients) KnativeServing() operatorv1alpha1.KnativeServingInterface {
	return c.Operator.KnativeServings(ServingOperatorNamespace)
}

func (c *Clients) KnativeServingAll() operatorv1alpha1.KnativeServingInterface {
	return c.Operator.KnativeServings(metav1.NamespaceAll)
}

func (c *Clients) KnativeEventing() operatorv1alpha1.KnativeEventingInterface {
	return c.Operator.KnativeEventings(EventingOperatorNamespace)
}

func (c *Clients) KnativeEventingAll() operatorv1alpha1.KnativeEventingInterface {
	return c.Operator.KnativeEventings(metav1.NamespaceAll)
}
<commit_msg>drop use of pkg/test.KubeClient (#655)<commit_after>/*
Copyright 2019 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://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.
*/

// This file contains an object which encapsulates k8s clients which are useful for e2e tests.

package test

import (
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/operator/pkg/client/clientset/versioned"
	operatorv1alpha1 "knative.dev/operator/pkg/client/clientset/versioned/typed/operator/v1alpha1"
)

// Clients holds instances of interfaces for making requests to Knative Serving.
type Clients struct {
	KubeClient kubernetes.Interface
	Dynamic    dynamic.Interface
	Operator   operatorv1alpha1.OperatorV1alpha1Interface
	Config     *rest.Config
}

// NewClients instantiates and returns several clientsets required for making request to the
// Knative Serving cluster specified by the combination of clusterName and configPath.
func NewClients(configPath string, clusterName string) (*Clients, error) {
	clients := &Clients{}
	cfg, err := buildClientConfig(configPath, clusterName)
	if err != nil {
		return nil, err
	}

	// We poll, so set our limits high.
	cfg.QPS = 100
	cfg.Burst = 200

	clients.KubeClient, err = kubernetes.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	clients.Dynamic, err = dynamic.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	clients.Operator, err = newKnativeOperatorAlphaClients(cfg)
	if err != nil {
		return nil, err
	}

	clients.Config = cfg
	return clients, nil
}

func buildClientConfig(kubeConfigPath string, clusterName string) (*rest.Config, error) {
	overrides := clientcmd.ConfigOverrides{}
	// Override the cluster name if provided.
	if clusterName != "" {
		overrides.Context.Cluster = clusterName
	}
	return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeConfigPath},
		&overrides).ClientConfig()
}

func newKnativeOperatorAlphaClients(cfg *rest.Config) (operatorv1alpha1.OperatorV1alpha1Interface, error) {
	cs, err := versioned.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}
	return cs.OperatorV1alpha1(), nil
}

func (c *Clients) KnativeServing() operatorv1alpha1.KnativeServingInterface {
	return c.Operator.KnativeServings(ServingOperatorNamespace)
}

func (c *Clients) KnativeServingAll() operatorv1alpha1.KnativeServingInterface {
	return c.Operator.KnativeServings(metav1.NamespaceAll)
}

func (c *Clients) KnativeEventing() operatorv1alpha1.KnativeEventingInterface {
	return c.Operator.KnativeEventings(EventingOperatorNamespace)
}

func (c *Clients) KnativeEventingAll() operatorv1alpha1.KnativeEventingInterface {
	return c.Operator.KnativeEventings(metav1.NamespaceAll)
}
<|endoftext|>