<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/panjf2000/gnet"
)

var res string
var resBytes []byte

type request struct {
	proto, method string
	path, query   string
	head, body    string
	remoteAddr    string
}

type httpServer struct {
	*gnet.EventServer
}

var errMsg = "Internal Server Error"
var errMsgBytes = []byte(errMsg)

type httpCodec struct {
	req request
}

func (hc *httpCodec) Encode(c gnet.Conn, buf []byte) (out []byte, err error) {
	if c.Context() == nil {
		return appendHandle(out, res), nil
	}
	return appendResp(out, "500 Error", "", errMsg+"\n"), nil
}

func (hc *httpCodec) Decode(c gnet.Conn) ([]byte, error) {
	buf := c.Read()
	// process the pipeline
	leftover, err := parseReq(buf, &hc.req)
	// bad thing happened
	if err != nil {
		c.SetContext(err)
		return nil, err
	} else if len(leftover) == len(buf) {
		// request not ready, yet
		return nil, nil
	}
	c.ResetBuffer()
	return buf, nil
}

func (hs *httpServer) OnInitComplete(srv gnet.Server) (action gnet.Action) {
	log.Printf("HTTP server is listening on %s (multi-cores: %t, loops: %d)\n",
		srv.Addr.String(), srv.Multicore, srv.NumLoops)
	return
}

func (hs *httpServer) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	// process the pipeline
	if c.Context() != nil {
		// bad thing happened
		out = errMsgBytes
		action = gnet.Close
		return
	}
	// handle the request
	out = resBytes
	return
}

func main() {
	var port int
	var multicore bool

	// Example command: go run main.go --port 8080 --multicore true
	flag.IntVar(&port, "port", 8080, "server port")
	flag.BoolVar(&multicore, "multicore", true, "multicore")
	flag.Parse()

	res = "Hello, World!"
	resBytes = []byte(res)

	http := new(httpServer)
	hc := new(httpCodec)

	// Start serving!
	log.Fatal(gnet.Serve(http, fmt.Sprintf("tcp://:%d", port), gnet.WithMulticore(multicore), gnet.WithCodec(hc)))
}

// appendHandle handles the incoming request and appends the response to
// the provided bytes, which is then returned to the caller.
func appendHandle(b []byte, res string) []byte {
	return appendResp(b, "200 OK", "", res)
}

// appendResp will append a valid http response to the provide bytes.
// The status param should be the code plus text such as "200 OK".
// The head parameter should be a series of lines ending with "\r\n" or empty.
func appendResp(b []byte, status, head, body string) []byte {
	b = append(b, "HTTP/1.1"...)
	b = append(b, ' ')
	b = append(b, status...)
	b = append(b, '\r', '\n')
	b = append(b, "Server: gnet\r\n"...)
	b = append(b, "Content-Type: text/plain\r\n"...)
	b = append(b, "Date: "...)
	b = time.Now().AppendFormat(b, "Mon, 02 Jan 2006 15:04:05 GMT")
	b = append(b, '\r', '\n')
	if len(body) > 0 {
		b = append(b, "Content-Length: "...)
		b = strconv.AppendInt(b, int64(len(body)), 10)
		b = append(b, '\r', '\n')
	}
	b = append(b, head...)
	b = append(b, '\r', '\n')
	if len(body) > 0 {
		b = append(b, body...)
	}
	return b
}

// parseReq is a very simple http request parser. This operation
// waits for the entire payload to be buffered before returning a
// valid request.
func parseReq(data []byte, req *request) (leftover []byte, err error) {
	sdata := string(data)
	var i, s int
	var head string
	var clen int
	var q = -1
	// method, path, proto line
	for ; i < len(sdata); i++ {
		if sdata[i] == ' ' {
			req.method = sdata[s:i]
			for i, s = i+1, i+1; i < len(sdata); i++ {
				if sdata[i] == '?' && q == -1 {
					q = i - s
				} else if sdata[i] == ' ' {
					if q != -1 {
						req.path = sdata[s:q]
						req.query = req.path[q+1 : i]
					} else {
						req.path = sdata[s:i]
					}
					for i, s = i+1, i+1; i < len(sdata); i++ {
						if sdata[i] == '\n' && sdata[i-1] == '\r' {
							req.proto = sdata[s:i]
							i, s = i+1, i+1
							break
						}
					}
					break
				}
			}
			break
		}
	}
	if req.proto == "" {
		return data, fmt.Errorf("malformed request")
	}
	head = sdata[:s]
	for ; i < len(sdata); i++ {
		if i > 1 && sdata[i] == '\n' && sdata[i-1] == '\r' {
			line := sdata[s : i-1]
			s = i + 1
			if line == "" {
				req.head = sdata[len(head)+2 : i+1]
				i++
				if clen > 0 {
					if len(sdata[i:]) < clen {
						break
					}
					req.body = sdata[i : i+clen]
					i += clen
				}
				return data[i:], nil
			}
			if strings.HasPrefix(line, "Content-Length:") {
				n, err := strconv.ParseInt(strings.TrimSpace(line[len("Content-Length:"):]), 10, 64)
				if err == nil {
					clen = int(n)
				}
			}
		}
	}
	// not enough data
	return data, nil
}
<commit_msg>Fix a bug about http pipeline in gnet (#5499)<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/panjf2000/gnet"
)

var res string

type request struct {
	proto, method string
	path, query   string
	head, body    string
	remoteAddr    string
}

type httpServer struct {
	*gnet.EventServer
}

var errMsg = "Internal Server Error"
var errMsgBytes = []byte(errMsg)

type httpCodec struct {
	req request
}

func (hc *httpCodec) Encode(c gnet.Conn, buf []byte) (out []byte, err error) {
	if c.Context() == nil {
		return buf, nil
	}
	return appendResp(out, "500 Error", "", errMsg+"\n"), nil
}

func (hc *httpCodec) Decode(c gnet.Conn) (out []byte, err error) {
	buf := c.Read()
	c.ResetBuffer()

	// process the pipeline
	var leftover []byte
pipeline:
	leftover, err = parseReq(buf, &hc.req)
	// bad thing happened
	if err != nil {
		c.SetContext(err)
		return nil, err
	} else if len(leftover) == len(buf) {
		// request not ready, yet
		return
	}
	out = appendHandle(out, res)
	buf = leftover
	goto pipeline
}

func (hs *httpServer) OnInitComplete(srv gnet.Server) (action gnet.Action) {
	log.Printf("HTTP server is listening on %s (multi-cores: %t, loops: %d)\n",
		srv.Addr.String(), srv.Multicore, srv.NumLoops)
	return
}

func (hs *httpServer) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	if c.Context() != nil {
		// bad thing happened
		out = errMsgBytes
		action = gnet.Close
		return
	}
	// handle the request
	out = frame
	return
}

func main() {
	var port int
	var multicore bool

	// Example command: go run main.go --port 8080 --multicore true
	flag.IntVar(&port, "port", 8080, "server port")
	flag.BoolVar(&multicore, "multicore", true, "multicore")
	flag.Parse()

	res = "Hello, World!"

	http := new(httpServer)
	hc := new(httpCodec)

	// Start serving!
	log.Fatal(gnet.Serve(http, fmt.Sprintf("tcp://:%d", port), gnet.WithMulticore(multicore), gnet.WithCodec(hc)))
}

// appendHandle handles the incoming request and appends the response to
// the provided bytes, which is then returned to the caller.
func appendHandle(b []byte, res string) []byte {
	return appendResp(b, "200 OK", "", res)
}

// appendResp will append a valid http response to the provide bytes.
// The status param should be the code plus text such as "200 OK".
// The head parameter should be a series of lines ending with "\r\n" or empty.
func appendResp(b []byte, status, head, body string) []byte {
	b = append(b, "HTTP/1.1"...)
	b = append(b, ' ')
	b = append(b, status...)
	b = append(b, '\r', '\n')
	b = append(b, "Server: gnet\r\n"...)
	b = append(b, "Content-Type: text/plain\r\n"...)
	b = append(b, "Date: "...)
	b = time.Now().AppendFormat(b, "Mon, 02 Jan 2006 15:04:05 GMT")
	b = append(b, '\r', '\n')
	if len(body) > 0 {
		b = append(b, "Content-Length: "...)
		b = strconv.AppendInt(b, int64(len(body)), 10)
		b = append(b, '\r', '\n')
	}
	b = append(b, head...)
	b = append(b, '\r', '\n')
	if len(body) > 0 {
		b = append(b, body...)
	}
	return b
}

// parseReq is a very simple http request parser. This operation
// waits for the entire payload to be buffered before returning a
// valid request.
func parseReq(data []byte, req *request) (leftover []byte, err error) {
	sdata := string(data)
	var i, s int
	var head string
	var clen int
	var q = -1
	// method, path, proto line
	for ; i < len(sdata); i++ {
		if sdata[i] == ' ' {
			req.method = sdata[s:i]
			for i, s = i+1, i+1; i < len(sdata); i++ {
				if sdata[i] == '?' && q == -1 {
					q = i - s
				} else if sdata[i] == ' ' {
					if q != -1 {
						req.path = sdata[s:q]
						req.query = req.path[q+1 : i]
					} else {
						req.path = sdata[s:i]
					}
					for i, s = i+1, i+1; i < len(sdata); i++ {
						if sdata[i] == '\n' && sdata[i-1] == '\r' {
							req.proto = sdata[s:i]
							i, s = i+1, i+1
							break
						}
					}
					break
				}
			}
			break
		}
	}
	if req.proto == "" {
		return data, fmt.Errorf("malformed request")
	}
	head = sdata[:s]
	for ; i < len(sdata); i++ {
		if i > 1 && sdata[i] == '\n' && sdata[i-1] == '\r' {
			line := sdata[s : i-1]
			s = i + 1
			if line == "" {
				req.head = sdata[len(head)+2 : i+1]
				i++
				if clen > 0 {
					if len(sdata[i:]) < clen {
						break
					}
					req.body = sdata[i : i+clen]
					i += clen
				}
				return data[i:], nil
			}
			if strings.HasPrefix(line, "Content-Length:") {
				n, err := strconv.ParseInt(strings.TrimSpace(line[len("Content-Length:"):]), 10, 64)
				if err == nil {
					clen = int(n)
				}
			}
		}
	}
	// not enough data
	return data, nil
}
<|endoftext|>


<commit_before>package functional

import (
	"strings"
	"testing"

	"github.com/coreos/fleet/functional/platform"
)

func TestUnitSSHActions(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.DestroyAll()

	if err := cluster.CreateMultiple(1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = waitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if _, _, err := fleetctl("start", "--no-block", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: %v", err)
	}

	units, err := waitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}

	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	stdout, _, err := fleetctl("--strict-host-key-checking=false", "ssh", "hello.service", "echo", "foo")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl ssh: %v", err)
	}

	if !strings.Contains(stdout, "foo") {
		t.Errorf("Could not find expected string in command output:\n%s", stdout)
	}

	stdout, _, err = fleetctl("--strict-host-key-checking=false", "status", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl status: %v", err)
	}

	if !strings.Contains(stdout, "Active: active") {
		t.Errorf("Could not find expected string in status output:\n%s", stdout)
	}

	stdout, _, err = fleetctl("--strict-host-key-checking=false", "journal", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl journal: %v", err)
	}

	if !strings.Contains(stdout, "Hello, World!") {
		t.Errorf("Could not find expected string in journal output:\n%s", stdout)
	}
}
<commit_msg>test(functional): Add unit restart test<commit_after>package functional

import (
	"strings"
	"testing"

	"github.com/coreos/fleet/functional/platform"
)

func TestUnitRestart(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.DestroyAll()

	if err := cluster.CreateMultiple(1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = waitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if _, _, err := fleetctl("start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: %v", err)
	}

	units, err := waitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	if _, _, err := fleetctl("stop", "hello.service"); err != nil {
		t.Fatal(err)
	}
	units, err = waitForNActiveUnits(0)
	if err != nil {
		t.Fatal(err)
	}
	if len(units) != 0 {
		t.Fatal("Zero units should be running, found %v", units)
	}

	if _, _, err := fleetctl("start", "hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: %v", err)
	}
	units, err = waitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found = units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

}

