<commit_before>// Copyright 2015 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/control-center/serviced/utils"
)

type ThinPoolCreate struct {
	Args struct {
		Purpose string   `description:"Purpose of the thin pool (docker|serviced)"`
		Devices []string `description:"Block devices to use" required:"1"`
	} `positional-args:"yes" required:"yes"`
}

type LogicalVolumeInfo struct {
	Name        string
	KernelMajor uint
	KernelMinor uint
}

// runCommand runs the command and returns the stdout, stderr, exit code, and error.
// If the command ran but returned non-zero, the error is nil
func runCommand(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
	var stderrBuffer bytes.Buffer
	var stdoutBuffer bytes.Buffer
	cmd.Stderr = &stderrBuffer
	cmd.Stdout = &stdoutBuffer
	cmdErr := cmd.Run()
	exitCode, success := utils.GetExitStatus(cmdErr)
	if success {
		cmdErr = nil
	}
	return stdoutBuffer.String(), stderrBuffer.String(), exitCode, cmdErr
}

func (c *ThinPoolCreate) Execute(args []string) error {
	App.initializeLogging()
	purpose := c.Args.Purpose
	devices := c.Args.Devices
	logger := log.WithFields(log.Fields{
		"purpose": purpose,
		"devices": devices,
	})
	if purpose != "serviced" && purpose != "docker" {
		logger.Fatal("Purpose must be one of (docker, serviced)")
	}

	logger.Info("Creating thin-pool")
	thinPoolName, err := createThinPool(purpose, devices)
	if err != nil {
		logger.Fatal(err)
	}

	fmt.Printf("Created thin-pool device '%s'\n", thinPoolName)

	return nil
}

func createThinPool(purpose string, devices []string) (string, error) {
	if err := ensurePhysicalDevices(devices); err != nil {
		return "", err
	}

	volumeGroup := purpose
	if err := createVolumeGroup(volumeGroup, devices); err != nil {
		return "", err
	}

	metadataVolume, err := createMetadataVolume(volumeGroup)
	if err != nil {
		return "", err
	}

	dataVolume, err := createDataVolume(volumeGroup)
	if err != nil {
		return "", err
	}

	err = convertToThinPool(volumeGroup, dataVolume, metadataVolume)
	if err != nil {
		return "", err
	}

	thinPoolName, err := getThinPoolNameForLogicalVolume(volumeGroup, dataVolume)
	if err != nil {
		return "", err
	}

	return thinPoolName, nil
}

func ensurePhysicalDevices(devices []string) error {
	for _, device := range devices {
		cmd := exec.Command("pvs", device)
		_, _, exitCode, err := runCommand(cmd)
		if err != nil {
			return err
		}
		if exitCode == 0 {
			continue
		}

		args := []string{"pvcreate", device}
		log.Info(strings.Join(args, " "))
		cmd = exec.Command(args[0], args[1:]...)
		stdout, stderr, exitCode, err := runCommand(cmd)
		if err != nil {
			return err
		}
		if exitCode != 0 {
			return fmt.Errorf("Error(%d) running '%s':\n%s",
				exitCode, strings.Join(args, " "), stderr)
		}
		log.Info(stdout)
	}
	return nil
}

func createVolumeGroup(volumeGroup string, devices []string) error {
	args := append([]string{"vgcreate", volumeGroup}, devices...)
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return err
	}
	if exitCode != 0 {
		return fmt.Errorf("Error(%d) running '%s':\n%s",
			exitCode, strings.Join(args, " "), stderr)
	}
	log.Info(stdout)
	return nil
}

func createMetadataVolume(volumeGroup string) (string, error) {
	units := "s" // volume size will be measured in sectors
	totalSize, err := getVolumeGroupSize(volumeGroup, units)
	metadataSize := (totalSize + 999) / 1000
	metadataName := volumeGroup + "-meta"

	args := []string{"lvcreate",
		"--size", fmt.Sprintf("%d%s", metadataSize, units),
		"--name", metadataName,
		volumeGroup}
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return "", err
	}
	if exitCode != 0 {
		return "", fmt.Errorf("Error(%d) running '%s':\n%s",
			exitCode, strings.Join(args, " "), stderr)
	}
	log.Info(stdout)
	return metadataName, err
}

func createDataVolume(volumeGroup string) (string, error) {
	units := "b" // volume size will be measured in bytes
	totalSize, err := getVolumeGroupSize(volumeGroup, units)
	dataSize := (totalSize*90/100 + 511) &^ 511
	dataName := volumeGroup + "-pool"

	args := []string{"lvcreate",
		"--size", fmt.Sprintf("%d%s", dataSize, units),
		"--name", dataName,
		volumeGroup}
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return "", err
	}
	if exitCode != 0 {
		return "", fmt.Errorf("Error(%d) running '%s':\n%s",
			exitCode, strings.Join(args, " "), stderr)
	}
	log.Info(stdout)
	return dataName, err
}

func convertToThinPool(volumeGroup, dataVolume string, metadataVolume string) error {
	args := []string{"lvconvert",
		"--zero", "n",
		"--thinpool", fmt.Sprintf("%s/%s", volumeGroup, dataVolume),
		"--poolmetadata", fmt.Sprintf("%s/%s", volumeGroup, metadataVolume),
	}
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return err
	}
	if exitCode != 0 {
		return fmt.Errorf("Error(%d) running '%s':\n%s",
			exitCode, strings.Join(args, " "), stderr)
	}
	log.Info(stdout)
	return nil
}

func getVolumeGroupSize(volumeGroup string, units string) (uint64, error) {
	args := []string{"vgs",
		"--noheadings",
		"--nosuffix",
		"--units", units,
		"--options", "vg_free",
		volumeGroup}
	cmd := exec.Command(args[0], args[1:]...)
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return 0, err
	}
	if exitCode != 0 {
		return 0, fmt.Errorf("Error(%d) running '%s':\n%s",
			exitCode, strings.Join(args, " "), stderr)
	}

	sizeString := strings.Trim(stdout, " \n")
	size, err := strconv.ParseUint(sizeString, 10, 64)
	if err != nil {
		return 0, err
	}
	return size, nil
}

func getInfoForLogicalVolume(volumeGroup string, logicalVolume string) (LogicalVolumeInfo, error) {
	lvi := LogicalVolumeInfo{}
	args := []string{"lvs",
		"--noheadings",
		"--nameprefixes",
		"--options", "lv_name,lv_kernel_major,lv_kernel_minor",
		volumeGroup}
	cmd := exec.Command(args[0], args[1:]...)
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return lvi, err
	}
	if exitCode != 0 {
		return lvi, fmt.Errorf("Error(%d) running '%s':\n%s",
			exitCode, strings.Join(args, " "), stderr)
	}

	parseError := fmt.Errorf("Failed to parse command output:\n'%s'\n%s",
		strings.Join(args, " "), stdout)

	// Example command output:
	// LVM2_LV_NAME='docker-pool' LVM2_LV_KERNEL_MAJOR='252' LVM2_LV_KERNEL_MINOR='4'
	regexName := regexp.MustCompile("LVM2_LV_NAME='(.+?)'")
	regexMajor := regexp.MustCompile("LVM2_LV_KERNEL_MAJOR='(.+?)'")
	regexMinor := regexp.MustCompile("LVM2_LV_KERNEL_MINOR='(.+?)'")
	for _, line := range strings.Split(stdout, "\n") {
		match := regexName.FindStringSubmatch(line)
		if len(match) != 2 || match[1] != logicalVolume {
			continue
		}

		match = regexMajor.FindStringSubmatch(line)
		if len(match) != 2 {
			return lvi, parseError
		}
		major, err := strconv.ParseUint(match[1], 10, 32)
		if err != nil {
			return lvi, parseError
		}

		match = regexMinor.FindStringSubmatch(line)
		if len(match) != 2 {
			return lvi, parseError
		}
		minor, err := strconv.ParseUint(match[1], 10, 32)
		if err != nil {
			return lvi, parseError
		}

		lvi.Name = logicalVolume
		lvi.KernelMajor = uint(major)
		lvi.KernelMinor = uint(minor)
		return lvi, nil
	}

	return lvi, fmt.Errorf("Failed to find logical volume: '%s'", name)
}

func getThinPoolNameForLogicalVolume(volumeGroup string, logicalVolume string) (string, error) {
	info, err := getInfoForLogicalVolume(volumeGroup, logicalVolume)
	if err != nil {
		return "", err
	}
	filename := fmt.Sprintf("/sys/dev/block/%d:%d/dm/name",
		info.KernelMajor, info.KernelMinor)
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("Error reading %s: %s", filename, err)
	}
	return strings.Trim(string(contents), "\n"), nil
}
<commit_msg>Normalize exit code error handling<commit_after>// Copyright 2015 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/control-center/serviced/utils"
)

type ThinPoolCreate struct {
	Args struct {
		Purpose string   `description:"Purpose of the thin pool (docker|serviced)"`
		Devices []string `description:"Block devices to use" required:"1"`
	} `positional-args:"yes" required:"yes"`
}

type LogicalVolumeInfo struct {
	Name        string
	KernelMajor uint
	KernelMinor uint
}

// runCommand runs the command and returns the stdout, stderr, exit code, and error.
// If the command ran but returned non-zero, the error is nil
func runCommand(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
	var stderrBuffer bytes.Buffer
	var stdoutBuffer bytes.Buffer
	cmd.Stderr = &stderrBuffer
	cmd.Stdout = &stdoutBuffer
	cmdErr := cmd.Run()
	exitCode, success := utils.GetExitStatus(cmdErr)
	if success {
		cmdErr = nil
	}
	return stdoutBuffer.String(), stderrBuffer.String(), exitCode, cmdErr
}

func checkCommand(cmd *exec.Cmd) (stdout string, stderr string, err error) {
	stdout, stderr, exitCode, err := runCommand(cmd)
	if err != nil {
		return stdout, stderr, err
	}
	if exitCode != 0 {
		return stdout, stderr, fmt.Errorf("Error(%d) running command '%s':\n%s",
			exitCode, strings.Join(cmd.Args, " "), stderr)
	}
	return stdout, stderr, nil
}

func (c *ThinPoolCreate) Execute(args []string) error {
	App.initializeLogging()
	purpose := c.Args.Purpose
	devices := c.Args.Devices
	logger := log.WithFields(log.Fields{
		"purpose": purpose,
		"devices": devices,
	})
	if purpose != "serviced" && purpose != "docker" {
		logger.Fatal("Purpose must be one of (docker, serviced)")
	}

	logger.Info("Creating thin-pool")
	thinPoolName, err := createThinPool(purpose, devices)
	if err != nil {
		logger.Fatal(err)
	}

	fmt.Printf("Created thin-pool device '%s'\n", thinPoolName)

	return nil
}

func createThinPool(purpose string, devices []string) (string, error) {
	if err := ensurePhysicalDevices(devices); err != nil {
		return "", err
	}

	volumeGroup := purpose
	if err := createVolumeGroup(volumeGroup, devices); err != nil {
		return "", err
	}

	metadataVolume, err := createMetadataVolume(volumeGroup)
	if err != nil {
		return "", err
	}

	dataVolume, err := createDataVolume(volumeGroup)
	if err != nil {
		return "", err
	}

	err = convertToThinPool(volumeGroup, dataVolume, metadataVolume)
	if err != nil {
		return "", err
	}

	thinPoolName, err := getThinPoolNameForLogicalVolume(volumeGroup, dataVolume)
	if err != nil {
		return "", err
	}

	return thinPoolName, nil
}

func ensurePhysicalDevices(devices []string) error {
	for _, device := range devices {
		cmd := exec.Command("pvs", device)
		_, _, exitCode, err := runCommand(cmd)
		if err != nil {
			return err
		}
		if exitCode == 0 {
			continue
		}

		args := []string{"pvcreate", device}
		log.Info(strings.Join(args, " "))
		cmd = exec.Command(args[0], args[1:]...)
		stdout, _, err := checkCommand(cmd)
		if err != nil {
			return err
		}
		log.Info(stdout)
	}
	return nil
}

func createVolumeGroup(volumeGroup string, devices []string) error {
	args := append([]string{"vgcreate", volumeGroup}, devices...)
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, _, err := checkCommand(cmd)
	if err != nil {
		return err
	}
	log.Info(stdout)
	return nil
}

