<commit_before>package main

import (
    "fmt"
    "encoding/json"
    "errors"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

/*
 * Checks the car numberplate.
 *
 * The numberplate is handed out by the DOT.
 */
func IsConfirmed(car *Car) bool {
    // cannot have a numberplate without car papers
    if (!IsRegistered(car)) {
        return false
    }

    // cannot give you a numberplate without insurance contract
    if (!IsInsured(car)) {
        return false
    }

    confirmed := car.Certificate.Numberplate != ""

    // because the car is registered, the car VIN can be trusted
    if (confirmed) {
        fmt.Printf("Car with VIN '%s' is confirmed\n", car.Vin)
    } else {
        fmt.Printf("Car with VIN '%s' has no valid numberplate\n", car.Vin)
    }

    return confirmed
}

/*
 * Checks for a valid car VIN.
 *
 * The car VIN is valid if the DOT certificate contains
 * the same information. Registration guarantees that
 * certificate VIN and a car VIN are equal and that
 * a certificate was issued by the DOT at least once.
 */
func IsRegistered(car *Car) bool {
    // cannot be registered without certificate
    if (car.Certificate.Vin == "") {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
        return false
    }

    // validate car VIN
    carVin := car.Vin
    registered := car.Certificate.Vin == carVin

    if (registered) {
        fmt.Printf("Car created at ts '%d' is registered with VIN '%s'\n", car.CreatedTs, carVin)
    } else {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
    }

    return registered
}

/*
 * Returns the registration proposal index with all
 * registration proposals.
 */
func (t *CarChaincode) getRegistrationProposals(stub shim.ChaincodeStubInterface) (map[string]RegistrationProposal, error) {
    response := t.read(stub, registrationProposalIndexStr)
    proposalIndex := make(map[string]RegistrationProposal)
    err := json.Unmarshal(response.Payload, &proposalIndex)
    if err != nil {
        return nil, errors.New("Error parsing registration proposal index")
    }

    return proposalIndex, nil
}

/*
 * Reads all registration proposals.
 */
func (t *CarChaincode) readRegistrationProposals(stub shim.ChaincodeStubInterface) pb.Response {
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    indexAsBytes, _ := json.Marshal(proposalIndex)
    return shim.Success(indexAsBytes)
}

/*
 * Returns a registration proposal for a car.
 */
func (t *CarChaincode) getRegistrationProposal(stub shim.ChaincodeStubInterface, car string) pb.Response {
    // load all proposals
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    ret := proposalIndex[car]
    retAsBytes, _ := json.Marshal(ret)
    return shim.Success(retAsBytes)
}

/*
 * Registers a car.
 *
 * Registration guarantees that certificate VIN
 * and a car VIN are equal and that a certificate
 * was issued by the DOT at least once.
 *
 * To register a car, a RegistrationProposal needs to be present.
 * This proposal is removed/deleted after successfull registration.
 * This is not consistent with reality, but serves the purpose
 * for now, because the Form 13.20 A (RegistrationProposal)
 * is not used anywhere else right now. Like this, the RegistrationProposal
 * only serves the purpose to signal the DOT, that there is a new
 * car waiting for registration.
 *
 * On success,
 * returns the car with certificate.
 */
func (t *CarChaincode) register(stub shim.ChaincodeStubInterface, username string, vin string) pb.Response {
    // reading the car already checks that the user
    // is the actual owner of the car
    carResponse := t.readCar(stub, username, vin)
    car := Car {}
    json.Unmarshal(carResponse.Payload, &car)
    if vin != car.Vin {
        return shim.Error(fmt.Sprintf("Cannot register, invalid VIN.\nCar VIN is '%s' and you want to register VIN '%s'", car.Vin, vin))
    }

    // get all registration proposals
    proposals, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    // check if there exists a registration proposal for that car
    if proposals[car.Vin].Car != vin {
        return shim.Error(fmt.Sprintf("There exists no registration proposal for car with VIN: %s", vin))
    }

    // create a certificate, approve vin
    // and update the car in the ledger
    cert := Certificate { Username: username,
                          Vin:      vin }
    car.Certificate = cert
    carAsBytes, _ := json.Marshal(car)
    err = stub.PutState(car.Vin, carAsBytes)
    if err != nil {
        return shim.Error("Error writing car")
    }

    // remove the proposal we just registered
    delete(proposals, car.Vin)

    // save the new proposal index
    // without the car we just registered
    proposalsAsBytes, _ := json.Marshal(proposals)
    err = stub.PutState(registrationProposalIndexStr, proposalsAsBytes)
    if err != nil {
        return shim.Error("Error writing proposal index")
    }

    fmt.Printf("Successfully registered car created at ts '%d' with VIN '%s'\n", car.CreatedTs, vin)

    return shim.Success(carAsBytes)
}

/*
 * Confirms a car and assigns a numberplate.
 *
 * Only the owner of a car can request confirmation of a car.
 * Car needs to be insured as a requirement for getting
 * the permit to drive on the roads. Only insured cars can get
 * confirmed and get a numberplate.
 *
 * Required arguments:
 * [0] Vin         string
 * [1] Numberplate string
 *
 * On success,
 * returns the car with numberplate.
 */
func (t *CarChaincode) confirm(stub shim.ChaincodeStubInterface, username string, args []string) pb.Response {
    vin := args[0]
    numberplate := args[1]

    if vin == "" {
        return shim.Error("'confirm' expects a non-empty VIN to assign a numberplate")
    }

    // check numberplate argument
    if numberplate == "" {
        return shim.Error("Car numberplate is empty. Please provide a numberplate to confirm your car")
    }

    // fetch the car from the ledger
    // this already checks for ownership
    carResponse := t.readCar(stub, username, vin)
    car := Car{}
    err := json.Unmarshal(carResponse.Payload, &car)
    if err != nil {
        return shim.Error("Failed to fetch car with vin '" + vin + "' from ledger")
    }

    // check if car is insured
    if !IsInsured(&car) {
        return shim.Error("Car is not insured. Please insure car first before trying to confirm it")
    }

    // check if numberplate is already in use
    // carIndex, err := t.getCarIndex(stub)
    // for k, v := range carIndex {
    //  if v.Numberplate == numberplate {
    //      return shim.Error("Car numberplate already in use. Please use another one!")
    //
    // }

    // assign the numberplate to the car
    car.Certificate.Numberplate = numberplate

    // write udpated car back to ledger
    carAsBytes, _ := json.Marshal(car)
    err = stub.PutState(vin, carAsBytes)
    if err != nil {
        return shim.Error("Error writing car")
    }

    // car confirmation successfull,
    // return the car with numberplate
    return shim.Success(carAsBytes)
}<commit_msg>checks for already existing numberplates<commit_after>package main

import (
    "fmt"
    "encoding/json"
    "errors"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

/*
 * Checks the car numberplate.
 *
 * The numberplate is handed out by the DOT.
 */
func IsConfirmed(car *Car) bool {
    // cannot have a numberplate without car papers
    if (!IsRegistered(car)) {
        return false
    }

    // cannot give you a numberplate without insurance contract
    if (!IsInsured(car)) {
        return false
    }

    confirmed := car.Certificate.Numberplate != ""

    // because the car is registered, the car VIN can be trusted
    if (confirmed) {
        fmt.Printf("Car with VIN '%s' is confirmed\n", car.Vin)
    } else {
        fmt.Printf("Car with VIN '%s' has no valid numberplate\n", car.Vin)
    }

    return confirmed
}

/*
 * Checks for a valid car VIN.
 *
 * The car VIN is valid if the DOT certificate contains
 * the same information. Registration guarantees that
 * certificate VIN and a car VIN are equal and that
 * a certificate was issued by the DOT at least once.
 */
func IsRegistered(car *Car) bool {
    // cannot be registered without certificate
    if (car.Certificate.Vin == "") {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
        return false
    }

    // validate car VIN
    carVin := car.Vin
    registered := car.Certificate.Vin == carVin

    if (registered) {
        fmt.Printf("Car created at ts '%d' is registered with VIN '%s'\n", car.CreatedTs, carVin)
    } else {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
    }

    return registered
}

/*
 * Returns the registration proposal index with all
 * registration proposals.
 */
func (t *CarChaincode) getRegistrationProposals(stub shim.ChaincodeStubInterface) (map[string]RegistrationProposal, error) {
    response := t.read(stub, registrationProposalIndexStr)
    proposalIndex := make(map[string]RegistrationProposal)
    err := json.Unmarshal(response.Payload, &proposalIndex)
    if err != nil {
        return nil, errors.New("Error parsing registration proposal index")
    }

    return proposalIndex, nil
}

/*
 * Reads all registration proposals.
 */
func (t *CarChaincode) readRegistrationProposals(stub shim.ChaincodeStubInterface) pb.Response {
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    indexAsBytes, _ := json.Marshal(proposalIndex)
    return shim.Success(indexAsBytes)
}

/*
 * Returns a registration proposal for a car.
 */
func (t *CarChaincode) getRegistrationProposal(stub shim.ChaincodeStubInterface, car string) pb.Response {
    // load all proposals
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    ret := proposalIndex[car]
    retAsBytes, _ := json.Marshal(ret)
    return shim.Success(retAsBytes)
}

/*
 * Registers a car.
 *
 * Registration guarantees that certificate VIN
 * and a car VIN are equal and that a certificate
 * was issued by the DOT at least once.
 *
 * To register a car, a RegistrationProposal needs to be present.
 * This proposal is removed/deleted after successfull registration.
 * This is not consistent with reality, but serves the purpose
 * for now, because the Form 13.20 A (RegistrationProposal)
 * is not used anywhere else right now. Like this, the RegistrationProposal
 * only serves the purpose to signal the DOT, that there is a new
 * car waiting for registration.
 *
 * On success,
 * returns the car with certificate.
 */
func (t *CarChaincode) register(stub shim.ChaincodeStubInterface, username string, vin string) pb.Response {
    // reading the car already checks that the user
    // is the actual owner of the car
    carResponse := t.readCar(stub, username, vin)
    car := Car {}
    json.Unmarshal(carResponse.Payload, &car)
    if vin != car.Vin {
        return shim.Error(fmt.Sprintf("Cannot register, invalid VIN.\nCar VIN is '%s' and you want to register VIN '%s'", car.Vin, vin))
    }

    // get all registration proposals
    proposals, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    // check if there exists a registration proposal for that car
    if proposals[car.Vin].Car != vin {
        return shim.Error(fmt.Sprintf("There exists no registration proposal for car with VIN: %s", vin))
    }

    // create a certificate, approve vin
    // and update the car in the ledger
    cert := Certificate { Username: username,
                          Vin:      vin }
    car.Certificate = cert
    carAsBytes, _ := json.Marshal(car)
    err = stub.PutState(car.Vin, carAsBytes)
    if err != nil {
        return shim.Error("Error writing car")
    }

    // remove the proposal we just registered
    delete(proposals, car.Vin)

    // save the new proposal index
    // without the car we just registered
    proposalsAsBytes, _ := json.Marshal(proposals)
    err = stub.PutState(registrationProposalIndexStr, proposalsAsBytes)
    if err != nil {
        return shim.Error("Error writing proposal index")
    }

    fmt.Printf("Successfully registered car created at ts '%d' with VIN '%s'\n", car.CreatedTs, vin)

    return shim.Success(carAsBytes)
}

/*
 * Confirms a car and assigns a numberplate.
 *
 * Only the owner of a car can request confirmation of a car.
 * Car needs to be insured as a requirement for getting
 * the permit to drive on the roads. Only insured cars can get
 * confirmed and get a numberplate.
 *
 * Required arguments:
 * [0] Vin         string
 * [1] Numberplate string
 *
 * On success,
 * returns the car with numberplate.
 */
func (t *CarChaincode) confirm(stub shim.ChaincodeStubInterface, username string, args []string) pb.Response {
    vin := args[0]
    numberplate := args[1]

    if vin == "" {
        return shim.Error("'confirm' expects a non-empty VIN to assign a numberplate")
    }

    // check numberplate argument
    if numberplate == "" {
        return shim.Error("Car numberplate is empty. Please provide a numberplate to confirm your car")
    }

    // fetch the car from the ledger
    // this already checks for ownership
    carResponse := t.readCar(stub, username, vin)
    car := Car{}
    err := json.Unmarshal(carResponse.Payload, &car)
    if err != nil {
        return shim.Error("Failed to fetch car with vin '" + vin + "' from ledger")
    }

    // check if car is insured
    if !IsInsured(&car) {
        return shim.Error("Car is not insured. Please insure car first before trying to confirm it")
    }

    // check if numberplate is already in use
    carIndex, err := t.getCarIndex(stub)
    carToCheck := Car{}
    for carVin, user := range carIndex {
        // get the full car object with certificate
        carToCheckResp := t.readCar(stub, user, carVin)
        err := json.Unmarshal(carToCheckResp.Payload, &carToCheck)
        if err != nil {
            return shim.Error("Failed to fetch car with vin '" + carVin + "' from ledger")
        }

        if carToCheck.Certificate.Numberplate == numberplate {
            return shim.Error("Car numberplate already in use. Please use another one!")
        }
    }

    // assign the numberplate to the car
    car.Certificate.Numberplate = numberplate

    // write udpated car back to ledger
    carAsBytes, _ := json.Marshal(car)
    err = stub.PutState(vin, carAsBytes)
    if err != nil {
        return shim.Error("Error writing car")
    }

    // car confirmation successfull,
    // return the car with numberplate
    return shim.Success(carAsBytes)
}<|endoftext|>


<commit_before>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 cmd

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"time"

	"github.com/osrg/gobgp/packet/mrt"
	"github.com/osrg/gobgp/table"
	"github.com/spf13/cobra"
)

func injectMrt(filename string, count int, skip int, onlyBest bool) error {

	file, err := os.Open(filename)
	if err != nil {
		return fmt.Errorf("failed to open file: %s", err)
	}

	idx := 0

	ch := make(chan []*table.Path, 1<<20)

	go func() {

		var peers []*mrt.Peer

		for {
			buf := make([]byte, mrt.MRT_COMMON_HEADER_LEN)
			_, err := file.Read(buf)
			if err == io.EOF {
				break
			} else if err != nil {
				exitWithError(fmt.Errorf("failed to read: %s", err))
			}

			h := &mrt.MRTHeader{}
			err = h.DecodeFromBytes(buf)
			if err != nil {
				exitWithError(fmt.Errorf("failed to parse"))
			}

			buf = make([]byte, h.Len)
			_, err = file.Read(buf)
			if err != nil {
				exitWithError(fmt.Errorf("failed to read"))
			}

			msg, err := mrt.ParseMRTBody(h, buf)
			if err != nil {
				printError(fmt.Errorf("failed to parse: %s", err))
				continue
			}

			if globalOpts.Debug {
				fmt.Println(msg)
			}

			if msg.Header.Type == mrt.TABLE_DUMPv2 {
				subType := mrt.MRTSubTypeTableDumpv2(msg.Header.SubType)
				switch subType {
				case mrt.PEER_INDEX_TABLE:
					peers = msg.Body.(*mrt.PeerIndexTable).Peers
					continue
				default:
					exitWithError(fmt.Errorf("unsupported subType: %v", subType))
				}

				if peers == nil {
					exitWithError(fmt.Errorf("not found PEER_INDEX_TABLE"))
				}

				rib := msg.Body.(*mrt.Rib)
				nlri := rib.Prefix

				paths := make([]*table.Path, 0, len(rib.Entries))

				for _, e := range rib.Entries {
					if len(peers) < int(e.PeerIndex) {
						exitWithError(fmt.Errorf("invalid peer index: %d (PEER_INDEX_TABLE has only %d peers)\n", e.PeerIndex, len(peers)))
					}
					source := &table.PeerInfo{
						AS: peers[e.PeerIndex].AS,
						ID: peers[e.PeerIndex].BgpId,
					}
					t := time.Unix(int64(e.OriginatedTime), 0)
					paths = append(paths, table.NewPath(source, nlri, false, e.PathAttributes, t, false))
				}

				if onlyBest {
					dst := table.NewDestination(nlri)
					for _, p := range paths {
						dst.AddNewPath(p)
					}
					best, _, _ := dst.Calculate([]string{table.GLOBAL_RIB_NAME})
					if best[table.GLOBAL_RIB_NAME] == nil {
						exitWithError(fmt.Errorf("Can't find the best %v", nlri))
					}
					paths = []*table.Path{best[table.GLOBAL_RIB_NAME]}
				}

				if idx >= skip {
					ch <- paths
				}

				idx += 1
				if idx == count+skip {
					break
				}
			}
		}

		close(ch)
	}()

	stream, err := client.AddPathByStream()
	if err != nil {
		return fmt.Errorf("failed to modpath: %s", err)
	}

	for paths := range ch {
		err = stream.Send(paths...)
		if err != nil {
			return fmt.Errorf("failed to send: %s", err)
		}
	}

	if err := stream.Close(); err != nil {
		return fmt.Errorf("failed to send: %s", err)
	}
	return nil
}

func NewMrtCmd() *cobra.Command {
	globalInjectCmd := &cobra.Command{
		Use: CMD_GLOBAL,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) < 1 {
				exitWithError(fmt.Errorf("usage: gobgp mrt inject global <filename> [<count> [<skip>]]"))
			}
			filename := args[0]
			count := -1
			skip := 0
			if len(args) > 1 {
				var err error
				count, err = strconv.Atoi(args[1])
				if err != nil {
					exitWithError(fmt.Errorf("invalid count value: %s", args[1]))
				}
				if len(args) > 2 {
					skip, err = strconv.Atoi(args[2])
					if err != nil {
						exitWithError(fmt.Errorf("invalid skip value: %s", args[2]))
					}
				}
			}
			err := injectMrt(filename, count, skip, mrtOpts.Best)
			if err != nil {
				exitWithError(err)
			}
		},
	}

	injectCmd := &cobra.Command{
		Use: CMD_INJECT,
	}
	injectCmd.AddCommand(globalInjectCmd)

	mrtCmd := &cobra.Command{
		Use: CMD_MRT,
	}
	mrtCmd.AddCommand(injectCmd)

	mrtCmd.PersistentFlags().BoolVarP(&mrtOpts.Best, "only-best", "", false, "inject only best paths")
	return mrtCmd
}
<commit_msg>cli: fix bug of injecting mrt table dump v2 data<commit_after>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 cmd

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"time"

	"github.com/osrg/gobgp/packet/mrt"
	"github.com/osrg/gobgp/table"
	"github.com/spf13/cobra"
)

