<commit_before>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import() //(`sort`)

const (
        stepPrincipal = iota
        stepCaptures
        stepPromotions
        stepKillers
        stepRemaining
)

type MoveEx struct {
        move   Move
        score  int
}

type MoveList struct {
        position  *Position
        moves     [256]MoveEx
        ply       int
        head      int
        tail      int
        step      int
}

var moveList [MaxPly]MoveList

func (p *Position) StartMoveGen(ply int) (ml *MoveList) {
        ml = &moveList[ply]
        ml.position = p
        ml.moves = [256]MoveEx{}
        ml.ply = ply
        ml.head, ml.tail = 0, 0
        return
}

func (ml *MoveList) NextMove() (move Move) {
        if ml.head == ml.tail {
                return 0
        }
        move = ml.moves[ml.head].move
        ml.head++
        return
}

func (ml *MoveList) GenerateMoves() *MoveList {
        color := ml.position.color
        ml.pawnMoves(color)
        ml.pieceMoves(color)
        ml.kingMoves(color)
        return ml
}

func (ml *MoveList) pawnMoves(color int) *MoveList {
        pawns := ml.position.outposts[Pawn(color)]

        for pawns != 0 {
                square := pawns.pop()
                targets := ml.position.targets[square]
                for targets != 0 {
                        target := targets.pop()
                        if target > H1 && target < A8 {
                                ml.moves[ml.tail].move = ml.position.pawnMove(square, target)
                                ml.tail++
                        } else { // Promotion.
                                m1, m2, m3, m4 := ml.position.pawnPromotion(square, target)
                                ml.moves[ml.tail].move = m1
                                ml.tail++
                                ml.moves[ml.tail].move = m2
                                ml.tail++
                                ml.moves[ml.tail].move = m3
                                ml.tail++
                                ml.moves[ml.tail].move = m4
                                ml.tail++
                        }
                }
        }
        return ml
}

func (ml *MoveList) pieceMoves(color int) *MoveList {
	for _, kind := range [4]int{ KNIGHT, BISHOP, ROOK, QUEEN } {
	        outposts := ml.position.outposts[Piece(kind|color)]
	        for outposts != 0 {
	                square := outposts.pop()
	                targets := ml.position.targets[square]
	                for targets != 0 {
	                        target := targets.pop()
	                        ml.moves[ml.tail].move = NewMove(ml.position, square, target)
	                        ml.tail++
	                }
	        }
	}
        return ml
}

func (ml *MoveList) kingMoves(color int) *MoveList {
        var move Move
        king := ml.position.outposts[King(color)]
        if king != 0 {
                square := king.pop()
                targets := ml.position.targets[square]
                for targets != 0 {
                        target := targets.pop()
                        if square == homeKing[color] && Abs(square - target) == 2 {
                                move = NewCastle(ml.position, square, target)
                        } else {
                                move = NewMove(ml.position, square, target)
                        }
                        ml.moves[ml.tail].move = move
                        ml.tail++
                }
        }
        return ml
}

func (ml *MoveList) GenerateCaptures() *MoveList {
        color := ml.position.color
        ml.pawnCaptures(color)
        ml.pieceCaptures(color)
        return ml
}

// Generates all pseudo-legal pawn captures and Queen promotions.
func (ml *MoveList) pawnCaptures(color int) *MoveList {
        pawns := ml.position.outposts[Pawn(color)]

        for pawns != 0 {
                square := pawns.pop()
                //
                // First check capture targets on rows 2-7 (no promotions).
                //
                targets := ml.position.targets[square] & ml.position.board[color^1] & 0x00FFFFFFFFFFFF00
                for targets != 0 {
                        target := targets.pop()
                        ml.moves[ml.tail].move = NewMove(ml.position, square, target)
                        ml.tail++
                }
                //
                // Now check promo rows. The might include capture targets as well
                // as empty promo square in front of the pawn.
                //
                if RelRow(square, color) == 6 {
                        eight := [2]int{ 8, -8 }
                        lastRow := [2]Bitmask{ 0xFF00000000000000,  0x00000000000000FF }
                        targets  = ml.position.targets[square] & lastRow[color]
                        targets |= ml.position.board[2] & Bit(square + eight[color])

                        for targets != 0 {
                                target := targets.pop()
                                ml.moves[ml.tail].move = NewMove(ml.position, square, target).promote(QUEEN)
                                ml.tail++
                        }
                }
        }
        return ml
}

// Generates all pseudo-legal captures by pieces other than pawn.
func (ml *MoveList) pieceCaptures(color int) *MoveList {
	for _, kind := range [5]int{ KNIGHT, BISHOP, ROOK, QUEEN, KING } {
	        outposts := ml.position.outposts[Piece(kind|color)]
	        for outposts != 0 {
	                square := outposts.pop()
	                targets := ml.position.targets[square] & ml.position.board[color^1]
	                for targets != 0 {
	                        target := targets.pop()
	                        ml.moves[ml.tail].move = NewMove(ml.position, square, target)
	                        ml.tail++
	                }
	        }
	}
	return ml
}

// All moves.
func (p *Position) Moves(ply int) (moves []Move) {
        for square, piece := range p.pieces {
                if piece != 0 && piece.color() == p.color {
                        moves = append(moves, p.possibleMoves(square, piece)...)
                }
        }
        moves = p.reorderMoves(moves, p.game.bestLine[0][ply], p.game.killers[ply])
        Log("%d candidates for %s: %v\n", len(moves), C(p.color), moves)
        return
}

func (p *Position) Captures(ply int) (moves []Move) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.color() == p.color {
                        moves = append(moves, p.possibleCaptures(i, piece)...)
                }
        }
        if bestMove := p.game.bestLine[0][ply]; bestMove != 0 && bestMove.capture() != 0 {
                moves = p.reorderCaptures(moves, bestMove)
        } else {
                //sort.Sort(byScore{moves})
        }

        Log("%d capture candidates for %s: %v\n", len(moves), C(p.color), moves)
        return
}

// All moves for the piece in certain square. This might include illegal
// moves that cause check to the king.
func (p *Position) possibleMoves(square int, piece Piece) (moves []Move) {
        targets := p.targets[square]

        for targets != 0 {
                target := targets.pop()
                //
                // For regular moves each target square represents one possible
                // move. For pawn promotion, however, we have to generate four
                // possible moves, one for each promoted piece.
                //
                if !p.isPawnPromotion(piece, target) {
                        moves = append(moves, NewMove(p, square, target))
                } else {
                        for _,name := range([]int{ QUEEN, ROOK, BISHOP, KNIGHT }) {
                                candidate := NewMove(p, square, target).promote(name)
                                moves = append(moves, candidate)
                        }
                }
        }
        return
}

// All capture moves for the piece in certain square. This might include
// illegal moves that cause check to the king.
func (p *Position) possibleCaptures(square int, piece Piece) (moves []Move) {
        targets := p.targets[square]

        for targets != 0 {
                target := targets.pop()
                capture := p.pieces[target]
                if capture != 0 {
                        if !p.isPawnPromotion(piece, target) {
                                moves = append(moves, NewMove(p, square, target))
                        } else {
                                for _,name := range([]int{ QUEEN, ROOK, BISHOP, KNIGHT }) {
                                        candidate := NewMove(p, square, target).promote(name)
                                        moves = append(moves, candidate)
                                }
                        }
                } else if p.flags.enpassant != 0 && target == p.flags.enpassant {
                        moves = append(moves, NewMove(p, square, target))
                }
        }
        return
}

func (p *Position) reorderMoves(moves []Move, bestMove Move, goodMove [2]Move) []Move {
        var principal, killers, captures, promotions, remaining []Move

        for _, move := range moves {
                if len(principal) == 0 && bestMove != 0 && move == bestMove {
                        principal = append(principal, move)
                } else if move.capture() != 0 {
                        captures = append(captures, move)
                } else if move.promo() != 0 {
                        promotions = append(promotions, move)
                } else if (goodMove[0] != 0 && move == goodMove[0]) || (goodMove[1] != 0 && move == goodMove[1]) {
                        killers = append(killers, move)
                } else {
                        remaining = append(remaining, move)
                }
        }
        if len(killers) > 1 && killers[0] == goodMove[1] {
                killers[0], killers[1] = killers[1], killers[0]
        }

        //sort.Sort(byScore{captures})
        //sort.Sort(byScore{remaining})
        return append(append(append(append(append(principal, captures...), promotions...), killers...), remaining...))
}

func (p *Position) reorderCaptures(moves []Move, bestMove Move) []Move {
        var principal, remaining []Move

        for _, move := range moves {
                if len(principal) == 0 && move == bestMove {
                        principal = append(principal, move)
                } else {
                        remaining = append(remaining, move)
                }
        }
        //sort.Sort(byScore{remaining})
        return append(principal, remaining...)
}

// Sorting moves by their relative score based on piece/square for regular moves
// or least valuaeable attacker/most valueable victim for captures.
// type byScore struct {
//         moves []Move
// }
// func (her byScore) Len() int           { return len(her.moves)}
// func (her byScore) Swap(i, j int)      { her.moves[i], her.moves[j] = her.moves[j], her.moves[i] }
// func (her byScore) Less(i, j int) bool { return her.moves[i].score > her.moves[j].score }

func (p *Position) pawnMove(square, target int) Move {
        color := p.color

        if RelRow(square, color) == 1 && RelRow(target, color) == 3 {
                if p.isEnpassant(target, color) {
                        return NewEnpassant(p, square, target)
                } else {
                        return NewPawnJump(p, square, target)
                }
        }

        return NewMove(p, square, target)
}

func (p *Position) pawnPromotion(square, target int) (m1, m2, m3, m4 Move) {
        m1 = NewMove(p, square, target).promote(QUEEN)
        m2 = NewMove(p, square, target).promote(ROOK)
        m3 = NewMove(p, square, target).promote(BISHOP)
        m4 = NewMove(p, square, target).promote(KNIGHT)
        return
}

func (p *Position) isEnpassant(target, color int) bool {
        pawns := p.outposts[Pawn(color^1)] // Opposite color pawns.
        switch col := Col(target); col {
        case 0:
                return pawns.isSet(target + 1)
        case 7:
                return pawns.isSet(target - 1)
        default:
                return pawns.isSet(target + 1) || pawns.isSet(target - 1)
        }
        return false
}
<commit_msg>Small tweaks<commit_after>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import() //(`sort`)