func createMetadataVolume(volumeGroup string) (string, error) {
	units := "s" // volume size will be measured in sectors
	totalSize, err := getVolumeGroupSize(volumeGroup, units)
	metadataSize := (totalSize + 999) / 1000
	metadataName := volumeGroup + "-meta"

	args := []string{"lvcreate",
		"--size", fmt.Sprintf("%d%s", metadataSize, units),
		"--name", metadataName,
		volumeGroup}
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, _, err := checkCommand(cmd)
	if err != nil {
		return "", err
	}
	log.Info(stdout)
	return metadataName, err
}

func createDataVolume(volumeGroup string) (string, error) {
	units := "b" // volume size will be measured in bytes
	totalSize, err := getVolumeGroupSize(volumeGroup, units)
	dataSize := (totalSize*90/100 + 511) &^ 511
	dataName := volumeGroup + "-pool"

	args := []string{"lvcreate",
		"--size", fmt.Sprintf("%d%s", dataSize, units),
		"--name", dataName,
		volumeGroup}
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, _, err := checkCommand(cmd)
	if err != nil {
		return "", err
	}
	log.Info(stdout)
	return dataName, err
}

func convertToThinPool(volumeGroup, dataVolume string, metadataVolume string) error {
	args := []string{"lvconvert",
		"--zero", "n",
		"--thinpool", fmt.Sprintf("%s/%s", volumeGroup, dataVolume),
		"--poolmetadata", fmt.Sprintf("%s/%s", volumeGroup, metadataVolume),
	}
	log.Info(strings.Join(args, " "))
	cmd := exec.Command(args[0], args[1:]...)
	stdout, _, err := checkCommand(cmd)
	if err != nil {
		return err
	}
	log.Info(stdout)
	return nil
}

func getVolumeGroupSize(volumeGroup string, units string) (uint64, error) {
	args := []string{"vgs",
		"--noheadings",
		"--nosuffix",
		"--units", units,
		"--options", "vg_free",
		volumeGroup}
	cmd := exec.Command(args[0], args[1:]...)
	stdout, _, err := checkCommand(cmd)
	if err != nil {
		return 0, err
	}

	sizeString := strings.Trim(stdout, " \n")
	size, err := strconv.ParseUint(sizeString, 10, 64)
	if err != nil {
		return 0, err
	}
	return size, nil
}

func getInfoForLogicalVolume(volumeGroup string, logicalVolume string) (LogicalVolumeInfo, error) {
	lvi := LogicalVolumeInfo{}
	args := []string{"lvs",
		"--noheadings",
		"--nameprefixes",
		"--options", "lv_name,lv_kernel_major,lv_kernel_minor",
		volumeGroup}
	cmd := exec.Command(args[0], args[1:]...)
	stdout, _, err := checkCommand(cmd)
	if err != nil {
		return lvi, err
	}

	parseError := fmt.Errorf("Failed to parse command output:\n'%s'\n%s",
		strings.Join(args, " "), stdout)

	// Example command output:
	// LVM2_LV_NAME='docker-pool' LVM2_LV_KERNEL_MAJOR='252' LVM2_LV_KERNEL_MINOR='4'
	regexName := regexp.MustCompile("LVM2_LV_NAME='(.+?)'")
	regexMajor := regexp.MustCompile("LVM2_LV_KERNEL_MAJOR='(.+?)'")
	regexMinor := regexp.MustCompile("LVM2_LV_KERNEL_MINOR='(.+?)'")
	for _, line := range strings.Split(stdout, "\n") {
		match := regexName.FindStringSubmatch(line)
		if len(match) != 2 || match[1] != logicalVolume {
			continue
		}

		match = regexMajor.FindStringSubmatch(line)
		if len(match) != 2 {
			return lvi, parseError
		}
		major, err := strconv.ParseUint(match[1], 10, 32)
		if err != nil {
			return lvi, parseError
		}

		match = regexMinor.FindStringSubmatch(line)
		if len(match) != 2 {
			return lvi, parseError
		}
		minor, err := strconv.ParseUint(match[1], 10, 32)
		if err != nil {
			return lvi, parseError
		}

		lvi.Name = logicalVolume
		lvi.KernelMajor = uint(major)
		lvi.KernelMinor = uint(minor)
		return lvi, nil
	}

	return lvi, fmt.Errorf("Failed to find logical volume: '%s'", name)
}

func getThinPoolNameForLogicalVolume(volumeGroup string, logicalVolume string) (string, error) {
	info, err := getInfoForLogicalVolume(volumeGroup, logicalVolume)
	if err != nil {
		return "", err
	}
	filename := fmt.Sprintf("/sys/dev/block/%d:%d/dm/name",
		info.KernelMajor, info.KernelMinor)
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("Error reading %s: %s", filename, err)
	}
	return strings.Trim(string(contents), "\n"), nil
}
<|endoftext|>


<commit_before>package suite

import (
	"errors"
	"fmt"
	"os"
	"sync"
	"time"

	"qa/runner"
	"qa/runner/server"
	"qa/tapjio"
)

type testEventUnion struct {
	testBegan *tapjio.TestStartedEvent
	testEvent *tapjio.TestEvent
	testError error
}

type testSuiteRunner struct {
	seed    int
	runners []runner.TestRunner
	count   int
	srv     *server.Server
}

func NewTestSuiteRunner(seed int,
	srv *server.Server,
	runners []runner.TestRunner) *testSuiteRunner {

	count := 0
	for _, runner := range runners {
		count += runner.TestCount()
	}

	return &testSuiteRunner{
		seed:    seed,
		runners: runners,
		count:   count,
		srv:     srv,
	}
}

func (self *testSuiteRunner) Run(
	workerEnvs []map[string]string,
	visitor tapjio.Visitor) (final tapjio.FinalEvent, err error) {

	numWorkers := len(workerEnvs)
	startTime := time.Now().UTC()

	suite := tapjio.NewSuiteEvent(startTime, self.count, self.seed)
	final = *tapjio.NewFinalEvent(suite)

	err = visitor.SuiteStarted(*suite)
	if err != nil {
		return
	}

	defer func() {
		final.Time = time.Now().UTC().Sub(startTime).Seconds()

		finalErr := visitor.SuiteFinished(final)
		if err == nil {
			err = finalErr
		}
	}()

	var testRunnerChan = make(chan runner.TestRunner, numWorkers)

	// Enqueue each testRunner on testRunnerChan
	go func() {
		// Sort runners by test count. This heuristic helps our workers avoid being idle
		// near the end of the run by running testRunners with the most tests first, avoiding
		// scenarios where the last testRunner we run has many tests, causing the entire test
		// run to drag on needlessly while other workers are idle.
		runner.By(func(r1, r2 *runner.TestRunner) bool { return (*r2).TestCount() < (*r1).TestCount() }).Sort(self.runners)

		for _, testRunner := range self.runners {
			testRunnerChan <- testRunner
		}
		close(testRunnerChan)
	}()

	var abort = false
	var traceChan = make(chan tapjio.TraceEvent, numWorkers)
	var testChan = make(chan testEventUnion, numWorkers)

	var awaitJobs sync.WaitGroup
	awaitJobs.Add(numWorkers)

	for _, workerEnv := range workerEnvs {
		env := workerEnv
		go func() {
			defer awaitJobs.Done()
			for testRunner := range testRunnerChan {
				if abort {
					for i := testRunner.TestCount(); i > 0; i-- {
						testChan <- testEventUnion{testError: errors.New("already aborted")}
					}
				} else {
					var awaitRun sync.WaitGroup
					awaitRun.Add(1)
					testRunner.Run(
						env,
						tapjio.DecodingCallbacks{
							OnTestBegin: func(test tapjio.TestStartedEvent) error {
								testChan <- testEventUnion{&test, nil, nil}
								return nil
							},
							OnTest: func(test tapjio.TestEvent) error {
								testChan <- testEventUnion{nil, &test, nil}
								return nil
							},
							OnTrace: func(trace tapjio.TraceEvent) error {
								traceChan <- trace
								return nil
							},
							OnEnd: func(reason error) error {
								awaitRun.Done()
								return nil
							},
						})
					awaitRun.Wait()
				}
			}
		}()
	}

	go func() {
		awaitJobs.Wait()
		close(traceChan)
	}()

	for traceChan != nil {
		select {
		case trace, ok := <-traceChan:
			if !ok {
				traceChan = nil
				continue
			}

			err = visitor.TraceEvent(trace)
			if err != nil {
				return
			}
		case testEventUnion := <-testChan:
			begin := testEventUnion.testBegan
			if begin != nil {
				err = visitor.TestStarted(*begin)
				if err != nil {
					return
				}
			} else {
				err = testEventUnion.testError
				if err == nil {
					test := testEventUnion.testEvent
					final.Counts.Increment(test.Status)

					err = visitor.TestFinished(*test)
					if err != nil {
						return
					}
				}

				if err != nil {
					abort = true
					final.Counts.Increment(tapjio.Error)
					fmt.Fprintln(os.Stderr, "Error:", err)
					return
				}
			}
		}
	}

	return
}
<commit_msg>Fix another race in worker result processing<commit_after>package suite

import (
	"errors"
	"fmt"
	"os"
	"sync"
	"time"

	"qa/runner"
	"qa/runner/server"
	"qa/tapjio"
)

type testEventUnion struct {
	trace     *tapjio.TraceEvent
	testBegan *tapjio.TestStartedEvent
	testEvent *tapjio.TestEvent
	testError error
}

type testSuiteRunner struct {
	seed    int
	runners []runner.TestRunner
	count   int
	srv     *server.Server
}

func NewTestSuiteRunner(seed int,
	srv *server.Server,
	runners []runner.TestRunner) *testSuiteRunner {

	count := 0
	for _, runner := range runners {
		count += runner.TestCount()
	}

	return &testSuiteRunner{
		seed:    seed,
		runners: runners,
		count:   count,
		srv:     srv,
	}
}

func (self *testSuiteRunner) Run(
	workerEnvs []map[string]string,
	visitor tapjio.Visitor) (final tapjio.FinalEvent, err error) {

	numWorkers := len(workerEnvs)
	startTime := time.Now().UTC()

	suite := tapjio.NewSuiteEvent(startTime, self.count, self.seed)
	final = *tapjio.NewFinalEvent(suite)

	err = visitor.SuiteStarted(*suite)
	if err != nil {
		return
	}

	defer func() {
		final.Time = time.Now().UTC().Sub(startTime).Seconds()

		finalErr := visitor.SuiteFinished(final)
		if err == nil {
			err = finalErr
		}
	}()

	var testRunnerChan = make(chan runner.TestRunner, numWorkers)

	// Enqueue each testRunner on testRunnerChan
	go func() {
		// Sort runners by test count. This heuristic helps our workers avoid being idle
		// near the end of the run by running testRunners with the most tests first, avoiding
		// scenarios where the last testRunner we run has many tests, causing the entire test
		// run to drag on needlessly while other workers are idle.
		runner.By(func(r1, r2 *runner.TestRunner) bool { return (*r2).TestCount() < (*r1).TestCount() }).Sort(self.runners)

		for _, testRunner := range self.runners {
			testRunnerChan <- testRunner
		}
		close(testRunnerChan)
	}()

	var abort = false
	var testChan = make(chan testEventUnion, numWorkers)

	var awaitJobs sync.WaitGroup
	awaitJobs.Add(numWorkers)

	for _, workerEnv := range workerEnvs {
		env := workerEnv
		go func() {
			defer awaitJobs.Done()
			for testRunner := range testRunnerChan {
				if abort {
					for i := testRunner.TestCount(); i > 0; i-- {
						testChan <- testEventUnion{testError: errors.New("already aborted")}
					}
				} else {
					var awaitRun sync.WaitGroup
					awaitRun.Add(1)
					testRunner.Run(
						env,
						tapjio.DecodingCallbacks{
							OnTestBegin: func(test tapjio.TestStartedEvent) error {
								testChan <- testEventUnion{nil, &test, nil, nil}
								return nil
							},
							OnTest: func(test tapjio.TestEvent) error {
								testChan <- testEventUnion{nil, nil, &test, nil}
								return nil
							},
							OnTrace: func(trace tapjio.TraceEvent) error {
								testChan <- testEventUnion{&trace, nil, nil, nil}
								return nil
							},
							OnEnd: func(reason error) error {
								awaitRun.Done()
								return nil
							},
						})
					awaitRun.Wait()
				}
			}
		}()
	}

	go func() {
		awaitJobs.Wait()
		close(testChan)
	}()

	for testEventUnion := range testChan {
		if testEventUnion.trace != nil {
			err = visitor.TraceEvent(*testEventUnion.trace)
			if err != nil {
				return
			}
			continue
		}

		begin := testEventUnion.testBegan
		if begin != nil {
			err = visitor.TestStarted(*begin)
			if err != nil {
				return
			}
			continue
		}

		err = testEventUnion.testError
		if err == nil {
			test := testEventUnion.testEvent
			final.Counts.Increment(test.Status)

			err = visitor.TestFinished(*test)
			if err != nil {
				return
			}
			continue
		}

		if err != nil {
			abort = true
			final.Counts.Increment(tapjio.Error)
			fmt.Fprintln(os.Stderr, "Error:", err)
			return
		}
	}

	return
}
<|endoftext|>


