<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"time"

	"github.com/apcera/termtables"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/mitchellh/go-wordwrap"
)

func listFunctions(svc *lambda.Lambda, region string, rx *regexp.Regexp) {
	resp, err := svc.ListFunctions(nil)
	if err != nil {
		log.Fatalln(err)
	} else if len(resp.Functions) == 0 {
		fmt.Println("0 lambda functions available.")
		return
	}
	table := termtables.CreateTable()
	table.UTF8Box()
	table.AddHeaders("#", "NAME", "UPDATED", "SIZE", "MEM LIMIT", "TIMEOUT", "DESCRIPTION")
	var filtered int
	for i, f := range resp.Functions {
		if rx != nil && !rx.MatchString(*f.FunctionName) {
			continue
		}
		filtered++
		descLimited := wordwrap.WrapString(*f.Description, 40)
		table.AddRow(strconv.Itoa(i+1), *f.FunctionName,
			parseDate(*f.LastModified).Format(time.RFC822),
			fmt.Sprintf("%.2fK", float32(*f.CodeSize)/1024.0),
			fmt.Sprintf("%dM", *f.MemorySize),
			time.Second*time.Duration(*f.Timeout), descLimited)
	}
	if filtered > 0 {
		table.AddTitle(fmt.Sprintf("AWS LAMBDA FUNCTIONS: %d (%s)", filtered, region))
		fmt.Println(table.Render())
		return
	}
	fmt.Printf("0 lambda functions matched `%s` pattern.\n", rx.String())
}

func parseDate(v string) time.Time {
	t, _ := time.ParseInLocation("2006-01-02T15:04:05.999-0700", v, time.UTC)
	return t
}

func findFuction(svc *lambda.Lambda, id int, name string) *lambda.FunctionConfiguration {
	listResp, err := svc.ListFunctions(nil)
	if err != nil {
		log.Fatalln(err)
	} else if len(listResp.Functions) == 0 {
		fmt.Println("error: 0 lambda functions available.")
		os.Exit(-1)
	}
	for i, f := range listResp.Functions {
		if i+1 == id || *f.FunctionName == name {
			return f
		}
	}
	switch {
	case id > 0:
		fmt.Printf("error: no such function with ID=%d found.\n", id)
	case len(name) > 0:
		fmt.Printf("error: no such function with NAME=%s found.\n", name)
	}
	os.Exit(-1)
	return nil
}

func functionSource(svc *lambda.Lambda, f *lambda.FunctionConfiguration, path string, onlyURL bool) {
	getResp, err := svc.GetFunction(&lambda.GetFunctionInput{
		FunctionName: f.FunctionName,
		Qualifier:    f.Version,
	})
	if err != nil {
		log.Println("error:", err)
		return
	}
	if onlyURL {
		log.Println(*getResp.Code.Location)
		return
	}
	resp, err := http.Get(*getResp.Code.Location)
	if err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()
	out, err := os.Create(path)
	if err != nil {
		log.Fatalln(err)
	}
	// Temporarily turn off pb due to an unknown bug in master
	//	bar := pb.New(int(resp.ContentLength)).SetUnits(pb.U_BYTES).SetRefreshRate(time.Millisecond * 10)
	//	barproxy := bar.NewProxyReader(resp.Body)
	//	bar.ShowSpeed = true
	//	bar.Start()
	//	io.Copy(out, barproxy)
	io.Copy(out, resp.Body)
	out.Close()
	// bar.Finish()
}

func functionInfo(f *lambda.FunctionConfiguration, region string) {
	table := termtables.CreateTable()
	table.UTF8Box()
	table.AddTitle(fmt.Sprintf("AWS LAMBDA FUNCTION %s (%s)", *f.FunctionName, region))
	table.AddRow("SHA256 Hash", *f.CodeSha256)
	table.AddRow("Code Size", fmt.Sprintf("%.2fK", float32(*f.CodeSize)/1024.0))
	table.AddRow("Description", wordwrap.WrapString(*f.Description, 60))
	table.AddRow("Amazon Resource Name", *f.FunctionArn)
	table.AddRow("Handler", *f.Handler)
	table.AddRow("Last Modified", parseDate(*f.LastModified).Format(time.RFC822))
	table.AddRow("Memory Size", fmt.Sprintf("%dM", *f.MemorySize))
	table.AddRow("Role", *f.Role)
	table.AddRow("Runtime", *f.Runtime)
	table.AddRow("Timeout", time.Second*time.Duration(*f.Timeout))
	table.AddRow("Version", *f.Version)
	fmt.Println(table.Render())
}

func listRegions() {
	table := termtables.CreateTable()
	table.UTF8Box()
	table.AddTitle("AWS LAMBDA REGIONS (2015-12-20)")
	table.AddRow("us-east-1", "US East (N. Virginia)")
	table.AddRow("us-west-2", "US West (Oregon)")
	table.AddRow("eu-west-1", "EU (Ireland)")
	table.AddRow("ap-northeast-1", "Asia Pacific (Tokyo)")
	fmt.Println(table.Render())
}
<commit_msg>Switch to portable tablewriter instead of termtables.<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/mitchellh/go-wordwrap"
	"github.com/xlab/tablewriter"
)

func listFunctions(svc *lambda.Lambda, region string, rx *regexp.Regexp) {
	resp, err := svc.ListFunctions(nil)
	if err != nil {
		log.Fatalln(err)
	} else if len(resp.Functions) == 0 {
		fmt.Println("0 lambda functions available.")
		return
	}
	table := tablewriter.CreateTable()
	table.UTF8Box()
	table.AddHeaders("#", "NAME", "UPDATED", "SIZE", "MEM LIMIT", "TIMEOUT", "DESCRIPTION")
	var filtered int
	for i, f := range resp.Functions {
		if rx != nil && !rx.MatchString(*f.FunctionName) {
			continue
		}
		filtered++
		descLimited := wordwrap.WrapString(*f.Description, 40)
		table.AddRow(strconv.Itoa(i+1), *f.FunctionName,
			parseDate(*f.LastModified).Format(time.RFC822),
			fmt.Sprintf("%.2fK", float32(*f.CodeSize)/1024.0),
			fmt.Sprintf("%dM", *f.MemorySize),
			time.Second*time.Duration(*f.Timeout), descLimited)
	}
	if filtered > 0 {
		table.AddTitle(fmt.Sprintf("AWS LAMBDA FUNCTIONS: %d (%s)", filtered, region))
		fmt.Println(table.Render())
		return
	}
	fmt.Printf("0 lambda functions matched `%s` pattern.\n", rx.String())
}

func parseDate(v string) time.Time {
	t, _ := time.ParseInLocation("2006-01-02T15:04:05.999-0700", v, time.UTC)
	return t
}

func findFuction(svc *lambda.Lambda, id int, name string) *lambda.FunctionConfiguration {
	listResp, err := svc.ListFunctions(nil)
	if err != nil {
		log.Fatalln(err)
	} else if len(listResp.Functions) == 0 {
		fmt.Println("error: 0 lambda functions available.")
		os.Exit(-1)
	}
	for i, f := range listResp.Functions {
		if i+1 == id || *f.FunctionName == name {
			return f
		}
	}
	switch {
	case id > 0:
		fmt.Printf("error: no such function with ID=%d found.\n", id)
	case len(name) > 0:
		fmt.Printf("error: no such function with NAME=%s found.\n", name)
	}
	os.Exit(-1)
	return nil
}

func functionSource(svc *lambda.Lambda, f *lambda.FunctionConfiguration, path string, onlyURL bool) {
	getResp, err := svc.GetFunction(&lambda.GetFunctionInput{
		FunctionName: f.FunctionName,
		Qualifier:    f.Version,
	})
	if err != nil {
		log.Println("error:", err)
		return
	}
	if onlyURL {
		log.Println(*getResp.Code.Location)
		return
	}
	resp, err := http.Get(*getResp.Code.Location)
	if err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()
	out, err := os.Create(path)
	if err != nil {
		log.Fatalln(err)
	}
	// Temporarily turn off pb due to an unknown bug in master
	//	bar := pb.New(int(resp.ContentLength)).SetUnits(pb.U_BYTES).SetRefreshRate(time.Millisecond * 10)
	//	barproxy := bar.NewProxyReader(resp.Body)
	//	bar.ShowSpeed = true
	//	bar.Start()
	//	io.Copy(out, barproxy)
	io.Copy(out, resp.Body)
	out.Close()
	// bar.Finish()
}

func functionInfo(f *lambda.FunctionConfiguration, region string) {
	table := tablewriter.CreateTable()
	table.UTF8Box()
	table.AddTitle(fmt.Sprintf("AWS LAMBDA FUNCTION %s (%s)", *f.FunctionName, region))
	table.AddRow("SHA256 Hash", *f.CodeSha256)
	table.AddRow("Code Size", fmt.Sprintf("%.2fK", float32(*f.CodeSize)/1024.0))
	table.AddRow("Description", wordwrap.WrapString(*f.Description, 60))
	table.AddRow("Amazon Resource Name", *f.FunctionArn)
	table.AddRow("Handler", *f.Handler)
	table.AddRow("Last Modified", parseDate(*f.LastModified).Format(time.RFC822))
	table.AddRow("Memory Size", fmt.Sprintf("%dM", *f.MemorySize))
	table.AddRow("Role", *f.Role)
	table.AddRow("Runtime", *f.Runtime)
	table.AddRow("Timeout", time.Second*time.Duration(*f.Timeout))
	table.AddRow("Version", *f.Version)
	fmt.Println(table.Render())
}

func listRegions() {
	table := tablewriter.CreateTable()
	table.UTF8Box()
	table.AddTitle("AWS LAMBDA REGIONS (2015-12-20)")
	table.AddRow("us-east-1", "US East (N. Virginia)")
	table.AddRow("us-west-2", "US West (Oregon)")
	table.AddRow("eu-west-1", "EU (Ireland)")
	table.AddRow("ap-northeast-1", "Asia Pacific (Tokyo)")
	fmt.Println(table.Render())
}
<|endoftext|>


<commit_before>package main

import (
    "net"
//    "golang.org/x/net/ipv4"
    "fmt"
)

type IP_Conn struct {
    pc        *net.IPConn
    version   uint8
    dst, src  string
    headerLen uint16
    //len uint16
    //id uint16
    ttl      uint8
    protocol uint8
    //checksum int
}

func NewIP_Conn(dst string) (*IP_Conn, error) {
    pc, err := net.ListenIP("ip4:17", &net.IPAddr{IP: net.ParseIP(dst)})
    if err != nil {
        fmt.Println("Failed to ListenIP")
        return nil, err
    }

    return &IP_Conn{
        pc:        pc,
        version:   4,
        headerLen: 20,
        dst:       dst,
        src:       "127.0.0.1",
        ttl:       8,
        protocol:  17,
    }, nil
}

func calcChecksum(head []byte, excludeChecksum bool) uint16 {
    totalSum := uint64(0)
    for ind, elem := range head {
        if (ind == 10 || ind == 11) && excludeChecksum { // Ignore the checksum in some situations
            continue
        }

        if ind%2 == 0 {
            totalSum += (uint64)(uint16(elem) << 8)
        } else {
            totalSum += (uint64)(uint16(elem))
        }
    }

    for prefix := (totalSum >> 16); prefix != 0; {
        totalSum = uint64(uint16(totalSum)) + prefix
    }
    carried := uint16(totalSum)

    return ^carried
}

func slicePacket(b []byte) (payload []byte) {
    hdrLen := int(b[0] & 0x0f) * 4
    fmt.Println(hdrLen)
    return payload[hdrLen:]
}

func (ipc *IP_Conn) ReadFrom(b []byte) (payload []byte, e error) {
    _, _, err := ipc.pc.ReadFrom(b)
    p := slicePacket(b)

    return p, err
}