func TestUnitSSHActions(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.DestroyAll()

	if err := cluster.CreateMultiple(1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = waitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if _, _, err := fleetctl("start", "--no-block", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: %v", err)
	}

	units, err := waitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}

	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	stdout, _, err := fleetctl("--strict-host-key-checking=false", "ssh", "hello.service", "echo", "foo")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl ssh: %v", err)
	}

	if !strings.Contains(stdout, "foo") {
		t.Errorf("Could not find expected string in command output:\n%s", stdout)
	}

	stdout, _, err = fleetctl("--strict-host-key-checking=false", "status", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl status: %v", err)
	}

	if !strings.Contains(stdout, "Active: active") {
		t.Errorf("Could not find expected string in status output:\n%s", stdout)
	}

	stdout, _, err = fleetctl("--strict-host-key-checking=false", "journal", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl journal: %v", err)
	}

	if !strings.Contains(stdout, "Hello, World!") {
		t.Errorf("Could not find expected string in journal output:\n%s", stdout)
	}
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"os"
	"strings"
	"testing"
)

type netmaskTPair struct {
	in  uint8
	out string
	err error
}

type byteTPair struct {
	in      uint64
	inUnit  string
	out     float64
	outUnit string
}

var EPSILON float64 = 1

func floatEquals(a, b float64) bool {
	if (a-b) < EPSILON && (b-a) < EPSILON {
		return true
	}
	return false
}

func TestConvertBytes(t *testing.T) {
	testpairs := []byteTPair{
		{5238784, "", 4.996094, "MB"},
		{10485760, "", 10.000000, "MB"},
		{100910080, "", 96.235352, "MB"},
		{3267260416, "", 3.042873, "GB"},
		{306816327680, "", 285.744972, "GB"},
	}
	for _, pair := range testpairs {
		out, outUnit, err := ConvertBytes(pair.in)
		if err != nil {
			t.Logf("input: %v; %v != nil", pair, err)
			t.Fail()
		}
		if strings.Compare(outUnit, pair.outUnit) != 0 {
			t.Logf("input: %v; '%v' != '%v'", pair, outUnit, pair.outUnit)
			t.Fail()
		}
		equality := floatEquals(out, pair.out)
		if equality == false {
			t.Logf("input: %v; %f != %f; diff: %f, %v", pair, out, pair.out,
				(out - pair.out), equality)
			t.Fail()
		}
	}
}

func TestConvertBytesTo(t *testing.T) {
	testpairs := []byteTPair{
		{5238784, "kB", 5116, ""},
		{10485760, "kB", 10240, ""},
		{100910080, "MB", 96.235352, ""},
		{3267260416, "MB", 3115.902344, ""},
		{306816327680, "MB", 292602.851562, ""},
	}
	for _, pair := range testpairs {
		out, outUnit, err := ConvertBytesTo(pair.in, pair.inUnit)
		if err != nil {
			t.Logf("input: %v; %v != nil", pair, err)
			t.Fail()
		}
		if strings.Compare(outUnit, pair.inUnit) != 0 {
			t.Logf("input: %v; '%v' != '%v'", pair, outUnit, pair.inUnit)
			t.Fail()
		}
		equality := floatEquals(out, pair.out)
		if equality == false {
			t.Logf("input: %v; %f != %f; diff: %f, %v", pair, out, pair.out,
				(out - pair.out), equality)
			t.Fail()
		}
	}
}

func TestConvertNetmask(t *testing.T) {
	testpairs := []netmaskTPair{
		{8, "255.0.0.0", nil},
		{17, "255.255.128.0", nil},
		{24, "255.255.255.0", nil},
		{28, "255.255.255.240", nil},
		{33, "", fmt.Errorf("Invalid Netmask given.")},
	}
	for _, pair := range testpairs {
		out, err := ConvertNetmask(pair.in)
		if err == nil && pair.err != nil {
			t.Fatalf("%v != %v", err, pair.err)
		}
		if pair.err != nil {
			// probably not safe to continue
			continue
		}
		if out != pair.out {
			t.Fatalf("%v != %v", out, pair.out)
		}
	}
}

func TestGetHostEtc(t *testing.T) {
	testValue := "test_value"
	err := os.Setenv("HOST_ETC", testValue)
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostEtc()
	if strings.Compare(value, testValue) != 0 {
		t.Fatalf("%v != %v", value, testValue)
	}
}

func TestGetHostEtcNotSet(t *testing.T) {
	expectedVal := "/etc"
	err := os.Unsetenv("HOST_ETC")
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostEtc()
	if strings.Compare(value, expectedVal) != 0 {
		t.Fatalf("%v != %v", value, expectedVal)
	}
}

func TestGetHostProc(t *testing.T) {
	testValue := "test_value"
	err := os.Setenv("HOST_PROC", testValue)
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostProc()
	if strings.Compare(value, testValue) != 0 {
		t.Fatalf("%v != %v", value, testValue)
	}
}

func TestGetHostProcNotSet(t *testing.T) {
	expectedVal := "/proc"
	err := os.Unsetenv("HOST_PROC")
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostProc()
	if strings.Compare(value, expectedVal) != 0 {
		t.Fatalf("%v != %v", value, expectedVal)
	}
}

func TestGetHostSys(t *testing.T) {
	testValue := "test_value"
	err := os.Setenv("HOST_SYS", testValue)
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostSys()
	if strings.Compare(value, testValue) != 0 {
		t.Fatalf("%v != %v", value, testValue)
	}
}

func TestGetHostSysNotSet(t *testing.T) {
	expectedVal := "/sys"
	err := os.Unsetenv("HOST_SYS")
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostSys()
	if strings.Compare(value, expectedVal) != 0 {
		t.Fatalf("%v != %v", value, expectedVal)
	}
}
<commit_msg>Add 0B as an input to Conversion functions<commit_after>package common

import (
	"fmt"
	"os"
	"strings"
	"testing"
)

type netmaskTPair struct {
	in  uint8
	out string
	err error
}

type byteTPair struct {
	in      uint64
	inUnit  string
	out     float64
	outUnit string
}

var EPSILON float64 = 1

func floatEquals(a, b float64) bool {
	if (a-b) < EPSILON && (b-a) < EPSILON {
		return true
	}
	return false
}

func TestConvertBytes(t *testing.T) {
	testpairs := []byteTPair{
		{0, "", 0, "B"},
		{5238784, "", 4.996094, "MB"},
		{10485760, "", 10.000000, "MB"},
		{100910080, "", 96.235352, "MB"},
		{3267260416, "", 3.042873, "GB"},
		{306816327680, "", 285.744972, "GB"},
	}
	for _, pair := range testpairs {
		out, outUnit, err := ConvertBytes(pair.in)
		if err != nil {
			t.Logf("input: %v; %v != nil", pair, err)
			t.Fail()
		}
		if strings.Compare(outUnit, pair.outUnit) != 0 {
			t.Logf("input: %v; '%v' != '%v'", pair, outUnit, pair.outUnit)
			t.Fail()
		}
		equality := floatEquals(out, pair.out)
		if equality == false {
			t.Logf("input: %v; %f != %f; diff: %f, %v", pair, out, pair.out,
				(out - pair.out), equality)
			t.Fail()
		}
	}
}

func TestConvertBytesTo(t *testing.T) {
	testpairs := []byteTPair{
		{0, "MB", 0, ""},
		{5238784, "kB", 5116, ""},
		{10485760, "kB", 10240, ""},
		{100910080, "MB", 96.235352, ""},
		{3267260416, "MB", 3115.902344, ""},
		{306816327680, "MB", 292602.851562, ""},
	}
	for _, pair := range testpairs {
		out, outUnit, err := ConvertBytesTo(pair.in, pair.inUnit)
		if err != nil {
			t.Logf("input: %v; %v != nil", pair, err)
			t.Fail()
		}
		if strings.Compare(outUnit, pair.inUnit) != 0 {
			t.Logf("input: %v; '%v' != '%v'", pair, outUnit, pair.inUnit)
			t.Fail()
		}
		equality := floatEquals(out, pair.out)
		if equality == false {
			t.Logf("input: %v; %f != %f; diff: %f, %v", pair, out, pair.out,
				(out - pair.out), equality)
			t.Fail()
		}
	}
}

func TestConvertNetmask(t *testing.T) {
	testpairs := []netmaskTPair{
		{8, "255.0.0.0", nil},
		{17, "255.255.128.0", nil},
		{24, "255.255.255.0", nil},
		{28, "255.255.255.240", nil},
		{33, "", fmt.Errorf("Invalid Netmask given.")},
	}
	for _, pair := range testpairs {
		out, err := ConvertNetmask(pair.in)
		if err == nil && pair.err != nil {
			t.Fatalf("%v != %v", err, pair.err)
		}
		if pair.err != nil {
			// probably not safe to continue
			continue
		}
		if out != pair.out {
			t.Fatalf("%v != %v", out, pair.out)
		}
	}
}

func TestGetHostEtc(t *testing.T) {
	testValue := "test_value"
	err := os.Setenv("HOST_ETC", testValue)
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostEtc()
	if strings.Compare(value, testValue) != 0 {
		t.Fatalf("%v != %v", value, testValue)
	}
}

func TestGetHostEtcNotSet(t *testing.T) {
	expectedVal := "/etc"
	err := os.Unsetenv("HOST_ETC")
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostEtc()
	if strings.Compare(value, expectedVal) != 0 {
		t.Fatalf("%v != %v", value, expectedVal)
	}
}

func TestGetHostProc(t *testing.T) {
	testValue := "test_value"
	err := os.Setenv("HOST_PROC", testValue)
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostProc()
	if strings.Compare(value, testValue) != 0 {
		t.Fatalf("%v != %v", value, testValue)
	}
}

func TestGetHostProcNotSet(t *testing.T) {
	expectedVal := "/proc"
	err := os.Unsetenv("HOST_PROC")
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostProc()
	if strings.Compare(value, expectedVal) != 0 {
		t.Fatalf("%v != %v", value, expectedVal)
	}
}

func TestGetHostSys(t *testing.T) {
	testValue := "test_value"
	err := os.Setenv("HOST_SYS", testValue)
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostSys()
	if strings.Compare(value, testValue) != 0 {
		t.Fatalf("%v != %v", value, testValue)
	}
}

func TestGetHostSysNotSet(t *testing.T) {
	expectedVal := "/sys"
	err := os.Unsetenv("HOST_SYS")
	if err != nil {
		t.Fatalf("%v", err)
	}
	value := GetHostSys()
	if strings.Compare(value, expectedVal) != 0 {
		t.Fatalf("%v != %v", value, expectedVal)
	}
}
<|endoftext|>


<commit_before>/*
	Script to handle an email response to the reminder.
	Steps:
		1. Get Sender - is it one of the registered senders in queue and are they the hosting group?
		2. Check if they should be responding or if someone is being snarky.
		3. Look for Yes/No/Skip
			3a. Yes - update the order in the group
			3b. No - send an email to the next in line, update group
			3c. Skip - respond with the current turn order for next week
	Notes: Super procedural right now.  I need to clean up the code

*/
package hostqueue

import (
	"appengine"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/mail"
	"regexp"
	"strings"
)

func IncomingMail(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	defer r.Body.Close()

	m, err := mail.ReadMessage(r.Body)
	if err != nil {
		CreateGithubIssueAndPanic(err, r)
	}

	from := m.Header.Get("From")
	//clean up responses formatted with a name first.  Ex: 'Ann Addicks <test@test.com>'
	from = strings.Split(from, "<")[1]
	from = strings.Split(from, ">")[0]
	ctx.Infof("from : " + from)
	g, err := findGroup(ctx, from)
	if err != nil {
		log.Fatal(err)
	} else if isValidResponder(from, g) {
		responseRegex := regexp.MustCompile(`(yes\b|no\b|skip\b)(.*?)`)
		body, err := ioutil.ReadAll(m.Body)

		if err != nil {
			CreateGithubIssueAndPanic(err, r)
		}

		s := string(body)
		bodyString := strings.ToLower(s)
		bodyString = strings.Split(bodyString, "it is your turn to host!")[0]

		switch responseRegex.FindString(bodyString) {
		case "yes":
			// Update the order in the group by deleting the current host and appending them to the end.
			hosts := g.Hosts
			currentHost := hosts[g.Next]
			currentHost.TimesHosted++

			hosts = append(hosts[:g.Next], hosts[g.Next+1:]...)
			hosts = append(hosts, currentHost)
			g.Hosts = hosts
			g.Next = 0
			//hosts.LastHosted when do I set this?  I need another field on group as to when this happens.

			g.save(ctx)
			sendHostConfirmedMessage(g, r)
			ctx.Infof("Match Yes")
		case "no":
			//Send an email to the next in line && update the group
			hosts := g.Hosts

			if g.Next < (len(hosts) - 1) {
				g.Next++
			} else {
				g.Next = 0
			}

			g.save(ctx)
			sendReminder(g, r)
			ctx.Infof("Match No")
		case "skip":
			//Respond with the current turn order for next week
			sendSkipMessage(g, r)
			ctx.Infof("Match Skip")
		default:
			ctx.Infof("Could not find yes/no/skip")
		}
	} else {
		ctx.Infof("Sender is not valid")
	}
}