<commit_before>package featuremgmt

var (
	// Register each toggle here
	standardFeatureFlags = []FeatureFlag{
		{
			Name:        "trimDefaults",
			Description: "Use cue schema to remove values that will be applied automatically",
			State:       FeatureStateBeta,
		},
		{
			Name:        "envelopeEncryption",
			Description: "encrypt secrets",
			State:       FeatureStateBeta,
		},

		{
			Name:        "httpclientprovider_azure_auth",
			Description: "use http client for azure auth",
			State:       FeatureStateBeta,
		},
		{
			Name:            "service-accounts",
			Description:     "support service accounts",
			State:           FeatureStateBeta,
			RequiresLicense: true,
		},

		{
			Name:        "database_metrics",
			Description: "Add prometheus metrics for database tables",
			State:       FeatureStateStable,
		},
		{
			Name:        "dashboardPreviews",
			Description: "Create and show thumbnails for dashboard search results",
			State:       FeatureStateAlpha,
		},
		{
			Name:        "live-config",
			Description: "Save grafana live configuration in SQL tables",
			State:       FeatureStateAlpha,
		},
		{
			Name:        "live-pipeline",
			Description: "enable a generic live processing pipeline",
			State:       FeatureStateAlpha,
		},
		{
			Name:         "live-service-web-worker",
			Description:  "This will use a webworker thread to processes events rather than the main thread",
			State:        FeatureStateAlpha,
			FrontendOnly: true,
		},
		{
			Name:         "queryOverLive",
			Description:  "Use grafana live websocket to execute backend queries",
			State:        FeatureStateAlpha,
			FrontendOnly: true,
		},
		{
			Name:         "tempoSearch",
			Description:  "Enable searching in tempo datasources",
			State:        FeatureStateBeta,
			FrontendOnly: true,
		},
		{
			Name:        "tempoBackendSearch",
			Description: "Use backend for tempo search",
			State:       FeatureStateBeta,
		},
		{
			Name:         "tempoServiceGraph",
			Description:  "show service",
			State:        FeatureStateBeta,
			FrontendOnly: true,
		},
		{
			Name:         "fullRangeLogsVolume",
			Description:  "Show full range logs volume in explore",
			State:        FeatureStateBeta,
			FrontendOnly: true,
		},
		{
			Name:            "accesscontrol",
			Description:     "Support robust access control",
			State:           FeatureStateBeta,
			RequiresLicense: true,
		},
		{
			Name:        "prometheus_azure_auth",
			Description: "Use azure authentication for prometheus datasource",
			State:       FeatureStateBeta,
		},
		{
			Name:        "newNavigation",
			Description: "Try the next gen navigation model",
			State:       FeatureStateAlpha,
		},
		{
			Name:            "showFeatureFlagsInUI",
			Description:     "Show feature flags in the settings UI",
			State:           FeatureStateAlpha,
			RequiresDevMode: true,
		},
		{
			Name:        "disable_http_request_histogram",
			Description: "Do not create histograms for http requests",
			State:       FeatureStateAlpha,
		},
		{
			Name:            "validatedQueries",
			Description:     "only execute the query saved in a panel",
			State:           FeatureStateAlpha,
			RequiresDevMode: true,
		},
	}
)
<commit_msg>Accesscontrol: Feature does not need a license (#44517)<commit_after>package featuremgmt

var (
	// Register each toggle here
	standardFeatureFlags = []FeatureFlag{
		{
			Name:        "trimDefaults",
			Description: "Use cue schema to remove values that will be applied automatically",
			State:       FeatureStateBeta,
		},
		{
			Name:        "envelopeEncryption",
			Description: "encrypt secrets",
			State:       FeatureStateBeta,
		},

		{
			Name:        "httpclientprovider_azure_auth",
			Description: "use http client for azure auth",
			State:       FeatureStateBeta,
		},
		{
			Name:            "service-accounts",
			Description:     "support service accounts",
			State:           FeatureStateBeta,
			RequiresLicense: true,
		},

		{
			Name:        "database_metrics",
			Description: "Add prometheus metrics for database tables",
			State:       FeatureStateStable,
		},
		{
			Name:        "dashboardPreviews",
			Description: "Create and show thumbnails for dashboard search results",
			State:       FeatureStateAlpha,
		},
		{
			Name:        "live-config",
			Description: "Save grafana live configuration in SQL tables",
			State:       FeatureStateAlpha,
		},
		{
			Name:        "live-pipeline",
			Description: "enable a generic live processing pipeline",
			State:       FeatureStateAlpha,
		},
		{
			Name:         "live-service-web-worker",
			Description:  "This will use a webworker thread to processes events rather than the main thread",
			State:        FeatureStateAlpha,
			FrontendOnly: true,
		},
		{
			Name:         "queryOverLive",
			Description:  "Use grafana live websocket to execute backend queries",
			State:        FeatureStateAlpha,
			FrontendOnly: true,
		},
		{
			Name:         "tempoSearch",
			Description:  "Enable searching in tempo datasources",
			State:        FeatureStateBeta,
			FrontendOnly: true,
		},
		{
			Name:        "tempoBackendSearch",
			Description: "Use backend for tempo search",
			State:       FeatureStateBeta,
		},
		{
			Name:         "tempoServiceGraph",
			Description:  "show service",
			State:        FeatureStateBeta,
			FrontendOnly: true,
		},
		{
			Name:         "fullRangeLogsVolume",
			Description:  "Show full range logs volume in explore",
			State:        FeatureStateBeta,
			FrontendOnly: true,
		},
		{
			Name:        "accesscontrol",
			Description: "Support robust access control",
			State:       FeatureStateBeta,
		},
		{
			Name:        "prometheus_azure_auth",
			Description: "Use azure authentication for prometheus datasource",
			State:       FeatureStateBeta,
		},
		{
			Name:        "newNavigation",
			Description: "Try the next gen navigation model",
			State:       FeatureStateAlpha,
		},
		{
			Name:            "showFeatureFlagsInUI",
			Description:     "Show feature flags in the settings UI",
			State:           FeatureStateAlpha,
			RequiresDevMode: true,
		},
		{
			Name:        "disable_http_request_histogram",
			Description: "Do not create histograms for http requests",
			State:       FeatureStateAlpha,
		},
		{
			Name:            "validatedQueries",
			Description:     "only execute the query saved in a panel",
			State:           FeatureStateAlpha,
			RequiresDevMode: true,
		},
	}
)
<|endoftext|>


<commit_before>package rockredis

import (
	"bytes"

	"github.com/absolute8511/ZanRedisDB/common"
	"github.com/absolute8511/gorocksdb"
)

type Iterator interface {
	Next()
	Prev()
	Valid() bool
	Seek([]byte)
	SeekForPrev([]byte)
	SeekToFirst()
	SeekToLast()
	Close()
	RefKey() []byte
	Key() []byte
	RefValue() []byte
	Value() []byte
	NoTimestamp(vt byte)
}

type Range struct {
	Min  []byte
	Max  []byte
	Type uint8
}

type Limit struct {
	Offset int
	Count  int
}

type DBIterator struct {
	*gorocksdb.Iterator
	snap         *gorocksdb.Snapshot
	ro           *gorocksdb.ReadOptions
	db           *gorocksdb.DB
	removeTsType byte
}

func NewDBIterator(db *gorocksdb.DB, withSnap bool) (*DBIterator, error) {
	db.RLock()
	dbit := &DBIterator{
		db: db,
	}
	readOpts := gorocksdb.NewDefaultReadOptions()
	readOpts.SetFillCache(false)
	readOpts.SetVerifyChecksums(false)
	dbit.ro = readOpts
	var err error
	if withSnap {
		dbit.snap, err = db.NewSnapshot()
		if err != nil {
			dbit.Close()
			return nil, err
		}
		readOpts.SetSnapshot(dbit.snap)
	}
	dbit.Iterator, err = db.NewIterator(readOpts)
	if err != nil {
		dbit.Close()
		return nil, err
	}
	return dbit, nil
}

func (it *DBIterator) RefKey() []byte {
	return it.Iterator.Key().Data()
}

func (it *DBIterator) Key() []byte {
	return it.Iterator.Key().Bytes()
}

func (it *DBIterator) RefValue() []byte {
	v := it.Iterator.Value().Data()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) Value() []byte {
	v := it.Iterator.Value().Bytes()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) NoTimestamp(vt byte) {
	it.removeTsType = vt
}

func (it *DBIterator) Close() {
	if it.Iterator != nil {
		it.Iterator.Close()
	}
	if it.ro != nil {
		it.ro.Destroy()
	}
	if it.snap != nil {
		it.snap.Release()
	}
	it.db.RUnlock()
}

func NewDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	dbit, err := NewDBIterator(db, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewSnapshotDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	dbit, err := NewDBIterator(db, true)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	dbit, err := NewDBIterator(db, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

func NewSnapshotDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	dbit, err := NewDBIterator(db, true)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

type RangeLimitedIterator struct {
	Iterator
	l Limit
	r Range
	// maybe step should not auto increase, we need count for actually element
	step    int
	reverse bool
}

func (it *RangeLimitedIterator) Valid() bool {
	if it.l.Offset < 0 {
		return false
	}
	if it.l.Count >= 0 && it.step >= it.l.Count {
		return false
	}
	if !it.Iterator.Valid() {
		return false
	}

	if !it.reverse {
		if it.r.Max != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Max)
			if it.r.Type&common.RangeROpen > 0 {
				return !(r >= 0)
			} else {
				return !(r > 0)
			}
		}
	} else {
		if it.r.Min != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Min)
			if it.r.Type&common.RangeLOpen > 0 {
				return !(r <= 0)
			} else {
				return !(r < 0)
			}
		}
	}
	return true
}

func (it *RangeLimitedIterator) Next() {
	it.step++
	if !it.reverse {
		it.Iterator.Next()
	} else {
		it.Iterator.Prev()
	}
}

func NewRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, false)
}
func NewRevRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, true)
}
func NewRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, false)
}
func NewRevRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, true)
}
func rangeLimitIterator(i Iterator, r *Range, l *Limit, reverse bool) *RangeLimitedIterator {
	it := &RangeLimitedIterator{
		Iterator: i,
		l:        *l,
		r:        *r,
		reverse:  reverse,
		step:     0,
	}
	if l.Offset < 0 {
		return it
	}
	if !reverse {
		if r.Min == nil {
			it.Iterator.SeekToFirst()
		} else {
			it.Iterator.Seek(r.Min)
			if r.Type&common.RangeLOpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Min) {
					it.Iterator.Next()
				}
			}
		}
	} else {
		if r.Max == nil {
			it.Iterator.SeekToLast()
		} else {
			it.Iterator.SeekForPrev(r.Max)
			if !it.Iterator.Valid() {
				it.Iterator.SeekToLast()
				if it.Iterator.Valid() && bytes.Compare(it.Iterator.RefKey(), r.Max) == 1 {
					dbLog.Infof("iterator seek to last key %v should not great than seek to max %v", it.Iterator.RefKey(), r.Max)
				}
			}
			if r.Type&common.RangeROpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Max) {
					it.Iterator.Prev()
				}
			}
		}
	}
	for i := 0; i < l.Offset; i++ {
		if it.Iterator.Valid() {
			if !it.reverse {
				it.Iterator.Next()
			} else {
				it.Iterator.Prev()
			}
		}
	}
	return it
}
<commit_msg>optimize the iterator use read options for bound<commit_after>package rockredis

import (
	"bytes"

	"github.com/absolute8511/ZanRedisDB/common"
	"github.com/absolute8511/gorocksdb"
)

type Iterator interface {
	Next()
	Prev()
	Valid() bool
	Seek([]byte)
	SeekForPrev([]byte)
	SeekToFirst()
	SeekToLast()
	Close()
	RefKey() []byte
	Key() []byte
	RefValue() []byte
	Value() []byte
	NoTimestamp(vt byte)
}

type Range struct {
	Min  []byte
	Max  []byte
	Type uint8
}

type Limit struct {
	Offset int
	Count  int
}

type DBIterator struct {
	*gorocksdb.Iterator
	snap         *gorocksdb.Snapshot
	ro           *gorocksdb.ReadOptions
	db           *gorocksdb.DB
	removeTsType byte
}