const (
        stepPrincipal = iota
        stepCaptures
        stepPromotions
        stepKillers
        stepRemaining
)

type MoveEx struct {
        move   Move
        score  int
}

type MoveList struct {
        position  *Position
        moves     [256]MoveEx
        ply       int
        head      int
        tail      int
        step      int
}

var moveList [MaxPly]MoveList

func (p *Position) StartMoveGen(ply int) (ml *MoveList) {
        ml = &moveList[ply]
        ml.position = p
        ml.moves = [256]MoveEx{}
        ml.ply = ply
        ml.head, ml.tail = 0, 0
        return
}

func (ml *MoveList) NextMove() (move Move) {
        if ml.head == ml.tail {
                return 0
        }
        move = ml.moves[ml.head].move
        ml.head++
        return
}

func (ml *MoveList) GenerateMoves() *MoveList {
        color := ml.position.color
        ml.pawnMoves(color)
        ml.pieceMoves(color)
        ml.kingMoves(color)
        return ml
}

func (ml *MoveList) pawnMoves(color int) *MoveList {
        pawns := ml.position.outposts[Pawn(color)]

        for pawns != 0 {
                square := pawns.pop()
                targets := ml.position.targets[square]
                for targets != 0 {
                        target := targets.pop()
                        if target > H1 && target < A8 {
                                ml.moves[ml.tail].move = ml.position.pawnMove(square, target)
                                ml.tail++
                        } else { // Promotion.
                                m1, m2, m3, m4 := ml.position.pawnPromotion(square, target)
                                ml.moves[ml.tail].move = m1
                                ml.tail++
                                ml.moves[ml.tail].move = m2
                                ml.tail++
                                ml.moves[ml.tail].move = m3
                                ml.tail++
                                ml.moves[ml.tail].move = m4
                                ml.tail++
                        }
                }
        }
        return ml
}

func (ml *MoveList) pieceMoves(color int) *MoveList {
	for _, kind := range [4]int{ KNIGHT, BISHOP, ROOK, QUEEN } {
	        outposts := ml.position.outposts[Piece(kind|color)]
	        for outposts != 0 {
	                square := outposts.pop()
	                targets := ml.position.targets[square]
	                for targets != 0 {
	                        ml.moves[ml.tail].move = NewMove(ml.position, square, targets.pop())
	                        ml.tail++
	                }
	        }
	}
        return ml
}

func (ml *MoveList) kingMoves(color int) *MoveList {
        king := ml.position.outposts[King(color)]
        if king != 0 {
                square := king.pop()
                targets := ml.position.targets[square]
                for targets != 0 {
                        target := targets.pop()
                        if square == homeKing[color] && Abs(square - target) == 2 {
                                ml.moves[ml.tail].move = NewCastle(ml.position, square, target)
                        } else {
                                ml.moves[ml.tail].move = NewMove(ml.position, square, target)
                        }
                        ml.tail++
                }
        }
        return ml
}

func (ml *MoveList) GenerateCaptures() *MoveList {
        color := ml.position.color
        ml.pawnCaptures(color)
        ml.pieceCaptures(color)
        return ml
}

// Generates all pseudo-legal pawn captures and Queen promotions.
func (ml *MoveList) pawnCaptures(color int) *MoveList {
        pawns := ml.position.outposts[Pawn(color)]

        for pawns != 0 {
                square := pawns.pop()
                //
                // First check capture targets on rows 2-7 (no promotions).
                //
                targets := ml.position.targets[square] & ml.position.board[color^1] & 0x00FFFFFFFFFFFF00
                for targets != 0 {
                        ml.moves[ml.tail].move = NewMove(ml.position, square, targets.pop())
                        ml.tail++
                }
                //
                // Now check promo rows. The might include capture targets as well
                // as empty promo square in front of the pawn.
                //
                if RelRow(square, color) == 6 {
                        eight := [2]int{ 8, -8 }
                        lastRow := [2]Bitmask{ 0xFF00000000000000,  0x00000000000000FF }
                        targets  = ml.position.targets[square] & lastRow[color]
                        targets |= ml.position.board[2] & Bit(square + eight[color])

                        for targets != 0 {
                                ml.moves[ml.tail].move = NewMove(ml.position, square, targets.pop()).promote(QUEEN)
                                ml.tail++
                        }
                }
        }
        return ml
}

// Generates all pseudo-legal captures by pieces other than pawn.
func (ml *MoveList) pieceCaptures(color int) *MoveList {
	for _, kind := range [5]int{ KNIGHT, BISHOP, ROOK, QUEEN, KING } {
	        outposts := ml.position.outposts[Piece(kind|color)]
	        for outposts != 0 {
	                square := outposts.pop()
	                targets := ml.position.targets[square] & ml.position.board[color^1]
	                for targets != 0 {
	                        ml.moves[ml.tail].move = NewMove(ml.position, square, targets.pop())
	                        ml.tail++
	                }
	        }
	}
	return ml
}

// All moves.
func (p *Position) Moves(ply int) (moves []Move) {
        for square, piece := range p.pieces {
                if piece != 0 && piece.color() == p.color {
                        moves = append(moves, p.possibleMoves(square, piece)...)
                }
        }
        moves = p.reorderMoves(moves, p.game.bestLine[0][ply], p.game.killers[ply])
        Log("%d candidates for %s: %v\n", len(moves), C(p.color), moves)
        return
}

func (p *Position) Captures(ply int) (moves []Move) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.color() == p.color {
                        moves = append(moves, p.possibleCaptures(i, piece)...)
                }
        }
        if bestMove := p.game.bestLine[0][ply]; bestMove != 0 && bestMove.capture() != 0 {
                moves = p.reorderCaptures(moves, bestMove)
        } else {
                //sort.Sort(byScore{moves})
        }

        Log("%d capture candidates for %s: %v\n", len(moves), C(p.color), moves)
        return
}

// All moves for the piece in certain square. This might include illegal
// moves that cause check to the king.
func (p *Position) possibleMoves(square int, piece Piece) (moves []Move) {
        targets := p.targets[square]

        for targets != 0 {
                target := targets.pop()
                //
                // For regular moves each target square represents one possible
                // move. For pawn promotion, however, we have to generate four
                // possible moves, one for each promoted piece.
                //
                if !p.isPawnPromotion(piece, target) {
                        moves = append(moves, NewMove(p, square, target))
                } else {
                        for _,name := range([]int{ QUEEN, ROOK, BISHOP, KNIGHT }) {
                                candidate := NewMove(p, square, target).promote(name)
                                moves = append(moves, candidate)
                        }
                }
        }
        return
}

// All capture moves for the piece in certain square. This might include
// illegal moves that cause check to the king.
func (p *Position) possibleCaptures(square int, piece Piece) (moves []Move) {
        targets := p.targets[square]

        for targets != 0 {
                target := targets.pop()
                capture := p.pieces[target]
                if capture != 0 {
                        if !p.isPawnPromotion(piece, target) {
                                moves = append(moves, NewMove(p, square, target))
                        } else {
                                for _,name := range([]int{ QUEEN, ROOK, BISHOP, KNIGHT }) {
                                        candidate := NewMove(p, square, target).promote(name)
                                        moves = append(moves, candidate)
                                }
                        }
                } else if p.flags.enpassant != 0 && target == p.flags.enpassant {
                        moves = append(moves, NewMove(p, square, target))
                }
        }
        return
}

func (p *Position) reorderMoves(moves []Move, bestMove Move, goodMove [2]Move) []Move {
        var principal, killers, captures, promotions, remaining []Move

        for _, move := range moves {
                if len(principal) == 0 && bestMove != 0 && move == bestMove {
                        principal = append(principal, move)
                } else if move.capture() != 0 {
                        captures = append(captures, move)
                } else if move.promo() != 0 {
                        promotions = append(promotions, move)
                } else if (goodMove[0] != 0 && move == goodMove[0]) || (goodMove[1] != 0 && move == goodMove[1]) {
                        killers = append(killers, move)
                } else {
                        remaining = append(remaining, move)
                }
        }
        if len(killers) > 1 && killers[0] == goodMove[1] {
                killers[0], killers[1] = killers[1], killers[0]
        }

        //sort.Sort(byScore{captures})
        //sort.Sort(byScore{remaining})
        return append(append(append(append(append(principal, captures...), promotions...), killers...), remaining...))
}

func (p *Position) reorderCaptures(moves []Move, bestMove Move) []Move {
        var principal, remaining []Move

        for _, move := range moves {
                if len(principal) == 0 && move == bestMove {
                        principal = append(principal, move)
                } else {
                        remaining = append(remaining, move)
                }
        }
        //sort.Sort(byScore{remaining})
        return append(principal, remaining...)
}

// Sorting moves by their relative score based on piece/square for regular moves
// or least valuaeable attacker/most valueable victim for captures.
// type byScore struct {
//         moves []Move
// }
// func (her byScore) Len() int           { return len(her.moves)}
// func (her byScore) Swap(i, j int)      { her.moves[i], her.moves[j] = her.moves[j], her.moves[i] }
// func (her byScore) Less(i, j int) bool { return her.moves[i].score > her.moves[j].score }

func (p *Position) pawnMove(square, target int) Move {
        if RelRow(square, p.color) == 1 && RelRow(target, p.color) == 3 {
                if p.isEnpassant(target, p.color) {
                        return NewEnpassant(p, square, target)
                } else {
                        return NewPawnJump(p, square, target)
                }
        }

        return NewMove(p, square, target)
}

func (p *Position) pawnPromotion(square, target int) (Move, Move, Move, Move) {
        return NewMove(p, square, target).promote(QUEEN),
               NewMove(p, square, target).promote(ROOK),
               NewMove(p, square, target).promote(BISHOP),
               NewMove(p, square, target).promote(KNIGHT)
}

func (p *Position) isEnpassant(target, color int) bool {
        pawns := p.outposts[Pawn(color^1)] // Opposite color pawns.
        switch col := Col(target); col {
        case 0:
                return pawns.isSet(target + 1)
        case 7:
                return pawns.isSet(target - 1)
        default:
                return pawns.isSet(target + 1) || pawns.isSet(target - 1)
        }
        return false
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"github.com/kelseyhightower/envconfig"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"nimona.io/internal/version"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/hyperspace/provider"
	"nimona.io/pkg/localpeer"
	"nimona.io/pkg/log"
	"nimona.io/pkg/network"
	"nimona.io/pkg/peer"
)