/*Pull all the groups and loop through to find the email address.
  I need to learn more about querying app engines datastore to make this nicer.*/
func findGroup(ctx appengine.Context, from string) (Group, error) {
	groups, err := GetGroups(ctx)
	var g Group
	if err != nil {
		return g, err
	}

	for _, group := range groups {
		for _, host := range group.Hosts {
			if strings.Contains(host.Emails, from) {
				return group, nil
			}
		}
	}
	return g, fmt.Errorf("Cannot find a group for: %s", from)
}

//Check if they should be responding or if someone is being snarky.
func isValidResponder(from string, g Group) bool {
	validEmails := g.Hosts[g.Next].Emails
	return strings.Contains(validEmails, from)
}

//http://stackoverflow.com/questions/10485743/contains-method-for-a-slice
func contains(slice []string, item string) bool {
	set := make(map[string]struct{}, len(slice))
	for _, s := range slice {
		set[s] = struct{}{}
	}

	_, ok := set[item]
	return ok
}
<commit_msg>removed unused method.<commit_after>/*
	Script to handle an email response to the reminder.
	Steps:
		1. Get Sender - is it one of the registered senders in queue and are they the hosting group?
		2. Check if they should be responding or if someone is being snarky.
		3. Look for Yes/No/Skip
			3a. Yes - update the order in the group
			3b. No - send an email to the next in line, update group
			3c. Skip - respond with the current turn order for next week
	Notes: Super procedural right now.  I need to clean up the code

*/
package hostqueue

import (
	"appengine"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/mail"
	"regexp"
	"strings"
)

func IncomingMail(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	defer r.Body.Close()

	m, err := mail.ReadMessage(r.Body)
	if err != nil {
		CreateGithubIssueAndPanic(err, r)
	}

	from := m.Header.Get("From")
	//clean up responses formatted with a name first.  Ex: 'Ann Addicks <test@test.com>'
	from = strings.Split(from, "<")[1]
	from = strings.Split(from, ">")[0]
	ctx.Infof("from : " + from)
	g, err := findGroup(ctx, from)
	if err != nil {
		log.Fatal(err)
	} else if isValidResponder(from, g) {
		responseRegex := regexp.MustCompile(`(yes\b|no\b|skip\b)(.*?)`)
		body, err := ioutil.ReadAll(m.Body)

		if err != nil {
			CreateGithubIssueAndPanic(err, r)
		}

		s := string(body)
		bodyString := strings.ToLower(s)
		bodyString = strings.Split(bodyString, "it is your turn to host!")[0]

		switch responseRegex.FindString(bodyString) {
		case "yes":
			// Update the order in the group by deleting the current host and appending them to the end.
			hosts := g.Hosts
			currentHost := hosts[g.Next]
			currentHost.TimesHosted++

			hosts = append(hosts[:g.Next], hosts[g.Next+1:]...)
			hosts = append(hosts, currentHost)
			g.Hosts = hosts
			g.Next = 0
			//hosts.LastHosted when do I set this?  I need another field on group as to when this happens.

			g.save(ctx)
			sendHostConfirmedMessage(g, r)
			ctx.Infof("Match Yes")
		case "no":
			//Send an email to the next in line && update the group
			hosts := g.Hosts

			if g.Next < (len(hosts) - 1) {
				g.Next++
			} else {
				g.Next = 0
			}

			g.save(ctx)
			sendReminder(g, r)
			ctx.Infof("Match No")
		case "skip":
			//Respond with the current turn order for next week
			sendSkipMessage(g, r)
			ctx.Infof("Match Skip")
		default:
			ctx.Infof("Could not find yes/no/skip")
		}
	} else {
		ctx.Infof("Sender is not valid")
	}
}

/*Pull all the groups and loop through to find the email address.
  I need to learn more about querying app engines datastore to make this nicer.*/
func findGroup(ctx appengine.Context, from string) (Group, error) {
	groups, err := GetGroups(ctx)
	var g Group
	if err != nil {
		return g, err
	}

	for _, group := range groups {
		for _, host := range group.Hosts {
			if strings.Contains(host.Emails, from) {
				return group, nil
			}
		}
	}
	return g, fmt.Errorf("Cannot find a group for: %s", from)
}

//Check if they should be responding or if someone is being snarky.
func isValidResponder(from string, g Group) bool {
	validEmails := g.Hosts[g.Next].Emails
	return strings.Contains(validEmails, from)
}
<|endoftext|>


<commit_before>package language

import (
	"math"
	"strings"
)

// PluralSpec defines the CLDR plural rules for a language.
// http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
type PluralSpec struct {
	Plurals    map[Plural]struct{}
	PluralFunc func(*operands) Plural
}

// Plural returns the plural category for number as defined by
// the language's CLDR plural rules.
func (ps *PluralSpec) Plural(number interface{}) (Plural, error) {
	ops, err := newOperands(number)
	if err != nil {
		return Invalid, err
	}
	return ps.PluralFunc(ops), nil
}

// getPluralSpec returns the PluralSpec that matches the longest prefix of tag.
// It returns nil if no PluralSpec matches tag.
func getPluralSpec(tag string) *PluralSpec {
	tag = NormalizeTag(tag)
	subtag := tag
	for {
		if spec := pluralSpecs[subtag]; spec != nil {
			return spec
		}
		end := strings.LastIndex(subtag, "-")
		if end == -1 {
			return nil
		}
		subtag = subtag[:end]
	}
}

// Alphabetical by English name.
var pluralSpecs = map[string]*PluralSpec{
	// Arabic
	"ar": &PluralSpec{
		Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.W == 0 {
				switch ops.I {
				case 0:
					return Zero
				case 1:
					return One
				case 2:
					return Two
				default:
					mod100 := ops.I % 100
					if mod100 >= 3 && mod100 <= 10 {
						return Few
					}
					if mod100 >= 11 {
						return Many
					}
				}
			}
			return Other
		},
	},

	// Belarusian
	"be": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			mod10 := math.Mod(ops.N, 10)
			mod100 := math.Mod(ops.N, 100)
			if ops.T == 0 && mod10 == 1 && mod100 != 11 {
				return One
			}
			if ops.T == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.T == 0 && mod10 == 0) ||
				(ops.T == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.T == 0 && mod100 >= 11 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},

	// Burmese
	"my": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Catalan
	"ca": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Chinese
	// There is no need to distinguish between simplified and traditional
	// since they have the same pluralization.
	"zh": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Czech
	"cs": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			if ops.I >= 2 && ops.I <= 4 && ops.V == 0 {
				return Few
			}
			if ops.V > 0 {
				return Many
			}
			return Other
		},
	},

	// Danish
	"da": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 || (ops.I == 0 && ops.T != 0) {
				return One
			}
			return Other
		},
	},

	// Dutch
	"nl": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// English
	"en": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// French
	"fr": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 0 || ops.I == 1 {
				return One
			}
			return Other
		},
	},

	// German
	"de": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Icelandic
	"is": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if (ops.T == 0 && ops.I%10 == 1 && ops.I%100 != 11) || ops.T != 0 {
				return One
			}
			return Other
		},
	},

	// Indonesian
	"id": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Italian
	"it": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Korean
	"ko": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Japanese
	"ja": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Lithuanian
	"lt": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.F != 0 {
				return Many
			}
			mod100 := ops.I % 100
			if mod100 < 11 || mod100 > 19 {
				switch ops.I % 10 {
				case 0:
					return Other
				case 1:
					return One
				default:
					return Few
				}
			}
			return Other
		},
	},

	// Malay
	"ms": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Polish
	"pl": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.V == 0 && ops.I == 1 {
				return One
			}
			mod10 := ops.I % 10
			mod100 := ops.I % 100
			if ops.V == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.V == 0 && ops.I != 1 && mod10 >= 0 && mod10 <= 1) ||
				(ops.V == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.V == 0 && mod100 >= 12 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},

	// Portuguese (European)
	"pt": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Portuguese (Brazilian)
	"pt-br": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if (ops.I == 1 && ops.V == 0) || (ops.I == 0 && ops.T == 1) {
				return One
			}
			return Other
		},
	},

	// Russian
	"ru": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			mod10 := ops.I % 10
			mod100 := ops.I % 100
			if ops.V == 0 && mod10 == 1 && mod100 != 11 {
				return One
			}
			if ops.V == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.V == 0 && mod10 == 0) ||
				(ops.V == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.V == 0 && mod100 >= 11 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},

	// Spanish
	"es": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.W == 0 {
				return One
			}
			return Other
		},
	},

	// Bulgarian
	"bg": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.W == 0 {
				return One
			}
			return Other
		},
	},

	// Swedish
	"sv": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Thai
	"th": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Turkish
	"tr": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.W == 0 {
				return One
			}
			return Other
		},
	},

	// Ukrainian
	"uk": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			mod10 := ops.I % 10
			mod100 := ops.I % 100
			if ops.V == 0 && mod10 == 1 && mod100 != 11 {
				return One
			}
			if ops.V == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.V == 0 && mod10 == 0) ||
				(ops.V == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.V == 0 && mod100 >= 11 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},
}

func newPluralSet(plurals ...Plural) map[Plural]struct{} {
	set := make(map[Plural]struct{}, len(plurals))
	for _, plural := range plurals {
		set[plural] = struct{}{}
	}
	return set
}
<commit_msg>Croatian pluralspec<commit_after>package language

import (
	"math"
	"strings"
)

// PluralSpec defines the CLDR plural rules for a language.
// http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
// http://unicode.org/reports/tr35/tr35-numbers.html#Operands
type PluralSpec struct {
	Plurals    map[Plural]struct{}
	PluralFunc func(*operands) Plural
}

// Plural returns the plural category for number as defined by
// the language's CLDR plural rules.
func (ps *PluralSpec) Plural(number interface{}) (Plural, error) {
	ops, err := newOperands(number)
	if err != nil {
		return Invalid, err
	}
	return ps.PluralFunc(ops), nil
}

// getPluralSpec returns the PluralSpec that matches the longest prefix of tag.
// It returns nil if no PluralSpec matches tag.
func getPluralSpec(tag string) *PluralSpec {
	tag = NormalizeTag(tag)
	subtag := tag
	for {
		if spec := pluralSpecs[subtag]; spec != nil {
			return spec
		}
		end := strings.LastIndex(subtag, "-")
		if end == -1 {
			return nil
		}
		subtag = subtag[:end]
	}
}