// low_bound is inclusive
// upper bound is exclusive
func NewDBIterator(db *gorocksdb.DB, withSnap bool, prefixSame bool, lowbound []byte, upbound []byte, ignoreDel bool) (*DBIterator, error) {
	db.RLock()
	dbit := &DBIterator{
		db: db,
	}
	readOpts := gorocksdb.NewDefaultReadOptions()
	readOpts.SetFillCache(false)
	readOpts.SetVerifyChecksums(false)
	if prefixSame {
		readOpts.SetPrefixSameAsStart(true)
	}
	if lowbound != nil {
		readOpts.SetIterLowerBound(lowbound)
	}
	if upbound != nil {
		readOpts.SetIterUpperBound(upbound)
	}
	if ignoreDel {
		// may iterator some deleted keys still not compacted.
		readOpts.SetIgnoreRangeDeletions(true)
	}
	dbit.ro = readOpts
	var err error
	if withSnap {
		dbit.snap, err = db.NewSnapshot()
		if err != nil {
			dbit.Close()
			return nil, err
		}
		readOpts.SetSnapshot(dbit.snap)
	}
	dbit.Iterator, err = db.NewIterator(readOpts)
	if err != nil {
		dbit.Close()
		return nil, err
	}
	return dbit, nil
}

func (it *DBIterator) RefKey() []byte {
	return it.Iterator.Key().Data()
}

func (it *DBIterator) Key() []byte {
	return it.Iterator.Key().Bytes()
}

func (it *DBIterator) RefValue() []byte {
	v := it.Iterator.Value().Data()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) Value() []byte {
	v := it.Iterator.Value().Bytes()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) NoTimestamp(vt byte) {
	it.removeTsType = vt
}

func (it *DBIterator) Close() {
	if it.Iterator != nil {
		it.Iterator.Close()
	}
	if it.ro != nil {
		it.ro.Destroy()
	}
	if it.snap != nil {
		it.snap.Release()
	}
	it.db.RUnlock()
}

// note: all the iterator use the prefix iterator flag. Which means it may skip the keys for different table
// prefix.
func NewDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}

	dbit, err := NewDBIterator(db, false, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewSnapshotDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	dbit, err := NewDBIterator(db, true, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	dbit, err := NewDBIterator(db, false, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

func NewSnapshotDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	dbit, err := NewDBIterator(db, true, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

type RangeLimitedIterator struct {
	Iterator
	l Limit
	r Range
	// maybe step should not auto increase, we need count for actually element
	step    int
	reverse bool
}

func (it *RangeLimitedIterator) Valid() bool {
	if it.l.Offset < 0 {
		return false
	}
	if it.l.Count >= 0 && it.step >= it.l.Count {
		return false
	}
	if !it.Iterator.Valid() {
		return false
	}

	if !it.reverse {
		if it.r.Max != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Max)
			if it.r.Type&common.RangeROpen > 0 {
				return !(r >= 0)
			} else {
				return !(r > 0)
			}
		}
	} else {
		if it.r.Min != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Min)
			if it.r.Type&common.RangeLOpen > 0 {
				return !(r <= 0)
			} else {
				return !(r < 0)
			}
		}
	}
	return true
}

func (it *RangeLimitedIterator) Next() {
	it.step++
	if !it.reverse {
		it.Iterator.Next()
	} else {
		it.Iterator.Prev()
	}
}

func NewRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, false)
}
func NewRevRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, true)
}
func NewRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, false)
}
func NewRevRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, true)
}
func rangeLimitIterator(i Iterator, r *Range, l *Limit, reverse bool) *RangeLimitedIterator {
	it := &RangeLimitedIterator{
		Iterator: i,
		l:        *l,
		r:        *r,
		reverse:  reverse,
		step:     0,
	}
	if l.Offset < 0 {
		return it
	}
	if !reverse {
		if r.Min == nil {
			it.Iterator.SeekToFirst()
		} else {
			it.Iterator.Seek(r.Min)
			if r.Type&common.RangeLOpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Min) {
					it.Iterator.Next()
				}
			}
		}
	} else {
		if r.Max == nil {
			it.Iterator.SeekToLast()
		} else {
			it.Iterator.SeekForPrev(r.Max)
			if !it.Iterator.Valid() {
				it.Iterator.SeekToLast()
				if it.Iterator.Valid() && bytes.Compare(it.Iterator.RefKey(), r.Max) == 1 {
					dbLog.Infof("iterator seek to last key %v should not great than seek to max %v", it.Iterator.RefKey(), r.Max)
				}
			}
			if r.Type&common.RangeROpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Max) {
					it.Iterator.Prev()
				}
			}
		}
	}
	for i := 0; i < l.Offset; i++ {
		if it.Iterator.Valid() {
			if !it.reverse {
				it.Iterator.Next()
			} else {
				it.Iterator.Prev()
			}
		}
	}
	return it
}
<|endoftext|>


<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

// Package merge contains libraries for merging Resources and Patches
package filters

import (
	"sigs.k8s.io/kustomize/kyaml/yaml"
	"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
)

// GrepFilter merges Resources with the Group/Version/Kind/Namespace/Name together using
// a 2-way merge strategy.
//
// - Fields set to null in the source will be cleared from the destination
// - Fields with matching keys will be merged recursively
// - Lists with an associative key (e.g. name) will have their elements merged using the key
// - List without an associative key will have the dest list replaced by the source list
type MergeFilter struct {
	Reverse bool
}

type mergeKey struct {
	apiVersion string
	kind       string
	namespace  string
	name       string
}

// GrepFilter implements kio.GrepFilter by merge Resources with the same G/V/K/NS/N
func (c MergeFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
	// invert the merge precedence
	if c.Reverse {
		for i, j := 0, len(input)-1; i < j; i, j = i+1, j-1 {
			input[i], input[j] = input[j], input[i]
		}
	}

	// index the Resources by G/V/K/NS/N
	index := map[mergeKey][]*yaml.RNode{}
	for i := range input {
		meta, err := input[i].GetMeta()
		if err != nil {
			return nil, err
		}
		key := mergeKey{
			apiVersion: meta.APIVersion,
			kind:       meta.Kind,
			namespace:  meta.Namespace,
			name:       meta.Name,
		}
		index[key] = append(index[key], input[i])
	}

	// merge each of the G/V/K/NS/N lists
	var output []*yaml.RNode
	var err error
	for k := range index {
		var merged *yaml.RNode
		resources := index[k]
		for i := range resources {
			patch := resources[i]
			if merged == nil {
				// first resources, don't merge it
				merged = resources[i]
			} else {
				merged, err = merge2.Merge(patch, merged)
				if err != nil {
					return nil, err
				}
			}
		}
		output = append(output, merged)
	}
	return output, nil
}
<commit_msg>Fix godocs on MergeFilter<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

// Package merge contains libraries for merging Resources and Patches
package filters

import (
	"sigs.k8s.io/kustomize/kyaml/kio"
	"sigs.k8s.io/kustomize/kyaml/yaml"
	"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
)

// MergeFilter merges Resources with the Group/Version/Kind/Namespace/Name together using
// a 2-way merge strategy.
//
// - Fields set to null in the source will be cleared from the destination
// - Fields with matching keys will be merged recursively
// - Lists with an associative key (e.g. name) will have their elements merged using the key
// - List without an associative key will have the dest list replaced by the source list
type MergeFilter struct {
	Reverse bool
}

var _ kio.Filter = MergeFilter{}

type mergeKey struct {
	apiVersion string
	kind       string
	namespace  string
	name       string
}

// MergeFilter implements kio.Filter by merging Resources with the same G/V/K/NS/N
func (c MergeFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
	// invert the merge precedence
	if c.Reverse {
		for i, j := 0, len(input)-1; i < j; i, j = i+1, j-1 {
			input[i], input[j] = input[j], input[i]
		}
	}

	// index the Resources by G/V/K/NS/N
	index := map[mergeKey][]*yaml.RNode{}
	for i := range input {
		meta, err := input[i].GetMeta()
		if err != nil {
			return nil, err
		}
		key := mergeKey{
			apiVersion: meta.APIVersion,
			kind:       meta.Kind,
			namespace:  meta.Namespace,
			name:       meta.Name,
		}
		index[key] = append(index[key], input[i])
	}

	// merge each of the G/V/K/NS/N lists
	var output []*yaml.RNode
	var err error
	for k := range index {
		var merged *yaml.RNode
		resources := index[k]
		for i := range resources {
			patch := resources[i]
			if merged == nil {
				// first resources, don't merge it
				merged = resources[i]
			} else {
				merged, err = merge2.Merge(patch, merged)
				if err != nil {
					return nil, err
				}
			}
		}
		output = append(output, merged)
	}
	return output, nil
}
<|endoftext|>


<commit_before>package runtime

import (
	"fmt"
	E "github.com/ionous/sashimi/event"
	G "github.com/ionous/sashimi/game"
	M "github.com/ionous/sashimi/model"
	"github.com/ionous/sashimi/util/ident"
	"strings"
)

//
// ObjectAdapter wraps GameObject(s) for user script callbacks.
// WARNING: for users to test object equality, the ObjectAdapter must be comparable;
// it can't implement the interface as a pointer, and it cant have any cached values.
//
type ObjectAdapter struct {
	game *Game // for console, Go(), and relations
	gobj *GameObject
}

//
// String helps debugging.
//
func (oa ObjectAdapter) String() string {
	return oa.gobj.Id().String()
}

//
// Id uniquely identifies the object.
//
func (oa ObjectAdapter) Id() ident.Id {
	return oa.gobj.Id()
}

//
func (oa ObjectAdapter) Remove() {
	delete(oa.game.Objects, oa.gobj.Id())
}

//
// Name of the object.
//
// func (oa ObjectAdapter) Name() string {
// 	return oa.gobj.inst.Name()
// }

//
// Exists always returns true for ObjectAdapter; see also NullObject which always returns false.
//
func (oa ObjectAdapter) Exists() bool {
	return true
}

//
// Class returns true when this object is compatible with ( based on ) the named class. ( parent or other ancestor )
//
func (oa ObjectAdapter) Class(class string) (okay bool) {
	if cls, ok := oa.game.Model.Classes.FindClassBySingular(class); ok {
		okay = oa.gobj.Class().CompatibleWith(cls.Id())
	}
	return okay
}

//
// Is this object in the passed state?
//
func (oa ObjectAdapter) Is(state string) (ret bool) {
	if prop, index, ok := oa.gobj.Class().PropertyByChoice(state); !ok {
		oa.logError(fmt.Errorf("is: no such choice '%s'.'%s'", oa, state))
	} else {
		testChoice, _ := prop.IndexToChoice(index)
		currChoice := oa.gobj.Value(prop.Id())
		ret = currChoice == testChoice
	}
	return ret
}

//
// IsNow changes the state of an object.
//
func (oa ObjectAdapter) IsNow(state string) {
	if prop, index, ok := oa.gobj.Class().PropertyByChoice(state); !ok {
		oa.logError(fmt.Errorf("IsNow: no such choice '%s'.'%s'", oa, state))
	} else {
		// get the current choice from the implied property slot
		if currChoice, ok := oa.gobj.Value(prop.Id()).(ident.Id); !ok {
			err := TypeMismatch(oa.gobj.Id().String(), prop.Id().String())
			oa.logError(err)
		} else {
			newChoice, _ := prop.IndexToChoice(index)
			if currChoice != newChoice {
				oa.gobj.removeDirect(currChoice)        // delete the old choice's boolean,
				oa.gobj.setDirect(newChoice, true)      // and set the new
				oa.gobj.setDirect(prop.Id(), newChoice) // // set the property slot to the new choice
				oa.game.Properties.Notify(oa.gobj.Id(), prop.Id(), currChoice, newChoice)
			}
		}
	}
}

//
// Num value of the named property.
//
func (oa ObjectAdapter) Num(prop string) (ret float32) {
	id := M.MakeStringId(prop)
	if val, ok := oa.gobj.Value(id).(float32); !ok {
		oa.logError(TypeMismatch(prop, "get num"))
	} else {
		ret = val
	}
	return ret
}

//
// SetNum changes the value of an existing number property.
//
func (oa ObjectAdapter) SetNum(prop string, value float32) {
	id := M.MakeStringId(prop)
	if old, ok := oa.gobj.SetValue(id, value); !ok {
		oa.logError(TypeMismatch(prop, "set num"))
	} else {
		oa.game.Properties.Notify(oa.gobj.Id(), id, old, value)
	}
}