func injectMrt(filename string, count int, skip int, onlyBest bool) error {

	file, err := os.Open(filename)
	if err != nil {
		return fmt.Errorf("failed to open file: %s", err)
	}

	idx := 0

	ch := make(chan []*table.Path, 1<<20)

	go func() {

		var peers []*mrt.Peer

		for {
			buf := make([]byte, mrt.MRT_COMMON_HEADER_LEN)
			_, err := file.Read(buf)
			if err == io.EOF {
				break
			} else if err != nil {
				exitWithError(fmt.Errorf("failed to read: %s", err))
			}

			h := &mrt.MRTHeader{}
			err = h.DecodeFromBytes(buf)
			if err != nil {
				exitWithError(fmt.Errorf("failed to parse"))
			}

			buf = make([]byte, h.Len)
			_, err = file.Read(buf)
			if err != nil {
				exitWithError(fmt.Errorf("failed to read"))
			}

			msg, err := mrt.ParseMRTBody(h, buf)
			if err != nil {
				printError(fmt.Errorf("failed to parse: %s", err))
				continue
			}

			if globalOpts.Debug {
				fmt.Println(msg)
			}

			if msg.Header.Type == mrt.TABLE_DUMPv2 {
				subType := mrt.MRTSubTypeTableDumpv2(msg.Header.SubType)
				switch subType {
				case mrt.PEER_INDEX_TABLE:
					peers = msg.Body.(*mrt.PeerIndexTable).Peers
					continue
				case mrt.RIB_IPV4_UNICAST, mrt.RIB_IPV6_UNICAST:
				default:
					exitWithError(fmt.Errorf("unsupported subType: %v", subType))
				}

				if peers == nil {
					exitWithError(fmt.Errorf("not found PEER_INDEX_TABLE"))
				}

				rib := msg.Body.(*mrt.Rib)
				nlri := rib.Prefix

				paths := make([]*table.Path, 0, len(rib.Entries))

				for _, e := range rib.Entries {
					if len(peers) < int(e.PeerIndex) {
						exitWithError(fmt.Errorf("invalid peer index: %d (PEER_INDEX_TABLE has only %d peers)\n", e.PeerIndex, len(peers)))
					}
					source := &table.PeerInfo{
						AS: peers[e.PeerIndex].AS,
						ID: peers[e.PeerIndex].BgpId,
					}
					t := time.Unix(int64(e.OriginatedTime), 0)
					paths = append(paths, table.NewPath(source, nlri, false, e.PathAttributes, t, false))
				}

				if onlyBest {
					dst := table.NewDestination(nlri)
					for _, p := range paths {
						dst.AddNewPath(p)
					}
					best, _, _ := dst.Calculate([]string{table.GLOBAL_RIB_NAME})
					if best[table.GLOBAL_RIB_NAME] == nil {
						exitWithError(fmt.Errorf("Can't find the best %v", nlri))
					}
					paths = []*table.Path{best[table.GLOBAL_RIB_NAME]}
				}

				if idx >= skip {
					ch <- paths
				}

				idx += 1
				if idx == count+skip {
					break
				}
			}
		}

		close(ch)
	}()

	stream, err := client.AddPathByStream()
	if err != nil {
		return fmt.Errorf("failed to modpath: %s", err)
	}

	for paths := range ch {
		err = stream.Send(paths...)
		if err != nil {
			return fmt.Errorf("failed to send: %s", err)
		}
	}

	if err := stream.Close(); err != nil {
		return fmt.Errorf("failed to send: %s", err)
	}
	return nil
}