// Alphabetical by English name.
var pluralSpecs = map[string]*PluralSpec{
	// Arabic
	"ar": &PluralSpec{
		Plurals: newPluralSet(Zero, One, Two, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.W == 0 {
				switch ops.I {
				case 0:
					return Zero
				case 1:
					return One
				case 2:
					return Two
				default:
					mod100 := ops.I % 100
					if mod100 >= 3 && mod100 <= 10 {
						return Few
					}
					if mod100 >= 11 {
						return Many
					}
				}
			}
			return Other
		},
	},

	// Belarusian
	"be": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			mod10 := math.Mod(ops.N, 10)
			mod100 := math.Mod(ops.N, 100)
			if ops.T == 0 && mod10 == 1 && mod100 != 11 {
				return One
			}
			if ops.T == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.T == 0 && mod10 == 0) ||
				(ops.T == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.T == 0 && mod100 >= 11 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},

	// Burmese
	"my": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Catalan
	"ca": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Chinese
	// There is no need to distinguish between simplified and traditional
	// since they have the same pluralization.
	"zh": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Croatian
	"hr": &PluralSpec{
		Plurals: newPluralSet(One, Few, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.V == 0 &&
			(ops.I % 10 == 1 && ops.I % 100 != 11) ||
			(ops.F % 10 == 1 && ops.F % 100 != 11) {
				return One
			}
			if ops.V == 0 &&
			((ops.I % 10 >= 2 && ops.I % 10 <= 4) && (ops.I % 100 != 12 && ops.I % 100 != 13 && ops.I % 100 != 14)) ||
			((ops.F % 10 >= 2 && ops.F % 10 <= 4) && (ops.F % 100 != 12 && ops.F % 100 != 13 && ops.F % 100 != 14)) {
				return Few
			}
			return Other
		},
	},

	// Czech
	"cs": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			if ops.I >= 2 && ops.I <= 4 && ops.V == 0 {
				return Few
			}
			if ops.V > 0 {
				return Many
			}
			return Other
		},
	},

	// Danish
	"da": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 || (ops.I == 0 && ops.T != 0) {
				return One
			}
			return Other
		},
	},

	// Dutch
	"nl": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// English
	"en": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// French
	"fr": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 0 || ops.I == 1 {
				return One
			}
			return Other
		},
	},

	// German
	"de": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Icelandic
	"is": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if (ops.T == 0 && ops.I%10 == 1 && ops.I%100 != 11) || ops.T != 0 {
				return One
			}
			return Other
		},
	},

	// Indonesian
	"id": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Italian
	"it": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Korean
	"ko": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Japanese
	"ja": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Lithuanian
	"lt": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.F != 0 {
				return Many
			}
			mod100 := ops.I % 100
			if mod100 < 11 || mod100 > 19 {
				switch ops.I % 10 {
				case 0:
					return Other
				case 1:
					return One
				default:
					return Few
				}
			}
			return Other
		},
	},

	// Malay
	"ms": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Polish
	"pl": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.V == 0 && ops.I == 1 {
				return One
			}
			mod10 := ops.I % 10
			mod100 := ops.I % 100
			if ops.V == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.V == 0 && ops.I != 1 && mod10 >= 0 && mod10 <= 1) ||
				(ops.V == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.V == 0 && mod100 >= 12 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},

	// Portuguese (European)
	"pt": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Portuguese (Brazilian)
	"pt-br": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if (ops.I == 1 && ops.V == 0) || (ops.I == 0 && ops.T == 1) {
				return One
			}
			return Other
		},
	},

	// Russian
	"ru": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			mod10 := ops.I % 10
			mod100 := ops.I % 100
			if ops.V == 0 && mod10 == 1 && mod100 != 11 {
				return One
			}
			if ops.V == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.V == 0 && mod10 == 0) ||
				(ops.V == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.V == 0 && mod100 >= 11 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},

	// Spanish
	"es": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.W == 0 {
				return One
			}
			return Other
		},
	},

	// Bulgarian
	"bg": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.W == 0 {
				return One
			}
			return Other
		},
	},

	// Swedish
	"sv": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.V == 0 {
				return One
			}
			return Other
		},
	},

	// Thai
	"th": &PluralSpec{
		Plurals: newPluralSet(Other),
		PluralFunc: func(ops *operands) Plural {
			return Other
		},
	},

	// Turkish
	"tr": &PluralSpec{
		Plurals: newPluralSet(One, Other),
		PluralFunc: func(ops *operands) Plural {
			if ops.I == 1 && ops.W == 0 {
				return One
			}
			return Other
		},
	},

	// Ukrainian
	"uk": &PluralSpec{
		Plurals: newPluralSet(One, Few, Many, Other),
		PluralFunc: func(ops *operands) Plural {
			mod10 := ops.I % 10
			mod100 := ops.I % 100
			if ops.V == 0 && mod10 == 1 && mod100 != 11 {
				return One
			}
			if ops.V == 0 && mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14) {
				return Few
			}
			if (ops.V == 0 && mod10 == 0) ||
				(ops.V == 0 && mod10 >= 5 && mod10 <= 9) ||
				(ops.V == 0 && mod100 >= 11 && mod100 <= 14) {
				return Many
			}
			return Other
		},
	},
}

func newPluralSet(plurals ...Plural) map[Plural]struct{} {
	set := make(map[Plural]struct{}, len(plurals))
	for _, plural := range plurals {
		set[plural] = struct{}{}
	}
	return set
}
<|endoftext|>


<commit_before>package model

type Friend struct {
	Name string "yaml:name"
	Link string "yaml:link"
	Logo string "yaml:logo"
}
<commit_msg>修复Friend tag错误<commit_after>package model

type Friend struct {
	Name string `yaml:"name"`
	Link string `yaml:"link"`
	Logo string `yaml:"logo"`
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 sqlhist implements a temporal sparse merkle tree using SQL.
// Each epoch has its own sparse tree. By default, each new epoch is equal to
// the contents of the previous epoch.
package sqlhist

import (
	"bytes"
	"crypto/sha256"
	"database/sql"
	"errors"
	"fmt"

	"github.com/google/key-transparency/core/tree"
	"github.com/google/key-transparency/core/tree/sparse"
	"golang.org/x/net/context"
)

var (
	hasher          = sparse.CONIKSHasher
	errNilLeaf      = errors.New("nil leaf")
	errIndexLen     = errors.New("index len != 32")
	errInvalidEpoch = errors.New("invalid epoch")
)

const (
	maxDepth = sparse.IndexLen
	size     = sparse.HashSize
	readExpr = `
	SELECT Value FROM Nodes
	WHERE MapId = $1 AND NodeId = $2 and Version <= $3
	ORDER BY Version DESC LIMIT 1;`
	queueExpr = `
	INSERT OR REPLACE INTO Leaves (MapId, LeafId, Version, Data)
	VALUES ($1, $2, $3, $4);`
	pendingLeafsExpr = `
	SELECT LeafId, Version, Data FROM Leaves
	WHERE MapId = $1 AND Version >= $2;`
	setNodeExpr = `
	INSERT OR REPLACE INTO Nodes (MapId, NodeId, Version, Value)
	VALUES ($1, $2, $3, $4);`
	mapRowExpr    = `INSERT OR IGNORE INTO Maps (MapId) VALUES ($1);`
	readEpochExpr = `
	SELECT Version FROM Nodes
	WHERE MapId = $1 AND NodeId = $2
	ORDER BY Version DESC LIMIT 1;`
)

// Map stores a temporal sparse merkle tree, backed by an SQL database.
type Map struct {
	mapID []byte
	db    *sql.DB
	epoch int64 // The currently valid epoch. Insert at epoch+1.
}

// New creates a new map.
func New(db *sql.DB, mapID string) (*Map, error) {
	if err := db.Ping(); err != nil {
		return nil, fmt.Errorf("No DB connection: %v", err)
	}

	m := &Map{
		mapID: []byte(mapID),
		db:    db,
	}
	if err := m.create(); err != nil {
		return nil, err
	}
	if err := m.insertMapRow(); err != nil {
		return nil, err
	}
	if err := m.insertFirstRoot(); err != nil {
		return nil, err
	}
	epoch, err := m.readEpoch()
	if err != nil {
		return nil, err
	}
	m.epoch = epoch
	return m, nil
}

// Epoch returns the current epoch of the merkle tree.
func (m *Map) Epoch() int64 {
	return m.epoch
}

// QueueLeaf should only be called by the sequencer.
func (m *Map) QueueLeaf(ctx context.Context, index, leaf []byte) error {
	if got, want := len(index), size; got != want {
		return errIndexLen
	}
	if leaf == nil {
		return errNilLeaf
	}

	// Write leaf nodes
	stmt, err := m.db.Prepare(queueExpr)
	if err != nil {
		return err
	}
	defer stmt.Close()
	_, err = stmt.Exec(m.mapID, index, m.epoch+1, leaf)
	return err
}

type leafRow struct {
	index   []byte
	version int64
	data    []byte
}

// Commit takes all the Queued values since the last Commmit() and writes them.
// Commit is NOT multi-process safe. It should only be called from the sequencer.
func (m *Map) Commit() (int64, error) {
	// Get the list of pending leafs
	stmt, err := m.db.Prepare(pendingLeafsExpr)
	if err != nil {
		return -1, err
	}
	defer stmt.Close()
	rows, err := stmt.Query(m.mapID, m.epoch+1)
	if err != nil {
		return -1, err
	}
	leafRows := make([]leafRow, 0, 10)
	for rows.Next() {
		var r leafRow
		err = rows.Scan(&r.index, &r.version, &r.data)
		if err != nil {
			return -1, err
		}
		leafRows = append(leafRows, r)
	}

	for _, r := range leafRows {
		if err := m.SetNodeAt(nil, r.index, maxDepth, r.data, m.epoch+1); err != nil {
			// Recovery from here would mean updating nodes that
			// didn't get included so that they would be included
			// in the next epoch.
			return -1, fmt.Errorf("Failed to set node: %v", err)
		}
	}
	// Always update the root node.
	if len(leafRows) == 0 {
		root, err := m.ReadRootAt(nil, m.epoch)
		if err != nil {
			return -1, fmt.Errorf("No root for epoch %d: %v", m.epoch, err)
		}
		if err := m.SetNodeAt(nil, []byte{}, 0, root, m.epoch+1); err != nil {
			return -1, fmt.Errorf("Failed to set root: %v", err)
		}
	}
	// TODO: Delete Map heads from this file.

	m.epoch++
	return m.epoch, nil
}

// ReadRootAt returns the value of the root node in a specific epoch.
func (m *Map) ReadRootAt(ctx context.Context, epoch int64) ([]byte, error) {
	stmt, err := m.db.Prepare(readExpr)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	var value []byte
	rootID := m.nodeID("")
	if err := stmt.QueryRow(m.mapID, rootID, epoch).Scan(&value); err != nil {
		return nil, err
	}
	return value, nil
}

// ReadLeafAt returns the leaf value at epoch.
func (m *Map) ReadLeafAt(ctx context.Context, index []byte, epoch int64) ([]byte, error) {
	bindex := tree.BitString(index)
	readStmt, err := m.db.Prepare(readExpr)
	if err != nil {
		return nil, err
	}
	defer readStmt.Close()

	nodeID := m.nodeID(bindex)

	var value []byte
	if err = readStmt.QueryRow(m.mapID, nodeID, epoch).Scan(&value); err == sql.ErrNoRows {
		return nil, nil // Not found is not an error.
	} else if err != nil {
		return nil, err
	}
	return value, nil
}

// NeighborsAt returns the list of neighbors from the neighbor leaf to just below the root at epoch.
func (m *Map) NeighborsAt(ctx context.Context, index []byte, epoch int64) ([][]byte, error) {
	tx, err := m.db.Begin()
	if err != nil {
		return nil, err
	}
	nbrs, err := m.neighborsAt(tx, index, maxDepth, epoch)
	if err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			err = fmt.Errorf("neighborsAt failed: %v, and Rollback failed: %v", err, rbErr)
		}
		return nil, err
	}
	nbrs = compressNeighbors(nbrs, index, maxDepth)
	return nbrs, tx.Commit()
}

func (m *Map) neighborsAt(tx *sql.Tx, index []byte, depth int, epoch int64) ([][]byte, error) {
	bindex := tree.BitString(index)[:depth]
	neighborBIndexes := tree.Neighbors(bindex)
	neighborIDs := m.nodeIDs(neighborBIndexes)

	readStmt, err := tx.Prepare(readExpr)
	if err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			err = fmt.Errorf("Prepare failed: %v, and Rollback failed: %v", err, rbErr)
		}
		return nil, err
	}
	defer readStmt.Close()

	// Get neighbors.
	nbrValues := make([][]byte, len(neighborIDs))
	for i, nodeID := range neighborIDs {
		if err := readStmt.QueryRow(m.mapID, nodeID, epoch).Scan(&nbrValues[i]); err == sql.ErrNoRows {
			nbrValues[i] = hashEmpty(neighborBIndexes[i])
		} else if err != nil {
			if rbErr := tx.Rollback(); rbErr != nil {
				err = fmt.Errorf("QueryRow failed: %v, and Rollback failed: %v", err, rbErr)
			}
			return nil, err
		}
	}

	return nbrValues, nil
}