//
// Text value of the named property ( expanding any templated text. )
// ( interestingly, inform seems to error when trying to store or manipulate templated text. )
//
func (oa ObjectAdapter) Text(prop string) (ret string) {
	id := M.MakeStringId(prop)
	// is oa text stored as a template?
	if temp, ok := oa.gobj.temps[id.String()]; ok {
		if s, e := runTemplate(temp, oa.gobj.vals); e != nil {
			oa.logError(e)
		} else {
			ret = s
		}
	} else if val, ok := oa.gobj.Value(id).(string); !ok {
		oa.logError(TypeMismatch(prop, "get text"))
	} else {
		ret = val
	}
	return ret
}

//
// SetText changes the value of an existing text property.
//
func (oa ObjectAdapter) SetText(prop string, text string) {
	id := M.MakeStringId(prop)
	if e := oa.gobj.temps.New(id.String(), text); e != nil {
		oa.logError(e)
	} else if old, ok := oa.gobj.SetValue(id, text); !ok {
		oa.logError(TypeMismatch(prop, "set text"))
	} else {
		oa.game.Properties.Notify(oa.gobj.Id(), id, old, text)
	}
}

//
// Object returns a related object.
//
func (oa ObjectAdapter) Object(prop string) (ret G.IObject) {
	// TBD: should these be logged? its sure nice to have be able to test objects generically for properties
	var res ident.Id
	if p, ok := oa.gobj.Class().FindProperty(prop); ok {
		switch p := p.(type) {
		case *M.PointerProperty:
			if val, ok := oa.gobj.Value(p.Id()).(ident.Id); ok {
				res = val
			}
		case *M.RelativeProperty:
			// TBD: can the relative property changes automatically reflect into the value table
			// ex. on event?
			if rel, ok := oa.gobj.Value(p.Id()).(RelativeValue); ok {
				if p.ToMany() {
					oa.logError(fmt.Errorf("object requested, but relation is list"))
				} else {
					list := rel.List()
					if len(list) != 0 {
						res = ident.Id(list[0])
					}
				}
			}
		}
	}
	return NewObjectAdapter(oa.game, oa.game.Objects[res])
}

//
// Set changes an object relationship.
//
func (oa ObjectAdapter) Set(prop string, object G.IObject) {
	if p, ok := oa.gobj.Class().FindProperty(prop); ok {
		switch p := p.(type) {
		default:
			oa.logError(TypeMismatch(oa.String(), prop))
		case *M.PointerProperty:
			set := false
			if other, ok := object.(ObjectAdapter); !ok {
				oa.gobj.SetValue(p.Id(), ident.Id(""))
				set = true
			} else {
				oa.gobj.SetValue(p.Id(), other.gobj.Id())
				set = true
			}
			if !set {
				oa.logError(fmt.Errorf("couldnt set value for prop %s", prop))
			}
		case *M.RelativeProperty:
			if rel, ok := oa.gobj.Value(p.Id()).(RelativeValue); ok {

				// if the referenced object doesnt exist, we take it to mean they are clearing the reference.
				if other, ok := object.(ObjectAdapter); !ok {
					if removed, e := rel.ClearReference(); e != nil {
						oa.logError(e)
					} else {
						oa.game.Properties.Notify(oa.gobj.Id(), p.Id(), removed, ident.Empty())
					}
				} else {
					// FIX? the impedence b/t IObject and Reference is annoying.
					other := other.gobj.Id()
					if ref, ok := oa.game.Model.Instances[other]; !ok {
						oa.logError(fmt.Errorf("Set: couldnt find object names %s", other))
					} else if removed, e := rel.SetReference(ref); e != nil {
						oa.logError(e)
					} else {
						// removed is probably a single object
						oa.game.Properties.Notify(oa.gobj.Id(), p.Id(), removed, other)
					}
				}
			}
		}
	}
}

//
// ObjectList returns a list of related objects.
//
func (oa ObjectAdapter) ObjectList(prop string) (ret []G.IObject) {
	if p, ok := oa.gobj.Class().FindProperty(prop); ok {
		switch p := p.(type) {
		default:
			oa.logError(TypeMismatch(oa.String(), prop))
		case *M.RelativeProperty:
			if rel, ok := oa.gobj.Value(p.Id()).(RelativeValue); ok {
				list := rel.List()
				ret = make([]G.IObject, len(list))
				for i, objId := range list {
					ret[i] = NewObjectAdapter(oa.game, oa.game.Objects[objId])
				}
			}
		}
	}
	return ret
}

//
// Says provides this object with a voice.
//
func (oa ObjectAdapter) Says(text string) {
	// FIX: share some template love with GameEventAdapter.Say()
	lines := strings.Split(text, "\n")
	oa.game.output.ActorSays(oa.gobj, lines)
}

//
// Go sends all the events associated with the named action,
// and runs the default action if appropriate.
// @see also: Game.ProcessEventQueue
//
func (oa ObjectAdapter) Go(act string, objects ...G.IObject) {
	if action, ok := oa.game.Model.Actions.FindActionByName(act); !ok {
		e := fmt.Errorf("unknown action for Go %s", act)
		oa.logError(e)
	} else {
		// FIX, ugly: we need the props, even tho we already have the objects...
		nouns := make([]ident.Id, len(objects)+1)
		nouns[0] = oa.Id()
		for i, o := range objects {
			nouns[i+1] = o.Id()
		}
		if act, e := oa.game.newRuntimeAction(action, nouns...); e != nil {
			oa.logError(e)
		} else {
			tgt := ObjectTarget{oa.game, oa.gobj}
			msg := &E.Message{Name: action.Event(), Data: act}
			if e := oa.game.frame.SendMessage(tgt, msg); e != nil {
				oa.logError(e)
			}
		}
	}
}

//
//
//
func (oa ObjectAdapter) logError(err error) (hadError bool) {
	if err != nil {
		oa.game.log.Output(4, fmt.Sprint("!!!Error:", err.Error()))
		hadError = true
	}
	return hadError
}
<commit_msg>consolidate per-object property response into a single notify<commit_after>package runtime

import (
	"fmt"
	E "github.com/ionous/sashimi/event"
	G "github.com/ionous/sashimi/game"
	M "github.com/ionous/sashimi/model"
	"github.com/ionous/sashimi/util/ident"
	"strings"
)

//
// ObjectAdapter wraps GameObject(s) for user script callbacks.
// WARNING: for users to test object equality, the ObjectAdapter must be comparable;
// it can't implement the interface as a pointer, and it cant have any cached values.
//
type ObjectAdapter struct {
	game *Game // for console, Go(), and relations
	gobj *GameObject
}

//
// String helps debugging.
//
func (oa ObjectAdapter) String() string {
	return oa.gobj.Id().String()
}

//
// Id uniquely identifies the object.
//
func (oa ObjectAdapter) Id() ident.Id {
	return oa.gobj.Id()
}

//
func (oa ObjectAdapter) Remove() {
	delete(oa.game.Objects, oa.gobj.Id())
}

//
// Name of the object.
//
// func (oa ObjectAdapter) Name() string {
// 	return oa.gobj.inst.Name()
// }

//
// Exists always returns true for ObjectAdapter; see also NullObject which always returns false.
//
func (oa ObjectAdapter) Exists() bool {
	return true
}

//
// Class returns true when this object is compatible with ( based on ) the named class. ( parent or other ancestor )
//
func (oa ObjectAdapter) Class(class string) (okay bool) {
	if cls, ok := oa.game.Model.Classes.FindClassBySingular(class); ok {
		okay = oa.gobj.Class().CompatibleWith(cls.Id())
	}
	return okay
}

//
// Is this object in the passed state?
//
func (oa ObjectAdapter) Is(state string) (ret bool) {
	if prop, index, ok := oa.gobj.Class().PropertyByChoice(state); !ok {
		oa.logError(fmt.Errorf("is: no such choice '%s'.'%s'", oa, state))
	} else {
		testChoice, _ := prop.IndexToChoice(index)
		currChoice := oa.gobj.Value(prop.Id())
		ret = currChoice == testChoice
	}
	return ret
}

//
// IsNow changes the state of an object.
//
func (oa ObjectAdapter) IsNow(state string) {
	if prop, index, ok := oa.gobj.Class().PropertyByChoice(state); !ok {
		oa.logError(fmt.Errorf("IsNow: no such choice '%s'.'%s'", oa, state))
	} else {
		// get the current choice from the implied property slot
		if currChoice, ok := oa.gobj.Value(prop.Id()).(ident.Id); !ok {
			err := TypeMismatch(oa.gobj.Id().String(), prop.Id().String())
			oa.logError(err)
		} else {
			newChoice, _ := prop.IndexToChoice(index)
			if currChoice != newChoice {
				oa.gobj.removeDirect(currChoice)        // delete the old choice's boolean,
				oa.gobj.setDirect(newChoice, true)      // and set the new
				oa.gobj.setDirect(prop.Id(), newChoice) // // set the property slot to the new choice
				oa.game.Properties.Notify(oa.gobj.Id(), prop.Id(), currChoice, newChoice)
			}
		}
	}
}

//
// Num value of the named property.
//
func (oa ObjectAdapter) Num(prop string) (ret float32) {
	id := M.MakeStringId(prop)
	if val, ok := oa.gobj.Value(id).(float32); !ok {
		oa.logError(TypeMismatch(prop, "get num"))
	} else {
		ret = val
	}
	return ret
}

//
// SetNum changes the value of an existing number property.
//
func (oa ObjectAdapter) SetNum(prop string, value float32) {
	id := M.MakeStringId(prop)
	if old, ok := oa.gobj.SetValue(id, value); !ok {
		oa.logError(TypeMismatch(prop, "set num"))
	} else {
		oa.game.Properties.Notify(oa.gobj.Id(), id, old, value)
	}
}

//
// Text value of the named property ( expanding any templated text. )
// ( interestingly, inform seems to error when trying to store or manipulate templated text. )
//
func (oa ObjectAdapter) Text(prop string) (ret string) {
	id := M.MakeStringId(prop)
	// is oa text stored as a template?
	if temp, ok := oa.gobj.temps[id.String()]; ok {
		if s, e := runTemplate(temp, oa.gobj.vals); e != nil {
			oa.logError(e)
		} else {
			ret = s
		}
	} else if val, ok := oa.gobj.Value(id).(string); !ok {
		oa.logError(TypeMismatch(prop, "get text"))
	} else {
		ret = val
	}
	return ret
}

//
// SetText changes the value of an existing text property.
//
func (oa ObjectAdapter) SetText(prop string, text string) {
	id := M.MakeStringId(prop)
	if e := oa.gobj.temps.New(id.String(), text); e != nil {
		oa.logError(e)
	} else if old, ok := oa.gobj.SetValue(id, text); !ok {
		oa.logError(TypeMismatch(prop, "set text"))
	} else {
		oa.game.Properties.Notify(oa.gobj.Id(), id, old, text)
	}
}

//
// Object returns a related object.
//
func (oa ObjectAdapter) Object(prop string) (ret G.IObject) {
	// TBD: should these be logged? its sure nice to have be able to test objects generically for properties
	var res ident.Id
	if p, ok := oa.gobj.Class().FindProperty(prop); ok {
		switch p := p.(type) {
		case *M.PointerProperty:
			if val, ok := oa.gobj.Value(p.Id()).(ident.Id); ok {
				res = val
			}
		case *M.RelativeProperty:
			// TBD: can the relative property changes automatically reflect into the value table
			// ex. on event?
			if rel, ok := oa.gobj.Value(p.Id()).(RelativeValue); ok {
				if p.ToMany() {
					oa.logError(fmt.Errorf("object requested, but relation is list"))
				} else {
					list := rel.List()
					if len(list) != 0 {
						res = ident.Id(list[0])
					}
				}
			}
		}
	}
	return NewObjectAdapter(oa.game, oa.game.Objects[res])
}