func NewMrtCmd() *cobra.Command {
	globalInjectCmd := &cobra.Command{
		Use: CMD_GLOBAL,
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) < 1 {
				exitWithError(fmt.Errorf("usage: gobgp mrt inject global <filename> [<count> [<skip>]]"))
			}
			filename := args[0]
			count := -1
			skip := 0
			if len(args) > 1 {
				var err error
				count, err = strconv.Atoi(args[1])
				if err != nil {
					exitWithError(fmt.Errorf("invalid count value: %s", args[1]))
				}
				if len(args) > 2 {
					skip, err = strconv.Atoi(args[2])
					if err != nil {
						exitWithError(fmt.Errorf("invalid skip value: %s", args[2]))
					}
				}
			}
			err := injectMrt(filename, count, skip, mrtOpts.Best)
			if err != nil {
				exitWithError(err)
			}
		},
	}

	injectCmd := &cobra.Command{
		Use: CMD_INJECT,
	}
	injectCmd.AddCommand(globalInjectCmd)

	mrtCmd := &cobra.Command{
		Use: CMD_MRT,
	}
	mrtCmd.AddCommand(injectCmd)

	mrtCmd.PersistentFlags().BoolVarP(&mrtOpts.Best, "only-best", "", false, "inject only best paths")
	return mrtCmd
}
<|endoftext|>


<commit_before>package gotermBox

import (
	"bytes"
	"io"

	"github.com/antongulenko/golib"
	"github.com/antongulenko/goterm"
)

// CliLogBox can display a box spanning over the entire command-line screen
// containing arbitrary content that can be updated from outside, and an additional
// section at the bottom containing log messages captured using a LogBuffer.
type CliLogBox struct {
	// LogBuffer provides the underlying functionality for capturing log messages.
	// CliLogBox acts like an extension of LogBuffer. After calling Init(),
	// the log capturing must be taken care of using RegisterMessageHooks(),
	// InterceptLogger() and RestoreLogger().
	*LogBuffer

	// NoUtf8 can be set to true to replace UTF8 border drawing characters with
	// regular ASCII characters.
	NoUtf8 bool

	// LogLines configures the minimum number of log entries that must remain visible
	// in the lower part of the console box. The log entries are appended directly
	// to the actual output and usually take the rest of the screen. If the box content
	// is so long, that it would leave less than LogLines log entries, the content is
	// truncated. The truncation is visualized by three dots in the separator line
	// between the content and the log entries.
	LogLines int

	// MessageBuffer configures the number of messages stored in the underlying LogBuffer.
	MessageBuffer int
}

// Init initializes the underlying LogBuffer and should be called before any other methods.
func (box *CliLogBox) Init() {
	box.LogBuffer = NewDefaultLogBuffer(box.MessageBuffer)
}

// Updates refreshes the entire display output. It can be called in arbitrary time intervals,
// but should never be called concurrently. The content must be written by the given function,
// which also receives the width of the screen. If it prints lines that are longer than the screen
// width, they will be cut off. It can produce an arbitrary number of lines.
func (box *CliLogBox) Update(writeContent func(out io.Writer, width int)) {
	termSize := golib.GetTerminalSize()
	gotermBox := &goterm.Box{
		Buf:      new(bytes.Buffer),
		Width:    int(termSize.Col),
		Height:   int(termSize.Row) - 1, // Subtract 1 for the line with cursor
		PaddingX: 1,
		PaddingY: 0,
	}
	var separator, dots string
	if box.NoUtf8 {
		gotermBox.Border = "- | - - - -"
		separator = "-"
		dots = "... "
	} else {
		gotermBox.Border = "═ ║ ╔ ╗ ╚ ╝"
		separator = "═"
		dots = "··· "
	}
	lines := gotermBox.Height - 3 // borders + separator

	counter := newlineCounter{out: gotermBox}
	if box.LogLines > 0 {
		counter.max_lines = lines - box.LogLines
	}
	writeContent(&counter, gotermBox.Width)
	lines -= counter.num

	if counter.num > 0 {
		i := 0
		if counter.truncated {
			gotermBox.Write([]byte(dots))
			i += len(dots)
		}
		for i := 0; i < gotermBox.Width; i++ {
			gotermBox.Write([]byte(separator))
		}
		gotermBox.Write([]byte("\n"))
	}
	box.PrintMessages(gotermBox, lines)
	goterm.MoveCursor(1, 1)
	goterm.Print(gotermBox)
	goterm.Flush()
}

type newlineCounter struct {
	out       io.Writer
	num       int
	max_lines int
	truncated bool
}

func (counter *newlineCounter) Write(data []byte) (int, error) {
	total := len(data)
	if counter.max_lines <= 0 || counter.num < counter.max_lines {
		written := 0
		start := 0
		for i, char := range data {
			if char == '\n' {
				counter.num++
				num, err := counter.out.Write(data[start : i+1])
				written += num
				start = i + 1
				if err != nil {
					return written, err
				}
				if counter.max_lines > 0 && counter.num >= counter.max_lines {
					return total, err
				}
			}
		}
		num, err := counter.out.Write(data[start:])
		written += num
		if err != nil {
			return written, err
		}
	} else {
		counter.truncated = true
	}
	return total, nil
}
<commit_msg>fixing<commit_after>package gotermBox

import (
	"io"

	"github.com/antongulenko/golib"
	"github.com/antongulenko/goterm"
)

// CliLogBox can display a box spanning over the entire command-line screen
// containing arbitrary content that can be updated from outside, and an additional
// section at the bottom containing log messages captured using a LogBuffer.
type CliLogBox struct {
	// LogBuffer provides the underlying functionality for capturing log messages.
	// CliLogBox acts like an extension of LogBuffer. After calling Init(),
	// the log capturing must be taken care of using RegisterMessageHooks(),
	// InterceptLogger() and RestoreLogger().
	*LogBuffer

	// NoUtf8 can be set to true to replace UTF8 border drawing characters with
	// regular ASCII characters.
	NoUtf8 bool

	// LogLines configures the minimum number of log entries that must remain visible
	// in the lower part of the console box. The log entries are appended directly
	// to the actual output and usually take the rest of the screen. If the box content
	// is so long, that it would leave less than LogLines log entries, the content is
	// truncated. The truncation is visualized by three dots in the separator line
	// between the content and the log entries.
	LogLines int

	// MessageBuffer configures the number of messages stored in the underlying LogBuffer.
	MessageBuffer int
}

// Init initializes the underlying LogBuffer and should be called before any other methods.
func (box *CliLogBox) Init() {
	box.LogBuffer = NewDefaultLogBuffer(box.MessageBuffer)
}