func compressNeighbors(neighbors [][]byte, index []byte, depth int) [][]byte {
	bindex := tree.BitString(index)[:depth]
	neighborBIndexes := tree.Neighbors(bindex)
	compressed := make([][]byte, len(neighbors))
	for i, v := range neighbors {
		// TODO: convert values to arrays rather than slices for comparison.
		if !bytes.Equal(v, hashEmpty(neighborBIndexes[i])) {
			compressed[i] = v
		}
	}
	return compressed
}

// SetNodeAt sets intermediate and leaf node values directly at epoch.
func (m *Map) SetNodeAt(ctx context.Context, index []byte, depth int, value []byte, epoch int64) error {
	if value == nil || len(value) == 0 {
		return nil
	}
	bindex := tree.BitString(index)[:depth]
	nodeBindexes := tree.Path(bindex)
	nodeIDs := m.nodeIDs(nodeBindexes)

	// Read the neighbor nodes
	// Set the node
	// Compute new values
	// Set those values.

	tx, err := m.db.Begin()
	if err != nil {
		return err
	}
	writeStmt, err := tx.Prepare(setNodeExpr)
	if err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			err = fmt.Errorf("Prepare failed: %v, and Rollback failed: %v", err, rbErr)
		}
		return err
	}
	defer writeStmt.Close()

	// Get neighbors.
	nbrValues, err := m.neighborsAt(tx, index, depth, epoch)
	if err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			err = fmt.Errorf("neighborsAt failed: %v, and Rollback failed: %v", err, rbErr)
		}
		return err
	}

	nodeValues := sparse.NodeValues(hasher, bindex, value, nbrValues)

	// Save new nodes.
	for i, nodeValue := range nodeValues {
		_, err = writeStmt.Exec(m.mapID, nodeIDs[i], epoch, nodeValue)
		if err != nil {
			if rbErr := tx.Rollback(); rbErr != nil {
				err = fmt.Errorf("Exec failed: %v, and Rollback failed: %v", err, rbErr)
			}
			return err
		}
	}
	return tx.Commit()
}

// Create creates a new database.
func (m *Map) create() error {
	createStmt := `
	CREATE TABLE IF NOT EXISTS Maps (
		MapId	BLOB(32),
		PRIMARY KEY(MapID)
	);

	CREATE TABLE IF NOT EXISTS Leaves (
		MapId	BLOB(32) NOT NULL,
		LeafId	BLOB(32) NOT NULL,
		Version	INTEGER	 NOT NULL,
		Data	BLOB 	 NOT NULL,
		PRIMARY KEY(MapID, LeafId, Version),
		FOREIGN KEY(MapId) REFERENCES Maps(MapId) ON DELETE CASCADE
	);

	CREATE TABLE IF NOT EXISTS Nodes (
		MapId	BLOB(32) NOT NULL,
		NodeId	BLOB(32) NOT NULL,
		Version	INTEGER  NOT NULL,
		Value	BLOB(32) NOT NULL,
		PRIMARY KEY(MapId, NodeId, Version),
		FOREIGN KEY(MapId) REFERENCES Maps(MapId) ON DELETE CASCADE
	);

	CREATE TABLE IF NOT EXISTS MapHeads (
		MapId	BLOB(32) NOT NULL,
		Version INTEGER  NOT NULL,
		Timestamp TIMESTAMP NOT NULL,
		Value	Blob(32) NOT NULL,
		PRIMARY KEY(MapId, Version),
		FOREIGN KEY(MapId) REFERENCES Maps(MapId) ON DELETE CASCADE
	)
	`
	_, err := m.db.Exec(createStmt)
	if err != nil {
		return fmt.Errorf("Failed to create tables: %v", err)
	}
	return nil
}

func (m *Map) insertMapRow() error {
	stmt, err := m.db.Prepare(mapRowExpr)
	if err != nil {
		return fmt.Errorf("insertMapRow(): %v", err)
	}
	defer stmt.Close()
	_, err = stmt.Exec(m.mapID)
	if err != nil {
		return fmt.Errorf("insertMapRow(): %v", err)
	}
	return nil
}

func (m *Map) insertFirstRoot() error {
	rootID := m.nodeID("")
	nodeValue := hashEmpty("")
	writeStmt, err := m.db.Prepare(setNodeExpr)
	if err != nil {
		return fmt.Errorf("insertFirstRoot(): %v", err)
	}
	defer writeStmt.Close()
	_, err = writeStmt.Exec(m.mapID, rootID, -1, nodeValue)
	if err != nil {
		return fmt.Errorf("insertFirstRoot(): %v", err)
	}
	return nil
}

func (m *Map) readEpoch() (int64, error) {
	stmt, err := m.db.Prepare(readEpochExpr)
	if err != nil {
		return -1, fmt.Errorf("readEpoch(): %v", err)
	}
	defer stmt.Close()
	rootID := m.nodeID("")
	var epoch sql.NullInt64
	if err := stmt.QueryRow(m.mapID, rootID).Scan(&epoch); err != nil {
		return -1, fmt.Errorf("Error reading epoch: %v", err)
	}
	if !epoch.Valid {
		return -1, errInvalidEpoch
	}
	return epoch.Int64, nil
}

// Converts a list of bit strings into their node IDs.
func (m *Map) nodeIDs(bindexes []string) [][]byte {
	nodes := make([][]byte, len(bindexes))
	for i, bindex := range bindexes {
		nodes[i] = m.nodeID(bindex)
	}
	return nodes
}

// nodeID computes the location of a node, given its bit string index.
func (m *Map) nodeID(bindex string) []byte {
	h := sha256.New()
	h.Write(m.mapID)
	h.Write([]byte{0})
	h.Write([]byte(bindex))
	return h.Sum(nil)
}

// PrefixLen returns the index of the last non-zero item in the list
func PrefixLen(nodes [][]byte) int {
	// Iterate over the nodes from leaf to root.
	for i, v := range nodes {
		if v != nil {
			// return the first non-empty node.
			return len(nodes) - i
		}
	}
	return 0
}

func hashEmpty(bindex string) []byte {
	return hasher.HashEmpty(tree.InvertBitString(bindex))
}
<commit_msg>Refactor SetNodeAt<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 sqlhist implements a temporal sparse merkle tree using SQL.
// Each epoch has its own sparse tree. By default, each new epoch is equal to
// the contents of the previous epoch.
package sqlhist

import (
	"bytes"
	"crypto/sha256"
	"database/sql"
	"errors"
	"fmt"

	"github.com/google/key-transparency/core/tree"
	"github.com/google/key-transparency/core/tree/sparse"
	"golang.org/x/net/context"
)

var (
	hasher          = sparse.CONIKSHasher
	errNilLeaf      = errors.New("nil leaf")
	errIndexLen     = errors.New("index len != 32")
	errInvalidEpoch = errors.New("invalid epoch")
)

const (
	maxDepth = sparse.IndexLen
	size     = sparse.HashSize
	readExpr = `
	SELECT Value FROM Nodes
	WHERE MapId = $1 AND NodeId = $2 and Version <= $3
	ORDER BY Version DESC LIMIT 1;`
	queueExpr = `
	INSERT OR REPLACE INTO Leaves (MapId, LeafId, Version, Data)
	VALUES ($1, $2, $3, $4);`
	pendingLeafsExpr = `
	SELECT LeafId, Version, Data FROM Leaves
	WHERE MapId = $1 AND Version >= $2;`
	setNodeExpr = `
	INSERT OR REPLACE INTO Nodes (MapId, NodeId, Version, Value)
	VALUES ($1, $2, $3, $4);`
	mapRowExpr    = `INSERT OR IGNORE INTO Maps (MapId) VALUES ($1);`
	readEpochExpr = `
	SELECT Version FROM Nodes
	WHERE MapId = $1 AND NodeId = $2
	ORDER BY Version DESC LIMIT 1;`
)

// Map stores a temporal sparse merkle tree, backed by an SQL database.
type Map struct {
	mapID []byte
	db    *sql.DB
	epoch int64 // The currently valid epoch. Insert at epoch+1.
}

// New creates a new map.
func New(db *sql.DB, mapID string) (*Map, error) {
	if err := db.Ping(); err != nil {
		return nil, fmt.Errorf("No DB connection: %v", err)
	}

	m := &Map{
		mapID: []byte(mapID),
		db:    db,
	}
	if err := m.create(); err != nil {
		return nil, err
	}
	if err := m.insertMapRow(); err != nil {
		return nil, err
	}
	nodeValue := hashEmpty("")
	if err := m.setRootAt(nil, nodeValue[:], -1); err != nil {
		return nil, err
	}
	epoch, err := m.readEpoch()
	if err != nil {
		return nil, err
	}
	m.epoch = epoch
	return m, nil
}

// Epoch returns the current epoch of the merkle tree.
func (m *Map) Epoch() int64 {
	return m.epoch
}

// QueueLeaf should only be called by the sequencer.
func (m *Map) QueueLeaf(ctx context.Context, index, leaf []byte) error {
	if got, want := len(index), size; got != want {
		return errIndexLen
	}
	if leaf == nil {
		return errNilLeaf
	}

	// Write leaf nodes
	stmt, err := m.db.Prepare(queueExpr)
	if err != nil {
		return err
	}
	defer stmt.Close()
	_, err = stmt.Exec(m.mapID, index, m.epoch+1, leaf)
	return err
}

type leafRow struct {
	index   []byte
	version int64
	data    []byte
}

// Commit takes all the Queued values since the last Commmit() and writes them.
// Commit is NOT multi-process safe. It should only be called from the sequencer.
func (m *Map) Commit() (int64, error) {
	// Get the list of pending leafs
	stmt, err := m.db.Prepare(pendingLeafsExpr)
	if err != nil {
		return -1, err
	}
	defer stmt.Close()
	rows, err := stmt.Query(m.mapID, m.epoch+1)
	if err != nil {
		return -1, err
	}
	leafRows := make([]leafRow, 0, 10)
	for rows.Next() {
		var r leafRow
		err = rows.Scan(&r.index, &r.version, &r.data)
		if err != nil {
			return -1, err
		}
		leafRows = append(leafRows, r)
	}

	for _, r := range leafRows {
		if err := m.setLeafAt(nil, r.index, maxDepth, r.data, m.epoch+1); err != nil {
			// Recovery from here would mean updating nodes that
			// didn't get included so that they would be included
			// in the next epoch.
			return -1, fmt.Errorf("Failed to set node: %v", err)
		}
	}
	// Always update the root node.
	if len(leafRows) == 0 {
		root, err := m.ReadRootAt(nil, m.epoch)
		if err != nil {
			return -1, fmt.Errorf("No root for epoch %d: %v", m.epoch, err)
		}
		if err := m.setRootAt(nil, root, m.epoch+1); err != nil {
			return -1, fmt.Errorf("Failed to set root: %v", err)
		}
	}
	// TODO: Delete Map heads from this file.

	m.epoch++
	return m.epoch, nil
}

// ReadRootAt returns the value of the root node in a specific epoch.
func (m *Map) ReadRootAt(ctx context.Context, epoch int64) ([]byte, error) {
	stmt, err := m.db.Prepare(readExpr)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	var value []byte
	if err := stmt.QueryRow(m.mapID, m.nodeID(""), epoch).Scan(&value); err != nil {
		return nil, err
	}
	return value, nil
}

// ReadLeafAt returns the leaf value at epoch.
func (m *Map) ReadLeafAt(ctx context.Context, index []byte, epoch int64) ([]byte, error) {
	bindex := tree.BitString(index)
	readStmt, err := m.db.Prepare(readExpr)
	if err != nil {
		return nil, err
	}
	defer readStmt.Close()

	nodeID := m.nodeID(bindex)

	var value []byte
	if err = readStmt.QueryRow(m.mapID, nodeID, epoch).Scan(&value); err == sql.ErrNoRows {
		return nil, nil // Not found is not an error.
	} else if err != nil {
		return nil, err
	}
	return value, nil
}

// NeighborsAt returns the list of neighbors from the neighbor leaf to just below the root at epoch.
func (m *Map) NeighborsAt(ctx context.Context, index []byte, epoch int64) ([][]byte, error) {
	tx, err := m.db.Begin()
	if err != nil {
		return nil, err
	}
	nbrs, err := m.neighborsAt(tx, index, maxDepth, epoch)
	if err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			err = fmt.Errorf("neighborsAt failed: %v, and Rollback failed: %v", err, rbErr)
		}
		return nil, err
	}
	nbrs = compressNeighbors(nbrs, index, maxDepth)
	return nbrs, tx.Commit()
}