//
// Set changes an object relationship.
//
func (oa ObjectAdapter) Set(prop string, object G.IObject) {
	if p, ok := oa.gobj.Class().FindProperty(prop); ok {
		switch p := p.(type) {
		default:
			oa.logError(TypeMismatch(oa.String(), prop))
		case *M.PointerProperty:
			set := false
			if other, ok := object.(ObjectAdapter); !ok {
				oa.gobj.SetValue(p.Id(), ident.Id(""))
				set = true
			} else {
				oa.gobj.SetValue(p.Id(), other.gobj.Id())
				set = true
			}
			if !set {
				oa.logError(fmt.Errorf("couldnt set value for prop %s", prop))
			}
		case *M.RelativeProperty:
			if rel, ok := oa.gobj.Value(p.Id()).(RelativeValue); ok {
				var prev, next ident.Id
				var err error

				// if the new object doesnt exist, we take it to mean they are clearing the reference.
				if other, ok := object.(ObjectAdapter); !ok {
					if removed, e := rel.ClearReference(); e != nil {
						err = e
					} else {
						prev = removed
					}
				} else {
					// FIX? the impedence b/t IObject and Reference is annoying.
					other := other.gobj.Id()
					if ref, ok := oa.game.Model.Instances[other]; !ok {
						err = fmt.Errorf("Set: couldnt find object names %s", other)
					} else if removed, e := rel.SetReference(ref); e != nil {
						err = e
					} else {
						// removed is probably? a single object
						prev = removed
						next = other
					}
				}
				if err != nil {
					oa.logError(err)
				} else {
					oa.game.Properties.Notify(oa.gobj.Id(), p.Id(), prev, next)
				}
			}
		}
	}
}

//
// ObjectList returns a list of related objects.
//
func (oa ObjectAdapter) ObjectList(prop string) (ret []G.IObject) {
	if p, ok := oa.gobj.Class().FindProperty(prop); ok {
		switch p := p.(type) {
		default:
			oa.logError(TypeMismatch(oa.String(), prop))
		case *M.RelativeProperty:
			if rel, ok := oa.gobj.Value(p.Id()).(RelativeValue); ok {
				list := rel.List()
				ret = make([]G.IObject, len(list))
				for i, objId := range list {
					ret[i] = NewObjectAdapter(oa.game, oa.game.Objects[objId])
				}
			}
		}
	}
	return ret
}

//
// Says provides this object with a voice.
//
func (oa ObjectAdapter) Says(text string) {
	// FIX: share some template love with GameEventAdapter.Say()
	lines := strings.Split(text, "\n")
	oa.game.output.ActorSays(oa.gobj, lines)
}

//
// Go sends all the events associated with the named action,
// and runs the default action if appropriate.
// @see also: Game.ProcessEventQueue
//
func (oa ObjectAdapter) Go(act string, objects ...G.IObject) {
	if action, ok := oa.game.Model.Actions.FindActionByName(act); !ok {
		e := fmt.Errorf("unknown action for Go %s", act)
		oa.logError(e)
	} else {
		// FIX, ugly: we need the props, even tho we already have the objects...
		nouns := make([]ident.Id, len(objects)+1)
		nouns[0] = oa.Id()
		for i, o := range objects {
			nouns[i+1] = o.Id()
		}
		if act, e := oa.game.newRuntimeAction(action, nouns...); e != nil {
			oa.logError(e)
		} else {
			tgt := ObjectTarget{oa.game, oa.gobj}
			msg := &E.Message{Name: action.Event(), Data: act}
			if e := oa.game.frame.SendMessage(tgt, msg); e != nil {
				oa.logError(e)
			}
		}
	}
}

//
//
//
func (oa ObjectAdapter) logError(err error) (hadError bool) {
	if err != nil {
		oa.game.log.Output(4, fmt.Sprint("!!!Error:", err.Error()))
		hadError = true
	}
	return hadError
}
<|endoftext|>


<commit_before>package procspy

// /proc-based implementation.

import (
	"bytes"
	"fmt"
	"path/filepath"
	"strconv"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/armon/go-metrics"

	"github.com/weaveworks/common/fs"
	"github.com/weaveworks/scope/common/marshal"
	"github.com/weaveworks/scope/probe/process"
)

var (
	procRoot               = "/proc"
	namespaceKey           = []string{"procspy", "namespaces"}
	netNamespacePathSuffix = ""
)

type pidWalker struct {
	walker      process.Walker
	tickc       <-chan time.Time // Rate-limit clock. Sets the pace when traversing namespaces and /proc/PID/fd/* files.
	stopc       chan struct{}    // Abort walk
	fdBlockSize uint64           // Maximum number of /proc/PID/fd/* files to stat() per tick
}

func newPidWalker(walker process.Walker, tickc <-chan time.Time, fdBlockSize uint64) pidWalker {
	w := pidWalker{
		walker:      walker,
		tickc:       tickc,
		fdBlockSize: fdBlockSize,
		stopc:       make(chan struct{}),
	}
	return w
}

// SetProcRoot sets the location of the proc filesystem.
func SetProcRoot(root string) {
	procRoot = root
}

func getKernelVersion() (major, minor int, err error) {
	var u syscall.Utsname
	if err = syscall.Uname(&u); err != nil {
		return
	}

	// Kernel versions are not always a semver, so we have to do minimal parsing.
	release := marshal.FromUtsname(u.Release)
	if n, err := fmt.Sscanf(release, "%d.%d", &major, &minor); err != nil || n != 2 {
		return 0, 0, fmt.Errorf("Malformed version: %s", release)
	}
	return
}

func getNetNamespacePathSuffix() string {
	// With Linux 3.8 or later the network namespace of a process can be
	// determined by the inode of /proc/PID/net/ns.  Before that, Any file
	// under /proc/PID/net/ could be used but it's not documented and may
	// break in newer kernels.
	const (
		post38Path = "ns/net"
		pre38Path  = "net/dev"
	)

	if netNamespacePathSuffix != "" {
		return netNamespacePathSuffix
	}

	major, minor, err := getKernelVersion()
	if err != nil {
		log.Errorf("getNamespacePathSuffix: cannot get kernel version: %s", err)
		netNamespacePathSuffix = post38Path
		return netNamespacePathSuffix
	}

	if major < 3 || (major == 3 && minor < 8) {
		netNamespacePathSuffix = pre38Path
	} else {
		netNamespacePathSuffix = post38Path
	}
	return netNamespacePathSuffix
}

// Read the connections for a group of processes living in the same namespace,
// which are found (identically) in /proc/PID/net/tcp{,6} for any of the
// processes.
func readProcessConnections(buf *bytes.Buffer, namespaceProcs []*process.Process) (bool, error) {
	var (
		errRead  error
		errRead6 error
		read     int64
		read6    int64
	)

	for _, p := range namespaceProcs {
		dirName := strconv.Itoa(p.PID)

		read, errRead = readFile(filepath.Join(procRoot, dirName, "/net/tcp"), buf)
		read6, errRead6 = readFile(filepath.Join(procRoot, dirName, "/net/tcp6"), buf)

		if errRead != nil || errRead6 != nil {
			// try next process
			continue
		}
		// Return after succeeding on any process
		// (proc/PID/net/tcp and proc/PID/net/tcp6 are identical for all the processes in the same namespace)
		return read+read6 > 0, nil
	}

	// It would be cool an "or" error combinator
	if errRead != nil {
		return false, errRead
	}
	if errRead6 != nil {
		return false, errRead6
	}

	return false, nil

}

// walkNamespace does the work of walk for a single namespace
func (w pidWalker) walkNamespace(namespaceID uint64, buf *bytes.Buffer, sockets map[uint64]*Proc, namespaceProcs []*process.Process) error {

	if found, err := readProcessConnections(buf, namespaceProcs); err != nil || !found {
		return err
	}

	var statT syscall.Stat_t
	var fdBlockCount uint64
	for i, p := range namespaceProcs {

		// Get the sockets for all the processes in the namespace
		dirName := strconv.Itoa(p.PID)
		fdBase := filepath.Join(procRoot, dirName, "fd")

		if fdBlockCount > w.fdBlockSize {
			// we surpassed the filedescriptor rate limit
			select {
			case <-w.tickc:
			case <-w.stopc:
				return nil // abort
			}

			fdBlockCount = 0
			// read the connections again to
			// avoid the race between between /net/tcp{,6} and /proc/PID/fd/*
			if found, err := readProcessConnections(buf, namespaceProcs[i:]); err != nil || !found {
				return err
			}
		}

		fds, err := fs.ReadDirNames(fdBase)
		if err != nil {
			// Process is gone by now, or we don't have access.
			continue
		}

		var proc *Proc
		for _, fd := range fds {
			fdBlockCount++

			// Direct use of syscall.Stat() to save garbage.
			err = fs.Stat(filepath.Join(fdBase, fd), &statT)
			if err != nil {
				continue
			}

			// We want sockets only.
			if statT.Mode&syscall.S_IFMT != syscall.S_IFSOCK {
				continue
			}

			// Initialize proc lazily to avoid creating unnecessary
			// garbage
			if proc == nil {
				proc = &Proc{
					PID:            uint(p.PID),
					Name:           p.Name,
					NetNamespaceID: namespaceID,
				}
			}

			sockets[statT.Ino] = proc
		}

	}

	return nil
}

// walk walks over all numerical (PID) /proc entries. It reads
// /proc/PID/net/tcp{,6} for each namespace and sees if the ./fd/* files of each
// process in that namespace are symlinks to sockets. Returns a map from socket
// ID (inode) to PID.
func (w pidWalker) walk(buf *bytes.Buffer) (map[uint64]*Proc, error) {
	var (
		sockets    = map[uint64]*Proc{}              // map socket inode -> process
		namespaces = map[uint64][]*process.Process{} // map network namespace id -> processes
		statT      syscall.Stat_t
	)

	// We do two process traversals: One to group processes by namespace and
	// another one to obtain their connections.
	//
	// The first traversal is needed to allow obtaining the connections on a
	// per-namespace basis. This is done to minimize the race condition
	// between reading /net/tcp{,6} of each namespace and /proc/PID/fd/* for
	// the processes living in that namespace.

	w.walker.Walk(func(p, _ process.Process) {
		dirName := strconv.Itoa(p.PID)

		netNamespacePath := filepath.Join(procRoot, dirName, getNetNamespacePathSuffix())
		if err := fs.Stat(netNamespacePath, &statT); err != nil {
			return
		}

		namespaceID := statT.Ino
		namespaces[namespaceID] = append(namespaces[namespaceID], &p)
	})

	for namespaceID, procs := range namespaces {
		select {
		case <-w.tickc:
			w.walkNamespace(namespaceID, buf, sockets, procs)
		case <-w.stopc:
			break // abort
		}
	}

	metrics.SetGauge(namespaceKey, float32(len(namespaces)))
	return sockets, nil
}

func (w pidWalker) stop() {
	close(w.stopc)
}

// readFile reads an arbitrary file into a buffer.
func readFile(filename string, buf *bytes.Buffer) (int64, error) {
	f, err := fs.Open(filename)
	if err != nil {
		return -1, err
	}
	defer f.Close()
	return buf.ReadFrom(f)
}
<commit_msg>Fix minor typo<commit_after>package procspy

// /proc-based implementation.

import (
	"bytes"
	"fmt"
	"path/filepath"
	"strconv"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/armon/go-metrics"

	"github.com/weaveworks/common/fs"
	"github.com/weaveworks/scope/common/marshal"
	"github.com/weaveworks/scope/probe/process"
)

var (
	procRoot               = "/proc"
	namespaceKey           = []string{"procspy", "namespaces"}
	netNamespacePathSuffix = ""
)

type pidWalker struct {
	walker      process.Walker
	tickc       <-chan time.Time // Rate-limit clock. Sets the pace when traversing namespaces and /proc/PID/fd/* files.
	stopc       chan struct{}    // Abort walk
	fdBlockSize uint64           // Maximum number of /proc/PID/fd/* files to stat() per tick
}

func newPidWalker(walker process.Walker, tickc <-chan time.Time, fdBlockSize uint64) pidWalker {
	w := pidWalker{
		walker:      walker,
		tickc:       tickc,
		fdBlockSize: fdBlockSize,
		stopc:       make(chan struct{}),
	}
	return w
}

// SetProcRoot sets the location of the proc filesystem.
func SetProcRoot(root string) {
	procRoot = root
}

func getKernelVersion() (major, minor int, err error) {
	var u syscall.Utsname
	if err = syscall.Uname(&u); err != nil {
		return
	}

	// Kernel versions are not always a semver, so we have to do minimal parsing.
	release := marshal.FromUtsname(u.Release)
	if n, err := fmt.Sscanf(release, "%d.%d", &major, &minor); err != nil || n != 2 {
		return 0, 0, fmt.Errorf("Malformed version: %s", release)
	}
	return
}

func getNetNamespacePathSuffix() string {
	// With Linux 3.8 or later the network namespace of a process can be
	// determined by the inode of /proc/PID/net/ns.  Before that, Any file
	// under /proc/PID/net/ could be used but it's not documented and may
	// break in newer kernels.
	const (
		post38Path = "ns/net"
		pre38Path  = "net/dev"
	)

	if netNamespacePathSuffix != "" {
		return netNamespacePathSuffix
	}

	major, minor, err := getKernelVersion()
	if err != nil {
		log.Errorf("getNamespacePathSuffix: cannot get kernel version: %s", err)
		netNamespacePathSuffix = post38Path
		return netNamespacePathSuffix
	}

	if major < 3 || (major == 3 && minor < 8) {
		netNamespacePathSuffix = pre38Path
	} else {
		netNamespacePathSuffix = post38Path
	}
	return netNamespacePathSuffix
}