// Updates refreshes the entire display output. It can be called in arbitrary time intervals,
// but should never be called concurrently. The content must be written by the given function,
// which also receives the width of the screen. If it prints lines that are longer than the screen
// width, they will be cut off. It can produce an arbitrary number of lines.
func (box *CliLogBox) Update(writeContent func(out io.Writer, width int)) {
	termSize := golib.GetTerminalSize()
	gotermBox := goterm.NewBox(int(termSize.Col), int(termSize.Row), 0)
	gotermBox.Height -= 1 // Subtract 1 for the line with cursor

	var separator, dots string
	if box.NoUtf8 {
		gotermBox.Border = "- | - - - -"
		separator = "-"
		dots = "... "
	} else {
		gotermBox.Border = "═ ║ ╔ ╗ ╚ ╝"
		separator = "═"
		dots = "··· "
	}
	lines := gotermBox.Height - 3 // borders + separator

	counter := newlineCounter{out: gotermBox}
	if box.LogLines > 0 {
		counter.max_lines = lines - box.LogLines
	}
	writeContent(&counter, gotermBox.Width)
	lines -= counter.num

	if counter.num > 0 {
		i := 0
		if counter.truncated {
			gotermBox.Write([]byte(dots))
			i += len(dots)
		}
		for i := 0; i < gotermBox.Width; i++ {
			gotermBox.Write([]byte(separator))
		}
		gotermBox.Write([]byte("\n"))
	}
	box.PrintMessages(gotermBox, lines)
	goterm.MoveCursor(1, 1)
	goterm.Print(gotermBox)
	goterm.Flush()
}

type newlineCounter struct {
	out       io.Writer
	num       int
	max_lines int
	truncated bool
}

func (counter *newlineCounter) Write(data []byte) (int, error) {
	total := len(data)
	if counter.max_lines <= 0 || counter.num < counter.max_lines {
		written := 0
		start := 0
		for i, char := range data {
			if char == '\n' {
				counter.num++
				num, err := counter.out.Write(data[start : i+1])
				written += num
				start = i + 1
				if err != nil {
					return written, err
				}
				if counter.max_lines > 0 && counter.num >= counter.max_lines {
					return total, err
				}
			}
		}
		num, err := counter.out.Write(data[start:])
		written += num
		if err != nil {
			return written, err
		}
	} else {
		counter.truncated = true
	}
	return total, nil
}
<|endoftext|>


<commit_before>//
// Copyright 2020, Serena Fang
//
// 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 gitlab

import (
	"fmt"
	"time"
)

// InstanceClustersService handles communication with the
// instance clusters related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html
type InstanceClustersService struct {
	client *Client
}

// InstanceCluster represents a GitLab Instance Cluster.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/instance_clusters.html
type InstanceCluster struct {
	ID                 int                 `json:"id"`
	Name               string              `json:"name"`
	Domain             string              `json:"domain"`
	CreatedAt          *time.Time          `json:"created_at"`
	ProviderType       string              `json:"provider_type"`
	PlatformType       string              `json:"platform_type"`
	EnvironmentScope   string              `json:"environment_scope"`
	ClusterType        string              `json:"cluster_type"`
	User               *User               `json:"user"`
	PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"`
	ManagementProject  *ManagementProject  `json:"management_project"`
}

func (v InstanceCluster) String() string {
	return Stringify(v)
}

// PlatformKubernetes represents a GitLab Instance Cluster PlatformKubernetes.
type InstanceClusterPlatformKubernetes struct {
	APIURL            string `json:"api_url"`
	Token             string `json:"token"`
	CaCert            string `json:"ca_cert"`
	Namespace         string `json:"namespace"`
	AuthorizationType string `json:"authorization_type"`
}

// ListClusters gets a list of all instance clusters.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#list-instance-clusters
func (s *InstanceClustersService) ListClusters(options ...RequestOptionFunc) ([]*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters")

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var ics []*InstanceCluster
	resp, err := s.client.Do(req, &ics)
	if err != nil {
		return nil, resp, err
	}

	return ics, resp, err
}

// GetCluster gets an instance cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#get-a-single-instance-cluster
func (s *InstanceClustersService) GetCluster(cluster int, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters/%d", cluster)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	ic := new(InstanceCluster)
	resp, err := s.client.Do(req, &ic)
	if err != nil {
		return nil, resp, err
	}

	return ic, resp, err
}

// AddInstanceClusterOptions represents the available AddCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-cluster-to-instance
type AddInstanceClusterOptions struct {
	Name                *string                               `url:"name,omitempty" json:"name,omitempty"`
	Domain              *string                               `url:"domain,omitempty" json:"domain,omitempty"`
	Enabled             *bool                                 `url:"enabled,omitempty" json:"enabled,omitempty"`
	Managed             *bool                                 `url:"managed,omitempty" json:"managed,omitempty"`
	EnvironmentScope    *string                               `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	PlatformKubernetes  *PlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
	ManagementProjectID *string                               `url:"management_project_id,omitempty" json:"management_project_id,omitempty"`
}

// AddInstancePlatformKubernetesOptions represents the available PlatformKubernetes options for adding.
type PlatformKubernetesOptions struct {
	APIURL            *string `url:"api_url,omitempty" json:"api_url,omitempty"`
	Token             *string `url:"token,omitempty" json:"token,omitempty"`
	CaCert            *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"`
	Namespace         *string `url:"namespace,omitempty" json:"namespace,omitempty"`
	AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"`
}

// AddCluster adds an existing cluster to the instance.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-instance-cluster
func (s *InstanceClustersService) AddCluster(opt *AddInstanceClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters/add")

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	ic := new(InstanceCluster)
	resp, err := s.client.Do(req, ic)
	if err != nil {
		return nil, resp, err
	}

	return ic, resp, err
}

// EditInstanceClusterOptions represents the available EditCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#edit-instance-cluster
type EditInstanceClusterOptions struct {
	Name                *string                                `url:"name,omitempty" json:"name,omitempty"`
	Domain              *string                                `url:"domain,omitempty" json:"domain,omitempty"`
	EnvironmentScope    *string                                `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	ManagementProjectID *string                                `url:"management_project_id,omitempty" json:"management_project_id,omitempty"`
	PlatformKubernetes  *PlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
}

// EditCluster updates an existing instance cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#edit-instance-cluster
func (s *InstanceClustersService) EditCluster(cluster int, opt *EditInstanceClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters/%d", cluster)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	ic := new(InstanceCluster)
	resp, err := s.client.Do(req, ic)
	if err != nil {
		return nil, resp, err
	}

	return ic, resp, err
}

// DeleteCluster deletes an existing instance cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#delete-instance-cluster
func (s *InstanceClustersService) DeleteCluster(cluster int, options ...RequestOptionFunc) (*Response, error) {
	u := fmt.Sprintf("admin/clusters/%d", cluster)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>Remove redundant struct declarations<commit_after>//
// Copyright 2020, Serena Fang
//
// 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 gitlab

import (
	"fmt"
	"time"
)

// InstanceClustersService handles communication with the
// instance clusters related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html
type InstanceClustersService struct {
	client *Client
}

// InstanceCluster represents a GitLab Instance Cluster.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/instance_clusters.html
type InstanceCluster struct {
	ID                 int                 `json:"id"`
	Name               string              `json:"name"`
	Domain             string              `json:"domain"`
	CreatedAt          *time.Time          `json:"created_at"`
	ProviderType       string              `json:"provider_type"`
	PlatformType       string              `json:"platform_type"`
	EnvironmentScope   string              `json:"environment_scope"`
	ClusterType        string              `json:"cluster_type"`
	User               *User               `json:"user"`
	PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"`
	ManagementProject  *ManagementProject  `json:"management_project"`
}

func (v InstanceCluster) String() string {
	return Stringify(v)
}

// ListClusters gets a list of all instance clusters.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#list-instance-clusters
func (s *InstanceClustersService) ListClusters(options ...RequestOptionFunc) ([]*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters")

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var ics []*InstanceCluster
	resp, err := s.client.Do(req, &ics)
	if err != nil {
		return nil, resp, err
	}

	return ics, resp, err
}

// GetCluster gets an instance cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#get-a-single-instance-cluster
func (s *InstanceClustersService) GetCluster(cluster int, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters/%d", cluster)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	ic := new(InstanceCluster)
	resp, err := s.client.Do(req, &ic)
	if err != nil {
		return nil, resp, err
	}

	return ic, resp, err
}

// AddInstanceClusterOptions represents the available AddCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-cluster-to-instance
type AddInstanceClusterOptions struct {
	Name                *string                               `url:"name,omitempty" json:"name,omitempty"`
	Domain              *string                               `url:"domain,omitempty" json:"domain,omitempty"`
	Enabled             *bool                                 `url:"enabled,omitempty" json:"enabled,omitempty"`
	Managed             *bool                                 `url:"managed,omitempty" json:"managed,omitempty"`
	EnvironmentScope    *string                               `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	PlatformKubernetes  *PlatformKubernetesOptions `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
	ManagementProjectID *string                               `url:"management_project_id,omitempty" json:"management_project_id,omitempty"`
}

// AddInstancePlatformKubernetesOptions represents the available PlatformKubernetes options for adding.
type PlatformKubernetesOptions struct {
	APIURL            *string `url:"api_url,omitempty" json:"api_url,omitempty"`
	Token             *string `url:"token,omitempty" json:"token,omitempty"`
	CaCert            *string `url:"ca_cert,omitempty" json:"ca_cert,omitempty"`
	Namespace         *string `url:"namespace,omitempty" json:"namespace,omitempty"`
	AuthorizationType *string `url:"authorization_type,omitempty" json:"authorization_type,omitempty"`
}