// nolint: lll
type config struct {
	Peer struct {
		PrivateKey      crypto.PrivateKey `envconfig:"PRIVATE_KEY"`
		BindAddress     string            `envconfig:"BIND_ADDRESS" default:"0.0.0.0:0"`
		AnnounceAddress string            `envconfig:"ANNOUNCE_ADDRESS"`
		Bootstraps      []peer.Shorthand  `envconfig:"BOOTSTRAPS"`
	} `envconfig:"PEER"`
	Metrics struct {
		BindAddress string `envconfig:"BIND_ADDRESS" default:"0.0.0.0:0"`
	} `envconfig:"METRICS"`
}

func main() {
	ctx := context.New(
		context.WithCorrelationID("nimona"),
	)

	logger := log.FromContext(ctx).With(
		log.String("build.version", version.Version),
		log.String("build.commit", version.Commit),
		log.String("build.timestamp", version.Date),
	)

	cfg := &config{}
	if err := envconfig.Process("nimona", cfg); err != nil {
		logger.Fatal("error processing config", log.Error(err))
	}

	if cfg.Peer.PrivateKey.IsEmpty() {
		logger.Fatal("missing peer private key")
	}

	// construct local peer
	local := localpeer.New()
	// attach peer private key from config
	local.PutPrimaryPeerKey(cfg.Peer.PrivateKey)

	// construct new network
	net := network.New(
		ctx,
		network.WithLocalPeer(local),
	)

	// start listening
	lis, err := net.Listen(
		ctx,
		cfg.Peer.BindAddress,
		network.ListenOnLocalIPs,
		network.ListenOnPrivateIPs,
	)
	if err != nil {
		logger.Fatal("error while listening", log.Error(err))
	}

	// add announce address
	if cfg.Peer.AnnounceAddress != "" {
		local.PutAddresses("tcps:" + cfg.Peer.AnnounceAddress)
	}

	// convert shorthands into connection infos
	bootstrapProviders := []*peer.ConnectionInfo{}
	for _, s := range cfg.Peer.Bootstraps {
		bootstrapPeer, err := s.ConnectionInfo()
		if err != nil {
			logger.Fatal("error parsing bootstrap peer", log.Error(err))
		}
		bootstrapProviders = append(bootstrapProviders, bootstrapPeer)
	}

	// construct new hyperspace provider
	_, err = provider.New(
		ctx,
		net,
		bootstrapProviders,
	)
	if err != nil {
		logger.Fatal("error while constructing provider", log.Error(err))
	}

	logger = logger.With(
		log.String("peer.privateKey", local.GetPrimaryPeerKey().String()),
		log.String("peer.publicKey", local.GetPrimaryPeerKey().PublicKey().String()),
		log.Strings("peer.addresses", local.GetAddresses()),
	)

	logger.Info("bootstrap node ready")

	go func() {
		promauto.NewGaugeFunc(
			prometheus.GaugeOpts{
				Name: "build_info",
				Help: "Build info",
				ConstLabels: prometheus.Labels{
					"commit":     version.Commit,
					"build_date": version.Date,
					"version":    version.Version,
					"goversion":  runtime.Version(),
				},
			},
			func() float64 { return 1 },
		)
		logger.Info(
			"serving metrics",
			log.String("address", cfg.Metrics.BindAddress),
		)
		http.Handle("/metrics", promhttp.Handler())
		err := http.ListenAndServe(cfg.Metrics.BindAddress, nil)
		if err != nil {
			logger.Warn("error serving metrics", log.Error(err))
			return
		}
	}()

	// register for termination signals
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// and wait for one
	<-sigs

	// finally terminate everything
	logger.Info("shutting down")
	lis.Close() // nolint: errcheck
}
<commit_msg>chore(bootstrap): clean go version in build info<commit_after>package main

import (
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"

	"github.com/kelseyhightower/envconfig"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"nimona.io/internal/version"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/hyperspace/provider"
	"nimona.io/pkg/localpeer"
	"nimona.io/pkg/log"
	"nimona.io/pkg/network"
	"nimona.io/pkg/peer"
)

// nolint: lll
type config struct {
	Peer struct {
		PrivateKey      crypto.PrivateKey `envconfig:"PRIVATE_KEY"`
		BindAddress     string            `envconfig:"BIND_ADDRESS" default:"0.0.0.0:0"`
		AnnounceAddress string            `envconfig:"ANNOUNCE_ADDRESS"`
		Bootstraps      []peer.Shorthand  `envconfig:"BOOTSTRAPS"`
	} `envconfig:"PEER"`
	Metrics struct {
		BindAddress string `envconfig:"BIND_ADDRESS" default:"0.0.0.0:0"`
	} `envconfig:"METRICS"`
}