func (m *Map) neighborsAt(tx *sql.Tx, index []byte, depth int, epoch int64) ([][]byte, error) {
	bindex := tree.BitString(index)[:depth]
	neighborBIndexes := tree.Neighbors(bindex)
	neighborIDs := m.nodeIDs(neighborBIndexes)

	readStmt, err := tx.Prepare(readExpr)
	if err != nil {
		if rbErr := tx.Rollback(); rbErr != nil {
			err = fmt.Errorf("Prepare failed: %v, and Rollback failed: %v", err, rbErr)
		}
		return nil, err
	}
	defer readStmt.Close()

	// Get neighbors.
	nbrValues := make([][]byte, len(neighborIDs))
	for i, nodeID := range neighborIDs {
		if err := readStmt.QueryRow(m.mapID, nodeID, epoch).Scan(&nbrValues[i]); err == sql.ErrNoRows {
			nbrValues[i] = hashEmpty(neighborBIndexes[i])
		} else if err != nil {
			if rbErr := tx.Rollback(); rbErr != nil {
				err = fmt.Errorf("QueryRow failed: %v, and Rollback failed: %v", err, rbErr)
			}
			return nil, err
		}
	}

	return nbrValues, nil
}

func compressNeighbors(neighbors [][]byte, index []byte, depth int) [][]byte {
	bindex := tree.BitString(index)[:depth]
	neighborBIndexes := tree.Neighbors(bindex)
	compressed := make([][]byte, len(neighbors))
	for i, v := range neighbors {
		// TODO: convert values to arrays rather than slices for comparison.
		if !bytes.Equal(v, hashEmpty(neighborBIndexes[i])) {
			compressed[i] = v
		}
	}
	return compressed
}

// setLeafAt sets leaf node values directly at epoch.
func (m *Map) setLeafAt(ctx context.Context, index []byte, depth int, value []byte, epoch int64) (returnErr error) {
	if len(value) == 0 {
		return nil
	}
	bindex := tree.BitString(index)[:depth]
	nodeBindexes := tree.Path(bindex)
	nodeIDs := m.nodeIDs(nodeBindexes)

	// Read the neighbor nodes
	// Set the node
	// Compute new values
	// Set those values.

	tx, err := m.db.Begin()
	if err != nil {
		return err
	}
	defer func() {
		if returnErr != nil {
			if rbErr := tx.Rollback(); rbErr != nil {
				err = fmt.Errorf("setLeafAt failed: %v, and Rollback failed: %v", err, rbErr)
			}
		}
	}()

	writeStmt, err := tx.Prepare(setNodeExpr)
	if err != nil {
		return err
	}
	defer writeStmt.Close()

	// Get neighbors.
	nbrValues, err := m.neighborsAt(tx, index, depth, epoch)
	if err != nil {
		return err
	}

	nodeValues := sparse.NodeValues(hasher, bindex, value, nbrValues)

	// Save new nodes.
	for i, nodeValue := range nodeValues {
		_, err = writeStmt.Exec(m.mapID, nodeIDs[i], epoch, nodeValue)
		if err != nil {
			return err
		}
	}
	return tx.Commit()
}

// setRootAt sets root node values directly at epoch.
func (m *Map) setRootAt(ctx context.Context, value []byte, epoch int64) error {
	writeStmt, err := m.db.Prepare(setNodeExpr)
	if err != nil {
		return fmt.Errorf("setRootAt(): %v", err)
	}
	defer writeStmt.Close()
	_, err = writeStmt.Exec(m.mapID, m.nodeID(""), epoch, value[:])
	if err != nil {
		return fmt.Errorf("setRootAt(): %v", err)
	}
	return nil
}

// Create creates a new database.
func (m *Map) create() error {
	createStmt := `
	CREATE TABLE IF NOT EXISTS Maps (
		MapId	BLOB(32),
		PRIMARY KEY(MapID)
	);

	CREATE TABLE IF NOT EXISTS Leaves (
		MapId	BLOB(32) NOT NULL,
		LeafId	BLOB(32) NOT NULL,
		Version	INTEGER	 NOT NULL,
		Data	BLOB 	 NOT NULL,
		PRIMARY KEY(MapID, LeafId, Version),
		FOREIGN KEY(MapId) REFERENCES Maps(MapId) ON DELETE CASCADE
	);

	CREATE TABLE IF NOT EXISTS Nodes (
		MapId	BLOB(32) NOT NULL,
		NodeId	BLOB(32) NOT NULL,
		Version	INTEGER  NOT NULL,
		Value	BLOB(32) NOT NULL,
		PRIMARY KEY(MapId, NodeId, Version),
		FOREIGN KEY(MapId) REFERENCES Maps(MapId) ON DELETE CASCADE
	);

	CREATE TABLE IF NOT EXISTS MapHeads (
		MapId	BLOB(32) NOT NULL,
		Version INTEGER  NOT NULL,
		Timestamp TIMESTAMP NOT NULL,
		Value	Blob(32) NOT NULL,
		PRIMARY KEY(MapId, Version),
		FOREIGN KEY(MapId) REFERENCES Maps(MapId) ON DELETE CASCADE
	)
	`
	_, err := m.db.Exec(createStmt)
	if err != nil {
		return fmt.Errorf("Failed to create tables: %v", err)
	}
	return nil
}

func (m *Map) insertMapRow() error {
	stmt, err := m.db.Prepare(mapRowExpr)
	if err != nil {
		return fmt.Errorf("insertMapRow(): %v", err)
	}
	defer stmt.Close()
	_, err = stmt.Exec(m.mapID)
	if err != nil {
		return fmt.Errorf("insertMapRow(): %v", err)
	}
	return nil
}

func (m *Map) readEpoch() (int64, error) {
	stmt, err := m.db.Prepare(readEpochExpr)
	if err != nil {
		return -1, fmt.Errorf("readEpoch(): %v", err)
	}
	defer stmt.Close()
	var epoch sql.NullInt64
	if err := stmt.QueryRow(m.mapID, m.nodeID("")).Scan(&epoch); err != nil {
		return -1, fmt.Errorf("Error reading epoch: %v", err)
	}
	if !epoch.Valid {
		return -1, errInvalidEpoch
	}
	return epoch.Int64, nil
}

// Converts a list of bit strings into their node IDs.
func (m *Map) nodeIDs(bindexes []string) [][]byte {
	nodes := make([][]byte, len(bindexes))
	for i, bindex := range bindexes {
		nodes[i] = m.nodeID(bindex)
	}
	return nodes
}

// nodeID computes the location of a node, given its bit string index.
func (m *Map) nodeID(bindex string) []byte {
	h := sha256.New()
	h.Write(m.mapID)
	h.Write([]byte{0})
	h.Write([]byte(bindex))
	return h.Sum(nil)
}

// PrefixLen returns the index of the last non-zero item in the list
func PrefixLen(nodes [][]byte) int {
	// Iterate over the nodes from leaf to root.
	for i, v := range nodes {
		if v != nil {
			// return the first non-empty node.
			return len(nodes) - i
		}
	}
	return 0
}

func hashEmpty(bindex string) []byte {
	return hasher.HashEmpty(tree.InvertBitString(bindex))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"gother/statusboard"
	"gother/system"
	"net/http"
	"time"
)

func hello_handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello Go!")
}

func get_proc_handler() func(w http.ResponseWriter, r *http.Request) {
	type MemStat struct {
		label   string
		meminfo *system.MemInfo
	}
	memstats := make([]MemStat, 0)

	return func(w http.ResponseWriter, r *http.Request) {

		m := MemStat{
			label:   time.Now().Format("15:04:05"),
			meminfo: system.GetMemInfo(),
		}

		memstats = append(memstats, m)

		datapoints := map[string]*[]statusboard.DataPoint{
			"MemWired":    new([]statusboard.DataPoint),
			"MemActive":   new([]statusboard.DataPoint),
			"MemInactive": new([]statusboard.DataPoint),
			"MemFree":     new([]statusboard.DataPoint),
		}

		for _, memstat := range memstats {
			for memtype, datapoint := range datapoints {
				var val int
				switch memtype {
				case "MemWired":
					val = memstat.meminfo.Wired
				case "MemActive":
					val = memstat.meminfo.Active
				case "MemInactive":
					val = memstat.meminfo.Inactive
				case "MemFree":
					val = memstat.meminfo.Free
				}
				*datapoint = append(*datapoint,
					statusboard.DataPoint{
						Title: memstat.label,
						Value: val,
					})
			}
		}

		graph_entries := make([]statusboard.GraphEntry, 0)
		for memtype, datapoint := range datapoints {
			graph_entries = append(graph_entries,
				statusboard.GraphEntry{
					Title:      memtype,
					Datapoints: *datapoint,
				},
			)
		}
		jsonobj := statusboard.GraphJSON{
			Graph: statusboard.GraphData{
				Title:         "SystemInfo",
				Datasequences: graph_entries,
				Total:         false,
				Type:          "line",
			},
		}

		b, _ := json.Marshal(jsonobj)
		fmt.Fprintf(w, "%s", b)
	}
}

func main() {
	http.HandleFunc("/hello", hello_handler)
	http.HandleFunc("/proc", get_proc_handler())
	http.ListenAndServe(":8080", nil)
}
<commit_msg>change path<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"gother/statusboard"
	"gother/system"
	"net/http"
	"time"
)

func hello_handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello Go!")
}

func get_proc_handler() func(w http.ResponseWriter, r *http.Request) {
	type MemStat struct {
		label   string
		meminfo *system.MemInfo
	}
	memstats := make([]MemStat, 0)

	return func(w http.ResponseWriter, r *http.Request) {

		m := MemStat{
			label:   time.Now().Format("15:04:05"),
			meminfo: system.GetMemInfo(),
		}

		memstats = append(memstats, m)

		datapoints := map[string]*[]statusboard.DataPoint{
			"MemWired":    new([]statusboard.DataPoint),
			"MemActive":   new([]statusboard.DataPoint),
			"MemInactive": new([]statusboard.DataPoint),
			"MemFree":     new([]statusboard.DataPoint),
		}

		for _, memstat := range memstats {
			for memtype, datapoint := range datapoints {
				var val int
				switch memtype {
				case "MemWired":
					val = memstat.meminfo.Wired
				case "MemActive":
					val = memstat.meminfo.Active
				case "MemInactive":
					val = memstat.meminfo.Inactive
				case "MemFree":
					val = memstat.meminfo.Free
				}
				*datapoint = append(*datapoint,
					statusboard.DataPoint{
						Title: memstat.label,
						Value: val,
					})
			}
		}

		graph_entries := make([]statusboard.GraphEntry, 0)
		for memtype, datapoint := range datapoints {
			graph_entries = append(graph_entries,
				statusboard.GraphEntry{
					Title:      memtype,
					Datapoints: *datapoint,
				},
			)
		}
		jsonobj := statusboard.GraphJSON{
			Graph: statusboard.GraphData{
				Title:         "SystemInfo",
				Datasequences: graph_entries,
				Total:         false,
				Type:          "line",
			},
		}

		b, _ := json.Marshal(jsonobj)
		fmt.Fprintf(w, "%s", b)
	}
}

func main() {
	http.HandleFunc("/hello", hello_handler)
	http.HandleFunc("/proc/meminfo", get_proc_handler())
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package tdb

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/tecbot/gorocksdb"
	"gopkg.in/vmihailenco/msgpack.v2"
)

type query struct {
	table    string
	fields   []string
	from     time.Time
	to       time.Time
	onValues func(key map[string]interface{}, field string, vals []float64)
}