func (ipc *IP_Conn) WriteTo(p []byte) error {
    totalLen := uint16(ipc.headerLen) + uint16(len(p))
    fmt.Println(totalLen)
    packet := make([]byte, ipc.headerLen)
    packet[0] = (byte)((ipc.version << 4) + (uint8)(ipc.headerLen / 4)) // Version, IHL
    packet[1] = 0
    packet[2] = (byte)(totalLen >> 8) // Total Len
    packet[3] = (byte)(totalLen)
    packet[4] = 0 // Identification (for now)
    packet[5] = 0
    packet[6] = byte(1 << 6)         // Flags: Don't fragment
    packet[7] = 0                    // Fragment Offset
    packet[8] = (byte)(ipc.ttl)      // Time to Live
    packet[9] = (byte)(ipc.protocol) // Protocol

    // Src and Dst IPs
    srcIP := net.ParseIP(ipc.src)
    fmt.Println(srcIP)
//    fmt.Println(srcIP[12])
//    fmt.Println(srcIP[13])
//    fmt.Println(srcIP[14])
//    fmt.Println(srcIP[15])
    dstIP := net.ParseIP(ipc.dst)
    fmt.Println(dstIP)
    packet[12] = srcIP[12]
    packet[13] = srcIP[13]
    packet[14] = srcIP[14]
    packet[15] = srcIP[15]
    packet[16] = dstIP[12]
    packet[17] = dstIP[13]
    packet[18] = dstIP[14]
    packet[19] = dstIP[15]

    // IPv4 header test (before checksum)
    fmt.Println(packet)

    // Checksum
    checksum := calcChecksum(packet[:20], true)
    packet[10] = byte(checksum >> 8)
    packet[11] = byte(checksum)

    // Payload
    packet = append(packet, p...)
    fmt.Println(packet)

    dstIPAddr, err := net.ResolveIPAddr("ip", ipc.dst)
    if err != nil {
//        fmt.Println(err)
        return err
    }
    fmt.Println(dstIPAddr)

    ipc.pc.WriteMsgIP(packet, nil, dstIPAddr)
    return err
}

func (ipc *IP_Conn) Close() error {
    return ipc.pc.Close()
}

/* h := &ipv4.Header{
	Version:  ipv4.Version,      // protocol version
	Len:      20,                // header length
	TOS:      0,                 // type-of-service (0 is everything normal)
	TotalLen: len(x) + 20,       // packet total length (octets)
	ID:       0,                 // identification
	Flags:    ipv4.DontFragment, // flags
	FragOff:  0,                 // fragment offset
	TTL:      8,                 // time-to-live (maximum lifespan in seconds)
	Protocol: 17,                // next protocol (17 is UDP)
	Checksum: 0,                 // checksum (apparently autocomputed)
	//Src:    net.IPv4(127, 0, 0, 1), // source address, apparently done automatically
	Dst: net.ParseIP(c.manager.ipAddress), // destination address
	//Options                         // options, extension headers
}
*/
<commit_msg>More error messages<commit_after>package main

import (
    "net"
//    "golang.org/x/net/ipv4"
    "fmt"
)

type IP_Conn struct {
    pc        *net.IPConn
    version   uint8
    dst, src  string
    headerLen uint16
    //len uint16
    //id uint16
    ttl      uint8
    protocol uint8
    //checksum int
}

func NewIP_Conn(dst string) (*IP_Conn, error) {
    pc, err := net.ListenIP("ip4:17", &net.IPAddr{IP: net.ParseIP(dst)})
    if err != nil {
        fmt.Println("Failed to ListenIP")
        return nil, err
    }

    return &IP_Conn{
        pc:        pc,
        version:   4,
        headerLen: 20,
        dst:       dst,
        src:       "127.0.0.1",
        ttl:       8,
        protocol:  17,
    }, nil
}

func calcChecksum(head []byte, excludeChecksum bool) uint16 {
    totalSum := uint64(0)
    for ind, elem := range head {
        if (ind == 10 || ind == 11) && excludeChecksum { // Ignore the checksum in some situations
            continue
        }

        if ind%2 == 0 {
            totalSum += (uint64)(uint16(elem) << 8)
        } else {
            totalSum += (uint64)(uint16(elem))
        }
    }
    fmt.Println(totalSum)

    for prefix := (totalSum >> 16); prefix != 0; {
        totalSum = uint64(uint16(totalSum)) + prefix
    }
    carried := uint16(totalSum)

    return ^carried
}

func slicePacket(b []byte) (payload []byte) {
    hdrLen := int(b[0] & 0x0f) * 4
    fmt.Println(hdrLen)
    return payload[hdrLen:]
}

func (ipc *IP_Conn) ReadFrom(b []byte) (payload []byte, e error) {
    _, _, err := ipc.pc.ReadFrom(b)
    p := slicePacket(b)

    return p, err
}

func (ipc *IP_Conn) WriteTo(p []byte) error {
    totalLen := uint16(ipc.headerLen) + uint16(len(p))
    fmt.Println(totalLen)
    packet := make([]byte, ipc.headerLen)
    packet[0] = (byte)((ipc.version << 4) + (uint8)(ipc.headerLen / 4)) // Version, IHL
    packet[1] = 0
    packet[2] = (byte)(totalLen >> 8) // Total Len
    packet[3] = (byte)(totalLen)
    packet[4] = 0 // Identification (for now)
    packet[5] = 0
    packet[6] = byte(1 << 6)         // Flags: Don't fragment
    packet[7] = 0                    // Fragment Offset
    packet[8] = (byte)(ipc.ttl)      // Time to Live
    packet[9] = (byte)(ipc.protocol) // Protocol

    // Src and Dst IPs
    srcIP := net.ParseIP(ipc.src)
    fmt.Println(srcIP)
//    fmt.Println(srcIP[12])
//    fmt.Println(srcIP[13])
//    fmt.Println(srcIP[14])
//    fmt.Println(srcIP[15])
    dstIP := net.ParseIP(ipc.dst)
    fmt.Println(dstIP)
    packet[12] = srcIP[12]
    packet[13] = srcIP[13]
    packet[14] = srcIP[14]
    packet[15] = srcIP[15]
    packet[16] = dstIP[12]
    packet[17] = dstIP[13]
    packet[18] = dstIP[14]
    packet[19] = dstIP[15]

    // IPv4 header test (before checksum)
    fmt.Println(packet)

    // Checksum
    checksum := calcChecksum(packet[:20], true)
    packet[10] = byte(checksum >> 8)
    packet[11] = byte(checksum)

    // Payload
    packet = append(packet, p...)
    fmt.Println(packet)

    dstIPAddr, err := net.ResolveIPAddr("ip", ipc.dst)
    if err != nil {
//        fmt.Println(err)
        return err
    }
    fmt.Println(dstIPAddr)

    ipc.pc.WriteMsgIP(packet, nil, dstIPAddr)
    return err
}

func (ipc *IP_Conn) Close() error {
    return ipc.pc.Close()
}

/* h := &ipv4.Header{
	Version:  ipv4.Version,      // protocol version
	Len:      20,                // header length
	TOS:      0,                 // type-of-service (0 is everything normal)
	TotalLen: len(x) + 20,       // packet total length (octets)
	ID:       0,                 // identification
	Flags:    ipv4.DontFragment, // flags
	FragOff:  0,                 // fragment offset
	TTL:      8,                 // time-to-live (maximum lifespan in seconds)
	Protocol: 17,                // next protocol (17 is UDP)
	Checksum: 0,                 // checksum (apparently autocomputed)
	//Src:    net.IPv4(127, 0, 0, 1), // source address, apparently done automatically
	Dst: net.ParseIP(c.manager.ipAddress), // destination address
	//Options                         // options, extension headers
}
*/
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 mungers

import (
	"bytes"
	"fmt"
	"path/filepath"
	"sort"
	"strings"

	"github.com/golang/glog"
	githubapi "github.com/google/go-github/github"
	"github.com/spf13/cobra"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"
	c "k8s.io/contrib/mungegithub/mungers/matchers/comment"
	"k8s.io/kubernetes/pkg/util/sets"
)

const (
	approvalNotificationName = "ApprovalNotifier"
	approveCommand           = "approve"
	cancel                   = "cancel"
	ownersFileName           = "OWNERS"
)

// ApprovalHandler will try to add "approved" label once
// all files of change has been approved by approvers.
type ApprovalHandler struct {
	features *features.Features
}

func init() {
	h := &ApprovalHandler{}
	RegisterMungerOrDie(h)
}

// Name is the name usable in --pr-mungers
func (*ApprovalHandler) Name() string { return "approval-handler" }

// RequiredFeatures is a slice of 'features' that must be provided
func (*ApprovalHandler) RequiredFeatures() []string {
	return []string{features.RepoFeatureName, features.AliasesFeature}
}

// Initialize will initialize the munger
func (h *ApprovalHandler) Initialize(config *github.Config, features *features.Features) error {
	h.features = features
	return nil
}

// EachLoop is called at the start of every munge loop
func (*ApprovalHandler) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (*ApprovalHandler) AddFlags(cmd *cobra.Command, config *github.Config) {}

// Munge is the workhorse the will actually make updates to the PR
// The algorithm goes as:
// - Initially, we build an approverSet
//   - Go through all comments after latest commit.
//	- If anyone said "/approve", add them to approverSet.
// - Then, for each file, we see if any approver of this file is in approverSet and keep track of files without approval
//   - An approver of a file is defined as:
//     - Someone listed as an "approver" in an OWNERS file in the files directory OR
//     - in one of the file's parent directorie
// - Iff all files have been approved, the bot will add the "approved" label.
// - Iff a cancel command is found, that reviewer will be removed from the approverSet
// 	and the munger will remove the approved label if it has been applied
func (h *ApprovalHandler) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}
	files, ok := obj.ListFiles()
	if !ok {
		return
	}

	comments, ok := getCommentsAfterLastModified(obj)

	if !ok {
		return
	}

	ownersMap := h.getApprovedOwners(files, createApproverSet(comments))

	if err := h.updateNotification(obj, ownersMap); err != nil {
		return
	}

	for _, approverSet := range ownersMap {
		if approverSet.Len() == 0 {
			if obj.HasLabel(approvedLabel) {
				obj.RemoveLabel(approvedLabel)
			}
			return
		}
	}

	if !obj.HasLabel(approvedLabel) {
		obj.AddLabel(approvedLabel)
	}
}

func (h *ApprovalHandler) updateNotification(obj *github.MungeObject, ownersMap map[string]sets.String) error {
	notificationMatcher := c.MungerNotificationName(approvalNotificationName)
	comments, ok := obj.ListComments()
	if !ok {
		return fmt.Errorf("Unable to ListComments for %d", obj.Number())
	}

	notifications := c.FilterComments(comments, notificationMatcher)
	latestNotification := notifications.GetLast()
	if latestNotification == nil {
		body := h.getMessage(obj, ownersMap)
		obj.WriteComment(body)
	}

	latestApprove := c.FilterComments(comments, c.CommandName(approveCommand)).GetLast()
	if latestApprove == nil || latestApprove.CreatedAt == nil {
		// there was already a bot notification and nothing has changed since
		// or we wouldn't tell when the latestApproval occurred
		return nil
	}
	if latestApprove.CreatedAt.After(*latestNotification.CreatedAt) {
		// if someone approved since the last comment, we should update the comment
		glog.Infof("Latest approve was after last time notified")
		body := h.getMessage(obj, ownersMap)
		return obj.EditComment(latestNotification, body)
	}
	lastModified, ok := obj.LastModifiedTime()
	if !ok {
		return fmt.Errorf("Unable to get LastModifiedTime for %d", obj.Number())
	}
	if latestNotification.CreatedAt.Before(*lastModified) {
		// the PR was modified After our last notification, so we should update the approvers notification
		// i.e. People that have formerly approved haven't necessarily approved of new changes
		glog.Infof("PR Modified After Last Notification")
		body := h.getMessage(obj, ownersMap)
		return obj.EditComment(latestNotification, body)
	}
	return nil
}