// AddCluster adds an existing cluster to the instance.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-instance-cluster
func (s *InstanceClustersService) AddCluster(opt *AddInstanceClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters/add")

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	ic := new(InstanceCluster)
	resp, err := s.client.Do(req, ic)
	if err != nil {
		return nil, resp, err
	}

	return ic, resp, err
}

// EditCluster updates an existing instance cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#edit-instance-cluster
func (s *InstanceClustersService) EditCluster(cluster int, opt *EditClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
	u := fmt.Sprintf("admin/clusters/%d", cluster)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	ic := new(InstanceCluster)
	resp, err := s.client.Do(req, ic)
	if err != nil {
		return nil, resp, err
	}

	return ic, resp, err
}

// DeleteCluster deletes an existing instance cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/instance_clusters.html#delete-instance-cluster
func (s *InstanceClustersService) DeleteCluster(cluster int, options ...RequestOptionFunc) (*Response, error) {
	u := fmt.Sprintf("admin/clusters/%d", cluster)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/aclements/go-misc/internal/loganal"
)

// TODO: Search a set of log files or saved builder logs. If searching
// saved builder logs, optionally print to builder URLs instead of
// local file names.

// TODO: Optionally extract failures and show only those.

// TODO: Optionally classify matched logs by failure (and show either
// file name or extracted failure).

// TODO: Option to print Markdown-friendly output for GitHub.

// TODO: Option to print failure summary versus full failure message.

// TODO: Option to only show failures matching regexp? Currently we
// show all failures in files matching regexp, but sometimes you want
// to search the failures themselves. We could pre-filter the files by
// regexp, extract failures, and then match the failure messages.

var (
	// TODO: Allow mulitple -e's like grep.
	flagRegexp = flag.String("e", "", "show files matching `regexp`")
	re         *regexp.Regexp
)

func main() {
	// XXX What I want right now is just to point it at a bunch of
	// logs and have it extract the failures.
	flag.Parse()

	if *flagRegexp != "" {
		var err error
		re, err = regexp.Compile(*flagRegexp)
		if err != nil {
			fmt.Fprintf(os.Stderr, "bad regexp: %v\n", err)
			os.Exit(2)
		}
	}

	// Process files
	status := 1
	for _, path := range flag.Args() {
		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
				return nil
			}
			if info.IsDir() {
				return nil
			}

			found, err := process(path)
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
			} else if found && status == 1 {
				status = 0
			}
			return nil
		})
	}
	os.Exit(status)
}

func process(path string) (found bool, err error) {
	// TODO: Use streaming if possible.
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}

	// Check regexp match.
	if re != nil && !re.Match(data) {
		return false, nil
	}

	// Extract failures.
	failures, err := loganal.Extract(string(data), "", "")
	if err != nil {
		return false, err
	}

	// Print failures.
	for _, failure := range failures {
		msg := failure.FullMessage
		if msg == "" {
			msg = failure.Message
		}
		fmt.Printf("%s:\n%s\n\n", path, msg)
		continue
		lines := strings.Split(msg, "\n")
		for _, line := range lines {
			fmt.Printf("%s: %s\n", path, line)
		}
		fmt.Println()
	}
	return true, nil
}
<commit_msg>greplogs: flag to search dashboard logs<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/aclements/go-misc/internal/loganal"
)

// TODO: If searching dashboard logs, optionally print to builder URLs
// instead of local file names.

// TODO: Optionally extract failures and show only those.

// TODO: Optionally classify matched logs by failure (and show either
// file name or extracted failure).

// TODO: Option to print Markdown-friendly output for GitHub.

// TODO: Option to print failure summary versus full failure message.

// TODO: Option to only show failures matching regexp? Currently we
// show all failures in files matching regexp, but sometimes you want
// to search the failures themselves. We could pre-filter the files by
// regexp, extract failures, and then match the failure messages.

var (
	// TODO: Allow mulitple -e's like grep.
	flagRegexp = flag.String("e", "", "show files matching `regexp`")
	re         *regexp.Regexp

	flagDashboard = flag.Bool("dashboard", false, "search dashboard logs from fetchlogs")
)

func main() {
	// XXX What I want right now is just to point it at a bunch of
	// logs and have it extract the failures.
	flag.Parse()

	// Validate flags.
	if *flagRegexp != "" {
		var err error
		re, err = regexp.Compile(*flagRegexp)
		if err != nil {
			fmt.Fprintf(os.Stderr, "bad regexp: %v\n", err)
			os.Exit(2)
		}
	}
	if *flagDashboard && flag.NArg() > 0 {
		fmt.Fprintf(os.Stderr, "-dashboard and paths are incompatible\n")
		os.Exit(2)
	}

	// Gather paths.
	var paths []string
	var stripDir string
	if *flagDashboard {
		revDir := filepath.Join(xdgCacheDir(), "fetchlogs", "rev")
		paths = []string{revDir}
		stripDir = revDir + "/"
	} else {
		paths = flag.Args()
	}

	// Process files
	status := 1
	for _, path := range paths {
		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
				return nil
			}
			if info.IsDir() || strings.HasPrefix(filepath.Base(path), ".") {
				return nil
			}

			nicePath := path
			if stripDir != "" && strings.HasPrefix(path, stripDir) {
				nicePath = path[len(stripDir):]
			}

			found, err := process(path, nicePath)
			if err != nil {
				status = 2
				fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
			} else if found && status == 1 {
				status = 0
			}
			return nil
		})
	}
	os.Exit(status)
}

func process(path, nicePath string) (found bool, err error) {
	// TODO: Use streaming if possible.
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}

	// Check regexp match.
	if re != nil && !re.Match(data) {
		return false, nil
	}

	// Extract failures.
	failures, err := loganal.Extract(string(data), "", "")
	if err != nil {
		return false, err
	}

	// Print failures.
	for _, failure := range failures {
		msg := failure.FullMessage
		if msg == "" {
			msg = failure.Message
		}
		fmt.Printf("%s:\n%s\n\n", nicePath, msg)
	}
	return true, nil
}
<|endoftext|>


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

// Arqfs implements a file system interface to a collection of Arq backups.
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os/exec"

	"code.google.com/p/rsc/arq"
	"code.google.com/p/rsc/fuse"
	"code.google.com/p/rsc/keychain"
	"launchpad.net/goamz/aws"
)

func main() {
	access, secret, err := keychain.UserPasswd("s3.amazonaws.com", "")
	if err != nil {
		log.Fatal(err)
	}
	auth := aws.Auth{access, secret}

	conn, err := arq.Dial(auth)
	if err != nil {
		log.Fatal(err)
	}

	comps, err := conn.Computers()
	if err != nil {
		log.Fatal(err)
	}

	fs := &fuse.Tree{}
	for _, c := range comps {
		// TODO: what?
		_, pw, err := keychain.UserPasswd("arq.swtch.com", c.UUID)
		if err != nil {
			log.Fatal(err)
		}
		c.Unlock(pw)

		folders, err := c.Folders()
		if err != nil {
			log.Fatal(err)
		}

		lastDate := ""
		n := 0
		for _, f := range folders {
			if err := f.Load(); err != nil {
				log.Fatal(err)
			}
			trees, err := f.Trees()
			if err != nil {
				log.Fatal(err)
			}
			for _, t := range trees {
				y, m, d := t.Time.Date()
				date := fmt.Sprintf("%04d/%02d%02d", y, m, d)
				suffix := ""
				if date == lastDate {
					n++
					suffix = fmt.Sprintf(".%d", n)
				} else {
					n = 0
				}
				lastDate = date
				f, err := t.Root()
				if err != nil {
					log.Print(err)
				}
				// TODO: Pass times to fs.Add.
				fmt.Printf("%v %s %x\n", t.Time, c.Name+"/"+date+suffix+"/"+t.Path, t.Score)
				fs.Add(c.Name+"/"+date+suffix+"/"+t.Path, &fuseNode{f})
			}
		}
	}

	c, err := fuse.Mount("/mnt/arq")
	if err != nil {
		log.Fatal(err)
	}
	defer exec.Command("umount", "/mnt/arq").Run()

	fmt.Printf("serving /mnt/arq\n")
	c.Serve(fs)
}

type fuseNode struct {
	arq *arq.File
}

func (f *fuseNode) Attr() fuse.Attr {
	de := f.arq.Stat()
	return fuse.Attr{
		Mode:  de.Mode,
		Mtime: de.ModTime,
		Size:  uint64(de.Size),
	}
}

func (f *fuseNode) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
	ff, err := f.arq.Lookup(name)
	if err != nil {
		return nil, fuse.ENOENT
	}
	return &fuseNode{ff}, nil
}

func (f *fuseNode) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
	adir, err := f.arq.ReadDir()
	if err != nil {
		return nil, fuse.EIO
	}
	var dir []fuse.Dirent
	for _, ade := range adir {
		dir = append(dir, fuse.Dirent{
			Name: ade.Name,
		})
	}
	return dir, nil
}

// TODO: Implement Read+Release, not ReadAll, to avoid giant buffer.
func (f *fuseNode) ReadAll() ([]byte, fuse.Error) {
	rc, err := f.arq.Open()
	if err != nil {
		return nil, fuse.EIO
	}
	defer rc.Close()
	data, err := ioutil.ReadAll(rc)
	if err != nil {
		return data, fuse.EIO
	}
	return data, nil
}
<commit_msg>arq/arqfs: fix ReadAll signature<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Arqfs implements a file system interface to a collection of Arq backups.
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os/exec"

	"code.google.com/p/rsc/arq"
	"code.google.com/p/rsc/fuse"
	"code.google.com/p/rsc/keychain"
	"launchpad.net/goamz/aws"
)