func (db *DB) runQuery(q *query) error {
	if q.from.IsZero() {
		return fmt.Errorf("Please specify a from")
	}
	if len(q.fields) == 0 {
		return fmt.Errorf("Please specify at least one field")
	}
	t := db.getTable(q.table)
	if t == nil {
		return fmt.Errorf("Unknown table %v", q.table)
	}
	fields := make([][]byte, 0, len(q.fields))
	for _, field := range q.fields {
		fieldBytes, err := msgpack.Marshal(strings.ToLower(field))
		if err != nil {
			return fmt.Errorf("Unable to marshal field: %v", err)
		}
		fields = append(fields, fieldBytes)
	}
	sort.Sort(lexicographical(fields))
	if q.to.IsZero() {
		q.to = t.clock.Now()
	}
	from := roundTime(q.from, t.resolution)
	to := q.to
	if to.IsZero() {
		to = t.clock.Now()
	}
	to = roundTime(to, t.resolution)
	numPeriods := int(to.Sub(from)/t.resolution) + 1
	log.Tracef("Query will return %d periods", numPeriods)

	ro := gorocksdb.NewDefaultReadOptions()
	// Go ahead and fill the cache
	ro.SetFillCache(true)
	it := t.archiveByKey.NewIterator(ro)
	defer it.Close()
	for _, fieldBytes := range fields {
		scanned := 0
		read := 0
		for it.Seek(fieldBytes); it.ValidForPrefix(fieldBytes); it.Next() {
			scanned++
			k := it.Key()
			kr := bytes.NewReader(k.Data())
			dec := msgpack.NewDecoder(kr)
			storedField, err := dec.DecodeString()
			if err != nil {
				k.Free()
				return fmt.Errorf("Unable to decode field: %v", err)
			}
			key := make(map[string]interface{})
			err = dec.Decode(&key)
			if err != nil {
				k.Free()
				return fmt.Errorf("Unable to decode key: %v", err)
			}
			k.Free()

			v := it.Value()
			seq := sequence(v.Data())
			vals := make([]float64, numPeriods)
			if seq.isValid() {
				read++
				seqStart := seq.start()
				if log.IsTraceEnabled() {
					log.Tracef("Sequence starts at %v and has %d periods", seqStart.In(time.UTC), seq.numPeriods())
				}
				includeKey := false
				if !seqStart.Before(from) {
					if to.After(seqStart) {
						to = seqStart
					}
					startOffset := int(seqStart.Sub(to) / t.resolution)
					log.Tracef("Start offset %d", startOffset)
					copyPeriods := seq.numPeriods()
					for i := 0; i+startOffset < copyPeriods && i < numPeriods; i++ {
						includeKey = true
						val := seq.valueAt(i + startOffset)
						log.Tracef("Grabbing value %f", val)
						vals[i] = val
					}
				}
				if includeKey {
					q.onValues(key, storedField, vals)
				}
			}
			v.Free()
		}
		log.Tracef("Query read/scanned %d/%d", read, scanned)
	}
	return nil
}

type lexicographical [][]byte

func (a lexicographical) Len() int           { return len(a) }
func (a lexicographical) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a lexicographical) Less(i, j int) bool { return bytes.Compare(a[i], a[j]) < 0 }

func keysEqual(a map[string]interface{}, b map[string]interface{}) bool {
	if len(a) != len(b) {
		return false
	}
	for k, v := range a {
		if b[k] != v {
			return false
		}
	}
	return true
}
<commit_msg>Updating dates on query itself<commit_after>package tdb

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/tecbot/gorocksdb"
	"gopkg.in/vmihailenco/msgpack.v2"
)

type query struct {
	table    string
	fields   []string
	from     time.Time
	to       time.Time
	onValues func(key map[string]interface{}, field string, vals []float64)
}

func (db *DB) runQuery(q *query) error {
	if q.from.IsZero() {
		return fmt.Errorf("Please specify a from")
	}
	if len(q.fields) == 0 {
		return fmt.Errorf("Please specify at least one field")
	}
	t := db.getTable(q.table)
	if t == nil {
		return fmt.Errorf("Unknown table %v", q.table)
	}
	fields := make([][]byte, 0, len(q.fields))
	for _, field := range q.fields {
		fieldBytes, err := msgpack.Marshal(strings.ToLower(field))
		if err != nil {
			return fmt.Errorf("Unable to marshal field: %v", err)
		}
		fields = append(fields, fieldBytes)
	}
	sort.Sort(lexicographical(fields))
	if q.to.IsZero() {
		q.to = t.clock.Now()
	}
	q.from = roundTime(q.from, t.resolution)
	if q.to.IsZero() {
		q.to = t.clock.Now()
	}
	q.to = roundTime(q.to, t.resolution)
	numPeriods := int(q.to.Sub(q.from)/t.resolution) + 1
	log.Tracef("Query will return %d periods", numPeriods)

	ro := gorocksdb.NewDefaultReadOptions()
	// Go ahead and fill the cache
	ro.SetFillCache(true)
	it := t.archiveByKey.NewIterator(ro)
	defer it.Close()
	for _, fieldBytes := range fields {
		scanned := 0
		read := 0
		for it.Seek(fieldBytes); it.ValidForPrefix(fieldBytes); it.Next() {
			scanned++
			k := it.Key()
			kr := bytes.NewReader(k.Data())
			dec := msgpack.NewDecoder(kr)
			storedField, err := dec.DecodeString()
			if err != nil {
				k.Free()
				return fmt.Errorf("Unable to decode field: %v", err)
			}
			key := make(map[string]interface{})
			err = dec.Decode(&key)
			if err != nil {
				k.Free()
				return fmt.Errorf("Unable to decode key: %v", err)
			}
			k.Free()

			v := it.Value()
			seq := sequence(v.Data())
			vals := make([]float64, numPeriods)
			if seq.isValid() {
				read++
				seqStart := seq.start()
				if log.IsTraceEnabled() {
					log.Tracef("Sequence starts at %v and has %d periods", seqStart.In(time.UTC), seq.numPeriods())
				}
				includeKey := false
				if !seqStart.Before(q.from) {
					to := q.to
					if to.After(seqStart) {
						to = seqStart
					}
					startOffset := int(seqStart.Sub(to) / t.resolution)
					log.Tracef("Start offset %d", startOffset)
					copyPeriods := seq.numPeriods()
					for i := 0; i+startOffset < copyPeriods && i < numPeriods; i++ {
						includeKey = true
						val := seq.valueAt(i + startOffset)
						log.Tracef("Grabbing value %f", val)
						vals[i] = val
					}
				}
				if includeKey {
					q.onValues(key, storedField, vals)
				}
			}
			v.Free()
		}
		log.Tracef("Query read/scanned %d/%d", read, scanned)
	}
	return nil
}

type lexicographical [][]byte

func (a lexicographical) Len() int           { return len(a) }
func (a lexicographical) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a lexicographical) Less(i, j int) bool { return bytes.Compare(a[i], a[j]) < 0 }

func keysEqual(a map[string]interface{}, b map[string]interface{}) bool {
	if len(a) != len(b) {
		return false
	}
	for k, v := range a {
		if b[k] != v {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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 linter

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"

	"github.com/bradegler/secure-setup-terraform/pkg/lint"
)

const tokenLocalExec = "local-exec"
const tokenRemoteExec = "remote-exec"

var selectors = []string{".tf", ".tf.json"}

type TerraformLinter struct{}

// FindViolations inspects a set of bytes that represent hcl from a terraform configuration file
// looking for calls to the 'local-exec' provider.
func (tfl *TerraformLinter) FindViolations(content []byte, path string) ([]*lint.ViolationInstance, error) {
	tokens, diags := hclsyntax.LexConfig(content, path, hcl.Pos{Byte: 0, Line: 1, Column: 1})
	if diags.HasErrors() {
		return nil, fmt.Errorf("error lexing hcl file contents: [%s]", diags.Error())
	}

	var instances []*lint.ViolationInstance
	for _, token := range tokens {
		if token.Bytes != nil && token.Type == hclsyntax.TokenQuotedLit {
			if string(token.Bytes) == tokenLocalExec {
				instances = append(instances, &lint.ViolationInstance{ViolationType: tokenLocalExec, Path: path, Line: token.Range.Start.Line})
			}
			if string(token.Bytes) == tokenRemoteExec {
				instances = append(instances, &lint.ViolationInstance{ViolationType: tokenRemoteExec, Path: path, Line: token.Range.Start.Line})
			}
		}
	}
	return instances, nil
}

func (tfl *TerraformLinter) Selectors() []string { return selectors }
<commit_msg>added fix for local-exec found outside of a provisioner<commit_after>// Copyright 2022 Google LLC
//
// 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 linter

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"

	"github.com/bradegler/secure-setup-terraform/pkg/lint"
)

const tokenLocalExec = "local-exec"
const tokenRemoteExec = "remote-exec"

var selectors = []string{".tf", ".tf.json"}

type TerraformLinter struct{}

// FindViolations inspects a set of bytes that represent hcl from a terraform configuration file
// looking for calls to the 'local-exec' provider.
func (tfl *TerraformLinter) FindViolations(content []byte, path string) ([]*lint.ViolationInstance, error) {
	tokens, diags := hclsyntax.LexConfig(content, path, hcl.Pos{Byte: 0, Line: 1, Column: 1})
	if diags.HasErrors() {
		return nil, fmt.Errorf("error lexing hcl file contents: [%s]", diags.Error())
	}

	var instances []*lint.ViolationInstance
	inProvisioner := false
	for _, token := range tokens {
		if token.Bytes == nil {
			continue
		}

		// Each Ident token starts a new object, we are only looking for provisioner
		// type objects with specific types, local-exec and remote-exec
		if token.Type == hclsyntax.TokenIdent {
			inProvisioner = string(token.Bytes) == "provisioner"
		}
		if inProvisioner && token.Type == hclsyntax.TokenQuotedLit {
			if string(token.Bytes) == tokenLocalExec {
				instances = append(instances, &lint.ViolationInstance{ViolationType: tokenLocalExec, Path: path, Line: token.Range.Start.Line})
			}
			if string(token.Bytes) == tokenRemoteExec {
				instances = append(instances, &lint.ViolationInstance{ViolationType: tokenRemoteExec, Path: path, Line: token.Range.Start.Line})
			}
		}
	}
	return instances, nil
}

func (tfl *TerraformLinter) Selectors() []string { return selectors }
<|endoftext|>


<commit_before>package cc1101

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"github.com/ecc1/radio"
)

const (
	readFifoUsingBurst = true
	fifoSize           = 64
	maxPacketSize      = 110

	// Approximate time for one byte to be transmitted, based on
	// the data rate.  It was determined empirically so that few
	// if any iterations are needed in drainTxFifo().
	byteDuration = time.Millisecond
)

func (r *Radio) Start() {
	if !r.radioStarted {
		r.radioStarted = true
		go r.radio()
	}
}

func (r *Radio) Stop() {
	// stop radio goroutines and enter IDLE state
	panic("not implemented")
}

func (r *Radio) Incoming() <-chan radio.Packet {
	return r.receivedPackets
}

func (r *Radio) Outgoing() chan<- radio.Packet {
	return r.transmittedPackets
}

func (r *Radio) radio() {
	go r.awaitInterrupts()
	for {
		err := r.changeState(SRX, STATE_RX)
		if err != nil {
			log.Fatal(err)
		}
		select {
		case packet := <-r.transmittedPackets:
			err := r.changeState(SIDLE, STATE_IDLE)
			if err != nil {
				log.Fatal(err)
			}
			err = r.transmit(packet.Data)
			if err != nil {
				log.Fatal(err)
			}
			err = r.changeState(SIDLE, STATE_IDLE)
			if err != nil {
				log.Fatal(err)
			}
		case <-r.interrupt:
			err = r.receive()
			if err != nil {
				log.Fatal(err)
			}
		}
	}
}

func (r *Radio) awaitInterrupts() {
	for {
		if verbose {
			log.Printf("waiting for interrupt in %s state", r.State())
		}
		r.interruptPin.Wait()
		r.interrupt <- struct{}{}
	}
}

func (r *Radio) transmit(data []byte) error {
	if len(data) > maxPacketSize {
		log.Panicf("attempting to send %d-byte packet", len(data))
	}
	if verbose {
		log.Printf("sending %d-byte packet in %s state", len(data), r.State())
	}
	// Terminate packet with zero byte,
	// and pad with another to ensure final bytes
	// are transmitted before leaving TX state.
	var buffer [maxPacketSize + 2]byte
	copy(buffer[0:], data)
	buffer[len(data)] = 0
	buffer[len(data)+1] = 0
	packet := buffer[:len(data)+2]
	err := r.send(packet)
	if err == nil {
		r.stats.Packets.Sent++
		r.stats.Bytes.Sent += len(data)
	}
	return err
}