// findPeopleToApprove Takes the Owners Files that Are Needed for the PR and chooses a good
// subset of Approvers that are guaranteed to cover all of them (exact cover)
// This is a greedy approximation and not guaranteed to find the minimum number of OWNERS
func (h ApprovalHandler) findPeopleToApprove(ownersPaths sets.String, prAuthor string) sets.String {

	// approverCount contains a map: person -> set of relevant OWNERS file they are in
	approverCount := make(map[string]sets.String)
	for ownersFile := range ownersPaths {
		// LeafApprovers removes the last part of a path for dirs and files, so we append owners to the path
		for approver := range h.features.Repos.LeafApprovers(filepath.Join(ownersFile, ownersFileName)) {
			if approver == prAuthor {
				// don't add the author of the PR to the list of candidates that can approve
				continue
			}
			if _, ok := approverCount[approver]; ok {
				approverCount[approver].Insert(ownersFile)
			} else {
				approverCount[approver] = sets.NewString(ownersFile)
			}
		}
	}

	copyOfFiles := sets.NewString()
	for fn := range ownersPaths {
		copyOfFiles.Insert(fn)
	}

	approverGroup := sets.NewString()
	var bestPerson string
	for copyOfFiles.Len() > 0 {
		maxCovered := 0
		for k, v := range approverCount {
			if v.Intersection(copyOfFiles).Len() > maxCovered {
				maxCovered = len(v)
				bestPerson = k
			}
		}

		approverGroup.Insert(bestPerson)
		toDelete := sets.NewString()
		// remove all files in the directories that our approver approved AND
		// in the subdirectories that s/he approved.  HasPrefix finds subdirs
		for fn := range copyOfFiles {
			for approvedFile := range approverCount[bestPerson] {
				if strings.HasPrefix(fn, approvedFile) {
					toDelete.Insert(fn)
				}

			}
		}
		copyOfFiles.Delete(toDelete.List()...)
	}
	return approverGroup
}

// removeSubdirs takes a list of directories as an input and returns a set of directories with all
// subdirectories removed.  E.g. [/a,/a/b/c,/d/e,/d/e/f] -> [/a, /d/e]
func removeSubdirs(dirList []string) sets.String {
	toDel := sets.String{}
	for i := 0; i < len(dirList)-1; i++ {
		for j := i + 1; j < len(dirList); j++ {
			// ex /a/b has prefix /a so if remove /a/b since its already covered
			if strings.HasPrefix(dirList[i], dirList[j]) {
				toDel.Insert(dirList[i])
			} else if strings.HasPrefix(dirList[j], dirList[i]) {
				toDel.Insert(dirList[j])
			}
		}
	}
	finalSet := sets.NewString(dirList...)
	finalSet.Delete(toDel.List()...)
	return finalSet
}

// getMessage returns the comment body that we want the approval-handler to display on PRs
// The comment shows:
// 	- a list of approvers files (and links) needed to get the PR approved
// 	- a list of approvers files with strikethroughs that already have an approver's approval
// 	- a suggested list of people from each OWNERS files that can fully approve the PR
// 	- how an approver can indicate their approval
// 	- how an approver can cancel their approval
func (h *ApprovalHandler) getMessage(obj *github.MungeObject, ownersMap map[string]sets.String) string {
	// sort the keys so we always display OWNERS files in same order
	sliceOfKeys := make([]string, len(ownersMap))
	i := 0
	for path := range ownersMap {
		sliceOfKeys[i] = path
		i++
	}
	sort.Strings(sliceOfKeys)

	unapprovedOwners := sets.NewString()
	context := bytes.NewBufferString("")
	for _, path := range sliceOfKeys {
		approverSet := ownersMap[path]
		fullOwnersPath := filepath.Join(path, ownersFileName)
		link := fmt.Sprintf("https://github.com/%s/%s/blob/master/%v", obj.Org(), obj.Project(), fullOwnersPath)

		if approverSet.Len() == 0 {
			context.WriteString(fmt.Sprintf("- **[%s](%s)** \n", fullOwnersPath, link))
			unapprovedOwners.Insert(path)
		} else {
			context.WriteString(fmt.Sprintf("- ~~[%s](%s)~~ [%v]\n", fullOwnersPath, link, strings.Join(approverSet.List(), ",")))
		}
	}
	context.WriteString("\n")
	if unapprovedOwners.Len() > 0 {
		context.WriteString("We suggest the following people:\n")
		context.WriteString("cc ")
		toBeAssigned := h.findPeopleToApprove(unapprovedOwners, *obj.Issue.User.Login)
		for person := range toBeAssigned {
			context.WriteString("@" + person + " ")
		}
	}
	context.WriteString("\n You can indicate your approval by writing `/approve` in a comment")
	context.WriteString("\n You can cancel your approval by writing `/approve cancel` in a comment")
	notif := c.Notification{approvalNotificationName, "Needs approval from an approver in each of these OWNERS Files:\n", context.String()}
	return notif.String()
}

// createApproverSet iterates through the list of comments on a PR
// and identifies all of the people that have said /approve and adds
// them to the approverSet.  The function uses the latest approve or cancel comment
// to determine the Users intention
func createApproverSet(comments []*githubapi.IssueComment) sets.String {
	approverSet := sets.NewString()

	approverMatcher := c.CommandName(approveCommand)

	for _, comment := range c.FilterComments(comments, approverMatcher) {
		cmd := c.ParseCommand(comment)
		if cmd.Arguments == cancel {
			approverSet.Delete(*comment.User.Login)
		} else {
			approverSet.Insert(*comment.User.Login)
		}
	}
	return approverSet
}

// getApprovedOwners finds all the relevant OWNERS files for the PRs and identifies all the people from them
// that have approved the PR.  For all files that have not been approved, it finds the minimum number of owners files
// that cover all of them.  E.g. If /a/b/c.txt and /a/d.txt need approval, it will only indicate that an approval from
// someone in /a/OWNERS is needed
func (h ApprovalHandler) getApprovedOwners(files []*githubapi.CommitFile, approverSet sets.String) map[string]sets.String {
	ownersApprovers := make(map[string]sets.String)
	// TODO: go through the files starting at the top of the tree
	needsApproval := sets.NewString()
	for _, file := range files {
		fileOwners := h.features.Repos.Approvers(*file.Filename)
		ownersFile := h.features.Repos.FindOwnersForPath(*file.Filename)
		hasApproved := fileOwners.Intersection(approverSet)
		if len(hasApproved) != 0 {
			ownersApprovers[ownersFile] = hasApproved
		} else {
			needsApproval.Insert(ownersFile)
		}

	}
	needsApproval = removeSubdirs(needsApproval.List())
	for fn := range needsApproval {
		ownersApprovers[fn] = sets.NewString()
	}
	return ownersApprovers
}