func main() {
	access, secret, err := keychain.UserPasswd("s3.amazonaws.com", "")
	if err != nil {
		log.Fatal(err)
	}
	auth := aws.Auth{access, secret}

	conn, err := arq.Dial(auth)
	if err != nil {
		log.Fatal(err)
	}

	comps, err := conn.Computers()
	if err != nil {
		log.Fatal(err)
	}

	fs := &fuse.Tree{}
	for _, c := range comps {
		// TODO: what?
		_, pw, err := keychain.UserPasswd("arq.swtch.com", c.UUID)
		if err != nil {
			log.Fatal(err)
		}
		c.Unlock(pw)

		folders, err := c.Folders()
		if err != nil {
			log.Fatal(err)
		}

		lastDate := ""
		n := 0
		for _, f := range folders {
			if err := f.Load(); err != nil {
				log.Fatal(err)
			}
			trees, err := f.Trees()
			if err != nil {
				log.Fatal(err)
			}
			for _, t := range trees {
				y, m, d := t.Time.Date()
				date := fmt.Sprintf("%04d/%02d%02d", y, m, d)
				suffix := ""
				if date == lastDate {
					n++
					suffix = fmt.Sprintf(".%d", n)
				} else {
					n = 0
				}
				lastDate = date
				f, err := t.Root()
				if err != nil {
					log.Print(err)
				}
				// TODO: Pass times to fs.Add.
				fmt.Printf("%v %s %x\n", t.Time, c.Name+"/"+date+suffix+"/"+t.Path, t.Score)
				fs.Add(c.Name+"/"+date+suffix+"/"+t.Path, &fuseNode{f})
			}
		}
	}

	c, err := fuse.Mount("/mnt/arq")
	if err != nil {
		log.Fatal(err)
	}
	defer exec.Command("umount", "/mnt/arq").Run()

	fmt.Printf("serving /mnt/arq\n")
	c.Serve(fs)
}

type fuseNode struct {
	arq *arq.File
}

func (f *fuseNode) Attr() fuse.Attr {
	de := f.arq.Stat()
	return fuse.Attr{
		Mode:  de.Mode,
		Mtime: de.ModTime,
		Size:  uint64(de.Size),
	}
}

func (f *fuseNode) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
	ff, err := f.arq.Lookup(name)
	if err != nil {
		return nil, fuse.ENOENT
	}
	return &fuseNode{ff}, nil
}

func (f *fuseNode) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
	adir, err := f.arq.ReadDir()
	if err != nil {
		return nil, fuse.EIO
	}
	var dir []fuse.Dirent
	for _, ade := range adir {
		dir = append(dir, fuse.Dirent{
			Name: ade.Name,
		})
	}
	return dir, nil
}

// TODO: Implement Read+Release, not ReadAll, to avoid giant buffer.
func (f *fuseNode) ReadAll(intr fuse.Intr) ([]byte, fuse.Error) {
	rc, err := f.arq.Open()
	if err != nil {
		return nil, fuse.EIO
	}
	defer rc.Close()
	data, err := ioutil.ReadAll(rc)
	if err != nil {
		return data, fuse.EIO
	}
	return data, nil
}
<|endoftext|>


<commit_before>package chainntnfs

import (
	"bytes"
	"errors"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	bolt "github.com/coreos/bbolt"
	"github.com/lightningnetwork/lnd/channeldb"
)

const (
	// dbName is the default name of the database storing the height hints.
	dbName = "heighthint.db"

	// dbFilePermission is the default permission of the database file
	// storing the height hints.
	dbFilePermission = 0600
)

var (
	// spendHintBucket is the name of the bucket which houses the height
	// hint for outpoints. Each height hint represents the earliest height
	// at which its corresponding outpoint could have been spent within.
	spendHintBucket = []byte("spend-hints")

	// confirmHintBucket is the name of the bucket which houses the height
	// hints for transactions. Each height hint represents the earliest
	// height at which its corresponding transaction could have been
	// confirmed within.
	confirmHintBucket = []byte("confirm-hints")

	// ErrCorruptedHeightHintCache indicates that the on-disk bucketing
	// structure has altered since the height hint cache instance was
	// initialized.
	ErrCorruptedHeightHintCache = errors.New("height hint cache has been " +
		"corrupted")

	// ErrSpendHintNotFound is an error returned when a spend hint for an
	// outpoint was not found.
	ErrSpendHintNotFound = errors.New("spend hint not found")

	// ErrConfirmHintNotFound is an error returned when a confirm hint for a
	// transaction was not found.
	ErrConfirmHintNotFound = errors.New("confirm hint not found")
)

// SpendHintCache is an interface whose duty is to cache spend hints for
// outpoints. A spend hint is defined as the earliest height in the chain at
// which an outpoint could have been spent within.
type SpendHintCache interface {
	// CommitSpendHint commits a spend hint for the outpoints to the cache.
	CommitSpendHint(height uint32, ops ...wire.OutPoint) error

	// QuerySpendHint returns the latest spend hint for an outpoint.
	// ErrSpendHintNotFound is returned if a spend hint does not exist
	// within the cache for the outpoint.
	QuerySpendHint(op wire.OutPoint) (uint32, error)

	// PurgeSpendHint removes the spend hint for the outpoints from the
	// cache.
	PurgeSpendHint(ops ...wire.OutPoint) error
}

// ConfirmHintCache is an interface whose duty is to cache confirm hints for
// transactions. A confirm hint is defined as the earliest height in the chain
// at which a transaction could have been included in a block.
type ConfirmHintCache interface {
	// CommitConfirmHint commits a confirm hint for the transactions to the
	// cache.
	CommitConfirmHint(height uint32, txids ...chainhash.Hash) error

	// QueryConfirmHint returns the latest confirm hint for a transaction
	// hash. ErrConfirmHintNotFound is returned if a confirm hint does not
	// exist within the cache for the transaction hash.
	QueryConfirmHint(txid chainhash.Hash) (uint32, error)

	// PurgeConfirmHint removes the confirm hint for the transactions from
	// the cache.
	PurgeConfirmHint(txids ...chainhash.Hash) error
}

// HeightHintCache is an implementation of the SpendHintCache and
// ConfirmHintCache interfaces backed by a channeldb DB instance where the hints
// will be stored.
type HeightHintCache struct {
	db *channeldb.DB
}

// Compile-time checks to ensure HeightHintCache satisfies the SpendHintCache
// and ConfirmHintCache interfaces.
var _ SpendHintCache = (*HeightHintCache)(nil)
var _ ConfirmHintCache = (*HeightHintCache)(nil)

// NewHeightHintCache returns a new height hint cache backed by a database.
func NewHeightHintCache(db *channeldb.DB) (*HeightHintCache, error) {
	cache := &HeightHintCache{db}
	if err := cache.initBuckets(); err != nil {
		return nil, err
	}

	return cache, nil
}

// initBuckets ensures that the primary buckets used by the circuit are
// initialized so that we can assume their existence after startup.
func (c *HeightHintCache) initBuckets() error {
	return c.db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(spendHintBucket)
		if err != nil {
			return err
		}

		_, err = tx.CreateBucketIfNotExists(confirmHintBucket)
		return err
	})
}