func (r *Radio) send(data []byte) error {
	avail := fifoSize
	for {
		if avail > len(data) {
			avail = len(data)
		}
		err := r.WriteBurst(TXFIFO, data[:avail])
		if err != nil {
			return err
		}
		err = r.changeState(STX, STATE_TX)
		if err != nil {
			return err
		}
		data = data[avail:]
		if len(data) == 0 {
			break
		}
		// Transmitting a packet that is larger than the TXFIFO size.
		// See TI Design Note DN500 (swra109c).
		// Err on the short side here to avoid TXFIFO underflow.
		time.Sleep(fifoSize / 4 * byteDuration)
		for {
			n, err := r.ReadNumTxBytes()
			if err != nil {
				return err
			}
			if n < fifoSize {
				avail = fifoSize - int(n)
				if avail > len(data) {
					avail = len(data)
				}
				break
			}
		}
	}
	return r.drainTxFifo(avail)
}

func (r *Radio) drainTxFifo(numBytes int) error {
	time.Sleep(time.Duration(numBytes) * byteDuration)
	for {
		n, err := r.ReadNumTxBytes()
		if err != nil && err != TxFifoUnderflow {
			return err
		}
		if n == 0 || err == TxFifoUnderflow {
			break
		}
		s, err := r.ReadState()
		if err != nil {
			return err
		}
		if s != STATE_TX && s != STATE_TXFIFO_UNDERFLOW {
			return fmt.Errorf("unexpected %s state during TXFIFO drain", StateName(s))
		}
		if verbose {
			log.Printf("waiting to transmit %d bytes in %s state", n, r.State())
		}
		time.Sleep(byteDuration)
	}
	if verbose {
		log.Printf("TX FIFO drained in %s state", r.State())
	}
	return nil
}

func (r *Radio) receive() error {
	waiting := false
	for {
		numBytes, err := r.ReadNumRxBytes()
		if err == RxFifoOverflow {
			// Flush RX FIFO and change back to RX.
			r.changeState(SRX, STATE_RX)
			continue
		} else if err != nil {
			return err
		}
		// Don't read last byte of FIFO if packet is still
		// being received. See Section 20 of data sheet.
		if numBytes < 2 {
			if waiting {
				return nil
			}
			waiting = true
			time.Sleep(byteDuration)
			continue
		}
		waiting = false
		if readFifoUsingBurst {
			data, err := r.ReadBurst(RXFIFO, int(numBytes))
			if err != nil {
				return err
			}
			i := bytes.IndexByte(data, 0)
			if i == -1 {
				// No zero byte found; packet is still incoming.
				// Append all the data and continue to receive.
				_, err = r.receiveBuffer.Write(data)
				if err != nil {
					return err
				}
				continue
			}
			// End of packet.
			_, err = r.receiveBuffer.Write(data[:i])
			if err != nil {
				return err
			}
		} else {
			c, err := r.ReadRegister(RXFIFO)
			if err != nil {
				return err
			}
			if c != 0 {
				err = r.receiveBuffer.WriteByte(c)
				if err != nil {
					return err
				}
				continue
			}
		}
		// End of packet.
		rssi, err := r.ReadRSSI()
		if err != nil {
			return err
		}
		size := r.receiveBuffer.Len()
		if size != 0 {
			r.stats.Packets.Received++
			r.stats.Bytes.Received += size
			p := make([]byte, size)
			_, err := r.receiveBuffer.Read(p)
			if err != nil {
				return err
			}
			r.receiveBuffer.Reset()
			r.receivedPackets <- radio.Packet{Rssi: rssi, Data: p}
			if verbose {
				n, _ := r.ReadNumRxBytes()
				log.Printf("received %d-byte packet in %s state; %d bytes remaining", size, r.State(), n)
			}
		}
		return nil
	}
}

func (r *Radio) drainRxFifo() error {
	n, err := r.ReadNumRxBytes()
	if err == RxFifoOverflow {
		// Flush RX FIFO and change back to RX.
		return r.changeState(SRX, STATE_RX)
	}
	if err != nil || n == 0 {
		return err
	}
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	switch s {
	case STATE_RX:
		log.Printf("draining %d bytes from RXFIFO", n)
		_, err = r.ReadBurst(RXFIFO, int(n))
		return err
	default:
		return fmt.Errorf("unexpected %s state during RXFIFO drain", StateName(s))
	}
}

func (r *Radio) changeState(strobe byte, desired byte) error {
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	if verbose && s != desired {
		log.Printf("change from %s to %s", StateName(s), StateName(desired))
	}
	for {
		switch s {
		case desired:
			return nil
		case STATE_RXFIFO_OVERFLOW:
			s, err = r.Strobe(SFRX)
		case STATE_TXFIFO_UNDERFLOW:
			s, err = r.Strobe(SFTX)
		default:
			s, err = r.Strobe(strobe)
		}
		if err != nil {
			return err
		}
		s = (s >> STATE_SHIFT) & STATE_MASK
		if verbose {
			log.Printf("  %s", StateName(s))
		}
	}
}
<commit_msg>Simplify appending of zero bytes to packet<commit_after>package cc1101

import (
	"bytes"
	"fmt"
	"log"
	"time"

	"github.com/ecc1/radio"
)

const (
	readFifoUsingBurst = true
	fifoSize           = 64
	maxPacketSize      = 110

	// Approximate time for one byte to be transmitted, based on
	// the data rate.  It was determined empirically so that few
	// if any iterations are needed in drainTxFifo().
	byteDuration = time.Millisecond
)

func (r *Radio) Start() {
	if !r.radioStarted {
		r.radioStarted = true
		go r.radio()
	}
}

func (r *Radio) Stop() {
	// stop radio goroutines and enter IDLE state
	panic("not implemented")
}

func (r *Radio) Incoming() <-chan radio.Packet {
	return r.receivedPackets
}

func (r *Radio) Outgoing() chan<- radio.Packet {
	return r.transmittedPackets
}

func (r *Radio) radio() {
	go r.awaitInterrupts()
	for {
		err := r.changeState(SRX, STATE_RX)
		if err != nil {
			log.Fatal(err)
		}
		select {
		case packet := <-r.transmittedPackets:
			err := r.changeState(SIDLE, STATE_IDLE)
			if err != nil {
				log.Fatal(err)
			}
			err = r.transmit(packet.Data)
			if err != nil {
				log.Fatal(err)
			}
			err = r.changeState(SIDLE, STATE_IDLE)
			if err != nil {
				log.Fatal(err)
			}
		case <-r.interrupt:
			err = r.receive()
			if err != nil {
				log.Fatal(err)
			}
		}
	}
}

func (r *Radio) awaitInterrupts() {
	for {
		if verbose {
			log.Printf("waiting for interrupt in %s state", r.State())
		}
		r.interruptPin.Wait()
		r.interrupt <- struct{}{}
	}
}

func (r *Radio) transmit(data []byte) error {
	if len(data) > maxPacketSize {
		log.Panicf("attempting to send %d-byte packet", len(data))
	}
	if verbose {
		log.Printf("sending %d-byte packet in %s state", len(data), r.State())
	}
	// Terminate packet with zero byte,
	// and pad with another to ensure final bytes
	// are transmitted before leaving TX state.
	packet := make([]byte, len(data), len(data)+2)
	copy(packet, data)
	packet = packet[:cap(packet)]
	err := r.send(packet)
	if err == nil {
		r.stats.Packets.Sent++
		r.stats.Bytes.Sent += len(data)
	}
	return err
}

func (r *Radio) send(data []byte) error {
	avail := fifoSize
	for {
		if avail > len(data) {
			avail = len(data)
		}
		err := r.WriteBurst(TXFIFO, data[:avail])
		if err != nil {
			return err
		}
		err = r.changeState(STX, STATE_TX)
		if err != nil {
			return err
		}
		data = data[avail:]
		if len(data) == 0 {
			break
		}
		// Transmitting a packet that is larger than the TXFIFO size.
		// See TI Design Note DN500 (swra109c).
		// Err on the short side here to avoid TXFIFO underflow.
		time.Sleep(fifoSize / 4 * byteDuration)
		for {
			n, err := r.ReadNumTxBytes()
			if err != nil {
				return err
			}
			if n < fifoSize {
				avail = fifoSize - int(n)
				if avail > len(data) {
					avail = len(data)
				}
				break
			}
		}
	}
	return r.drainTxFifo(avail)
}

func (r *Radio) drainTxFifo(numBytes int) error {
	time.Sleep(time.Duration(numBytes) * byteDuration)
	for {
		n, err := r.ReadNumTxBytes()
		if err != nil && err != TxFifoUnderflow {
			return err
		}
		if n == 0 || err == TxFifoUnderflow {
			break
		}
		s, err := r.ReadState()
		if err != nil {
			return err
		}
		if s != STATE_TX && s != STATE_TXFIFO_UNDERFLOW {
			return fmt.Errorf("unexpected %s state during TXFIFO drain", StateName(s))
		}
		if verbose {
			log.Printf("waiting to transmit %d bytes in %s state", n, r.State())
		}
		time.Sleep(byteDuration)
	}
	if verbose {
		log.Printf("TX FIFO drained in %s state", r.State())
	}
	return nil
}

func (r *Radio) receive() error {
	waiting := false
	for {
		numBytes, err := r.ReadNumRxBytes()
		if err == RxFifoOverflow {
			// Flush RX FIFO and change back to RX.
			r.changeState(SRX, STATE_RX)
			continue
		} else if err != nil {
			return err
		}
		// Don't read last byte of FIFO if packet is still
		// being received. See Section 20 of data sheet.
		if numBytes < 2 {
			if waiting {
				return nil
			}
			waiting = true
			time.Sleep(byteDuration)
			continue
		}
		waiting = false
		if readFifoUsingBurst {
			data, err := r.ReadBurst(RXFIFO, int(numBytes))
			if err != nil {
				return err
			}
			i := bytes.IndexByte(data, 0)
			if i == -1 {
				// No zero byte found; packet is still incoming.
				// Append all the data and continue to receive.
				_, err = r.receiveBuffer.Write(data)
				if err != nil {
					return err
				}
				continue
			}
			// End of packet.
			_, err = r.receiveBuffer.Write(data[:i])
			if err != nil {
				return err
			}
		} else {
			c, err := r.ReadRegister(RXFIFO)
			if err != nil {
				return err
			}
			if c != 0 {
				err = r.receiveBuffer.WriteByte(c)
				if err != nil {
					return err
				}
				continue
			}
		}
		// End of packet.
		rssi, err := r.ReadRSSI()
		if err != nil {
			return err
		}
		size := r.receiveBuffer.Len()
		if size != 0 {
			r.stats.Packets.Received++
			r.stats.Bytes.Received += size
			p := make([]byte, size)
			_, err := r.receiveBuffer.Read(p)
			if err != nil {
				return err
			}
			r.receiveBuffer.Reset()
			r.receivedPackets <- radio.Packet{Rssi: rssi, Data: p}
			if verbose {
				n, _ := r.ReadNumRxBytes()
				log.Printf("received %d-byte packet in %s state; %d bytes remaining", size, r.State(), n)
			}
		}
		return nil
	}
}

func (r *Radio) drainRxFifo() error {
	n, err := r.ReadNumRxBytes()
	if err == RxFifoOverflow {
		// Flush RX FIFO and change back to RX.
		return r.changeState(SRX, STATE_RX)
	}
	if err != nil || n == 0 {
		return err
	}
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	switch s {
	case STATE_RX:
		log.Printf("draining %d bytes from RXFIFO", n)
		_, err = r.ReadBurst(RXFIFO, int(n))
		return err
	default:
		return fmt.Errorf("unexpected %s state during RXFIFO drain", StateName(s))
	}
}

func (r *Radio) changeState(strobe byte, desired byte) error {
	s, err := r.ReadState()
	if err != nil {
		return err
	}
	if verbose && s != desired {
		log.Printf("change from %s to %s", StateName(s), StateName(desired))
	}
	for {
		switch s {
		case desired:
			return nil
		case STATE_RXFIFO_OVERFLOW:
			s, err = r.Strobe(SFRX)
		case STATE_TXFIFO_UNDERFLOW:
			s, err = r.Strobe(SFTX)
		default:
			s, err = r.Strobe(strobe)
		}
		if err != nil {
			return err
		}
		s = (s >> STATE_SHIFT) & STATE_MASK
		if verbose {
			log.Printf("  %s", StateName(s))
		}
	}
}
<|endoftext|>