// gets the comments since the obj was last changed.  If we can't figure out when the object was last changed
// return all the comments on the issue
func getCommentsAfterLastModified(obj *github.MungeObject) ([]*githubapi.IssueComment, bool) {
	comments, ok := obj.ListComments()
	if !ok {
		return comments, ok
	}
	lastModified, ok := obj.LastModifiedTime()
	if !ok {
		return comments, ok
	}
	return c.FilterComments(comments, c.CreatedAfter(*lastModified)), true
}
<commit_msg>allow maintainers to add approved label explicitly<commit_after>/*
Copyright 2016 The Kubernetes 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 mungers

import (
	"bytes"
	"fmt"
	"path/filepath"
	"sort"
	"strings"

	"github.com/golang/glog"
	githubapi "github.com/google/go-github/github"
	"github.com/spf13/cobra"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"
	c "k8s.io/contrib/mungegithub/mungers/matchers/comment"
	"k8s.io/contrib/mungegithub/mungers/matchers/event"
	"k8s.io/kubernetes/pkg/util/sets"
)

const (
	approvalNotificationName = "ApprovalNotifier"
	approveCommand           = "approve"
	cancel                   = "cancel"
	ownersFileName           = "OWNERS"
)

// ApprovalHandler will try to add "approved" label once
// all files of change has been approved by approvers.
type ApprovalHandler struct {
	features *features.Features
}

func init() {
	h := &ApprovalHandler{}
	RegisterMungerOrDie(h)
}

// Name is the name usable in --pr-mungers
func (*ApprovalHandler) Name() string { return "approval-handler" }

// RequiredFeatures is a slice of 'features' that must be provided
func (*ApprovalHandler) RequiredFeatures() []string {
	return []string{features.RepoFeatureName, features.AliasesFeature}
}

// Initialize will initialize the munger
func (h *ApprovalHandler) Initialize(config *github.Config, features *features.Features) error {
	h.features = features
	return nil
}

// EachLoop is called at the start of every munge loop
func (*ApprovalHandler) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (*ApprovalHandler) AddFlags(cmd *cobra.Command, config *github.Config) {}

// Munge is the workhorse the will actually make updates to the PR
// The algorithm goes as:
// - Initially, we build an approverSet
//   - Go through all comments after latest commit.
//	- If anyone said "/approve", add them to approverSet.
// - Then, for each file, we see if any approver of this file is in approverSet and keep track of files without approval
//   - An approver of a file is defined as:
//     - Someone listed as an "approver" in an OWNERS file in the files directory OR
//     - in one of the file's parent directorie
// - Iff all files have been approved, the bot will add the "approved" label.
// - Iff a cancel command is found, that reviewer will be removed from the approverSet
// 	and the munger will remove the approved label if it has been applied
func (h *ApprovalHandler) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}
	files, ok := obj.ListFiles()
	if !ok {
		return
	}

	comments, ok := getCommentsAfterLastModified(obj)

	if !ok {
		return
	}

	ownersMap := h.getApprovedOwners(files, createApproverSet(comments))

	if err := h.updateNotification(obj, ownersMap); err != nil {
		return
	}

	for _, approverSet := range ownersMap {
		if approverSet.Len() == 0 {
			// if a human explicitly added the label, allow it through
			if obj.HasLabel(approvedLabel) && !humanAddedApproved(obj) {
				obj.RemoveLabel(approvedLabel)
			}
			return
		}
	}

	if !obj.HasLabel(approvedLabel) {
		obj.AddLabel(approvedLabel)
	}
}

func humanAddedApproved(obj *github.MungeObject) bool {
	events, ok := obj.GetEvents()
	if !ok {
		return false
	}
	approveAddedMatcher := event.And([]event.Matcher{event.AddLabel{}, event.LabelName(approvedLabel)})
	labelEvents := event.FilterEvents(events, approveAddedMatcher)
	lastAdded := labelEvents.GetLast()
	if lastAdded == nil || lastAdded.Actor == nil || lastAdded.Actor.Login == nil {
		return false
	}
	return *lastAdded.Actor.Login != botName
}

func (h *ApprovalHandler) updateNotification(obj *github.MungeObject, ownersMap map[string]sets.String) error {
	notificationMatcher := c.MungerNotificationName(approvalNotificationName)
	comments, ok := obj.ListComments()
	if !ok {
		return fmt.Errorf("Unable to ListComments for %d", obj.Number())
	}

	notifications := c.FilterComments(comments, notificationMatcher)
	latestNotification := notifications.GetLast()
	if latestNotification == nil {
		body := h.getMessage(obj, ownersMap)
		obj.WriteComment(body)
	}

	latestApprove := c.FilterComments(comments, c.CommandName(approveCommand)).GetLast()
	if latestApprove == nil || latestApprove.CreatedAt == nil {
		// there was already a bot notification and nothing has changed since
		// or we wouldn't tell when the latestApproval occurred
		return nil
	}
	if latestApprove.CreatedAt.After(*latestNotification.CreatedAt) {
		// if someone approved since the last comment, we should update the comment
		glog.Infof("Latest approve was after last time notified")
		body := h.getMessage(obj, ownersMap)
		return obj.EditComment(latestNotification, body)
	}
	lastModified, ok := obj.LastModifiedTime()
	if !ok {
		return fmt.Errorf("Unable to get LastModifiedTime for %d", obj.Number())
	}
	if latestNotification.CreatedAt.Before(*lastModified) {
		// the PR was modified After our last notification, so we should update the approvers notification
		// i.e. People that have formerly approved haven't necessarily approved of new changes
		glog.Infof("PR Modified After Last Notification")
		body := h.getMessage(obj, ownersMap)
		return obj.EditComment(latestNotification, body)
	}
	return nil
}

// findPeopleToApprove Takes the Owners Files that Are Needed for the PR and chooses a good
// subset of Approvers that are guaranteed to cover all of them (exact cover)
// This is a greedy approximation and not guaranteed to find the minimum number of OWNERS
func (h ApprovalHandler) findPeopleToApprove(ownersPaths sets.String, prAuthor string) sets.String {

	// approverCount contains a map: person -> set of relevant OWNERS file they are in
	approverCount := make(map[string]sets.String)
	for ownersFile := range ownersPaths {
		// LeafApprovers removes the last part of a path for dirs and files, so we append owners to the path
		for approver := range h.features.Repos.LeafApprovers(filepath.Join(ownersFile, ownersFileName)) {
			if approver == prAuthor {
				// don't add the author of the PR to the list of candidates that can approve
				continue
			}
			if _, ok := approverCount[approver]; ok {
				approverCount[approver].Insert(ownersFile)
			} else {
				approverCount[approver] = sets.NewString(ownersFile)
			}
		}
	}

	copyOfFiles := sets.NewString()
	for fn := range ownersPaths {
		copyOfFiles.Insert(fn)
	}

	approverGroup := sets.NewString()
	var bestPerson string
	for copyOfFiles.Len() > 0 {
		maxCovered := 0
		for k, v := range approverCount {
			if v.Intersection(copyOfFiles).Len() > maxCovered {
				maxCovered = len(v)
				bestPerson = k
			}
		}

		approverGroup.Insert(bestPerson)
		toDelete := sets.NewString()
		// remove all files in the directories that our approver approved AND
		// in the subdirectories that s/he approved.  HasPrefix finds subdirs
		for fn := range copyOfFiles {
			for approvedFile := range approverCount[bestPerson] {
				if strings.HasPrefix(fn, approvedFile) {
					toDelete.Insert(fn)
				}

			}
		}
		copyOfFiles.Delete(toDelete.List()...)
	}
	return approverGroup
}

// removeSubdirs takes a list of directories as an input and returns a set of directories with all
// subdirectories removed.  E.g. [/a,/a/b/c,/d/e,/d/e/f] -> [/a, /d/e]
func removeSubdirs(dirList []string) sets.String {
	toDel := sets.String{}
	for i := 0; i < len(dirList)-1; i++ {
		for j := i + 1; j < len(dirList); j++ {
			// ex /a/b has prefix /a so if remove /a/b since its already covered
			if strings.HasPrefix(dirList[i], dirList[j]) {
				toDel.Insert(dirList[i])
			} else if strings.HasPrefix(dirList[j], dirList[i]) {
				toDel.Insert(dirList[j])
			}
		}
	}
	finalSet := sets.NewString(dirList...)
	finalSet.Delete(toDel.List()...)
	return finalSet
}

// getMessage returns the comment body that we want the approval-handler to display on PRs
// The comment shows:
// 	- a list of approvers files (and links) needed to get the PR approved
// 	- a list of approvers files with strikethroughs that already have an approver's approval
// 	- a suggested list of people from each OWNERS files that can fully approve the PR
// 	- how an approver can indicate their approval
// 	- how an approver can cancel their approval
func (h *ApprovalHandler) getMessage(obj *github.MungeObject, ownersMap map[string]sets.String) string {
	// sort the keys so we always display OWNERS files in same order
	sliceOfKeys := make([]string, len(ownersMap))
	i := 0
	for path := range ownersMap {
		sliceOfKeys[i] = path
		i++
	}
	sort.Strings(sliceOfKeys)

	unapprovedOwners := sets.NewString()
	context := bytes.NewBufferString("")
	for _, path := range sliceOfKeys {
		approverSet := ownersMap[path]
		fullOwnersPath := filepath.Join(path, ownersFileName)
		link := fmt.Sprintf("https://github.com/%s/%s/blob/master/%v", obj.Org(), obj.Project(), fullOwnersPath)

		if approverSet.Len() == 0 {
			context.WriteString(fmt.Sprintf("- **[%s](%s)** \n", fullOwnersPath, link))
			unapprovedOwners.Insert(path)
		} else {
			context.WriteString(fmt.Sprintf("- ~~[%s](%s)~~ [%v]\n", fullOwnersPath, link, strings.Join(approverSet.List(), ",")))
		}
	}
	context.WriteString("\n")
	if unapprovedOwners.Len() > 0 {
		context.WriteString("We suggest the following people:\n")
		context.WriteString("cc ")
		toBeAssigned := h.findPeopleToApprove(unapprovedOwners, *obj.Issue.User.Login)
		for person := range toBeAssigned {
			context.WriteString("@" + person + " ")
		}
	}
	context.WriteString("\n You can indicate your approval by writing `/approve` in a comment")
	context.WriteString("\n You can cancel your approval by writing `/approve cancel` in a comment")
	notif := c.Notification{approvalNotificationName, "Needs approval from an approver in each of these OWNERS Files:\n", context.String()}
	return notif.String()
}

// createApproverSet iterates through the list of comments on a PR
// and identifies all of the people that have said /approve and adds
// them to the approverSet.  The function uses the latest approve or cancel comment
// to determine the Users intention
func createApproverSet(comments []*githubapi.IssueComment) sets.String {
	approverSet := sets.NewString()

	approverMatcher := c.CommandName(approveCommand)

	for _, comment := range c.FilterComments(comments, approverMatcher) {
		cmd := c.ParseCommand(comment)
		if cmd.Arguments == cancel {
			approverSet.Delete(*comment.User.Login)
		} else {
			approverSet.Insert(*comment.User.Login)
		}
	}
	return approverSet
}

// getApprovedOwners finds all the relevant OWNERS files for the PRs and identifies all the people from them
// that have approved the PR.  For all files that have not been approved, it finds the minimum number of owners files
// that cover all of them.  E.g. If /a/b/c.txt and /a/d.txt need approval, it will only indicate that an approval from
// someone in /a/OWNERS is needed
func (h ApprovalHandler) getApprovedOwners(files []*githubapi.CommitFile, approverSet sets.String) map[string]sets.String {
	ownersApprovers := make(map[string]sets.String)
	// TODO: go through the files starting at the top of the tree
	needsApproval := sets.NewString()
	for _, file := range files {
		fileOwners := h.features.Repos.Approvers(*file.Filename)
		ownersFile := h.features.Repos.FindOwnersForPath(*file.Filename)
		hasApproved := fileOwners.Intersection(approverSet)
		if len(hasApproved) != 0 {
			ownersApprovers[ownersFile] = hasApproved
		} else {
			needsApproval.Insert(ownersFile)
		}

	}
	needsApproval = removeSubdirs(needsApproval.List())
	for fn := range needsApproval {
		ownersApprovers[fn] = sets.NewString()
	}
	return ownersApprovers
}

// gets the comments since the obj was last changed.  If we can't figure out when the object was last changed
// return all the comments on the issue
func getCommentsAfterLastModified(obj *github.MungeObject) ([]*githubapi.IssueComment, bool) {
	comments, ok := obj.ListComments()
	if !ok {
		return comments, ok
	}
	lastModified, ok := obj.LastModifiedTime()
	if !ok {
		return comments, ok
	}
	return c.FilterComments(comments, c.CreatedAfter(*lastModified)), true
}
<|endoftext|>


<commit_before>package models

type Registration struct {
    Id            int `name:"id" type:"int" null:"NOT NULL" extra:"PRIMARY"`
    FaceId        int `name:"face_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"faces" refField:"id" refFieldShow:"id"`
    ParamValuesId int `name:"param_values_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"param_values" refField:"id" refFieldShow:"id"`
}

func (c *ModelManager) Registrations() *RegistrationModel {
    model := new(RegistrationModel)

    model.TableName = "registrations"
    model.Caption = "Регистрации"

    model.Columns = []string{"id", "face_id", "param_values_id"}
    model.ColNames = []string{"ID", "Лицо", "Значение"}

    model.Fields = new(Registration)
    model.WherePart = make(map[string]interface{}, 0)
    model.OrderBy = "id"
    model.Limit = "ALL"
    model.Offset = 0

    model.Sub = false
    model.SubTable = nil
    model.SubField = ""

    return model
}

type RegistrationModel struct {
    Entity
}
<commit_msg>registration entity: remove param_val_id field<commit_after>package models

type Registration struct {
    Id     int `name:"id" type:"int" null:"NOT NULL" extra:"PRIMARY"`
    FaceId int `name:"face_id" type:"int" null:"NOT NULL" extra:"REFERENCES" refTable:"faces" refField:"id" refFieldShow:"id"`
}

func (c *ModelManager) Registrations() *RegistrationModel {
    model := new(RegistrationModel)

    model.TableName = "registrations"
    model.Caption = "Регистрации"

    model.Columns = []string{"id", "face_id", "param_values_id"}
    model.ColNames = []string{"ID", "Лицо", "Значение"}

    model.Fields = new(Registration)
    model.WherePart = make(map[string]interface{}, 0)
    model.OrderBy = "id"
    model.Limit = "ALL"
    model.Offset = 0

    model.Sub = false
    model.SubTable = nil
    model.SubField = ""

    return model
}

type RegistrationModel struct {
    Entity
}
<|endoftext|>


<commit_before>package metadata

import (
	"io/ioutil"
	"net"
	"strconv"
	"strings"

	"github.com/bosun-monitor/opentsdb"
	"github.com/bosun-monitor/util"
)

func init() {
	metafuncs = append(metafuncs, metaLinuxVersion, metaLinuxIfaces)
}

func metaLinuxVersion() {
	_ = util.ReadCommand(func(line string) error {
		AddMeta("", nil, "uname", line, true)
		return nil
	}, "uname", "-a")
	_ = util.ReadCommand(func(line string) error {
		fields := strings.Fields(line)
		hasNum := false
		for i := 0; i < len(fields); {
			if strings.HasPrefix(fields[i], `\`) {
				fields = append(fields[:i], fields[i+1:]...)
			} else {
				if v, _ := strconv.ParseFloat(fields[i], 32); v > 0 {
					hasNum = true
				}
				i++
			}
		}
		if !hasNum {
			return nil
		}
		AddMeta("", nil, "version", strings.Join(fields, " "), true)
		return nil
	}, "cat", "/etc/issue")
}

func metaLinuxIfaces() {
	metaIfaces(func(iface net.Interface, tags opentsdb.TagSet) {
		speed, err := ioutil.ReadFile("/sys/class/net/" + iface.Name + "/speed")
		if err != nil {
			return
		}
		v, _ := strconv.Atoi(strings.TrimSpace(string(speed)))
		if v > 0 {
			const MbitToBit = 1e6
			AddMeta("", tags, "speed", v*MbitToBit, true)
		}
	})
}
<commit_msg>metadata: Get bond master for linux interfaces<commit_after>package metadata

import (
	"errors"
	"io/ioutil"
	"net"
	"strconv"
	"strings"

	"github.com/bosun-monitor/opentsdb"
	"github.com/bosun-monitor/util"
)

func init() {
	metafuncs = append(metafuncs, metaLinuxVersion, metaLinuxIfaces)
}

func metaLinuxVersion() {
	_ = util.ReadCommand(func(line string) error {
		AddMeta("", nil, "uname", line, true)
		return nil
	}, "uname", "-a")
	_ = util.ReadCommand(func(line string) error {
		fields := strings.Fields(line)
		hasNum := false
		for i := 0; i < len(fields); {
			if strings.HasPrefix(fields[i], `\`) {
				fields = append(fields[:i], fields[i+1:]...)
			} else {
				if v, _ := strconv.ParseFloat(fields[i], 32); v > 0 {
					hasNum = true
				}
				i++
			}
		}
		if !hasNum {
			return nil
		}
		AddMeta("", nil, "version", strings.Join(fields, " "), true)
		return nil
	}, "cat", "/etc/issue")
}

var doneErr = errors.New("")

func metaLinuxIfaces() {
	metaIfaces(func(iface net.Interface, tags opentsdb.TagSet) {
		if speed, err := ioutil.ReadFile("/sys/class/net/" + iface.Name + "/speed"); err == nil {
			v, _ := strconv.Atoi(strings.TrimSpace(string(speed)))
			if v > 0 {
				const MbitToBit = 1e6
				AddMeta("", tags, "speed", v*MbitToBit, true)
			}
		}
		_ = util.ReadCommand(func(line string) error {
			sp := strings.Fields(line)
			for i := 4; i < len(sp); i += 2 {
				if sp[i-1] == "master" {
					AddMeta("", tags, "master", sp[i], true)
					return doneErr
				}
			}
			return nil
		}, "ip", "-o", "addr", "show", iface.Name)
	})
}
<|endoftext|>


<commit_before>package sqlite

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestFoo(t *testing.T) {
	td, err := ioutil.TempDir("", "go-sqlite-test")
	if err != nil {
		t.Fatalf("TempDir: %v", err)
	}
	dbName := filepath.Join(td, "foo.db")
	defer os.Remove(dbName)

	db, err := Open(dbName)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	err = db.Exec("CREATE TABLE IF NOT EXISTS foo (a INT, b VARCHAR(200))")
	if err != nil {
		t.Fatalf("create table: %v", err)
	}

	err = db.Exec("INSERT INTO foo VALUES (1, ?)", "foo")
	if err != nil {
		t.Fatalf("insert: %v", err)
	}
	err = db.Exec("INSERT INTO foo VALUES (2, DATETIME('now'))")
	if err != nil {
		t.Fatalf("insert: %v", err)
	}
	err = db.Close()
	if err != nil {
		t.Fatalf("close: %v", err)
	}

	fi, err := os.Stat(dbName)
	if err != nil {
		t.Fatalf("Stat: %v", err)
	}
	if fi.Size == 0 {
		t.Fatalf("FileInfo.Size after writes was 0")
	}
	t.Logf("fi.Size = %d", fi.Size)
}
<commit_msg>sqlite: remove the tempdir too<commit_after>package sqlite

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestFoo(t *testing.T) {
	td, err := ioutil.TempDir("", "go-sqlite-test")
	if err != nil {
		t.Fatalf("TempDir: %v", err)
	}
	dbName := filepath.Join(td, "foo.db")
	defer os.RemoveAll(td)

	db, err := Open(dbName)
	if err != nil {
		t.Fatalf("open: %v", err)
	}
	err = db.Exec("CREATE TABLE IF NOT EXISTS foo (a INT, b VARCHAR(200))")
	if err != nil {
		t.Fatalf("create table: %v", err)
	}

	err = db.Exec("INSERT INTO foo VALUES (1, ?)", "foo")
	if err != nil {
		t.Fatalf("insert: %v", err)
	}
	err = db.Exec("INSERT INTO foo VALUES (2, DATETIME('now'))")
	if err != nil {
		t.Fatalf("insert: %v", err)
	}
	err = db.Close()
	if err != nil {
		t.Fatalf("close: %v", err)
	}

	fi, err := os.Stat(dbName)
	if err != nil {
		t.Fatalf("Stat: %v", err)
	}
	if fi.Size == 0 {
		t.Fatalf("FileInfo.Size after writes was 0")
	}
	t.Logf("fi.Size = %d", fi.Size)
}
<|endoftext|>


<commit_before>package arduino

import (
  "encoding/binary"
  "fmt"
  "github.com/yanzay/autohome/modules/generic"
  "github.com/yanzay/automata"
  "math"
  "regexp"
  "strconv"
  "strings"
)

type ArduinoModule struct {
  generic.GenericModule
  arduino *automata.Arduino
  db      TemperatureGetSaver
  options map[string]string
}

type TemperatureGetSaver interface {
  SaveTemperature(float32)
  GetTemperatures(lastDate ...string) [][2]string
}

type tempItem struct {
  Datetime string
  Value    float32
}

func (a *ArduinoModule) Initialize(options map[string]string, db interface{}) {
  // ar, err := automata.NewSerial("/dev/tty.usbmodem1411")
  ar, err := automata.New(automata.EthernetArduino, "192.168.0.13:13666")
  if err != nil {
    fmt.Printf("Can't connect to arduino, continue without it. Error: %v\n", err)
    return
  }
  pins := strings.Split(options["digital_out_pins"], ",")
  for _, pin := range pins {
    ipin, _ := strconv.Atoi(pin)
    ar.SetDigitalOutput(byte(ipin))
  }
  a.db = db.(TemperatureGetSaver)
  a.options = options
  a.arduino = ar
}

func (a *ArduinoModule) Functions() []string {
  var funcs []string
  pins := strings.Split(a.options["digital_out_pins"], ",")
  for _, pin := range pins {
    funcs = append(funcs, "lightOn_"+pin)
    funcs = append(funcs, "lightOff_"+pin)
    funcs = append(funcs, "lightToggle_"+pin)
  }
  funcs = append(funcs, "getTemp")
  return funcs
}

func (a *ArduinoModule) Settings() []string {
  return []string{"port", "digital_out_pins"}
}

func (a *ArduinoModule) Send(command string) {
  if a.arduino == nil {
    fmt.Printf("Can't operate on Arduino, it's missed. Command: %s\n", command)
    return
  }
  com, _ := regexp.Compile("(.*)_([0-9]+)")
  // pin, _ := regexp.Compile(".*_([0-9]+)")
  var p int

  matches := com.FindStringSubmatch(command)
  if len(matches) > 2 {
    command = matches[1]
    fmt.Printf(command)
    p, _ = strconv.Atoi(matches[2])
    fmt.Printf(" with pin %v\n", byte(p))
  }
  // if withPin != "" {
  //   p, _ = strconv.Atoi(pin.FindString(command))
  //   command = withPin
  // }
  go func() {
    switch command {
    case "lightOn":
      a.arduino.On(byte(p))
    case "lightOff":
      a.arduino.Off(byte(p))
    case "lightToggle":
      a.arduino.Toggle(byte(p))
    case "getTemp":
      b := a.arduino.Temp()
      b = append(b)
      bits := binary.LittleEndian.Uint32(b)
      value := math.Float32frombits(bits)
      a.db.SaveTemperature(value)
    }
  }()
}

func (a *ArduinoModule) Handle(method, action string, params ...string) (string, map[string]string) {
  if method == "GET" {
    switch action {
    case "control":
      return "arduino/control", map[string]string{}
    case "stats":
      return "arduino/stats", a.getStats()
    case "last_stats":
      return "", a.getLastStats(params)
    }
  } else {
    switch action {
    case "control":
      a.Send("lightToggle")
    }
  }
  return "", map[string]string{}
}

func (a *ArduinoModule) Menus() []string {
  return []string{"control", "stats"}
}

func (a *ArduinoModule) getStats() map[string]string {
  stats := make(map[string]string)
  for _, item := range a.db.GetTemperatures() {
    stats[item[0]] = item[1]
  }
  return stats
}

func (a *ArduinoModule) getLastStats(params []string) map[string]string {
  stats := make(map[string]string)
  for _, item := range a.db.GetTemperatures(params[0]) {
    stats[item[0]] = item[1]
  }
  return stats
}
<commit_msg>Cleanup.<commit_after>package arduino

import (
  "encoding/binary"
  "fmt"
  "github.com/yanzay/autohome/modules/generic"
  "github.com/yanzay/automata"
  "math"
  "regexp"
  "strconv"
  "strings"
)

type ArduinoModule struct {
  generic.GenericModule
  arduino *automata.Arduino
  db      TemperatureGetSaver
  options map[string]string
}

type TemperatureGetSaver interface {
  SaveTemperature(float32)
  GetTemperatures(lastDate ...string) [][2]string
}

type tempItem struct {
  Datetime string
  Value    float32
}

func (a *ArduinoModule) Initialize(options map[string]string, db interface{}) {
  // ar, err := automata.NewSerial("/dev/tty.usbmodem1411")
  ar, err := automata.New(automata.EthernetArduino, "192.168.0.13:13666")
  if err != nil {
    fmt.Printf("Can't connect to arduino, continue without it. Error: %v\n", err)
    return
  }
  pins := strings.Split(options["digital_out_pins"], ",")
  for _, pin := range pins {
    ipin, _ := strconv.Atoi(pin)
    ar.SetDigitalOutput(byte(ipin))
  }
  a.db = db.(TemperatureGetSaver)
  a.options = options
  a.arduino = ar
}

func (a *ArduinoModule) Functions() []string {
  var funcs []string
  pins := strings.Split(a.options["digital_out_pins"], ",")
  for _, pin := range pins {
    funcs = append(funcs, "lightOn_"+pin)
    funcs = append(funcs, "lightOff_"+pin)
    funcs = append(funcs, "lightToggle_"+pin)
  }
  funcs = append(funcs, "getTemp")
  return funcs
}

func (a *ArduinoModule) Settings() []string {
  return []string{"port", "digital_out_pins"}
}

func (a *ArduinoModule) Send(command string) {
  if a.arduino == nil {
    fmt.Printf("Can't operate on Arduino, it's missed. Command: %s\n", command)
    return
  }
  com, _ := regexp.Compile("(.*)_([0-9]+)")
  var p int

  matches := com.FindStringSubmatch(command)
  if len(matches) > 2 {
    command = matches[1]
    fmt.Printf(command)
    p, _ = strconv.Atoi(matches[2])
    fmt.Printf(" with pin %v\n", byte(p))
  }

  go func() {
    switch command {
    case "lightOn":
      a.arduino.On(byte(p))
    case "lightOff":
      a.arduino.Off(byte(p))
    case "lightToggle":
      a.arduino.Toggle(byte(p))
    case "getTemp":
      b := a.arduino.Temp()
      b = append(b)
      bits := binary.LittleEndian.Uint32(b)
      value := math.Float32frombits(bits)
      a.db.SaveTemperature(value)
    }
  }()
}

func (a *ArduinoModule) Handle(method, action string, params ...string) (string, map[string]string) {
  if method == "GET" {
    switch action {
    case "control":
      return "arduino/control", map[string]string{}
    case "stats":
      return "arduino/stats", a.getStats()
    case "last_stats":
      return "", a.getLastStats(params)
    }
  } else {
    switch action {
    case "control":
      a.Send("lightToggle")
    }
  }
  return "", map[string]string{}
}

func (a *ArduinoModule) Menus() []string {
  return []string{"control", "stats"}
}

func (a *ArduinoModule) getStats() map[string]string {
  stats := make(map[string]string)
  for _, item := range a.db.GetTemperatures() {
    stats[item[0]] = item[1]
  }
  return stats
}

func (a *ArduinoModule) getLastStats(params []string) map[string]string {
  stats := make(map[string]string)
  for _, item := range a.db.GetTemperatures(params[0]) {
    stats[item[0]] = item[1]
  }
  return stats
}
<|endoftext|>


<commit_before>package assets

import (
	"bytes"
	"crypto/sha1"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

type file struct {
	info os.FileInfo
	path string
}

// An asset generator. The generator can be used to generate an asset go file
// with all the assets that were added to the generator embedded into it.
// The generated assets are made available by the specified go variable
// VariableName which is of type assets.FileSystem.
type Generator struct {
	// The package name to generate assets in,
	PackageName string

	// The variable name containing the asset filesystem (defaults to Assets),
	VariableName string

	// Strip the specified prefix from all paths,
	StripPrefix string

	fsDirsMap  map[string][]string
	fsFilesMap map[string]file
}

func (x *Generator) addPath(parent string, prefix string, info os.FileInfo) error {
	p := path.Join(parent, info.Name())

	f := file{
		info: info,
		path: path.Join(prefix, p),
	}

	x.fsFilesMap[p] = f

	if info.IsDir() {
		f, err := os.Open(f.path)
		fi, err := f.Readdir(-1)

		if err != nil {
			return err
		}

		x.fsDirsMap[p] = make([]string, 0, len(fi))

		for _, f := range fi {
			if err := x.addPath(p, prefix, f); err != nil {
				return err
			}
		}
	} else {
		x.appendFileInDir(parent, info.Name())
	}

	return nil
}

func (x *Generator) appendFileInDir(dir string, file string) {
	for _, v := range x.fsDirsMap[dir] {
		if v == file {
			return
		}
	}

	x.fsDirsMap[dir] = append(x.fsDirsMap[dir], file)
}

func (x *Generator) addParents(p string, prefix string) error {
	dname, fname := path.Split(p)

	if len(dname) == 0 {
		return nil
	}

	wosep := dname[0 : len(dname)-1]

	if err := x.addParents(wosep, prefix); err != nil {
		return err
	}

	if len(wosep) == 0 {
		wosep = "/"
	}

	x.appendFileInDir(wosep, fname)

	if _, ok := x.fsFilesMap[wosep]; !ok {
		pp := path.Join(prefix, wosep)
		s, err := os.Stat(pp)

		if err != nil {
			return err
		}

		x.fsFilesMap[wosep] = file{
			info: s,
			path: pp,
		}
	}

	return nil
}

func (x *Generator) splitRelPrefix(p string) (string, string) {
	i := 0
	relp := "../"

	for strings.HasPrefix(p[i:], relp) {
		i += len(relp)
	}

	return path.Join(p[0:i], "."), path.Join("/", p[i:])
}

// Add a file or directory asset to the generator. Added directories will be
// recursed automatically.
func (x *Generator) Add(p string) error {
	if x.fsFilesMap == nil {
		x.fsFilesMap = make(map[string]file)
	}

	if x.fsDirsMap == nil {
		x.fsDirsMap = make(map[string][]string)
	}

	p = path.Clean(p)

	info, err := os.Stat(p)

	if err != nil {
		return err
	}

	prefix, p := x.splitRelPrefix(p)

	if err := x.addParents(p, prefix); err != nil {
		return err
	}

	return x.addPath(path.Dir(p), prefix, info)
}

func (x *Generator) stripPrefix(p string) (string, bool) {
	if len(x.StripPrefix) == 0 {
		return p, true
	}

	if strings.HasPrefix(p, x.StripPrefix) {
		return p[len(x.StripPrefix):], true
	} else {
		return p, false
	}
}

// Write the asset tree specified in the generator to the given writer. The
// written asset tree is a valid, standalone go file with the assets
// embedded into it.
func (x *Generator) Write(wr io.Writer) error {
	p := x.PackageName

	if len(p) == 0 {
		p = "main"
	}

	variableName := x.VariableName

	if len(variableName) == 0 {
		variableName = "Assets"
	}

	writer := &bytes.Buffer{}

	// Write package and import
	fmt.Fprintf(writer, "package %s\n\n", p)
	fmt.Fprintln(writer, "import (")
	fmt.Fprintln(writer, "\t\"github.com/jessevdk/go-assets\"")
	fmt.Fprintln(writer, "\t\"time\"")
	fmt.Fprintln(writer, ")")
	fmt.Fprintln(writer)

	vnames := make(map[string]string)

	// Write file contents as const strings
	if x.fsFilesMap != nil {
		// Create mapping from full file path to asset variable name.
		// This also reads the file and writes the contents as a const
		// string
		for k, v := range x.fsFilesMap {
			if v.info.IsDir() {
				continue
			}

			f, err := os.Open(v.path)

			if err != nil {
				return err
			}

			defer f.Close()

			data, err := ioutil.ReadAll(f)

			if err != nil {
				return err
			}

			s := sha1.New()
			io.WriteString(s, k)

			vname := fmt.Sprintf("__%s%x", variableName, s.Sum(nil))
			vnames[k] = vname

			fmt.Fprintf(writer, "var %s = %#v\n", vname, string(data))
		}

		fmt.Fprintln(writer)
	}

	fmt.Fprintf(writer, "var %s = assets.NewFileSystem(", variableName)

	if x.fsDirsMap == nil {
		x.fsDirsMap = make(map[string][]string)
	}

	if x.fsFilesMap == nil {
		x.fsFilesMap = make(map[string]file)
	}

	dirmap := make(map[string][]string)

	for k, v := range x.fsDirsMap {
		if kk, ok := x.stripPrefix(k); ok {
			if len(kk) == 0 {
				kk = "/"
			}

			dirmap[kk] = v
		}
	}

	fmt.Fprintf(writer, "%#v, ", dirmap)
	fmt.Fprintf(writer, "map[string]*assets.File{\n")

	// Write files
	for k, v := range x.fsFilesMap {
		kk, ok := x.stripPrefix(k)

		if !ok {
			continue
		}

		if len(kk) == 0 {
			kk = "/"
		}

		mt := v.info.ModTime()

		var dt string

		if !v.info.IsDir() {
			dt = "[]byte(" + vnames[k] + ")"
		} else {
			dt = "nil"
		}

		fmt.Fprintf(writer, "\t\t%#v: &assets.File{\n", kk)
		fmt.Fprintf(writer, "\t\t\tPath: %#v,\n", kk)
		fmt.Fprintf(writer, "\t\t\tFileMode: %#v,\n", v.info.Mode())
		fmt.Fprintf(writer, "\t\t\tMtime: time.Unix(%#v, %#v),\n", mt.Unix(), mt.UnixNano())
		fmt.Fprintf(writer, "\t\t\tData: %s,\n", dt)
		fmt.Fprintf(writer, "\t\t},")
	}

	fmt.Fprintln(writer, "\t}, \"\")")

	ret, err := format.Source(writer.Bytes())

	if err != nil {
		return err
	}

	wr.Write(ret)
	return nil
}
<commit_msg>If the number of files is > /proc/sys/fs/file-max things will fail, fixing this.<commit_after>package assets

import (
	"bytes"
	"crypto/sha1"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

type file struct {
	info os.FileInfo
	path string
}

// An asset generator. The generator can be used to generate an asset go file
// with all the assets that were added to the generator embedded into it.
// The generated assets are made available by the specified go variable
// VariableName which is of type assets.FileSystem.
type Generator struct {
	// The package name to generate assets in,
	PackageName string

	// The variable name containing the asset filesystem (defaults to Assets),
	VariableName string

	// Strip the specified prefix from all paths,
	StripPrefix string

	fsDirsMap  map[string][]string
	fsFilesMap map[string]file
}

func (x *Generator) addPath(parent string, prefix string, info os.FileInfo) error {
	p := path.Join(parent, info.Name())

	f := file{
		info: info,
		path: path.Join(prefix, p),
	}

	x.fsFilesMap[p] = f

	if info.IsDir() {
		f, err := os.Open(f.path)
		fi, err := f.Readdir(-1)
		f.Close()
		if err != nil {
			return err
		}

		x.fsDirsMap[p] = make([]string, 0, len(fi))

		for _, f := range fi {
			if err := x.addPath(p, prefix, f); err != nil {
				return err
			}
		}
	} else {
		x.appendFileInDir(parent, info.Name())
	}

	return nil
}

func (x *Generator) appendFileInDir(dir string, file string) {
	for _, v := range x.fsDirsMap[dir] {
		if v == file {
			return
		}
	}

	x.fsDirsMap[dir] = append(x.fsDirsMap[dir], file)
}

func (x *Generator) addParents(p string, prefix string) error {
	dname, fname := path.Split(p)

	if len(dname) == 0 {
		return nil
	}

	wosep := dname[0 : len(dname)-1]

	if err := x.addParents(wosep, prefix); err != nil {
		return err
	}

	if len(wosep) == 0 {
		wosep = "/"
	}

	x.appendFileInDir(wosep, fname)

	if _, ok := x.fsFilesMap[wosep]; !ok {
		pp := path.Join(prefix, wosep)
		s, err := os.Stat(pp)

		if err != nil {
			return err
		}

		x.fsFilesMap[wosep] = file{
			info: s,
			path: pp,
		}
	}

	return nil
}

func (x *Generator) splitRelPrefix(p string) (string, string) {
	i := 0
	relp := "../"

	for strings.HasPrefix(p[i:], relp) {
		i += len(relp)
	}

	return path.Join(p[0:i], "."), path.Join("/", p[i:])
}

// Add a file or directory asset to the generator. Added directories will be
// recursed automatically.
func (x *Generator) Add(p string) error {
	if x.fsFilesMap == nil {
		x.fsFilesMap = make(map[string]file)
	}

	if x.fsDirsMap == nil {
		x.fsDirsMap = make(map[string][]string)
	}

	p = path.Clean(p)

	info, err := os.Stat(p)

	if err != nil {
		return err
	}

	prefix, p := x.splitRelPrefix(p)

	if err := x.addParents(p, prefix); err != nil {
		return err
	}

	return x.addPath(path.Dir(p), prefix, info)
}

func (x *Generator) stripPrefix(p string) (string, bool) {
	if len(x.StripPrefix) == 0 {
		return p, true
	}

	if strings.HasPrefix(p, x.StripPrefix) {
		return p[len(x.StripPrefix):], true
	} else {
		return p, false
	}
}

// Write the asset tree specified in the generator to the given writer. The
// written asset tree is a valid, standalone go file with the assets
// embedded into it.
func (x *Generator) Write(wr io.Writer) error {
	p := x.PackageName

	if len(p) == 0 {
		p = "main"
	}

	variableName := x.VariableName

	if len(variableName) == 0 {
		variableName = "Assets"
	}

	writer := &bytes.Buffer{}

	// Write package and import
	fmt.Fprintf(writer, "package %s\n\n", p)
	fmt.Fprintln(writer, "import (")
	fmt.Fprintln(writer, "\t\"github.com/jessevdk/go-assets\"")
	fmt.Fprintln(writer, "\t\"time\"")
	fmt.Fprintln(writer, ")")
	fmt.Fprintln(writer)

	vnames := make(map[string]string)

	// Write file contents as const strings
	if x.fsFilesMap != nil {
		// Create mapping from full file path to asset variable name.
		// This also reads the file and writes the contents as a const
		// string
		for k, v := range x.fsFilesMap {
			if v.info.IsDir() {
				continue
			}

			f, err := os.Open(v.path)

			if err != nil {
				return err
			}

			data, err := ioutil.ReadAll(f)

			f.Close()

			if err != nil {
				return err
			}

			s := sha1.New()
			io.WriteString(s, k)

			vname := fmt.Sprintf("__%s%x", variableName, s.Sum(nil))
			vnames[k] = vname

			fmt.Fprintf(writer, "var %s = %#v\n", vname, string(data))
		}

		fmt.Fprintln(writer)
	}

	fmt.Fprintf(writer, "var %s = assets.NewFileSystem(", variableName)

	if x.fsDirsMap == nil {
		x.fsDirsMap = make(map[string][]string)
	}

	if x.fsFilesMap == nil {
		x.fsFilesMap = make(map[string]file)
	}

	dirmap := make(map[string][]string)

	for k, v := range x.fsDirsMap {
		if kk, ok := x.stripPrefix(k); ok {
			if len(kk) == 0 {
				kk = "/"
			}

			dirmap[kk] = v
		}
	}

	fmt.Fprintf(writer, "%#v, ", dirmap)
	fmt.Fprintf(writer, "map[string]*assets.File{\n")

	// Write files
	for k, v := range x.fsFilesMap {
		kk, ok := x.stripPrefix(k)

		if !ok {
			continue
		}

		if len(kk) == 0 {
			kk = "/"
		}

		mt := v.info.ModTime()

		var dt string

		if !v.info.IsDir() {
			dt = "[]byte(" + vnames[k] + ")"
		} else {
			dt = "nil"
		}

		fmt.Fprintf(writer, "\t\t%#v: &assets.File{\n", kk)
		fmt.Fprintf(writer, "\t\t\tPath: %#v,\n", kk)
		fmt.Fprintf(writer, "\t\t\tFileMode: %#v,\n", v.info.Mode())
		fmt.Fprintf(writer, "\t\t\tMtime: time.Unix(%#v, %#v),\n", mt.Unix(), mt.UnixNano())
		fmt.Fprintf(writer, "\t\t\tData: %s,\n", dt)
		fmt.Fprintf(writer, "\t\t},")
	}

	fmt.Fprintln(writer, "\t}, \"\")")

	ret, err := format.Source(writer.Bytes())

	if err != nil {
		return err
	}

	wr.Write(ret)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/mitchellh/go-homedir"
)

type UnknownLicenseError struct {
	License string
}

func (e UnknownLicenseError) Error() string {
	return fmt.Sprintf(`error: unknown license %q
see 'license -list' for the list of available licenses`, e.License)
}

func generate() {
	err := doGenerate()
	if err != nil {
		errLogger.Println(err)
		os.Exit(1)
	}
	os.Exit(0)
}

func doGenerate() error {
	flags.License = strings.ToLower(flags.License)

	home, err := homedir.Dir()
	if err != nil {
		return err
	}

	p := filepath.Join(home, ".license", "data", "tmpl", flags.License+".tmpl")
	t, err := template.ParseFiles(p)
	if err != nil {
		if os.IsNotExist(err) {
			return UnknownLicenseError{flags.License}
		}
		return err
	}

	var out io.Writer = os.Stdout
	if flags.Output != "" {
		f, err := os.Create(filepath.Clean(flags.Output))
		if err != nil {
			return err
		}
		out = f
	}

	// For non-nil error, data may have been written, but at least
	// we can set a non-zero exit code.
	return t.Execute(out, struct {
		Name string
		Year string
	}{flags.Name, flags.Year})
}
<commit_msg>Fetch licenses on first run<commit_after>package main

import (
	"fmt"
	"html/template"
	"io"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/mitchellh/go-homedir"
)

type UnknownLicenseError struct {
	License string
}

func (e UnknownLicenseError) Error() string {
	return fmt.Sprintf(`error: unknown license %q
see 'license -list' for the list of available licenses`, e.License)
}

func generate() {
	err := doGenerate()
	if err != nil {
		errLogger.Println(err)
		os.Exit(1)
	}
	os.Exit(0)
}

func doGenerate() error {
	flags.License = strings.ToLower(flags.License)

	home, err := homedir.Dir()
	if err != nil {
		return err
	}

	if _, err := os.Stat(path.Join(home, ".license")); os.IsNotExist(err) {
		if err := doUpdate(); err != nil {
			return err
		}
	}

	p := filepath.Join(home, ".license", "data", "tmpl", flags.License+".tmpl")
	t, err := template.ParseFiles(p)
	if err != nil {
		if os.IsNotExist(err) {
			return UnknownLicenseError{flags.License}
		}
		return err
	}

	var out io.Writer = os.Stdout
	if flags.Output != "" {
		f, err := os.Create(filepath.Clean(flags.Output))
		if err != nil {
			return err
		}
		out = f
	}

	// For non-nil error, data may have been written, but at least
	// we can set a non-zero exit code.
	return t.Execute(out, struct {
		Name string
		Year string
	}{flags.Name, flags.Year})
}
<|endoftext|>


<commit_before>package localfs

import (
	"context"
	"os"
	"path/filepath"

	"github.com/natefinch/atomic"
	"github.com/pkg/errors"

	"github.com/kopia/kopia/fs"
)

// CopyOptions contains the options for copying a file system tree
type CopyOptions struct {
	// If a directory already exists, overwrite the directory.
	OverwriteDirectories bool
	// Indicate whether or not to overwrite existing files. When set to false,
	// the copier does not modify already existing files and returns an error
	// instead.
	OverwriteFiles bool
}

// Copy copies e into targetPath in the local file system. If e is an
// fs.Directory, then the contents are recursively copied.
// The targetPath must not exist, except when the target path is the root
// directory. In that case, e must be a fs.Directory and its contents are copied
// to the root directory.
// Copy does not overwrite files or directories and returns an error in that
// case. It also returns an error when the the contents cannot be restored,
// for example due to an I/O error.
func Copy(ctx context.Context, targetPath string, e fs.Entry, opt CopyOptions) error {
	targetPath, err := filepath.Abs(filepath.FromSlash(targetPath))
	if err != nil {
		return err
	}

	c := copier{CopyOptions: opt}
	return c.copyEntry(ctx, e, targetPath)
}

type copier struct {
	CopyOptions
}

func (c *copier) copyEntry(ctx context.Context, e fs.Entry, targetPath string) error {
	var err error

	switch e := e.(type) {
	case fs.Directory:
		err = c.copyDirectory(ctx, e, targetPath)
	case fs.File:
		err = c.copyFileContent(ctx, targetPath, e)
	case fs.Symlink:
		// Not yet implemented
		log.Warningf("Not creating symlink %q from %v", targetPath, e)
		return nil
	default:
		return errors.Errorf("invalid FS entry type for %q: %#v", targetPath, e)
	}

	if err != nil {
		return err
	}

	return c.setAttributes(targetPath, e)
}

// set permission, modification time and user/group ids on targetPath
func (c *copier) setAttributes(targetPath string, e fs.Entry) error {
	const modBits = os.ModePerm | os.ModeSetgid | os.ModeSetuid | os.ModeSticky

	le, err := NewEntry(targetPath)
	if err != nil {
		return errors.Wrap(err, "could not create local FS entry for "+targetPath)
	}

	// Set owner user and group from e
	if le.Owner() != e.Owner() {
		if err = os.Chown(targetPath, int(e.Owner().UserID), int(e.Owner().GroupID)); err != nil && !os.IsPermission(err) {
			return errors.Wrap(err, "could not change owner/group for "+targetPath)
		}
	}

	// Set file permissions from e
	if (le.Mode() & modBits) != (e.Mode() & modBits) {
		if err = os.Chmod(targetPath, e.Mode()&modBits); err != nil && !os.IsPermission(err) {
			return errors.Wrap(err, "could not change permissions on "+targetPath)
		}
	}

	// Set mod time from e
	if !le.ModTime().Equal(e.ModTime()) {
		// Note: Set atime to ModTime as well
		if err = os.Chtimes(targetPath, e.ModTime(), e.ModTime()); err != nil && !os.IsPermission(err) {
			return errors.Wrap(err, "could not change mod time on "+targetPath)
		}
	}

	return nil
}

func (c *copier) copyDirectory(ctx context.Context, d fs.Directory, targetPath string) error {
	if err := c.createDirectory(targetPath); err != nil {
		return err
	}

	return c.copyDirectoryContent(ctx, d, targetPath)
}

func (c *copier) copyDirectoryContent(ctx context.Context, d fs.Directory, targetPath string) error {
	entries, err := d.Readdir(ctx)
	if err != nil {
		return err
	}

	for _, e := range entries {
		if err := c.copyEntry(ctx, e, filepath.Join(targetPath, e.Name())); err != nil {
			return err
		}
	}

	return nil
}

func (c *copier) createDirectory(path string) error {
	switch stat, err := os.Stat(path); {
	case os.IsNotExist(err):
		return os.MkdirAll(path, 0700)
	case err != nil:
		return errors.Wrap(err, "failed to stat path "+path)
	case stat.Mode().IsDir():
		return errors.Errorf("directory already exists, not overwriting it: %q", path)
	default:
		return errors.Errorf("unable to create directory, %q already exists and it is not a directory", path)
	}
}

func (c *copier) copyFileContent(ctx context.Context, targetPath string, f fs.File) error {
	switch _, err := os.Stat(targetPath); {
	case os.IsNotExist(err): // copy file below
	case err == nil:
		if !c.OverwriteFiles {
			return errors.Errorf("unable to create %q, it already exists", targetPath)
		}
		log.Debug("Overwriting existing file: ", targetPath)
	default:
		return errors.Wrap(err, "failed to stat "+targetPath)
	}

	r, err := f.Open(ctx)
	if err != nil {
		return errors.Wrap(err, "unable to open snapshot file for "+targetPath)
	}
	defer r.Close() //nolint:errcheck

	return atomic.WriteFile(targetPath, r)
}
<commit_msg>Allow copying to an existing directory<commit_after>package localfs

import (
	"context"
	"io"
	"os"
	"path/filepath"

	"github.com/natefinch/atomic"
	"github.com/pkg/errors"

	"github.com/kopia/kopia/fs"
)

// CopyOptions contains the options for copying a file system tree
type CopyOptions struct {
	// If a directory already exists, overwrite the directory.
	OverwriteDirectories bool
	// Indicate whether or not to overwrite existing files. When set to false,
	// the copier does not modify already existing files and returns an error
	// instead.
	OverwriteFiles bool
}

// Copy copies e into targetPath in the local file system. If e is an
// fs.Directory, then the contents are recursively copied.
// The targetPath must not exist, except when the target path is the root
// directory. In that case, e must be a fs.Directory and its contents are copied
// to the root directory.
// Copy does not overwrite files or directories and returns an error in that
// case. It also returns an error when the the contents cannot be restored,
// for example due to an I/O error.
func Copy(ctx context.Context, targetPath string, e fs.Entry, opt CopyOptions) error {
	targetPath, err := filepath.Abs(filepath.FromSlash(targetPath))
	if err != nil {
		return err
	}

	c := copier{CopyOptions: opt}
	return c.copyEntry(ctx, e, targetPath)
}

type copier struct {
	CopyOptions
}

func (c *copier) copyEntry(ctx context.Context, e fs.Entry, targetPath string) error {
	var err error

	switch e := e.(type) {
	case fs.Directory:
		err = c.copyDirectory(ctx, e, targetPath)
	case fs.File:
		err = c.copyFileContent(ctx, targetPath, e)
	case fs.Symlink:
		// Not yet implemented
		log.Warningf("Not creating symlink %q from %v", targetPath, e)
		return nil
	default:
		return errors.Errorf("invalid FS entry type for %q: %#v", targetPath, e)
	}

	if err != nil {
		return err
	}

	return c.setAttributes(targetPath, e)
}

// set permission, modification time and user/group ids on targetPath
func (c *copier) setAttributes(targetPath string, e fs.Entry) error {
	const modBits = os.ModePerm | os.ModeSetgid | os.ModeSetuid | os.ModeSticky

	le, err := NewEntry(targetPath)
	if err != nil {
		return errors.Wrap(err, "could not create local FS entry for "+targetPath)
	}

	// Set owner user and group from e
	if le.Owner() != e.Owner() {
		if err = os.Chown(targetPath, int(e.Owner().UserID), int(e.Owner().GroupID)); err != nil && !os.IsPermission(err) {
			return errors.Wrap(err, "could not change owner/group for "+targetPath)
		}
	}

	// Set file permissions from e
	if (le.Mode() & modBits) != (e.Mode() & modBits) {
		if err = os.Chmod(targetPath, e.Mode()&modBits); err != nil && !os.IsPermission(err) {
			return errors.Wrap(err, "could not change permissions on "+targetPath)
		}
	}

	// Set mod time from e
	if !le.ModTime().Equal(e.ModTime()) {
		// Note: Set atime to ModTime as well
		if err = os.Chtimes(targetPath, e.ModTime(), e.ModTime()); err != nil && !os.IsPermission(err) {
			return errors.Wrap(err, "could not change mod time on "+targetPath)
		}
	}

	return nil
}

func (c *copier) copyDirectory(ctx context.Context, d fs.Directory, targetPath string) error {
	if err := c.createDirectory(targetPath); err != nil {
		return err
	}

	return c.copyDirectoryContent(ctx, d, targetPath)
}

func (c *copier) copyDirectoryContent(ctx context.Context, d fs.Directory, targetPath string) error {
	entries, err := d.Readdir(ctx)
	if err != nil {
		return err
	}

	for _, e := range entries {
		if err := c.copyEntry(ctx, e, filepath.Join(targetPath, e.Name())); err != nil {
			return err
		}
	}

	return nil
}

func (c *copier) createDirectory(path string) error {
	switch stat, err := os.Stat(path); {
	case os.IsNotExist(err):
		return os.MkdirAll(path, 0700)
	case err != nil:
		return errors.Wrap(err, "failed to stat path "+path)
	case stat.Mode().IsDir():
		if !c.OverwriteDirectories {
			if empty, _ := isEmptyDirectory(path); !empty {
				return errors.Errorf("non-empty directory already exists, not overwriting it: %q", path)
			}
		}
		log.Debug("Not creating already existing directory: ", path)
		return nil
	default:
		return errors.Errorf("unable to create directory, %q already exists and it is not a directory", path)
	}
}

func (c *copier) copyFileContent(ctx context.Context, targetPath string, f fs.File) error {
	switch _, err := os.Stat(targetPath); {
	case os.IsNotExist(err): // copy file below
	case err == nil:
		if !c.OverwriteFiles {
			return errors.Errorf("unable to create %q, it already exists", targetPath)
		}
		log.Debug("Overwriting existing file: ", targetPath)
	default:
		return errors.Wrap(err, "failed to stat "+targetPath)
	}

	r, err := f.Open(ctx)
	if err != nil {
		return errors.Wrap(err, "unable to open snapshot file for "+targetPath)
	}
	defer r.Close() //nolint:errcheck

	log.Debug("copying file contents to: ", targetPath)

	return atomic.WriteFile(targetPath, r)
}

func isEmptyDirectory(name string) (bool, error) {
	f, err := os.Open(name)
	if err != nil {
		return false, err
	}

	defer f.Close()

	if _, err = f.Readdirnames(1); err == io.EOF {
		return true, nil
	}

	return false, err // Either not empty or error
}
<|endoftext|>


<commit_before>package main

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

	"github.com/pkg/errors"

	"github.com/jBugman/fun-lang/func-parse/parser"
)

func main() {
	source, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		fmt.Fprintln(os.Stderr, errors.Wrap(err, "reading input"))
		os.Exit(1)
	}

	result, e := parser.Parse(source)
	if e != nil {
		const filename = "<standard input>"
		fmt.Fprintf(os.Stderr, "%s:%d:%d: %s\n", filename, e.Pos().Line, e.Pos().Col, e)
		os.Exit(1)
	}

	output, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		fmt.Fprintln(os.Stderr, errors.Wrap(err, "marshal json"))
		os.Exit(1)
	}
	os.Stdout.Write(output)
}
<commit_msg>JSON-wrapped errors<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"

	"github.com/pkg/errors"

	"github.com/jBugman/fun-lang/func-parse/fun/code"
	"github.com/jBugman/fun-lang/func-parse/parser"
)

func main() {
	source, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		abortWith(errors.Wrap(err, "reading stdin"))
	}

	result, e := parser.Parse(source)
	if e != nil {
		abortWithJ(jsonError{
			Error: e.Error(),
			Pos:   e.Pos(),
		})
	}

	output, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		abortWith(errors.Wrap(err, "marshal json"))
	}
	os.Stdout.Write(output)
}

type jsonError struct {
	Error string   `json:"error"`
	Pos   code.Pos `json:"pos,omitempty"`
}

func abortWith(err error) {
	abortWithJ(jsonError{Error: err.Error()})
}

func abortWithJ(err jsonError) {
	output, _ := json.MarshalIndent(err, "", "  ")
	os.Stderr.Write(output)
	os.Stderr.WriteString("\n")
	os.Exit(1)
}
<|endoftext|>


<commit_before>package hello

import (
  "io"
  "io/ioutil"
  "log"
  "encoding/json"
  "fmt"
  "math/rand"
  "net/http"
  "strconv"

  "appengine"
  "appengine/blobstore"
  "appengine/datastore"
//  "appengine/memcache"
  "appengine/urlfetch"

  "github.com/ant0ine/go-json-rest"
)

type Book struct {
  Author string
  Title string
  Id int
  Paragraphs int
  Key string
}

type BookBlob struct {
  Book

  Data []string
}

func GetParagraphs(w *rest.ResponseWriter, r *rest.Request) {
  count, _ := strconv.Atoi(r.FormValue("num"))
  if count == 0 { count = 4 }

  c := appengine.NewContext(r.Request)
  q := datastore.NewQuery("Book")

  var books []Book
  q.GetAll(c, &books)

  book := books[rand.Intn(len(books))]
  start := rand.Intn(book.Paragraphs - count)

  // ------
  client := urlfetch.Client(c)
  resp, err := client.Get(fmt.Sprintf("http://localhost:8080/books/%d", book.Id))
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  defer resp.Body.Close()
  body, _ := ioutil.ReadAll(resp.Body)

  var blob BookBlob
  json.Unmarshal(body, &blob)
  blob.Data = blob.Data[start:start+count]
  w.WriteJson(blob)
}

func GetBook(w *rest.ResponseWriter, r *rest.Request) {
  c := appengine.NewContext(r.Request)
  key := datastore.NewKey(c, "Book", r.PathParam("id"), 0, nil)
  var book Book
  datastore.Get(c, key, &book)
  blobstore.Send(w.ResponseWriter, appengine.BlobKey(book.Key))
}

func StoreBook(w *rest.ResponseWriter, r *rest.Request) {
  book := Book{}
  r.DecodeJsonPayload(&book)
  context := appengine.NewContext(r.Request)
  key := datastore.NewKey(context, "Book", strconv.Itoa(book.Id), 0, nil)
  if _, err := datastore.Put(context, key, &book); err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  w.WriteJson(map[string]string{ "success": "true" })
}

func UploadID(w *rest.ResponseWriter, r *rest.Request) {
  c := appengine.NewContext(r.Request)
  uploadURL, err := blobstore.UploadURL(c, "/upload/id", nil)
  if err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  w.WriteJson(map[string]string{ "succes": "true", "url": uploadURL.String() })
}

func BlobID(w http.ResponseWriter, r *http.Request) {
  blobs, _, _ := blobstore.ParseUpload(r)
  io.WriteString(w, fmt.Sprintf("{ \"success\":\"true\", \"key\":\"%s\" }",
    blobs["file"][0].BlobKey))
}

func init() {
  handler := rest.ResourceHandler{}
  handler.SetRoutes(
    rest.Route{"GET", "/paragraphs", GetParagraphs},
    rest.Route{"GET", "/books/:id", GetBook},
    rest.Route{"POST", "/books", StoreBook},
    rest.Route{"GET", "/upload", UploadID},
  )
  http.Handle("/", &handler)
  http.HandleFunc("/upload/id", BlobID)

  log.Print("start")
}
<commit_msg>not the cleanest, but it gets the job done<commit_after>package hello

import (
  "io"
  "io/ioutil"
  "log"
  "encoding/json"
  "fmt"
  "math/rand"
  "net/http"
  "strconv"

  "appengine"
  "appengine/blobstore"
  "appengine/datastore"
  "appengine/memcache"
  "appengine/urlfetch"

  "github.com/ant0ine/go-json-rest"
)

type Book struct {
  Author string
  Title string
  Id int
  Paragraphs int
  Key string
}

type BookBlob struct {
  Book

  Data []string
}

func downloadBook(c appengine.Context, i int) BookBlob {
  client := urlfetch.Client(c)
  resp, _ := client.Get(fmt.Sprintf("http://localhost:8080/books/%d", i))
  defer resp.Body.Close()
  body, _ := ioutil.ReadAll(resp.Body)

  var blob BookBlob
  json.Unmarshal(body, &blob)
  return blob
}

func memcacheBook(c appengine.Context, blob BookBlob) {

  for k, v := range blob.Data {
    paragraph := &memcache.Item{
      Key: fmt.Sprintf("%d:%d", blob.Id, k),
      Value: []byte(v),
    }

    if err := memcache.Add(c, paragraph); err != nil {
      log.Print(err)
    }
  }

}

func getParagraph(c appengine.Context, book int, index int) string {

  // Get the item from the memcache
  if item, err := memcache.Get(c, fmt.Sprintf("%d:%d", book, index)); err == memcache.ErrCacheMiss {
    blob := downloadBook(c, book)
    memcacheBook(c, blob)
    return getParagraph(c, book, index)
  } else if err != nil {
    log.Print("err")
  } else {
    return string(item.Value)
  }

  return ""
}

func GetParagraphs(w *rest.ResponseWriter, r *rest.Request) {
  count, _ := strconv.Atoi(r.FormValue("num"))
  if count == 0 { count = 4 }

  c := appengine.NewContext(r.Request)
  q := datastore.NewQuery("Book")

  var books []Book
  q.GetAll(c, &books)

  var blob BookBlob
  blob.Book = books[rand.Intn(len(books))]
  start := rand.Intn(blob.Paragraphs - count)

  var subset []string
  for i := start; i < start + count; i++ {
    subset = append(subset, getParagraph(c, blob.Id, i))
  }

  blob.Data = subset
  w.WriteJson(blob)
}

func GetBook(w *rest.ResponseWriter, r *rest.Request) {
  c := appengine.NewContext(r.Request)
  key := datastore.NewKey(c, "Book", r.PathParam("id"), 0, nil)
  var book Book
  datastore.Get(c, key, &book)
  blobstore.Send(w.ResponseWriter, appengine.BlobKey(book.Key))
}

func StoreBook(w *rest.ResponseWriter, r *rest.Request) {
  book := Book{}
  r.DecodeJsonPayload(&book)
  context := appengine.NewContext(r.Request)
  key := datastore.NewKey(context, "Book", strconv.Itoa(book.Id), 0, nil)
  if _, err := datastore.Put(context, key, &book); err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  w.WriteJson(map[string]string{ "success": "true" })
}

func UploadID(w *rest.ResponseWriter, r *rest.Request) {
  c := appengine.NewContext(r.Request)
  uploadURL, err := blobstore.UploadURL(c, "/upload/id", nil)
  if err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }

  w.WriteJson(map[string]string{ "succes": "true", "url": uploadURL.String() })
}

func BlobID(w http.ResponseWriter, r *http.Request) {
  blobs, _, _ := blobstore.ParseUpload(r)
  io.WriteString(w, fmt.Sprintf("{ \"success\":\"true\", \"key\":\"%s\" }",
    blobs["file"][0].BlobKey))
}

func init() {
  handler := rest.ResourceHandler{}
  handler.SetRoutes(
    rest.Route{"GET", "/paragraphs", GetParagraphs},
    rest.Route{"GET", "/books/:id", GetBook},
    rest.Route{"POST", "/books", StoreBook},
    rest.Route{"GET", "/upload", UploadID},
  )
  http.Handle("/", &handler)
  http.HandleFunc("/upload/id", BlobID)

  log.Print("start")
}
<|endoftext|>