func main() {
	ctx := context.New(
		context.WithCorrelationID("nimona"),
	)

	logger := log.FromContext(ctx).With(
		log.String("build.version", version.Version),
		log.String("build.commit", version.Commit),
		log.String("build.timestamp", version.Date),
	)

	cfg := &config{}
	if err := envconfig.Process("nimona", cfg); err != nil {
		logger.Fatal("error processing config", log.Error(err))
	}

	if cfg.Peer.PrivateKey.IsEmpty() {
		logger.Fatal("missing peer private key")
	}

	// construct local peer
	local := localpeer.New()
	// attach peer private key from config
	local.PutPrimaryPeerKey(cfg.Peer.PrivateKey)

	// construct new network
	net := network.New(
		ctx,
		network.WithLocalPeer(local),
	)

	// start listening
	lis, err := net.Listen(
		ctx,
		cfg.Peer.BindAddress,
		network.ListenOnLocalIPs,
		network.ListenOnPrivateIPs,
	)
	if err != nil {
		logger.Fatal("error while listening", log.Error(err))
	}

	// add announce address
	if cfg.Peer.AnnounceAddress != "" {
		local.PutAddresses("tcps:" + cfg.Peer.AnnounceAddress)
	}

	// convert shorthands into connection infos
	bootstrapProviders := []*peer.ConnectionInfo{}
	for _, s := range cfg.Peer.Bootstraps {
		bootstrapPeer, err := s.ConnectionInfo()
		if err != nil {
			logger.Fatal("error parsing bootstrap peer", log.Error(err))
		}
		bootstrapProviders = append(bootstrapProviders, bootstrapPeer)
	}

	// construct new hyperspace provider
	_, err = provider.New(
		ctx,
		net,
		bootstrapProviders,
	)
	if err != nil {
		logger.Fatal("error while constructing provider", log.Error(err))
	}

	logger = logger.With(
		log.String("peer.privateKey", local.GetPrimaryPeerKey().String()),
		log.String("peer.publicKey", local.GetPrimaryPeerKey().PublicKey().String()),
		log.Strings("peer.addresses", local.GetAddresses()),
	)

	logger.Info("bootstrap node ready")

	go func() {
		promauto.NewGaugeFunc(
			prometheus.GaugeOpts{
				Name: "build_info",
				Help: "Build info",
				ConstLabels: prometheus.Labels{
					"commit":     version.Commit,
					"build_date": version.Date,
					"version":    version.Version,
					"goversion": strings.Replace(
						runtime.Version(),
						"go", "v", 1,
					),
				},
			},
			func() float64 { return 1 },
		)
		logger.Info(
			"serving metrics",
			log.String("address", cfg.Metrics.BindAddress),
		)
		http.Handle("/metrics", promhttp.Handler())
		err := http.ListenAndServe(cfg.Metrics.BindAddress, nil)
		if err != nil {
			logger.Warn("error serving metrics", log.Error(err))
			return
		}
	}()

	// register for termination signals
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// and wait for one
	<-sigs

	// finally terminate everything
	logger.Info("shutting down")
	lis.Close() // nolint: errcheck
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func init() {
	adminCommands = append(adminCommands, cli.Command{
		Name:   "reify",
		Action: cli.ShowSubcommandHelp,
		Subcommands: []cli.Command{
			{
				Name:      "disc",
				Usage:     "reify a disc",
				UsageText: "bytemark --admin reify disc <disc>",
				Flags: []cli.Flag{
					cli.IntFlag{
						Name:  "disc",
						Usage: "the ID of the disc to migrate",
					},
				},
				Action: With(OptionalArgs("disc"), RequiredFlags("disc"), AuthProvider, func(c *Context) (err error) {
					if err := global.Client.ReifyDisc(c.Int("disc")); err != nil {
						return err
					}

					log.Outputf("Reification started for disc %d\n", c.Int("disc"))

					return nil
				}),
			},
		},
	})
}
<commit_msg>Fix usage text<commit_after>package main

import (
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func init() {
	adminCommands = append(adminCommands, cli.Command{
		Name:   "reify",
		Action: cli.ShowSubcommandHelp,
		Subcommands: []cli.Command{
			{
				Name:      "disc",
				Usage:     "reify a disc",
				UsageText: "bytemark --admin reify disc <disc>",
				Flags: []cli.Flag{
					cli.IntFlag{
						Name:  "disc",
						Usage: "the ID of the disc to reify",
					},
				},
				Action: With(OptionalArgs("disc"), RequiredFlags("disc"), AuthProvider, func(c *Context) (err error) {
					if err := global.Client.ReifyDisc(c.Int("disc")); err != nil {
						return err
					}

					log.Outputf("Reification started for disc %d\n", c.Int("disc"))

					return nil
				}),
			},
		},
	})
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker Compose CLI 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 compose

import (
	"context"

	"github.com/docker/compose-cli/pkg/api"
	"github.com/spf13/cobra"
)

type removeOptions struct {
	*projectOptions
	force   bool
	stop    bool
	volumes bool
}

func removeCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := removeOptions{
		projectOptions: p,
	}
	cmd := &cobra.Command{
		Use:   "rm [SERVICE...]",
		Short: "Removes stopped service containers",
		Long: `Removes stopped service containers

By default, anonymous volumes attached to containers will not be removed. You
can override this with -v. To list all volumes, use "docker volume ls".

Any data which is not in a volume will be lost.`,
		RunE: Adapt(func(ctx context.Context, args []string) error {
			return runRemove(ctx, backend, opts, args)
		}),
	}
	f := cmd.Flags()
	f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal")
	f.BoolVarP(&opts.stop, "stop", "s", false, "Stop the containers, if required, before removing")
	f.BoolVarP(&opts.volumes, "volumes", "v", false, "Remove any anonymous volumes attached to containers")
	f.BoolP("all", "a", false, "Deprecated - no effect")
	f.MarkHidden("all") //nolint:errcheck

	return cmd
}

func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
	project, err := opts.toProject(services)
	if err != nil {
		return err
	}

	if opts.stop {
		return backend.Stop(ctx, project, api.StopOptions{
			Services: services,
		})
	}

	return backend.Remove(ctx, project, api.RemoveOptions{
		Services: services,
	})
}
<commit_msg>pass --force and --volumes options to backend<commit_after>/*
   Copyright 2020 Docker Compose CLI 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 compose

import (
	"context"

	"github.com/docker/compose-cli/pkg/api"
	"github.com/spf13/cobra"
)

type removeOptions struct {
	*projectOptions
	force   bool
	stop    bool
	volumes bool
}

func removeCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := removeOptions{
		projectOptions: p,
	}
	cmd := &cobra.Command{
		Use:   "rm [SERVICE...]",
		Short: "Removes stopped service containers",
		Long: `Removes stopped service containers

By default, anonymous volumes attached to containers will not be removed. You
can override this with -v. To list all volumes, use "docker volume ls".

Any data which is not in a volume will be lost.`,
		RunE: Adapt(func(ctx context.Context, args []string) error {
			return runRemove(ctx, backend, opts, args)
		}),
	}
	f := cmd.Flags()
	f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal")
	f.BoolVarP(&opts.stop, "stop", "s", false, "Stop the containers, if required, before removing")
	f.BoolVarP(&opts.volumes, "volumes", "v", false, "Remove any anonymous volumes attached to containers")
	f.BoolP("all", "a", false, "Deprecated - no effect")
	f.MarkHidden("all") //nolint:errcheck

	return cmd
}

func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
	project, err := opts.toProject(services)
	if err != nil {
		return err
	}

	if opts.stop {
		return backend.Stop(ctx, project, api.StopOptions{
			Services: services,
		})
	}

	return backend.Remove(ctx, project, api.RemoveOptions{
		Services: services,
		Force:    opts.force,
		Volumes:  opts.volumes,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/urfave/cli"
	"golang.org/x/net/context"
	pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)

var runtimePodSandboxCommand = cli.Command{
	Name:  "sandbox",
	Usage: "Manage sandbox",
	Subcommands: []cli.Command{
		runPodSandboxCommand,
		stopPodSandboxCommand,
		removePodSandboxCommand,
		podSandboxStatusCommand,
		listPodSandboxCommand,
	},
}

var runPodSandboxCommand = cli.Command{
	Name:  "run",
	Usage: "run a pod",
	Action: func(context *cli.Context) error {
		sandboxSpec := context.Args().First()
		spec, err := os.Open(sandboxSpec)
		if err != nil {
			return fmt.Errorf("open spec file failed: %v", err)
		}
		defer spec.Close()

		var podSandboxConfig pb.PodSandboxConfig
		specParser := json.NewDecoder(spec)
		err = specParser.Decode(&podSandboxConfig)
		if err != nil {
			return fmt.Errorf("parser podSandboxConfig failed: %v", err)
		}

		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		// Test RuntimeServiceClient.RunPodSandbox
		err = RunPodSandbox(client, &podSandboxConfig)
		if err != nil {
			return fmt.Errorf("Run pod sandbox failed: %v", err)
		}
		return nil
	},
}

var stopPodSandboxCommand = cli.Command{
	Name:  "stop",
	Usage: "stop a pod sandbox",
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		id := context.Args().First()
		err = StopPodSandbox(client, id)
		if err != nil {
			return fmt.Errorf("stopping the pod sandbox failed: %v", err)
		}
		return nil
	},
}

var removePodSandboxCommand = cli.Command{
	Name:  "remove",
	Usage: "remove a pod sandbox",
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		id := context.Args().First()
		err = RemovePodSandbox(client, id)
		if err != nil {
			return fmt.Errorf("removing the pod sandbox failed: %v", err)
		}
		return nil
	},
}

var podSandboxStatusCommand = cli.Command{
	Name:  "status",
	Usage: "return the status of a pod",
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		id := context.Args().First()
		err = PodSandboxStatus(client, id)
		if err != nil {
			return fmt.Errorf("getting the pod sandbox status failed: %v", err)
		}
		return nil
	},
}

var listPodSandboxCommand = cli.Command{
	Name:  "list",
	Usage: "list pod sandboxes",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "id",
			Value: "",
			Usage: "filter by pod sandbox id",
		},
		cli.StringFlag{
			Name:  "state,s",
			Value: "",
			Usage: "filter by pod sandbox state",
		},
		cli.StringSliceFlag{
			Name:  "label,l",
			Usage: "filter by key=value label",
		},
		cli.BoolFlag{
			Name:  "quiet,q",
			Usage: "list only pod IDs",
		},
	},
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		opts := listOptions{
			id:     context.String("id"),
			state:  context.String("state"),
			quiet:  context.Bool("quiet"),
			labels: make(map[string]string),
		}

		for _, l := range context.StringSlice("label") {
			pair := strings.Split(l, "=")
			if len(pair) != 2 {
				return fmt.Errorf("incorrectly specified label: %v", l)
			}
			opts.labels[pair[0]] = pair[1]
		}

		err = ListPodSandboxes(client, opts)
		if err != nil {
			return fmt.Errorf("listing pod sandboxes failed: %v", err)
		}
		return nil
	},
}

// RunPodSandbox sends a RunPodSandboxRequest to the server, and parses
// the returned RunPodSandboxResponse.
func RunPodSandbox(client pb.RuntimeServiceClient, config *pb.PodSandboxConfig) error {
	r, err := client.RunPodSandbox(context.Background(), &pb.RunPodSandboxRequest{Config: config})
	if err != nil {
		return err
	}
	fmt.Println(r.PodSandboxId)
	return nil
}

// StopPodSandbox sends a StopPodSandboxRequest to the server, and parses
// the returned StopPodSandboxResponse.
func StopPodSandbox(client pb.RuntimeServiceClient, ID string) error {
	if ID == "" {
		return fmt.Errorf("ID cannot be empty")
	}
	_, err := client.StopPodSandbox(context.Background(), &pb.StopPodSandboxRequest{PodSandboxId: ID})
	if err != nil {
		return err
	}
	fmt.Printf("Stop sandbox success ID: %s\n", ID)
	return nil
}

// RemovePodSandbox sends a RemovePodSandboxRequest to the server, and parses
// the returned RemovePodSandboxResponse.
func RemovePodSandbox(client pb.RuntimeServiceClient, ID string) error {
	if ID == "" {
		return fmt.Errorf("ID cannot be empty")
	}
	_, err := client.RemovePodSandbox(context.Background(), &pb.RemovePodSandboxRequest{PodSandboxId: ID})
	if err != nil {
		return err
	}
	fmt.Printf("Remove sandbox success ID: %s\n", ID)
	return nil
}

// PodSandboxStatus sends a PodSandboxStatusRequest to the server, and parses
// the returned PodSandboxStatusResponse.
func PodSandboxStatus(client pb.RuntimeServiceClient, ID string) error {
	if ID == "" {
		return fmt.Errorf("ID cannot be empty")
	}
	r, err := client.PodSandboxStatus(context.Background(), &pb.PodSandboxStatusRequest{PodSandboxId: ID})
	if err != nil {
		return err
	}
	fmt.Printf("ID: %s\n", r.Status.Id)
	if r.Status.Metadata != nil {
		if r.Status.Metadata.Name != "" {
			fmt.Printf("Name: %s\n", r.Status.Metadata.Name)
		}
		if r.Status.Metadata.Uid != "" {
			fmt.Printf("UID: %s\n", r.Status.Metadata.Uid)
		}
		if r.Status.Metadata.Namespace != "" {
			fmt.Printf("Namespace: %s\n", r.Status.Metadata.Namespace)
		}
		fmt.Printf("Attempt: %v\n", r.Status.Metadata.Attempt)
	}
	fmt.Printf("Status: %s\n", r.Status.State)
	ctm := time.Unix(0, r.Status.CreatedAt)
	fmt.Printf("Created: %v\n", ctm)
	fmt.Printf("Network namespace: %s\n", r.Status.Linux.Namespaces.Network)
	if r.Status.Network != nil {
		fmt.Printf("IP Address: %v\n", r.Status.Network.Ip)
	}
	if r.Status.Labels != nil {
		fmt.Println("Labels:")
		for _, k := range getSortedKeys(r.Status.Labels) {
			fmt.Printf("\t%s -> %s\n", k, r.Status.Labels[k])
		}
	}
	if r.Status.Annotations != nil {
		fmt.Println("Annotations:")
		for _, k := range getSortedKeys(r.Status.Annotations) {
			fmt.Printf("\t%s -> %s\n", k, r.Status.Annotations[k])
		}
	}
	return nil
}

// ListPodSandboxes sends a ListPodSandboxRequest to the server, and parses
// the returned ListPodSandboxResponse.
func ListPodSandboxes(client pb.RuntimeServiceClient, opts listOptions) error {
	filter := &pb.PodSandboxFilter{}
	if opts.id != "" {
		filter.Id = opts.id
	}
	if opts.state != "" {
		st := &pb.PodSandboxStateValue{}
		st.State = pb.PodSandboxState_SANDBOX_NOTREADY
		switch opts.state {
		case "ready":
			st.State = pb.PodSandboxState_SANDBOX_READY
			filter.State = st
		case "notready":
			st.State = pb.PodSandboxState_SANDBOX_NOTREADY
			filter.State = st
		default:
			log.Fatalf("--state should be ready or notready")
		}
	}
	if opts.labels != nil {
		filter.LabelSelector = opts.labels
	}
	r, err := client.ListPodSandbox(context.Background(), &pb.ListPodSandboxRequest{
		Filter: filter,
	})
	if err != nil {
		return err
	}
	for _, pod := range r.Items {
		if opts.quiet {
			fmt.Println(pod.Id)
			continue
		}
		fmt.Printf("ID: %s\n", pod.Id)
		if pod.Metadata != nil {
			if pod.Metadata.Name != "" {
				fmt.Printf("Name: %s\n", pod.Metadata.Name)
			}
			if pod.Metadata.Uid != "" {
				fmt.Printf("UID: %s\n", pod.Metadata.Uid)
			}
			if pod.Metadata.Namespace != "" {
				fmt.Printf("Namespace: %s\n", pod.Metadata.Namespace)
			}
			fmt.Printf("Attempt: %v\n", pod.Metadata.Attempt)
		}
		fmt.Printf("Status: %s\n", pod.State)
		ctm := time.Unix(0, pod.CreatedAt)
		fmt.Printf("Created: %v\n", ctm)
		if pod.Labels != nil {
			fmt.Println("Labels:")
			for _, k := range getSortedKeys(pod.Labels) {
				fmt.Printf("\t%s -> %s\n", k, pod.Labels[k])
			}
		}
		if pod.Annotations != nil {
			fmt.Println("Annotations:")
			for _, k := range getSortedKeys(pod.Annotations) {
				fmt.Printf("\t%s -> %s\n", k, pod.Annotations[k])
			}
		}
		fmt.Println()
	}
	return nil
}
<commit_msg>fix nit in sandbox.go<commit_after>package main

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/urfave/cli"
	"golang.org/x/net/context"
	pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)

var runtimePodSandboxCommand = cli.Command{
	Name:  "sandbox",
	Usage: "Manage sandbox",
	Subcommands: []cli.Command{
		runPodSandboxCommand,
		stopPodSandboxCommand,
		removePodSandboxCommand,
		podSandboxStatusCommand,
		listPodSandboxCommand,
	},
}

var runPodSandboxCommand = cli.Command{
	Name:  "run",
	Usage: "run a pod",
	Action: func(context *cli.Context) error {
		sandboxSpec := context.Args().First()
		podSandboxConfig, err := loadPodSandboxConfig(sandboxSpec)
		if err != nil {
			return fmt.Errorf("load podSandboxConfig failed: %v", err)
		}

		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		// Test RuntimeServiceClient.RunPodSandbox
		err = RunPodSandbox(client, podSandboxConfig)
		if err != nil {
			return fmt.Errorf("Run pod sandbox failed: %v", err)
		}
		return nil
	},
}

var stopPodSandboxCommand = cli.Command{
	Name:  "stop",
	Usage: "stop a pod sandbox",
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		id := context.Args().First()
		err = StopPodSandbox(client, id)
		if err != nil {
			return fmt.Errorf("stopping the pod sandbox failed: %v", err)
		}
		return nil
	},
}

var removePodSandboxCommand = cli.Command{
	Name:  "remove",
	Usage: "remove a pod sandbox",
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		id := context.Args().First()
		err = RemovePodSandbox(client, id)
		if err != nil {
			return fmt.Errorf("removing the pod sandbox failed: %v", err)
		}
		return nil
	},
}

var podSandboxStatusCommand = cli.Command{
	Name:  "status",
	Usage: "return the status of a pod",
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		id := context.Args().First()
		err = PodSandboxStatus(client, id)
		if err != nil {
			return fmt.Errorf("getting the pod sandbox status failed: %v", err)
		}
		return nil
	},
}

var listPodSandboxCommand = cli.Command{
	Name:  "list",
	Usage: "list pod sandboxes",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "id",
			Value: "",
			Usage: "filter by pod sandbox id",
		},
		cli.StringFlag{
			Name:  "state,s",
			Value: "",
			Usage: "filter by pod sandbox state",
		},
		cli.StringSliceFlag{
			Name:  "label,l",
			Usage: "filter by key=value label",
		},
		cli.BoolFlag{
			Name:  "quiet,q",
			Usage: "list only pod IDs",
		},
	},
	Action: func(context *cli.Context) error {
		// Set up a connection to the server.
		conn, err := getRuntimeClientConnection(context)
		if err != nil {
			return fmt.Errorf("failed to connect: %v", err)
		}
		defer conn.Close()
		client := pb.NewRuntimeServiceClient(conn)

		opts := listOptions{
			id:     context.String("id"),
			state:  context.String("state"),
			quiet:  context.Bool("quiet"),
			labels: make(map[string]string),
		}

		for _, l := range context.StringSlice("label") {
			pair := strings.Split(l, "=")
			if len(pair) != 2 {
				return fmt.Errorf("incorrectly specified label: %v", l)
			}
			opts.labels[pair[0]] = pair[1]
		}

		err = ListPodSandboxes(client, opts)
		if err != nil {
			return fmt.Errorf("listing pod sandboxes failed: %v", err)
		}
		return nil
	},
}

// RunPodSandbox sends a RunPodSandboxRequest to the server, and parses
// the returned RunPodSandboxResponse.
func RunPodSandbox(client pb.RuntimeServiceClient, config *pb.PodSandboxConfig) error {
	r, err := client.RunPodSandbox(context.Background(), &pb.RunPodSandboxRequest{Config: config})
	if err != nil {
		return err
	}
	fmt.Println(r.PodSandboxId)
	return nil
}

// StopPodSandbox sends a StopPodSandboxRequest to the server, and parses
// the returned StopPodSandboxResponse.
func StopPodSandbox(client pb.RuntimeServiceClient, ID string) error {
	if ID == "" {
		return fmt.Errorf("ID cannot be empty")
	}
	_, err := client.StopPodSandbox(context.Background(), &pb.StopPodSandboxRequest{PodSandboxId: ID})
	if err != nil {
		return err
	}
	fmt.Printf("Stop sandbox success ID: %s\n", ID)
	return nil
}

// RemovePodSandbox sends a RemovePodSandboxRequest to the server, and parses
// the returned RemovePodSandboxResponse.
func RemovePodSandbox(client pb.RuntimeServiceClient, ID string) error {
	if ID == "" {
		return fmt.Errorf("ID cannot be empty")
	}
	_, err := client.RemovePodSandbox(context.Background(), &pb.RemovePodSandboxRequest{PodSandboxId: ID})
	if err != nil {
		return err
	}
	fmt.Printf("Remove sandbox success ID: %s\n", ID)
	return nil
}

// PodSandboxStatus sends a PodSandboxStatusRequest to the server, and parses
// the returned PodSandboxStatusResponse.
func PodSandboxStatus(client pb.RuntimeServiceClient, ID string) error {
	if ID == "" {
		return fmt.Errorf("ID cannot be empty")
	}
	r, err := client.PodSandboxStatus(context.Background(), &pb.PodSandboxStatusRequest{PodSandboxId: ID})
	if err != nil {
		return err
	}
	fmt.Printf("ID: %s\n", r.Status.Id)
	if r.Status.Metadata != nil {
		if r.Status.Metadata.Name != "" {
			fmt.Printf("Name: %s\n", r.Status.Metadata.Name)
		}
		if r.Status.Metadata.Uid != "" {
			fmt.Printf("UID: %s\n", r.Status.Metadata.Uid)
		}
		if r.Status.Metadata.Namespace != "" {
			fmt.Printf("Namespace: %s\n", r.Status.Metadata.Namespace)
		}
		fmt.Printf("Attempt: %v\n", r.Status.Metadata.Attempt)
	}
	fmt.Printf("Status: %s\n", r.Status.State)
	ctm := time.Unix(0, r.Status.CreatedAt)
	fmt.Printf("Created: %v\n", ctm)
	fmt.Printf("Network namespace: %s\n", r.Status.Linux.Namespaces.Network)
	if r.Status.Network != nil {
		fmt.Printf("IP Address: %v\n", r.Status.Network.Ip)
	}
	if r.Status.Labels != nil {
		fmt.Println("Labels:")
		for _, k := range getSortedKeys(r.Status.Labels) {
			fmt.Printf("\t%s -> %s\n", k, r.Status.Labels[k])
		}
	}
	if r.Status.Annotations != nil {
		fmt.Println("Annotations:")
		for _, k := range getSortedKeys(r.Status.Annotations) {
			fmt.Printf("\t%s -> %s\n", k, r.Status.Annotations[k])
		}
	}
	return nil
}

// ListPodSandboxes sends a ListPodSandboxRequest to the server, and parses
// the returned ListPodSandboxResponse.
func ListPodSandboxes(client pb.RuntimeServiceClient, opts listOptions) error {
	filter := &pb.PodSandboxFilter{}
	if opts.id != "" {
		filter.Id = opts.id
	}
	if opts.state != "" {
		st := &pb.PodSandboxStateValue{}
		st.State = pb.PodSandboxState_SANDBOX_NOTREADY
		switch opts.state {
		case "ready":
			st.State = pb.PodSandboxState_SANDBOX_READY
			filter.State = st
		case "notready":
			st.State = pb.PodSandboxState_SANDBOX_NOTREADY
			filter.State = st
		default:
			log.Fatalf("--state should be ready or notready")
		}
	}
	if opts.labels != nil {
		filter.LabelSelector = opts.labels
	}
	r, err := client.ListPodSandbox(context.Background(), &pb.ListPodSandboxRequest{
		Filter: filter,
	})
	if err != nil {
		return err
	}
	for _, pod := range r.Items {
		if opts.quiet {
			fmt.Println(pod.Id)
			continue
		}
		fmt.Printf("ID: %s\n", pod.Id)
		if pod.Metadata != nil {
			if pod.Metadata.Name != "" {
				fmt.Printf("Name: %s\n", pod.Metadata.Name)
			}
			if pod.Metadata.Uid != "" {
				fmt.Printf("UID: %s\n", pod.Metadata.Uid)
			}
			if pod.Metadata.Namespace != "" {
				fmt.Printf("Namespace: %s\n", pod.Metadata.Namespace)
			}
			fmt.Printf("Attempt: %v\n", pod.Metadata.Attempt)
		}
		fmt.Printf("Status: %s\n", pod.State)
		ctm := time.Unix(0, pod.CreatedAt)
		fmt.Printf("Created: %v\n", ctm)
		if pod.Labels != nil {
			fmt.Println("Labels:")
			for _, k := range getSortedKeys(pod.Labels) {
				fmt.Printf("\t%s -> %s\n", k, pod.Labels[k])
			}
		}
		if pod.Annotations != nil {
			fmt.Println("Annotations:")
			for _, k := range getSortedKeys(pod.Annotations) {
				fmt.Printf("\t%s -> %s\n", k, pod.Annotations[k])
			}
		}
		fmt.Println()
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/heroku/authenticater"
	metrics "github.com/rcrowley/go-metrics"
	log "github.com/sirupsen/logrus"
)

type payload struct {
	SourceAddr string
	RequestID  string
	Body       []byte
	WaitCh     chan struct{}
}

func NewPayload(sa string, ri string, b []byte) payload {
	return payload{
		SourceAddr: sa,
		RequestID:  ri,
		Body:       b,
		WaitCh:     make(chan struct{}, 1),
	}
}

type FixerFunc func(*http.Request, io.Reader, string, string, string) (bool, int64, []byte, error)

type httpServer struct {
	Config                IssConfig
	FixerFunc             FixerFunc
	shutdownCh            shutdownCh
	deliverer             deliverer
	isShuttingDown        bool
	auth                  authenticater.Authenticater
	posts                 metrics.Timer   // tracks metrics about posts
	healthChecks          metrics.Timer   // tracks metrics about health checks
	pErrors               metrics.Counter // tracks the count of post errors
	pSuccesses            metrics.Counter // tracks the number of post successes
	pAuthErrors           metrics.Counter // tracks the count of auth errors
	pAuthSuccesses        metrics.Counter // tracks the number of auth successes
	pMetadataLogsReceived metrics.Counter // tracks the number of logs that have metadata that have been received
	pLogsReceived         metrics.Counter // tracks the number of logs that have been received
	pMetadataLogsSent     metrics.Counter // tracks the number of logs that have metadata that have been received
	pLogsSent             metrics.Counter // tracks the number of logs that have been received
	pAuthUsers            map[string]metrics.Counter
	sync.WaitGroup
}

func newHTTPServer(config IssConfig, auth authenticater.Authenticater, fixerFunc FixerFunc, deliverer deliverer) *httpServer {
	return &httpServer{
		auth:                  auth,
		Config:                config,
		FixerFunc:             fixerFunc,
		deliverer:             deliverer,
		shutdownCh:            make(shutdownCh),
		posts:                 metrics.GetOrRegisterTimer("log-iss.http.logs", config.MetricsRegistry),
		healthChecks:          metrics.GetOrRegisterTimer("log-iss.http.healthchecks", config.MetricsRegistry),
		pErrors:               metrics.GetOrRegisterCounter("log-iss.http.logs.errors", config.MetricsRegistry),
		pSuccesses:            metrics.GetOrRegisterCounter("log-iss.http.logs.successes", config.MetricsRegistry),
		pAuthErrors:           metrics.GetOrRegisterCounter("log-iss.auth.errors", config.MetricsRegistry),
		pAuthSuccesses:        metrics.GetOrRegisterCounter("log-iss.auth.successes", config.MetricsRegistry),
		pMetadataLogsReceived: metrics.GetOrRegisterCounter("log-iss.metadata_logs.received", config.MetricsRegistry),
		pLogsReceived:         metrics.GetOrRegisterCounter("log-iss.logs.received", config.MetricsRegistry),
		pMetadataLogsSent:     metrics.GetOrRegisterCounter("log-iss.metadata_logs.sent", config.MetricsRegistry),
		pLogsSent:             metrics.GetOrRegisterCounter("log-iss.logs.sent", config.MetricsRegistry),
		pAuthUsers:            make(map[string]metrics.Counter),
		isShuttingDown:        false,
	}
}

func (s *httpServer) handleHTTPError(w http.ResponseWriter, errMsg string, errCode int, fields ...log.Fields) {
	ff := log.Fields{"post.code": errCode}
	for _, f := range fields {
		for k, v := range f {
			ff[k] = v
		}
	}

	s.pErrors.Inc(1)
	log.WithFields(ff).Error(errMsg)
	http.Error(w, errMsg, errCode)
}

func extractRemoteAddr(r *http.Request) string {
	remoteAddr := r.Header.Get("X-Forwarded-For")
	if remoteAddr == "" {
		remoteAddrParts := strings.Split(r.RemoteAddr, ":")
		remoteAddr = strings.Join(remoteAddrParts[:len(remoteAddrParts)-1], ":")
	}
	return remoteAddr
}

func (s *httpServer) Run() error {
	go s.awaitShutdown()

	//FXME: check outlet depth?
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		defer s.healthChecks.UpdateSince(time.Now())
		if s.isShuttingDown {
			http.Error(w, "Shutting down", 503)
			return
		}

	})

	http.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) {
		defer s.posts.UpdateSince(time.Now())

		if s.Config.EnforceSsl && r.Header.Get("X-Forwarded-Proto") != "https" {
			s.handleHTTPError(w, "Only SSL requests accepted", 400)
			return
		}

		if s.isShuttingDown {
			s.handleHTTPError(w, "Shutting down", 503)
			return
		}

		if r.Method != "POST" {
			s.handleHTTPError(w, "Only POST is accepted", 400)
			return
		}

		if r.Header.Get("Content-Type") != "application/logplex-1" {
			s.handleHTTPError(w, "Only Content-Type application/logplex-1 is accepted", 400)
			return
		}

		if !s.auth.Authenticate(r) {
			s.pAuthErrors.Inc(1)
			s.handleHTTPError(w, "Unable to authenticate request", 401)
			return
		} else {
			s.pAuthSuccesses.Inc(1)
		}

		remoteAddr := extractRemoteAddr(r)
		requestID := r.Header.Get("X-Request-Id")
		logplexDrainToken := r.Header.Get("Logplex-Drain-Token")

		body := r.Body
		var err error

		if r.Header.Get("Content-Encoding") == "gzip" {
			body, err = gzip.NewReader(r.Body)
			if err != nil {
				s.handleHTTPError(w, "Could not decode gzip request", 500)
				return
			}
			defer body.Close()
		}

		// This should only be reached if authentication information is valid.
		if authUser, _, ok := r.BasicAuth(); ok {
			var um metrics.Counter
			um, ok = s.pAuthUsers[authUser]
			if !ok {
				if s.Config.Debug {
					fmt.Printf("DEBUG: create: log-iss.auth.user.%s\n", authUser)
				}
				um = metrics.GetOrRegisterCounter(fmt.Sprintf("log-iss.auth.user.%s", authUser), s.Config.MetricsRegistry)
				s.pAuthUsers[authUser] = um
			}

			if s.Config.Debug {
				fmt.Printf("DEBUG: log-iss.auth.user.%s++\n", authUser)
			}
			um.Inc(1)
		}

		if err, status := s.process(r, body, remoteAddr, requestID, logplexDrainToken, s.Config.MetadataId); err != nil {
			s.handleHTTPError(
				w, err.Error(), status,
				log.Fields{"remote_addr": remoteAddr, "requestId": requestID, "logdrain_token": logplexDrainToken},
			)
			return
		}

		s.pSuccesses.Inc(1)
	})

	return http.ListenAndServe(":"+s.Config.HttpPort, nil)
}

func (s *httpServer) awaitShutdown() {
	<-s.shutdownCh
	s.isShuttingDown = true
	log.WithFields(log.Fields{"ns": "http", "at": "shutdown"}).Info()
}

func (s *httpServer) process(req *http.Request, r io.Reader, remoteAddr string, requestID string, logplexDrainToken string, metadataId string) (error, int) {
	s.Add(1)
	defer s.Done()

	hasMetadata, numLogs, fixedBody, err := s.FixerFunc(req, r, remoteAddr, logplexDrainToken, metadataId)
	if err != nil {
		return errors.New("Problem fixing body: " + err.Error()), http.StatusBadRequest
	}

	s.pLogsReceived.Inc(numLogs)
	if hasMetadata {
		s.pMetadataLogsReceived.Inc(numLogs)
	}

	// Scrub tokens from fixedBody
	for user, token := range s.Config.TokenMap() {
		t := []byte(token)
		if bytes.Contains(fixedBody, t) {
			fixedBody = bytes.Replace(fixedBody, t, []byte(user), -1)
		}
	}

	payload := NewPayload(remoteAddr, requestID, fixedBody)
	if err := s.deliverer.Deliver(payload); err != nil {
		return errors.New("Problem delivering body: " + err.Error()), http.StatusGatewayTimeout
	}

	s.pLogsSent.Inc(numLogs)
	if hasMetadata {
		s.pMetadataLogsSent.Inc(numLogs)
	}

	return nil, 200
}
<commit_msg>Fixing rebase issue<commit_after>package main

import (
	"bytes"
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/heroku/authenticater"
	metrics "github.com/rcrowley/go-metrics"
	log "github.com/sirupsen/logrus"
)

type payload struct {
	SourceAddr string
	RequestID  string
	Body       []byte
	WaitCh     chan struct{}
}

func NewPayload(sa string, ri string, b []byte) payload {
	return payload{
		SourceAddr: sa,
		RequestID:  ri,
		Body:       b,
		WaitCh:     make(chan struct{}, 1),
	}
}

type FixerFunc func(*http.Request, io.Reader, string, string, string) (bool, int64, []byte, error)

type httpServer struct {
	Config                IssConfig
	FixerFunc             FixerFunc
	shutdownCh            shutdownCh
	deliverer             deliverer
	isShuttingDown        bool
	auth                  authenticater.Authenticater
	posts                 metrics.Timer   // tracks metrics about posts
	healthChecks          metrics.Timer   // tracks metrics about health checks
	pErrors               metrics.Counter // tracks the count of post errors
	pSuccesses            metrics.Counter // tracks the number of post successes
	pAuthErrors           metrics.Counter // tracks the count of auth errors
	pAuthSuccesses        metrics.Counter // tracks the number of auth successes
	pMetadataLogsReceived metrics.Counter // tracks the number of logs that have metadata that have been received
	pLogsReceived         metrics.Counter // tracks the number of logs that have been received
	pMetadataLogsSent     metrics.Counter // tracks the number of logs that have metadata that have been received
	pLogsSent             metrics.Counter // tracks the number of logs that have been received
	pAuthUsers            map[string]metrics.Counter
	sync.WaitGroup
}

func newHTTPServer(config IssConfig, auth authenticater.Authenticater, fixerFunc FixerFunc, deliverer deliverer) *httpServer {
	return &httpServer{
		auth:                  auth,
		Config:                config,
		FixerFunc:             fixerFunc,
		deliverer:             deliverer,
		shutdownCh:            make(shutdownCh),
		posts:                 metrics.GetOrRegisterTimer("log-iss.http.logs", config.MetricsRegistry),
		healthChecks:          metrics.GetOrRegisterTimer("log-iss.http.healthchecks", config.MetricsRegistry),
		pErrors:               metrics.GetOrRegisterCounter("log-iss.http.logs.errors", config.MetricsRegistry),
		pSuccesses:            metrics.GetOrRegisterCounter("log-iss.http.logs.successes", config.MetricsRegistry),
		pAuthErrors:           metrics.GetOrRegisterCounter("log-iss.auth.errors", config.MetricsRegistry),
		pAuthSuccesses:        metrics.GetOrRegisterCounter("log-iss.auth.successes", config.MetricsRegistry),
		pMetadataLogsReceived: metrics.GetOrRegisterCounter("log-iss.metadata_logs.received", config.MetricsRegistry),
		pLogsReceived:         metrics.GetOrRegisterCounter("log-iss.logs.received", config.MetricsRegistry),
		pMetadataLogsSent:     metrics.GetOrRegisterCounter("log-iss.metadata_logs.sent", config.MetricsRegistry),
		pLogsSent:             metrics.GetOrRegisterCounter("log-iss.logs.sent", config.MetricsRegistry),
		pAuthUsers:            make(map[string]metrics.Counter),
		isShuttingDown:        false,
	}
}

func (s *httpServer) handleHTTPError(w http.ResponseWriter, errMsg string, errCode int, fields ...log.Fields) {
	ff := log.Fields{"post.code": errCode}
	for _, f := range fields {
		for k, v := range f {
			ff[k] = v
		}
	}

	s.pErrors.Inc(1)
	log.WithFields(ff).Error(errMsg)
	http.Error(w, errMsg, errCode)
}

func extractRemoteAddr(r *http.Request) string {
	remoteAddr := r.Header.Get("X-Forwarded-For")
	if remoteAddr == "" {
		remoteAddrParts := strings.Split(r.RemoteAddr, ":")
		remoteAddr = strings.Join(remoteAddrParts[:len(remoteAddrParts)-1], ":")
	}
	return remoteAddr
}

func (s *httpServer) Run() error {
	go s.awaitShutdown()

	//FXME: check outlet depth?
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		defer s.healthChecks.UpdateSince(time.Now())
		if s.isShuttingDown {
			http.Error(w, "Shutting down", 503)
			return
		}

	})

	http.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) {
		defer s.posts.UpdateSince(time.Now())

		if s.Config.EnforceSsl && r.Header.Get("X-Forwarded-Proto") != "https" {
			s.handleHTTPError(w, "Only SSL requests accepted", 400)
			return
		}

		if s.isShuttingDown {
			s.handleHTTPError(w, "Shutting down", 503)
			return
		}

		if r.Method != "POST" {
			s.handleHTTPError(w, "Only POST is accepted", 400)
			return
		}

		if r.Header.Get("Content-Type") != "application/logplex-1" {
			s.handleHTTPError(w, "Only Content-Type application/logplex-1 is accepted", 400)
			return
		}

		if !s.auth.Authenticate(r) {
			s.pAuthErrors.Inc(1)
			s.handleHTTPError(w, "Unable to authenticate request", 401)
			return
		} else {
			s.pAuthSuccesses.Inc(1)
		}

		remoteAddr := extractRemoteAddr(r)
		requestID := r.Header.Get("X-Request-Id")
		logplexDrainToken := r.Header.Get("Logplex-Drain-Token")

		body := r.Body
		var err error

		if r.Header.Get("Content-Encoding") == "gzip" {
			body, err = gzip.NewReader(r.Body)
			if err != nil {
				s.handleHTTPError(w, "Could not decode gzip request", 500)
				return
			}
			defer body.Close()
		}

		// This should only be reached if authentication information is valid.
		if authUser, _, ok := r.BasicAuth(); ok {
			var um metrics.Counter
			um, ok = s.pAuthUsers[authUser]
			if !ok {
				if s.Config.Debug {
					fmt.Printf("DEBUG: create: log-iss.auth.user.%s\n", authUser)
				}
				um = metrics.GetOrRegisterCounter(fmt.Sprintf("log-iss.auth.user.%s", authUser), s.Config.MetricsRegistry)
				s.pAuthUsers[authUser] = um
			}

			if s.Config.Debug {
				fmt.Printf("DEBUG: log-iss.auth.user.%s++\n", authUser)
			}
			um.Inc(1)
		}

		if err, status := s.process(r, body, remoteAddr, requestID, logplexDrainToken, s.Config.MetadataId); err != nil {
			s.handleHTTPError(
				w, err.Error(), status,
				log.Fields{"remote_addr": remoteAddr, "requestId": requestID, "logdrain_token": logplexDrainToken},
			)
			return
		}

		s.pSuccesses.Inc(1)
	})

	return http.ListenAndServe(":"+s.Config.HttpPort, nil)
}

func (s *httpServer) awaitShutdown() {
	<-s.shutdownCh
	s.isShuttingDown = true
	log.WithFields(log.Fields{"ns": "http", "at": "shutdown"}).Info()
}

func (s *httpServer) process(req *http.Request, r io.Reader, remoteAddr string, requestID string, logplexDrainToken string, metadataId string) (error, int) {
	s.Add(1)
	defer s.Done()

	hasMetadata, numLogs, fixedBody, err := s.FixerFunc(req, r, remoteAddr, logplexDrainToken, metadataId)
	if err != nil {
		return errors.New("Problem fixing body: " + err.Error()), http.StatusBadRequest
	}

	s.pLogsReceived.Inc(numLogs)
	if hasMetadata {
		s.pMetadataLogsReceived.Inc(numLogs)
	}

	// Scrub tokens from fixedBody
	for user, token := range s.Config.TokenMap() {
		t := []byte(token)
		if bytes.Contains(fixedBody, t) {
			fixedBody = bytes.Replace(fixedBody, t, []byte(user), -1)
		}
	}

	payload := NewPayload(remoteAddr, requestID, fixedBody)
	if err := s.deliverer.Deliver(payload); err != nil {
		return errors.New("Problem delivering body: " + err.Error()), http.StatusGatewayTimeout
	}

	s.pLogsSent.Inc(numLogs)
	if hasMetadata {
		s.pMetadataLogsSent.Inc(numLogs)
	}

	return nil, 200
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"

	"github.com/mattn/go-mastodon"
	"github.com/urfave/cli"
)

func cmdToot(c *cli.Context) error {
	if !c.Args().Present() {
		return errors.New("arguments required")
	}

	var toot string
	ff := c.String("ff")
	if ff != "" {
		text, err := readFile(ff)
		if err != nil {
			log.Fatal(err)
		}
		toot = string(text)
	} else {
		toot = argstr(c)
	}
	client := c.App.Metadata["client"].(*mastodon.Client)
	_, err := client.PostStatus(&mastodon.Toot{
		Status: toot,
	})
	return err
}
<commit_msg>Fix `mstdn.exe toot -ff -` errors `arguments required`<commit_after>package main

import (
	"errors"
	"log"

	"github.com/mattn/go-mastodon"
	"github.com/urfave/cli"
)

func cmdToot(c *cli.Context) error {
	var toot string
	ff := c.String("ff")
	if ff != "" {
		text, err := readFile(ff)
		if err != nil {
			log.Fatal(err)
		}
		toot = string(text)
	} else {
		if !c.Args().Present() {
			return errors.New("arguments required")
		}
		toot = argstr(c)
	}
	client := c.App.Metadata["client"].(*mastodon.Client)
	_, err := client.PostStatus(&mastodon.Toot{
		Status: toot,
	})
	return err
}
<|endoftext|>


<commit_before>package sirius

type EID string
type ExtensionConfig map[string]interface{}

type Extension interface {
	Run(Message, ExtensionConfig) (MessageAction, error)
}

type ExtensionLoader interface {
	Load(EID) (Extension, error)
}

// Read fetches a value of any type for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Read(key string, def interface{}) interface{} {
	if val, ok := cfg[key]; ok {
		return val
	}

	return def
}

// String fetches a string value for key.
// Returns def if key is not set
func (cfg ExtensionConfig) String(key string, def string) string {
	if val, ok := cfg[key]; ok {
		if s, ok := val.(string); ok {
			return s
		}
	}

	return def
}

// Integer fetches an integer value for key.
// Returns def if key is not set
func (cfg ExtensionConfig) Integer(key string, def int) int {
	if val, ok := cfg[key]; ok {
		if i, ok := val.(int); ok {
			return i
		}
	}

	return def
}

// Boolean fetches a boolean value for key.
// Returns false if key is not set
func (cfg ExtensionConfig) Boolean(key string) bool {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case bool:
			return b
		case int:
			// Require explicit 0 or 1
			if b == 0 {
				return false
			} else if b == 1 {
				return true
			}
		}
	}

	return false
}

// Float fetches a float value for key.
// Returns def if key is not set
func (cfg ExtensionConfig) Float(key string, def float64) float64 {
	if val, ok := cfg[key]; ok {
		switch f := val.(type) {
		case float32:
			return float64(f)
		case float64:
			return f
		}
	}

	return def
}

// List fetches a list value for key.
// Returns an empty list if key is not set.
func (cfg ExtensionConfig) List(key string) []string {
	if val, ok := cfg[key]; ok {
		if l, ok := val.([]string); ok {
			return l
		}
	}

	return []string{}
}
<commit_msg>Add proper punctuation<commit_after>package sirius

type EID string
type ExtensionConfig map[string]interface{}

type Extension interface {
	Run(Message, ExtensionConfig) (MessageAction, error)
}

type ExtensionLoader interface {
	Load(EID) (Extension, error)
}

// Read fetches a value of any type for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Read(key string, def interface{}) interface{} {
	if val, ok := cfg[key]; ok {
		return val
	}

	return def
}

// String fetches a string value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) String(key string, def string) string {
	if val, ok := cfg[key]; ok {
		if s, ok := val.(string); ok {
			return s
		}
	}

	return def
}

// Integer fetches an integer value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Integer(key string, def int) int {
	if val, ok := cfg[key]; ok {
		if i, ok := val.(int); ok {
			return i
		}
	}

	return def
}

// Boolean fetches a boolean value for key.
// Returns false if key is not set.
func (cfg ExtensionConfig) Boolean(key string) bool {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case bool:
			return b
		case int:
			// Require explicit 0 or 1
			if b == 0 {
				return false
			} else if b == 1 {
				return true
			}
		}
	}

	return false
}

// Float fetches a float value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Float(key string, def float64) float64 {
	if val, ok := cfg[key]; ok {
		switch f := val.(type) {
		case float32:
			return float64(f)
		case float64:
			return f
		}
	}

	return def
}

// List fetches a list value for key.
// Returns an empty list if key is not set.
func (cfg ExtensionConfig) List(key string) []string {
	if val, ok := cfg[key]; ok {
		if l, ok := val.([]string); ok {
			return l
		}
	}

	return []string{}
}
<|endoftext|>


<commit_before>package main

//go:generate esc -o templates.go ../../templates

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/fsnotify/fsnotify"
	"github.com/subosito/snowboard"
	"github.com/subosito/snowboard/engines/drafter"
	"github.com/subosito/snowboard/engines/drafterc"
)

const versionStr = "v0.3.2"

var (
	version  = flag.Bool("v", false, "Display version information")
	input    = flag.String("i", "", "API Blueprint file")
	output   = flag.String("o", "index.html", "HTML output file")
	watch    = flag.Bool("w", false, "Watch input (and template, if any) file for changes")
	serve    = flag.Bool("s", false, "Serve HTML via 0.0.0.0:8088")
	tplFile  = flag.String("t", "alpha", "Custom template for documentation")
	engineF  = flag.String("e", "cgo", "Use different engine. Supported engines: cgo, cli")
	validate = flag.Bool("l", false, "Validate input only")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage:\n  snowboard [OPTIONS]\n\nOptions:\n")
		flag.PrintDefaults()
		os.Exit(0)
	}

	flag.Parse()

	engine := parserEngine()

	if *version {
		fmt.Printf("Snowboard version: %s\n", versionStr)
		fmt.Println("Engine:")

		for name, v := range engine.Version() {
			fmt.Printf("  %s version: %s\n", name, v)
		}

		os.Exit(0)
	}

	if *input == "" {
		flag.Usage()
	}

	if *validate {
		cEngine := checkerEngine()

		b, err := readFile(*input)
		checkErr(err)

		bf := bytes.NewReader(b)

		out, err := snowboard.Validate(bf, cEngine)
		if err == nil && out == nil {
			fmt.Fprintf(os.Stdout, "OK\n")
			os.Exit(0)
		}

		if err != nil {
			checkErr(err)
		}

		s := "--------"
		w := tabwriter.NewWriter(os.Stdout, 8, 0, 0, ' ', tabwriter.Debug)
		fmt.Fprintln(w, "Row\tCol\tDescription")
		fmt.Fprintf(w, "%s\t%s\t%s\n", s, s, strings.Repeat(s, 12))

		for _, n := range out.Annotations {
			for _, m := range n.SourceMaps {
				fmt.Fprintf(w, "%d\t%d\t%s\n", m.Row, m.Col, n.Description)
			}
		}

		w.Flush()
		os.Exit(1)
	}

	if *watch {
		watcher, err := fsnotify.NewWatcher()
		checkErr(err)
		defer watcher.Close()

		done := make(chan bool)
		go func() {
			for {
				select {
				case event := <-watcher.Events:
					if event.Op&fsnotify.Write == fsnotify.Write {
						renderHTML(engine)
					}
				case err := <-watcher.Errors:
					log.Println("Error:", err)
				}
			}
		}()

		err = watcher.Add(*input)
		checkErr(err)

		_, err = os.Stat(*tplFile)
		if err == nil {
			err = watcher.Add(*tplFile)
			checkErr(err)
		}

		renderHTML(engine)
		serveHTML()

		<-done
	} else {
		renderHTML(engine)
		serveHTML()
	}
}

func readFile(fn string) ([]byte, error) {
	info, err := os.Stat(fn)
	if err != nil {
		return nil, errors.New("File is not exist")
	}

	if info.IsDir() {
		return nil, errors.New("File is a directory")
	}

	return ioutil.ReadFile(fn)
}

func readTemplate(fn string) ([]byte, error) {
	tf, err := readFile(fn)
	if err == nil {
		return tf, nil
	}

	fs := FS(false)
	ff, err := fs.Open("/templates/" + fn + ".html")
	if err != nil {
		return nil, err
	}

	defer ff.Close()
	return ioutil.ReadAll(ff)
}

func checkErr(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(1)
	}
}

func renderHTML(engine snowboard.Parser) {
	bp, err := snowboard.Load(*input, engine)
	logErr(err)

	of, err := os.Create(*output)
	logErr(err)
	defer of.Close()

	tf, err := readTemplate(*tplFile)
	logErr(err)

	err = snowboard.HTML(string(tf), of, bp)
	logErr(err)
	log.Println("HTML has been generated!")
}

func logErr(err error) {
	if err != nil {
		log.Fatalln("Error: ", err)
	}
}

func serveHTML() {
	if !*serve {
		return
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, *output)
	})

	err := http.ListenAndServe(":8088", nil)
	logErr(err)
}

func parserEngine() snowboard.Parser {
	switch *engineF {
	case "cli":
		return drafterc.Engine{}
	}

	return drafter.Engine{}
}

func checkerEngine() snowboard.Checker {
	return drafter.Engine{}
}
<commit_msg>bump version<commit_after>package main

//go:generate esc -o templates.go ../../templates

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/fsnotify/fsnotify"
	"github.com/subosito/snowboard"
	"github.com/subosito/snowboard/engines/drafter"
	"github.com/subosito/snowboard/engines/drafterc"
)

const versionStr = "v0.3.3"

var (
	version  = flag.Bool("v", false, "Display version information")
	input    = flag.String("i", "", "API Blueprint file")
	output   = flag.String("o", "index.html", "HTML output file")
	watch    = flag.Bool("w", false, "Watch input (and template, if any) file for changes")
	serve    = flag.Bool("s", false, "Serve HTML via 0.0.0.0:8088")
	tplFile  = flag.String("t", "alpha", "Custom template for documentation")
	engineF  = flag.String("e", "cgo", "Use different engine. Supported engines: cgo, cli")
	validate = flag.Bool("l", false, "Validate input only")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage:\n  snowboard [OPTIONS]\n\nOptions:\n")
		flag.PrintDefaults()
		os.Exit(0)
	}

	flag.Parse()

	engine := parserEngine()

	if *version {
		fmt.Printf("Snowboard version: %s\n", versionStr)
		fmt.Println("Engine:")

		for name, v := range engine.Version() {
			fmt.Printf("  %s version: %s\n", name, v)
		}

		os.Exit(0)
	}

	if *input == "" {
		flag.Usage()
	}

	if *validate {
		cEngine := checkerEngine()

		b, err := readFile(*input)
		checkErr(err)

		bf := bytes.NewReader(b)

		out, err := snowboard.Validate(bf, cEngine)
		if err == nil && out == nil {
			fmt.Fprintf(os.Stdout, "OK\n")
			os.Exit(0)
		}

		if err != nil {
			checkErr(err)
		}

		s := "--------"
		w := tabwriter.NewWriter(os.Stdout, 8, 0, 0, ' ', tabwriter.Debug)
		fmt.Fprintln(w, "Row\tCol\tDescription")
		fmt.Fprintf(w, "%s\t%s\t%s\n", s, s, strings.Repeat(s, 12))

		for _, n := range out.Annotations {
			for _, m := range n.SourceMaps {
				fmt.Fprintf(w, "%d\t%d\t%s\n", m.Row, m.Col, n.Description)
			}
		}

		w.Flush()
		os.Exit(1)
	}

	if *watch {
		watcher, err := fsnotify.NewWatcher()
		checkErr(err)
		defer watcher.Close()

		done := make(chan bool)
		go func() {
			for {
				select {
				case event := <-watcher.Events:
					if event.Op&fsnotify.Write == fsnotify.Write {
						renderHTML(engine)
					}
				case err := <-watcher.Errors:
					log.Println("Error:", err)
				}
			}
		}()

		err = watcher.Add(*input)
		checkErr(err)

		_, err = os.Stat(*tplFile)
		if err == nil {
			err = watcher.Add(*tplFile)
			checkErr(err)
		}

		renderHTML(engine)
		serveHTML()

		<-done
	} else {
		renderHTML(engine)
		serveHTML()
	}
}

func readFile(fn string) ([]byte, error) {
	info, err := os.Stat(fn)
	if err != nil {
		return nil, errors.New("File is not exist")
	}

	if info.IsDir() {
		return nil, errors.New("File is a directory")
	}

	return ioutil.ReadFile(fn)
}

func readTemplate(fn string) ([]byte, error) {
	tf, err := readFile(fn)
	if err == nil {
		return tf, nil
	}

	fs := FS(false)
	ff, err := fs.Open("/templates/" + fn + ".html")
	if err != nil {
		return nil, err
	}

	defer ff.Close()
	return ioutil.ReadAll(ff)
}

func checkErr(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(1)
	}
}

func renderHTML(engine snowboard.Parser) {
	bp, err := snowboard.Load(*input, engine)
	logErr(err)

	of, err := os.Create(*output)
	logErr(err)
	defer of.Close()

	tf, err := readTemplate(*tplFile)
	logErr(err)

	err = snowboard.HTML(string(tf), of, bp)
	logErr(err)
	log.Println("HTML has been generated!")
}

func logErr(err error) {
	if err != nil {
		log.Fatalln("Error: ", err)
	}
}

func serveHTML() {
	if !*serve {
		return
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, *output)
	})

	err := http.ListenAndServe(":8088", nil)
	logErr(err)
}

func parserEngine() snowboard.Parser {
	switch *engineF {
	case "cli":
		return drafterc.Engine{}
	}

	return drafter.Engine{}
}

func checkerEngine() snowboard.Checker {
	return drafter.Engine{}
}
<|endoftext|>