// Read the connections for a group of processes living in the same namespace,
// which are found (identically) in /proc/PID/net/tcp{,6} for any of the
// processes.
func readProcessConnections(buf *bytes.Buffer, namespaceProcs []*process.Process) (bool, error) {
	var (
		errRead  error
		errRead6 error
		read     int64
		read6    int64
	)

	for _, p := range namespaceProcs {
		dirName := strconv.Itoa(p.PID)

		read, errRead = readFile(filepath.Join(procRoot, dirName, "/net/tcp"), buf)
		read6, errRead6 = readFile(filepath.Join(procRoot, dirName, "/net/tcp6"), buf)

		if errRead != nil || errRead6 != nil {
			// try next process
			continue
		}
		// Return after succeeding on any process
		// (proc/PID/net/tcp and proc/PID/net/tcp6 are identical for all the processes in the same namespace)
		return read+read6 > 0, nil
	}

	// It would be cool to have an "or" error combinator
	if errRead != nil {
		return false, errRead
	}
	if errRead6 != nil {
		return false, errRead6
	}

	return false, nil

}

// walkNamespace does the work of walk for a single namespace
func (w pidWalker) walkNamespace(namespaceID uint64, buf *bytes.Buffer, sockets map[uint64]*Proc, namespaceProcs []*process.Process) error {

	if found, err := readProcessConnections(buf, namespaceProcs); err != nil || !found {
		return err
	}

	var statT syscall.Stat_t
	var fdBlockCount uint64
	for i, p := range namespaceProcs {

		// Get the sockets for all the processes in the namespace
		dirName := strconv.Itoa(p.PID)
		fdBase := filepath.Join(procRoot, dirName, "fd")

		if fdBlockCount > w.fdBlockSize {
			// we surpassed the filedescriptor rate limit
			select {
			case <-w.tickc:
			case <-w.stopc:
				return nil // abort
			}

			fdBlockCount = 0
			// read the connections again to
			// avoid the race between between /net/tcp{,6} and /proc/PID/fd/*
			if found, err := readProcessConnections(buf, namespaceProcs[i:]); err != nil || !found {
				return err
			}
		}

		fds, err := fs.ReadDirNames(fdBase)
		if err != nil {
			// Process is gone by now, or we don't have access.
			continue
		}

		var proc *Proc
		for _, fd := range fds {
			fdBlockCount++

			// Direct use of syscall.Stat() to save garbage.
			err = fs.Stat(filepath.Join(fdBase, fd), &statT)
			if err != nil {
				continue
			}

			// We want sockets only.
			if statT.Mode&syscall.S_IFMT != syscall.S_IFSOCK {
				continue
			}

			// Initialize proc lazily to avoid creating unnecessary
			// garbage
			if proc == nil {
				proc = &Proc{
					PID:            uint(p.PID),
					Name:           p.Name,
					NetNamespaceID: namespaceID,
				}
			}

			sockets[statT.Ino] = proc
		}

	}

	return nil
}

// walk walks over all numerical (PID) /proc entries. It reads
// /proc/PID/net/tcp{,6} for each namespace and sees if the ./fd/* files of each
// process in that namespace are symlinks to sockets. Returns a map from socket
// ID (inode) to PID.
func (w pidWalker) walk(buf *bytes.Buffer) (map[uint64]*Proc, error) {
	var (
		sockets    = map[uint64]*Proc{}              // map socket inode -> process
		namespaces = map[uint64][]*process.Process{} // map network namespace id -> processes
		statT      syscall.Stat_t
	)

	// We do two process traversals: One to group processes by namespace and
	// another one to obtain their connections.
	//
	// The first traversal is needed to allow obtaining the connections on a
	// per-namespace basis. This is done to minimize the race condition
	// between reading /net/tcp{,6} of each namespace and /proc/PID/fd/* for
	// the processes living in that namespace.

	w.walker.Walk(func(p, _ process.Process) {
		dirName := strconv.Itoa(p.PID)

		netNamespacePath := filepath.Join(procRoot, dirName, getNetNamespacePathSuffix())
		if err := fs.Stat(netNamespacePath, &statT); err != nil {
			return
		}

		namespaceID := statT.Ino
		namespaces[namespaceID] = append(namespaces[namespaceID], &p)
	})

	for namespaceID, procs := range namespaces {
		select {
		case <-w.tickc:
			w.walkNamespace(namespaceID, buf, sockets, procs)
		case <-w.stopc:
			break // abort
		}
	}

	metrics.SetGauge(namespaceKey, float32(len(namespaces)))
	return sockets, nil
}

func (w pidWalker) stop() {
	close(w.stopc)
}

// readFile reads an arbitrary file into a buffer.
func readFile(filename string, buf *bytes.Buffer) (int64, error) {
	f, err := fs.Open(filename)
	if err != nil {
		return -1, err
	}
	defer f.Close()
	return buf.ReadFrom(f)
}
<|endoftext|>


<commit_before>// Generated struct for models.
package models

import (
	"strings"

	"github.com/lann/squirrel"
)

// GenerateCreateSQL generates plain sql for the given Profile
func (p *Profile) GenerateCreateSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Insert(p.TableName())
	columns := make([]string, 0)
	values := make([]interface{}, 0)
	if p.AvatarURL != "" {
		columns = append(columns, "avatar_url")
		values = append(values, p.AvatarURL)
	}
	if !p.CreatedAt.IsZero() {
		columns = append(columns, "created_at")
		values = append(values, p.CreatedAt)
	}
	if p.Description != "" {
		columns = append(columns, "description")
		values = append(values, p.Description)
	}
	if float64(p.ID) != float64(0) {
		columns = append(columns, "id")
		values = append(values, p.ID)
	}
	if p.LinkColor != "" {
		columns = append(columns, "link_color")
		values = append(values, p.LinkColor)
	}
	if p.Location != "" {
		columns = append(columns, "location")
		values = append(values, p.Location)
	}
	if p.ScreenName != "" {
		columns = append(columns, "screen_name")
		values = append(values, p.ScreenName)
	}
	if p.URL != "" {
		columns = append(columns, "url")
		values = append(values, p.URL)
	}
	return psql.Columns(columns...).Values(values...).ToSql()
}

// GenerateUpdateSQL generates plain update sql statement for the given Profile
func (p *Profile) GenerateUpdateSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Update(p.TableName())
	if p.AvatarURL != "" {
		psql = psql.Set("avatar_url", p.AvatarURL)
	}
	if !p.CreatedAt.IsZero() {
		psql = psql.Set("created_at", p.CreatedAt)
	}
	if p.Description != "" {
		psql = psql.Set("description", p.Description)
	}
	if float64(p.ID) != float64(0) {
		psql = psql.Set("id", p.ID)
	}
	if p.LinkColor != "" {
		psql = psql.Set("link_color", p.LinkColor)
	}
	if p.Location != "" {
		psql = psql.Set("location", p.Location)
	}
	if p.ScreenName != "" {
		psql = psql.Set("screen_name", p.ScreenName)
	}
	if p.URL != "" {
		psql = psql.Set("url", p.URL)
	}
	return psql.Where("id = ?", p.ID).ToSql()
}

// GenerateDeleteSQL generates plain delete sql statement for the given Profile
func (p *Profile) GenerateDeleteSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Delete(p.TableName())
	columns := make([]string, 0)
	values := make([]interface{}, 0)
	if p.AvatarURL != "" {
		columns = append(columns, "avatar_url = ?")
		values = append(values, p.AvatarURL)
	}
	if !p.CreatedAt.IsZero() {
		columns = append(columns, "created_at = ?")
		values = append(values, p.CreatedAt)
	}
	if p.Description != "" {
		columns = append(columns, "description = ?")
		values = append(values, p.Description)
	}
	if float64(p.ID) != float64(0) {
		columns = append(columns, "id = ?")
		values = append(values, p.ID)
	}
	if p.LinkColor != "" {
		columns = append(columns, "link_color = ?")
		values = append(values, p.LinkColor)
	}
	if p.Location != "" {
		columns = append(columns, "location = ?")
		values = append(values, p.Location)
	}
	if p.ScreenName != "" {
		columns = append(columns, "screen_name = ?")
		values = append(values, p.ScreenName)
	}
	if p.URL != "" {
		columns = append(columns, "url = ?")
		values = append(values, p.URL)
	}
	return psql.Where(strings.Join(columns, " AND "), values...).ToSql()
}

// GenerateSelectSQL generates plain select sql statement for the given Profile
func (p *Profile) GenerateSelectSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Select("*").From(p.TableName())
	columns := make([]string, 0)
	values := make([]interface{}, 0)
	if p.AvatarURL != "" {
		columns = append(columns, "avatar_url = ?")
		values = append(values, p.AvatarURL)
	}
	if !p.CreatedAt.IsZero() {
		columns = append(columns, "created_at = ?")
		values = append(values, p.CreatedAt)
	}
	if p.Description != "" {
		columns = append(columns, "description = ?")
		values = append(values, p.Description)
	}
	if float64(p.ID) != float64(0) {
		columns = append(columns, "id = ?")
		values = append(values, p.ID)
	}
	if p.LinkColor != "" {
		columns = append(columns, "link_color = ?")
		values = append(values, p.LinkColor)
	}
	if p.Location != "" {
		columns = append(columns, "location = ?")
		values = append(values, p.Location)
	}
	if p.ScreenName != "" {
		columns = append(columns, "screen_name = ?")
		values = append(values, p.ScreenName)
	}
	if p.URL != "" {
		columns = append(columns, "url = ?")
		values = append(values, p.URL)
	}
	return psql.Where(strings.Join(columns, " AND "), values...).ToSql()
}

// TableName returns the table name for Profile
func (p *Profile) TableName() string {
	return "profile"
}
<commit_msg>Gene: reorder fix<commit_after>// Generated struct for models.
package models

import (
	"strings"

	"github.com/lann/squirrel"
)

// GenerateCreateSQL generates plain sql for the given Account
func (a *Account) GenerateCreateSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Insert(a.TableName())
	columns := make([]string, 0)
	values := make([]interface{}, 0)
	if !a.CreatedAt.IsZero() {
		columns = append(columns, "created_at")
		values = append(values, a.CreatedAt)
	}
	if a.EmailAddress != "" {
		columns = append(columns, "email_address")
		values = append(values, a.EmailAddress)
	}
	if a.EmailStatusConstant != "" {
		columns = append(columns, "email_status_constant")
		values = append(values, a.EmailStatusConstant)
	}
	if float64(a.ID) != float64(0) {
		columns = append(columns, "id")
		values = append(values, a.ID)
	}
	if a.Password != "" {
		columns = append(columns, "password")
		values = append(values, a.Password)
	}
	if a.PasswordStatusConstant != "" {
		columns = append(columns, "password_status_constant")
		values = append(values, a.PasswordStatusConstant)
	}
	if float64(a.ProfileID) != float64(0) {
		columns = append(columns, "profile_id")
		values = append(values, a.ProfileID)
	}
	if a.Salt != "" {
		columns = append(columns, "salt")
		values = append(values, a.Salt)
	}
	if a.StatusConstant != "" {
		columns = append(columns, "status_constant")
		values = append(values, a.StatusConstant)
	}
	if a.URL != "" {
		columns = append(columns, "url")
		values = append(values, a.URL)
	}
	if a.URLName != "" {
		columns = append(columns, "url_name")
		values = append(values, a.URLName)
	}
	return psql.Columns(columns...).Values(values...).ToSql()
}

// GenerateUpdateSQL generates plain update sql statement for the given Account
func (a *Account) GenerateUpdateSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Update(a.TableName())
	if !a.CreatedAt.IsZero() {
		psql = psql.Set("created_at", a.CreatedAt)
	}
	if a.EmailAddress != "" {
		psql = psql.Set("email_address", a.EmailAddress)
	}
	if a.EmailStatusConstant != "" {
		psql = psql.Set("email_status_constant", a.EmailStatusConstant)
	}
	if float64(a.ID) != float64(0) {
		psql = psql.Set("id", a.ID)
	}
	if a.Password != "" {
		psql = psql.Set("password", a.Password)
	}
	if a.PasswordStatusConstant != "" {
		psql = psql.Set("password_status_constant", a.PasswordStatusConstant)
	}
	if float64(a.ProfileID) != float64(0) {
		psql = psql.Set("profile_id", a.ProfileID)
	}
	if a.Salt != "" {
		psql = psql.Set("salt", a.Salt)
	}
	if a.StatusConstant != "" {
		psql = psql.Set("status_constant", a.StatusConstant)
	}
	if a.URL != "" {
		psql = psql.Set("url", a.URL)
	}
	if a.URLName != "" {
		psql = psql.Set("url_name", a.URLName)
	}
	return psql.Where("id = ?", a.ID).ToSql()
}