// CommitSpendHint commits a spend hint for the outpoints to the cache.
func (c *HeightHintCache) CommitSpendHint(height uint32, ops ...wire.OutPoint) error {
	Log.Tracef("Updating spend hint to height %d for %v", height, ops)

	return c.db.Batch(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, op := range ops {
			var outpoint bytes.Buffer
			err := channeldb.WriteElement(&outpoint, op)
			if err != nil {
				return err
			}

			err = spendHints.Put(outpoint.Bytes(), hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QuerySpendHint returns the latest spend hint for an outpoint.
// ErrSpendHintNotFound is returned if a spend hint does not exist within the
// cache for the outpoint.
func (c *HeightHintCache) QuerySpendHint(op wire.OutPoint) (uint32, error) {
	var hint uint32
	err := c.db.View(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var outpoint bytes.Buffer
		if err := channeldb.WriteElement(&outpoint, op); err != nil {
			return err
		}

		spendHint := spendHints.Get(outpoint.Bytes())
		if spendHint == nil {
			return ErrSpendHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(spendHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeSpendHint removes the spend hint for the outpoints from the cache.
func (c *HeightHintCache) PurgeSpendHint(ops ...wire.OutPoint) error {
	Log.Tracef("Removing spend hints for %v", ops)

	return c.db.Batch(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, op := range ops {
			var outpoint bytes.Buffer
			err := channeldb.WriteElement(&outpoint, op)
			if err != nil {
				return err
			}

			err = spendHints.Delete(outpoint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// CommitConfirmHint commits a confirm hint for the transactions to the cache.
func (c *HeightHintCache) CommitConfirmHint(height uint32, txids ...chainhash.Hash) error {
	Log.Tracef("Updating confirm hints to height %d for %v", height, txids)

	return c.db.Batch(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, txid := range txids {
			var txHash bytes.Buffer
			err := channeldb.WriteElement(&txHash, txid)
			if err != nil {
				return err
			}

			err = confirmHints.Put(txHash.Bytes(), hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QueryConfirmHint returns the latest confirm hint for a transaction hash.
// ErrConfirmHintNotFound is returned if a confirm hint does not exist within
// the cache for the transaction hash.
func (c *HeightHintCache) QueryConfirmHint(txid chainhash.Hash) (uint32, error) {
	var hint uint32
	err := c.db.View(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var txHash bytes.Buffer
		if err := channeldb.WriteElement(&txHash, txid); err != nil {
			return err
		}

		confirmHint := confirmHints.Get(txHash.Bytes())
		if confirmHint == nil {
			return ErrConfirmHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(confirmHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeConfirmHint removes the confirm hint for the transactions from the
// cache.
func (c *HeightHintCache) PurgeConfirmHint(txids ...chainhash.Hash) error {
	Log.Tracef("Removing confirm hints for %v", txids)

	return c.db.Batch(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, txid := range txids {
			var txHash bytes.Buffer
			err := channeldb.WriteElement(&txHash, txid)
			if err != nil {
				return err
			}

			err = confirmHints.Delete(txHash.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}
<commit_msg>chainntnfs/height_hint_cache: add disable flag to hint cache<commit_after>package chainntnfs

import (
	"bytes"
	"errors"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	bolt "github.com/coreos/bbolt"
	"github.com/lightningnetwork/lnd/channeldb"
)

const (
	// dbName is the default name of the database storing the height hints.
	dbName = "heighthint.db"

	// dbFilePermission is the default permission of the database file
	// storing the height hints.
	dbFilePermission = 0600
)

var (
	// spendHintBucket is the name of the bucket which houses the height
	// hint for outpoints. Each height hint represents the earliest height
	// at which its corresponding outpoint could have been spent within.
	spendHintBucket = []byte("spend-hints")

	// confirmHintBucket is the name of the bucket which houses the height
	// hints for transactions. Each height hint represents the earliest
	// height at which its corresponding transaction could have been
	// confirmed within.
	confirmHintBucket = []byte("confirm-hints")

	// ErrCorruptedHeightHintCache indicates that the on-disk bucketing
	// structure has altered since the height hint cache instance was
	// initialized.
	ErrCorruptedHeightHintCache = errors.New("height hint cache has been " +
		"corrupted")

	// ErrSpendHintNotFound is an error returned when a spend hint for an
	// outpoint was not found.
	ErrSpendHintNotFound = errors.New("spend hint not found")

	// ErrConfirmHintNotFound is an error returned when a confirm hint for a
	// transaction was not found.
	ErrConfirmHintNotFound = errors.New("confirm hint not found")
)

// SpendHintCache is an interface whose duty is to cache spend hints for
// outpoints. A spend hint is defined as the earliest height in the chain at
// which an outpoint could have been spent within.
type SpendHintCache interface {
	// CommitSpendHint commits a spend hint for the outpoints to the cache.
	CommitSpendHint(height uint32, ops ...wire.OutPoint) error

	// QuerySpendHint returns the latest spend hint for an outpoint.
	// ErrSpendHintNotFound is returned if a spend hint does not exist
	// within the cache for the outpoint.
	QuerySpendHint(op wire.OutPoint) (uint32, error)

	// PurgeSpendHint removes the spend hint for the outpoints from the
	// cache.
	PurgeSpendHint(ops ...wire.OutPoint) error
}

// ConfirmHintCache is an interface whose duty is to cache confirm hints for
// transactions. A confirm hint is defined as the earliest height in the chain
// at which a transaction could have been included in a block.
type ConfirmHintCache interface {
	// CommitConfirmHint commits a confirm hint for the transactions to the
	// cache.
	CommitConfirmHint(height uint32, txids ...chainhash.Hash) error

	// QueryConfirmHint returns the latest confirm hint for a transaction
	// hash. ErrConfirmHintNotFound is returned if a confirm hint does not
	// exist within the cache for the transaction hash.
	QueryConfirmHint(txid chainhash.Hash) (uint32, error)

	// PurgeConfirmHint removes the confirm hint for the transactions from
	// the cache.
	PurgeConfirmHint(txids ...chainhash.Hash) error
}

// HeightHintCache is an implementation of the SpendHintCache and
// ConfirmHintCache interfaces backed by a channeldb DB instance where the hints
// will be stored.
type HeightHintCache struct {
	db       *channeldb.DB
	disabled bool
}

// Compile-time checks to ensure HeightHintCache satisfies the SpendHintCache
// and ConfirmHintCache interfaces.
var _ SpendHintCache = (*HeightHintCache)(nil)
var _ ConfirmHintCache = (*HeightHintCache)(nil)

// NewHeightHintCache returns a new height hint cache backed by a database.
func NewHeightHintCache(db *channeldb.DB, disable bool) (*HeightHintCache, error) {
	cache := &HeightHintCache{
		db:       db,
		disabled: disable,
	}
	if err := cache.initBuckets(); err != nil {
		return nil, err
	}

	return cache, nil
}

// initBuckets ensures that the primary buckets used by the circuit are
// initialized so that we can assume their existence after startup.
func (c *HeightHintCache) initBuckets() error {
	return c.db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(spendHintBucket)
		if err != nil {
			return err
		}

		_, err = tx.CreateBucketIfNotExists(confirmHintBucket)
		return err
	})
}

// CommitSpendHint commits a spend hint for the outpoints to the cache.
func (c *HeightHintCache) CommitSpendHint(height uint32, ops ...wire.OutPoint) error {
	if c.disabled {
		return nil
	}

	Log.Tracef("Updating spend hint to height %d for %v", height, ops)

	return c.db.Batch(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, op := range ops {
			var outpoint bytes.Buffer
			err := channeldb.WriteElement(&outpoint, op)
			if err != nil {
				return err
			}

			err = spendHints.Put(outpoint.Bytes(), hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QuerySpendHint returns the latest spend hint for an outpoint.
// ErrSpendHintNotFound is returned if a spend hint does not exist within the
// cache for the outpoint.
func (c *HeightHintCache) QuerySpendHint(op wire.OutPoint) (uint32, error) {
	if c.disabled {
		return 0, ErrSpendHintNotFound
	}

	var hint uint32
	err := c.db.View(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var outpoint bytes.Buffer
		if err := channeldb.WriteElement(&outpoint, op); err != nil {
			return err
		}

		spendHint := spendHints.Get(outpoint.Bytes())
		if spendHint == nil {
			return ErrSpendHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(spendHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeSpendHint removes the spend hint for the outpoints from the cache.
func (c *HeightHintCache) PurgeSpendHint(ops ...wire.OutPoint) error {
	if c.disabled {
		return nil
	}

	Log.Tracef("Removing spend hints for %v", ops)

	return c.db.Batch(func(tx *bolt.Tx) error {
		spendHints := tx.Bucket(spendHintBucket)
		if spendHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, op := range ops {
			var outpoint bytes.Buffer
			err := channeldb.WriteElement(&outpoint, op)
			if err != nil {
				return err
			}

			err = spendHints.Delete(outpoint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// CommitConfirmHint commits a confirm hint for the transactions to the cache.
func (c *HeightHintCache) CommitConfirmHint(height uint32, txids ...chainhash.Hash) error {
	if c.disabled {
		return nil
	}

	Log.Tracef("Updating confirm hints to height %d for %v", height, txids)

	return c.db.Batch(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var hint bytes.Buffer
		if err := channeldb.WriteElement(&hint, height); err != nil {
			return err
		}

		for _, txid := range txids {
			var txHash bytes.Buffer
			err := channeldb.WriteElement(&txHash, txid)
			if err != nil {
				return err
			}

			err = confirmHints.Put(txHash.Bytes(), hint.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}

// QueryConfirmHint returns the latest confirm hint for a transaction hash.
// ErrConfirmHintNotFound is returned if a confirm hint does not exist within
// the cache for the transaction hash.
func (c *HeightHintCache) QueryConfirmHint(txid chainhash.Hash) (uint32, error) {
	if c.disabled {
		return 0, ErrConfirmHintNotFound
	}

	var hint uint32
	err := c.db.View(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		var txHash bytes.Buffer
		if err := channeldb.WriteElement(&txHash, txid); err != nil {
			return err
		}

		confirmHint := confirmHints.Get(txHash.Bytes())
		if confirmHint == nil {
			return ErrConfirmHintNotFound
		}

		return channeldb.ReadElement(bytes.NewReader(confirmHint), &hint)
	})
	if err != nil {
		return 0, err
	}

	return hint, nil
}

// PurgeConfirmHint removes the confirm hint for the transactions from the
// cache.
func (c *HeightHintCache) PurgeConfirmHint(txids ...chainhash.Hash) error {
	if c.disabled {
		return nil
	}

	Log.Tracef("Removing confirm hints for %v", txids)

	return c.db.Batch(func(tx *bolt.Tx) error {
		confirmHints := tx.Bucket(confirmHintBucket)
		if confirmHints == nil {
			return ErrCorruptedHeightHintCache
		}

		for _, txid := range txids {
			var txHash bytes.Buffer
			err := channeldb.WriteElement(&txHash, txid)
			if err != nil {
				return err
			}

			err = confirmHints.Delete(txHash.Bytes())
			if err != nil {
				return err
			}
		}

		return nil
	})
}
<|endoftext|>


<commit_before>package internal

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
	"unicode"
)

const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

var (
	TimeoutErr = errors.New("Command timed out.")

	NotImplementedError = errors.New("not implemented yet")
)

// Duration just wraps time.Duration
type Duration struct {
	Duration time.Duration
}

// UnmarshalTOML parses the duration from the TOML config file
func (d *Duration) UnmarshalTOML(b []byte) error {
	var err error
	// Parse string duration, ie, "1s"
	d.Duration, err = time.ParseDuration(string(b[1 : len(b)-1]))
	if err == nil {
		return nil
	}

	// First try parsing as integer seconds
	sI, err := strconv.ParseInt(string(b), 10, 64)
	if err == nil {
		d.Duration = time.Second * time.Duration(sI)
		return nil
	}
	// Second try parsing as float seconds
	sF, err := strconv.ParseFloat(string(b), 64)
	if err == nil {
		d.Duration = time.Second * time.Duration(sF)
		return nil
	}

	return nil
}

// ReadLines reads contents from a file and splits them by new lines.
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
func ReadLines(filename string) ([]string, error) {
	return ReadLinesOffsetN(filename, 0, -1)
}

// ReadLines reads contents from file and splits them by new line.
// The offset tells at which line number to start.
// The count determines the number of lines to read (starting from offset):
//   n >= 0: at most n lines
//   n < 0: whole file
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return []string{""}, err
	}
	defer f.Close()

	var ret []string

	r := bufio.NewReader(f)
	for i := 0; i < n+int(offset) || n < 0; i++ {
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		if i < int(offset) {
			continue
		}
		ret = append(ret, strings.Trim(line, "\n"))
	}

	return ret, nil
}

// RandomString returns a random string of alpha-numeric characters
func RandomString(n int) string {
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}

// GetTLSConfig gets a tls.Config object from the given certs, key, and CA files.
// you must give the full path to the files.
// If all files are blank and InsecureSkipVerify=false, returns a nil pointer.
func GetTLSConfig(
	SSLCert, SSLKey, SSLCA string,
	InsecureSkipVerify bool,
) (*tls.Config, error) {
	if SSLCert == "" && SSLKey == "" && SSLCA == "" && !InsecureSkipVerify {
		return nil, nil
	}

	t := &tls.Config{
		InsecureSkipVerify: InsecureSkipVerify,
	}

	if SSLCA != "" {
		caCert, err := ioutil.ReadFile(SSLCA)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("Could not load TLS CA: %s",
				err))
		}

		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)
		t.RootCAs = caCertPool
	}

	if SSLCert != "" && SSLKey != "" {
		cert, err := tls.LoadX509KeyPair(SSLCert, SSLKey)
		if err != nil {
			return nil, errors.New(fmt.Sprintf(
				"Could not load TLS client key/certificate from %s:%s: %s",
				SSLKey, SSLCert, err))
		}

		t.Certificates = []tls.Certificate{cert}
		t.BuildNameToCertificate()
	}

	// will be nil by default if nothing is provided
	return t, nil
}

// SnakeCase converts the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
func SnakeCase(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}

// CombinedOutputTimeout runs the given command with the given timeout and
// returns the combined output of stdout and stderr.
// If the command times out, it attempts to kill the process.
func CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) {
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	if err := c.Start(); err != nil {
		return nil, err
	}
	err := WaitTimeout(c, timeout)
	return b.Bytes(), err
}

// RunTimeout runs the given command with the given timeout.
// If the command times out, it attempts to kill the process.
func RunTimeout(c *exec.Cmd, timeout time.Duration) error {
	if err := c.Start(); err != nil {
		return err
	}
	return WaitTimeout(c, timeout)
}

// WaitTimeout waits for the given command to finish with a timeout.
// It assumes the command has already been started.
// If the command times out, it attempts to kill the process.
func WaitTimeout(c *exec.Cmd, timeout time.Duration) error {
	timer := time.NewTimer(timeout)
	done := make(chan error)
	go func() { done <- c.Wait() }()
	select {
	case err := <-done:
		timer.Stop()
		return err
	case <-timer.C:
		if err := c.Process.Kill(); err != nil {
			log.Printf("E! FATAL error killing process: %s", err)
			return err
		}
		// wait for the command to return after killing it
		<-done
		return TimeoutErr
	}
}

// RandomSleep will sleep for a random amount of time up to max.
// If the shutdown channel is closed, it will return before it has finished
// sleeping.
func RandomSleep(max time.Duration, shutdown chan struct{}) {
	if max == 0 {
		return
	}
	maxSleep := big.NewInt(max.Nanoseconds())

	var sleepns int64
	if j, err := rand.Int(rand.Reader, maxSleep); err == nil {
		sleepns = j.Int64()
	}

	t := time.NewTimer(time.Nanosecond * time.Duration(sleepns))
	select {
	case <-t.C:
		return
	case <-shutdown:
		t.Stop()
		return
	}
}
<commit_msg>Fix panic in internal.Duration UnmarshalTOML<commit_after>package internal

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
	"unicode"
)

const alphanum string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

var (
	TimeoutErr = errors.New("Command timed out.")

	NotImplementedError = errors.New("not implemented yet")
)

// Duration just wraps time.Duration
type Duration struct {
	Duration time.Duration
}

// UnmarshalTOML parses the duration from the TOML config file
func (d *Duration) UnmarshalTOML(b []byte) error {
	var err error

	// Parse string duration, ie, "1s"
	if uq, err := strconv.Unquote(string(b)); err == nil && len(uq) > 0 {
		d.Duration, err = time.ParseDuration(uq)
		if err == nil {
			return nil
		}
	}

	// First try parsing as integer seconds
	sI, err := strconv.ParseInt(string(b), 10, 64)
	if err == nil {
		d.Duration = time.Second * time.Duration(sI)
		return nil
	}
	// Second try parsing as float seconds
	sF, err := strconv.ParseFloat(string(b), 64)
	if err == nil {
		d.Duration = time.Second * time.Duration(sF)
		return nil
	}

	return nil
}

// ReadLines reads contents from a file and splits them by new lines.
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
func ReadLines(filename string) ([]string, error) {
	return ReadLinesOffsetN(filename, 0, -1)
}

// ReadLines reads contents from file and splits them by new line.
// The offset tells at which line number to start.
// The count determines the number of lines to read (starting from offset):
//   n >= 0: at most n lines
//   n < 0: whole file
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return []string{""}, err
	}
	defer f.Close()

	var ret []string

	r := bufio.NewReader(f)
	for i := 0; i < n+int(offset) || n < 0; i++ {
		line, err := r.ReadString('\n')
		if err != nil {
			break
		}
		if i < int(offset) {
			continue
		}
		ret = append(ret, strings.Trim(line, "\n"))
	}

	return ret, nil
}

// RandomString returns a random string of alpha-numeric characters
func RandomString(n int) string {
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return string(bytes)
}

// GetTLSConfig gets a tls.Config object from the given certs, key, and CA files.
// you must give the full path to the files.
// If all files are blank and InsecureSkipVerify=false, returns a nil pointer.
func GetTLSConfig(
	SSLCert, SSLKey, SSLCA string,
	InsecureSkipVerify bool,
) (*tls.Config, error) {
	if SSLCert == "" && SSLKey == "" && SSLCA == "" && !InsecureSkipVerify {
		return nil, nil
	}

	t := &tls.Config{
		InsecureSkipVerify: InsecureSkipVerify,
	}

	if SSLCA != "" {
		caCert, err := ioutil.ReadFile(SSLCA)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("Could not load TLS CA: %s",
				err))
		}

		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)
		t.RootCAs = caCertPool
	}

	if SSLCert != "" && SSLKey != "" {
		cert, err := tls.LoadX509KeyPair(SSLCert, SSLKey)
		if err != nil {
			return nil, errors.New(fmt.Sprintf(
				"Could not load TLS client key/certificate from %s:%s: %s",
				SSLKey, SSLCert, err))
		}

		t.Certificates = []tls.Certificate{cert}
		t.BuildNameToCertificate()
	}

	// will be nil by default if nothing is provided
	return t, nil
}

// SnakeCase converts the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
func SnakeCase(in string) string {
	runes := []rune(in)
	length := len(runes)

	var out []rune
	for i := 0; i < length; i++ {
		if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
			out = append(out, '_')
		}
		out = append(out, unicode.ToLower(runes[i]))
	}

	return string(out)
}

// CombinedOutputTimeout runs the given command with the given timeout and
// returns the combined output of stdout and stderr.
// If the command times out, it attempts to kill the process.
func CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) {
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	if err := c.Start(); err != nil {
		return nil, err
	}
	err := WaitTimeout(c, timeout)
	return b.Bytes(), err
}

// RunTimeout runs the given command with the given timeout.
// If the command times out, it attempts to kill the process.
func RunTimeout(c *exec.Cmd, timeout time.Duration) error {
	if err := c.Start(); err != nil {
		return err
	}
	return WaitTimeout(c, timeout)
}

// WaitTimeout waits for the given command to finish with a timeout.
// It assumes the command has already been started.
// If the command times out, it attempts to kill the process.
func WaitTimeout(c *exec.Cmd, timeout time.Duration) error {
	timer := time.NewTimer(timeout)
	done := make(chan error)
	go func() { done <- c.Wait() }()
	select {
	case err := <-done:
		timer.Stop()
		return err
	case <-timer.C:
		if err := c.Process.Kill(); err != nil {
			log.Printf("E! FATAL error killing process: %s", err)
			return err
		}
		// wait for the command to return after killing it
		<-done
		return TimeoutErr
	}
}

// RandomSleep will sleep for a random amount of time up to max.
// If the shutdown channel is closed, it will return before it has finished
// sleeping.
func RandomSleep(max time.Duration, shutdown chan struct{}) {
	if max == 0 {
		return
	}
	maxSleep := big.NewInt(max.Nanoseconds())

	var sleepns int64
	if j, err := rand.Int(rand.Reader, maxSleep); err == nil {
		sleepns = j.Int64()
	}

	t := time.NewTimer(time.Nanosecond * time.Duration(sleepns))
	select {
	case <-t.C:
		return
	case <-shutdown:
		t.Stop()
		return
	}
}
<|endoftext|>