// GenerateDeleteSQL generates plain delete sql statement for the given Account
func (a *Account) GenerateDeleteSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Delete(a.TableName())
	columns := make([]string, 0)
	values := make([]interface{}, 0)
	if !a.CreatedAt.IsZero() {
		columns = append(columns, "created_at = ?")
		values = append(values, a.CreatedAt)
	}
	if a.EmailAddress != "" {
		columns = append(columns, "email_address = ?")
		values = append(values, a.EmailAddress)
	}
	if a.EmailStatusConstant != "" {
		columns = append(columns, "email_status_constant = ?")
		values = append(values, a.EmailStatusConstant)
	}
	if float64(a.ID) != float64(0) {
		columns = append(columns, "id = ?")
		values = append(values, a.ID)
	}
	if a.Password != "" {
		columns = append(columns, "password = ?")
		values = append(values, a.Password)
	}
	if a.PasswordStatusConstant != "" {
		columns = append(columns, "password_status_constant = ?")
		values = append(values, a.PasswordStatusConstant)
	}
	if float64(a.ProfileID) != float64(0) {
		columns = append(columns, "profile_id = ?")
		values = append(values, a.ProfileID)
	}
	if a.Salt != "" {
		columns = append(columns, "salt = ?")
		values = append(values, a.Salt)
	}
	if a.StatusConstant != "" {
		columns = append(columns, "status_constant = ?")
		values = append(values, a.StatusConstant)
	}
	if a.URL != "" {
		columns = append(columns, "url = ?")
		values = append(values, a.URL)
	}
	if a.URLName != "" {
		columns = append(columns, "url_name = ?")
		values = append(values, a.URLName)
	}
	return psql.Where(strings.Join(columns, " AND "), values...).ToSql()
}

// GenerateSelectSQL generates plain select sql statement for the given Account
func (a *Account) GenerateSelectSQL() (string, []interface{}, error) {
	psql := squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar).Select("*").From(a.TableName())
	columns := make([]string, 0)
	values := make([]interface{}, 0)
	if !a.CreatedAt.IsZero() {
		columns = append(columns, "created_at = ?")
		values = append(values, a.CreatedAt)
	}
	if a.EmailAddress != "" {
		columns = append(columns, "email_address = ?")
		values = append(values, a.EmailAddress)
	}
	if a.EmailStatusConstant != "" {
		columns = append(columns, "email_status_constant = ?")
		values = append(values, a.EmailStatusConstant)
	}
	if float64(a.ID) != float64(0) {
		columns = append(columns, "id = ?")
		values = append(values, a.ID)
	}
	if a.Password != "" {
		columns = append(columns, "password = ?")
		values = append(values, a.Password)
	}
	if a.PasswordStatusConstant != "" {
		columns = append(columns, "password_status_constant = ?")
		values = append(values, a.PasswordStatusConstant)
	}
	if float64(a.ProfileID) != float64(0) {
		columns = append(columns, "profile_id = ?")
		values = append(values, a.ProfileID)
	}
	if a.Salt != "" {
		columns = append(columns, "salt = ?")
		values = append(values, a.Salt)
	}
	if a.StatusConstant != "" {
		columns = append(columns, "status_constant = ?")
		values = append(values, a.StatusConstant)
	}
	if a.URL != "" {
		columns = append(columns, "url = ?")
		values = append(values, a.URL)
	}
	if a.URLName != "" {
		columns = append(columns, "url_name = ?")
		values = append(values, a.URLName)
	}
	return psql.Where(strings.Join(columns, " AND "), values...).ToSql()
}

// TableName returns the table name for Account
func (a *Account) TableName() string {
	return "account"
}
<|endoftext|>


<commit_before>//
// link.go -- link level protocol
//
package samtun

import (
  "bitbucket.org/majestrate/sam3"
  "bytes"
  "encoding/binary"
  "net"
)

type ipPacket []byte

func (pkt ipPacket) setDst(addr net.IP) {
  pkt[16] = addr[0]
  pkt[17] = addr[1]
  pkt[18] = addr[2]
  pkt[19] = addr[3]
}

func (pkt ipPacket) setSrc(addr net.IP) {
  pkt[12] = addr[0]
  pkt[13] = addr[1]
  pkt[14] = addr[2]
  pkt[15] = addr[3]
}

func (pkt ipPacket) Dst() net.IP {
  return net.IPv4(pkt[16], pkt[17], pkt[18], pkt[19])
}

func (pkt ipPacket) Src() net.IP {
  return net.IPv4(pkt[12], pkt[13], pkt[14], pkt[15])
}

// a link level message
// infact a bunch of ip packets
type linkFrame []ipPacket

// get a raw bytes representation of this frame
func (f linkFrame) Bytes() []byte {
  var buff bytes.Buffer
  // link frame protocol version
  buff.Write([]byte{0})
  // link frame packet count
  pkts := len(f)
  buff.Write([]byte{byte(pkts)})
  // for each packet
  for _, pkt := range f {
    // pack the packet int our buffer
    pktbuff := make([]byte, len(pkt) + 2)
    binary.BigEndian.PutUint16(pktbuff[:], uint16(len(pkt)))
    copy(pktbuff[:2], pkt)
    buff.Write(pktbuff)
  }
  return buff.Bytes()
}

// create a linkFrame from a byteslice
// returns nil if format invalid
func frameFromBytes(buff []byte) (f linkFrame) {
  if buff[0] == 0x00 {
    pkts := buff[1]
    idx := 0
    for pkts > 0 {
      plen := binary.BigEndian.Uint16(buff[:2+idx])
      if 2 + int(plen) + idx < len(buff) {
        pkt := make([]byte, int(plen))
        copy(pkt, buff[idx+2:2+len(pkt)+idx])
        f = append(f, ipPacket(pkt))
        pkts--
        idx += len(pkt) + 2
      } else {
        return nil
      }
    }
  }
  return
}

// a link layer message that is sent over i2p
type linkMessage struct {
  frame linkFrame
  addr sam3.I2PAddr
}

func (m *linkMessage) appendPacket(pkt ipPacket) {
  m.frame = append(m.frame, pkt)
}

// get raw bytes representation to send over the wire
func (m *linkMessage) WireBytes() []byte {
  return m.frame.Bytes()
}

type linkProtocol struct {
  // key name for link message data
  msgdata string
  // key name for link protocol version number
  version string
  // key name for link message type
  msgtype string
}

// given a byte slice, read out a linkMessage
//func (p linkProtocol) Parse(data []byte) (pkts []packet, err error) {
//  bencode.
//}

var link = linkProtocol{
  msgdata: "x",
  msgtype: "w",
  version: "v",
}

<commit_msg>wrong slice<commit_after>//
// link.go -- link level protocol
//
package samtun

import (
  "bitbucket.org/majestrate/sam3"
  "bytes"
  "encoding/binary"
  "net"
)

type ipPacket []byte

func (pkt ipPacket) setDst(addr net.IP) {
  pkt[16] = addr[0]
  pkt[17] = addr[1]
  pkt[18] = addr[2]
  pkt[19] = addr[3]
}

func (pkt ipPacket) setSrc(addr net.IP) {
  pkt[12] = addr[0]
  pkt[13] = addr[1]
  pkt[14] = addr[2]
  pkt[15] = addr[3]
}

func (pkt ipPacket) Dst() net.IP {
  return net.IPv4(pkt[16], pkt[17], pkt[18], pkt[19])
}

func (pkt ipPacket) Src() net.IP {
  return net.IPv4(pkt[12], pkt[13], pkt[14], pkt[15])
}

// a link level message
// infact a bunch of ip packets
type linkFrame []ipPacket

// get a raw bytes representation of this frame
func (f linkFrame) Bytes() []byte {
  var buff bytes.Buffer
  // link frame protocol version
  buff.Write([]byte{0})
  // link frame packet count
  pkts := len(f)
  buff.Write([]byte{byte(pkts)})
  // for each packet
  for _, pkt := range f {
    // pack the packet int our buffer
    pktbuff := make([]byte, len(pkt) + 2)
    binary.BigEndian.PutUint16(pktbuff[:], uint16(len(pkt)))
    copy(pktbuff[2:], pkt)
    buff.Write(pktbuff)
  }
  return buff.Bytes()
}

// create a linkFrame from a byteslice
// returns nil if format invalid
func frameFromBytes(buff []byte) (f linkFrame) {
  if buff[0] == 0x00 {
    pkts := buff[1]
    idx := 0
    for pkts > 0 {
      plen := binary.BigEndian.Uint16(buff[:2+idx])
      if 2 + int(plen) + idx < len(buff) {
        pkt := make([]byte, int(plen))
        copy(pkt, buff[idx+2:2+len(pkt)+idx])
        f = append(f, ipPacket(pkt))
        pkts--
        idx += len(pkt) + 2
      } else {
        return nil
      }
    }
  }
  return
}

// a link layer message that is sent over i2p
type linkMessage struct {
  frame linkFrame
  addr sam3.I2PAddr
}

func (m *linkMessage) appendPacket(pkt ipPacket) {
  m.frame = append(m.frame, pkt)
}

// get raw bytes representation to send over the wire
func (m *linkMessage) WireBytes() []byte {
  return m.frame.Bytes()
}

type linkProtocol struct {
  // key name for link message data
  msgdata string
  // key name for link protocol version number
  version string
  // key name for link message type
  msgtype string
}

// given a byte slice, read out a linkMessage
//func (p linkProtocol) Parse(data []byte) (pkts []packet, err error) {
//  bencode.
//}

var link = linkProtocol{
  msgdata: "x",
  msgtype: "w",
  version: "v",
}

<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/bobbytables/gangway/data"
)

// getDefinitionsResp contains the structure of the response
// that gangway will return when asked about all definitions
type getDefinitionsResp struct {
	Definitions []data.Definition `json:"definitions"`
}

// postDefinitionsResp contains the structure of the response
// that gangway returns upon a successful add of a definition
type postDefinitionsResp struct {
	Definition data.Definition `json:"definition"`
}

func (s *Server) getDefinitions(w http.ResponseWriter, r *http.Request) {
	defs, err := s.store.RetrieveDefinitions()
	if err != nil {
		logrus.WithError(err).Error()
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp := getDefinitionsResp{Definitions: defs}

	if err := json.NewEncoder(w).Encode(resp); err != nil {
		logrus.WithError(err).Error()
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

// postDefinitions handles adding definitions to the underlying store
func (s *Server) postDefinitions(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	var d data.Definition
	if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if vErr := data.IsValidDefinition(d); vErr != nil {
		s.writeError(w, vErr, 422)
		return
	}

	if err := s.store.AddDefinition(d); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
	resp := postDefinitionsResp{Definition: d}
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

}
<commit_msg>Add better errors.<commit_after>package server

import (
	"encoding/json"
	"net/http"

	"github.com/Sirupsen/logrus"
	"github.com/bobbytables/gangway/data"
)

// getDefinitionsResp contains the structure of the response
// that gangway will return when asked about all definitions
type getDefinitionsResp struct {
	Definitions []data.Definition `json:"definitions"`
}

// postDefinitionsResp contains the structure of the response
// that gangway returns upon a successful add of a definition
type postDefinitionsResp struct {
	Definition data.Definition `json:"definition"`
}

func (s *Server) getDefinitions(w http.ResponseWriter, r *http.Request) {
	defs, err := s.store.RetrieveDefinitions()
	if err != nil {
		logrus.WithError(err).Error("could not retrieve definitions")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp := getDefinitionsResp{Definitions: defs}

	if err := json.NewEncoder(w).Encode(resp); err != nil {
		logrus.WithError(err).Error("could not encode definitions")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

// postDefinitions handles adding definitions to the underlying store
func (s *Server) postDefinitions(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	var d data.Definition
	if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if vErr := data.IsValidDefinition(d); vErr != nil {
		s.writeError(w, vErr, 422)
		return
	}

	if err := s.store.AddDefinition(d); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
	resp := postDefinitionsResp{Definition: d}
	if err := json.NewEncoder(w).Encode(resp); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

}
<|endoftext|>