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

package infrastructure

import (
	"fmt"
	"os"
	"path"

	. "github.com/onsi/gomega"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/felix/fv/containers"
	"github.com/projectcalico/felix/fv/tcpdump"
	"github.com/projectcalico/felix/fv/utils"
)

// FIXME: isolate individual Felix instances in their own cgroups.  Unfortunately, this doesn't work on systems that are using cgroupv1
// see https://elixir.bootlin.com/linux/v5.3.11/source/include/linux/cgroup-defs.h#L788 for explanation.
const CreateCgroupV2 = false

type Felix struct {
	*containers.Container

	// ExpectedIPIPTunnelAddr contains the IP that the infrastructure expects to
	// get assigned to the IPIP tunnel.  Filled in by AddNode().
	ExpectedIPIPTunnelAddr string
	// ExpectedVXLANTunnelAddr contains the IP that the infrastructure expects to
	// get assigned to the VXLAN tunnel.  Filled in by AddNode().
	ExpectedVXLANTunnelAddr string
	// ExpectedWireguardTunnelAddr contains the IP that the infrastructure expects to
	// get assigned to the Wireguard tunnel.  Filled in by AddNode().
	ExpectedWireguardTunnelAddr string

	// IP of the Typha that this Felix is using (if any).
	TyphaIP string

	// If sets, acts like an external IP of a node. Filled in by AddNode().
	// XXX setup routes
	ExternalIP string

	startupDelayed bool
}

func (f *Felix) GetFelixPID() int {
	if f.startupDelayed {
		log.Panic("GetFelixPID() called but startup is delayed")
	}
	return f.GetSinglePID("calico-felix")
}

func (f *Felix) GetFelixPIDs() []int {
	if f.startupDelayed {
		log.Panic("GetFelixPIDs() called but startup is delayed")
	}
	return f.GetPIDs("calico-felix")
}

func (f *Felix) TriggerDelayedStart() {
	if !f.startupDelayed {
		log.Panic("TriggerDelayedStart() called but startup wasn't delayed")
	}
	f.Exec("touch", "/start-trigger")
	f.startupDelayed = false
}

func RunFelix(infra DatastoreInfra, id int, options TopologyOptions) *Felix {
	log.Info("Starting felix")
	ipv6Enabled := fmt.Sprint(options.EnableIPv6)

	args := infra.GetDockerArgs()
	args = append(args, "--privileged")

	// Add in the environment variables.
	envVars := map[string]string{
		// Enable core dumps.
		"GOTRACEBACK": "crash",
		"GORACE":      "history_size=2",
		// Tell the wrapper to set the core file name pattern so we can find the dump.
		"SET_CORE_PATTERN": "true",

		"FELIX_LOGSEVERITYSCREEN":        options.FelixLogSeverity,
		"FELIX_PROMETHEUSMETRICSENABLED": "true",
		"FELIX_BPFLOGLEVEL":              "debug",
		"FELIX_USAGEREPORTINGENABLED":    "false",
		"FELIX_IPV6SUPPORT":              ipv6Enabled,
		// Disable log dropping, because it can cause flakes in tests that look for particular logs.
		"FELIX_DEBUGDISABLELOGDROPPING": "true",
	}

	containerName := containers.UniqueName(fmt.Sprintf("felix-%d", id))
	if os.Getenv("FELIX_FV_ENABLE_BPF") == "true" {
		if !options.TestManagesBPF {
			log.Info("FELIX_FV_ENABLE_BPF=true, enabling BPF with env var")
			envVars["FELIX_BPFENABLED"] = "true"
		} else {
			log.Info("FELIX_FV_ENABLE_BPF=true but test manages BPF state itself, not using env var")
		}

		// Disable map repinning by default since BPF map names are global and we don't want our simulated instances to
		// share maps.
		envVars["FELIX_DebugBPFMapRepinEnabled"] = "false"

		if CreateCgroupV2 {
			envVars["FELIX_DEBUGBPFCGROUPV2"] = containerName
		}
	}

	if options.DelayFelixStart {
		args = append(args, "-e", "DELAY_FELIX_START=true")
	}

	for k, v := range options.ExtraEnvVars {
		envVars[k] = v
	}

	for k, v := range envVars {
		args = append(args, "-e", fmt.Sprintf("%s=%s", k, v))
	}

	// Add in the volumes.
	volumes := map[string]string{
		"/lib/modules": "/lib/modules",
		"/tmp":         "/tmp",
	}
	for k, v := range options.ExtraVolumes {
		volumes[k] = v
	}
	for k, v := range volumes {
		args = append(args, "-v", fmt.Sprintf("%s:%s", k, v))
	}

	args = append(args,
		utils.Config.FelixImage,
	)

	felixOpts := containers.RunOpts{
		AutoRemove: true,
	}
	if options.FelixStopGraceful {
		// Leave StopSignal defaulting to SIGTERM, and allow 10 seconds for Felix
		// to handle that gracefully.
		felixOpts.StopTimeoutSecs = 10
	} else {
		// Use SIGKILL to stop Felix immediately.
		felixOpts.StopSignal = "SIGKILL"
	}
	c := containers.RunWithFixedName(containerName, felixOpts, args...)

	if options.EnableIPv6 {
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.disable_ipv6=0")
		c.Exec("sysctl", "-w", "net.ipv6.conf.default.disable_ipv6=0")
		c.Exec("sysctl", "-w", "net.ipv6.conf.lo.disable_ipv6=0")
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.forwarding=1")
	} else {
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.disable_ipv6=1")
		c.Exec("sysctl", "-w", "net.ipv6.conf.default.disable_ipv6=1")
		c.Exec("sysctl", "-w", "net.ipv6.conf.lo.disable_ipv6=1")
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.forwarding=0")
	}

	// Configure our model host to drop forwarded traffic by default.  Modern
	// Kubernetes/Docker hosts now have this setting, and the consequence is that
	// whenever Calico policy intends to allow a packet, it must explicitly ACCEPT
	// that packet, not just allow it to pass through cali-FORWARD and assume it will
	// be accepted by the rest of the chain.  Establishing that setting in this FV
	// allows us to test that.
	c.Exec("iptables",
		"-w", "10", // Retry this for 10 seconds, e.g. if something else is holding the lock
		"-W", "100000", // How often to probe the lock in microsecs.
		"-P", "FORWARD", "DROP")

	return &Felix{
		Container:      c,
		startupDelayed: options.DelayFelixStart,
	}
}

func (f *Felix) Stop() {
	if CreateCgroupV2 {
		_ = f.ExecMayFail("rmdir", path.Join("/run/calico/cgroup/", f.Name))
	}
	f.Container.Stop()
}

func (f *Felix) Restart() {
	oldPID := f.GetFelixPID()
	f.Exec("kill", "-HUP", fmt.Sprint(oldPID))
	Eventually(f.GetFelixPID, "10s", "100ms").ShouldNot(Equal(oldPID))
}

// AttachTCPDump returns tcpdump attached to the container
func (f *Felix) AttachTCPDump(iface string) *tcpdump.TCPDump {
	return tcpdump.Attach(f.Container.Name, "", iface)
}

func (f *Felix) ProgramIptablesDNAT(serviceIP, targetIP, chain string) {
	f.Exec(
		"iptables",
		"-w", "10", // Retry this for 10 seconds, e.g. if something else is holding the lock
		"-W", "100000", // How often to probe the lock in microsecs.
		"-t", "nat", "-A", chain,
		"--destination", serviceIP,
		"-j", "DNAT", "--to-destination", targetIP,
	)
}
<commit_msg>Upstream minor rework of FV infra  to avoid OS->private conflicts later.<commit_after>// Copyright (c) 2017-2021 Tigera, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package infrastructure

import (
	"fmt"
	"os"
	"path"

	. "github.com/onsi/gomega"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/felix/fv/containers"
	"github.com/projectcalico/felix/fv/tcpdump"
	"github.com/projectcalico/felix/fv/utils"
)

// FIXME: isolate individual Felix instances in their own cgroups.  Unfortunately, this doesn't work on systems that are using cgroupv1
// see https://elixir.bootlin.com/linux/v5.3.11/source/include/linux/cgroup-defs.h#L788 for explanation.
const CreateCgroupV2 = false

type Felix struct {
	*containers.Container

	// ExpectedIPIPTunnelAddr contains the IP that the infrastructure expects to
	// get assigned to the IPIP tunnel.  Filled in by AddNode().
	ExpectedIPIPTunnelAddr string
	// ExpectedVXLANTunnelAddr contains the IP that the infrastructure expects to
	// get assigned to the VXLAN tunnel.  Filled in by AddNode().
	ExpectedVXLANTunnelAddr string
	// ExpectedWireguardTunnelAddr contains the IP that the infrastructure expects to
	// get assigned to the Wireguard tunnel.  Filled in by AddNode().
	ExpectedWireguardTunnelAddr string

	// IP of the Typha that this Felix is using (if any).
	TyphaIP string

	// If sets, acts like an external IP of a node. Filled in by AddNode().
	// XXX setup routes
	ExternalIP string

	startupDelayed bool
}

func (f *Felix) GetFelixPID() int {
	if f.startupDelayed {
		log.Panic("GetFelixPID() called but startup is delayed")
	}
	return f.GetSinglePID("calico-felix")
}

func (f *Felix) GetFelixPIDs() []int {
	if f.startupDelayed {
		log.Panic("GetFelixPIDs() called but startup is delayed")
	}
	return f.GetPIDs("calico-felix")
}

func (f *Felix) TriggerDelayedStart() {
	if !f.startupDelayed {
		log.Panic("TriggerDelayedStart() called but startup wasn't delayed")
	}
	f.Exec("touch", "/start-trigger")
	f.startupDelayed = false
}

func RunFelix(infra DatastoreInfra, id int, options TopologyOptions) *Felix {
	log.Info("Starting felix")
	ipv6Enabled := fmt.Sprint(options.EnableIPv6)

	args := infra.GetDockerArgs()
	args = append(args, "--privileged")

	// Collect the environment variables for starting this particular container.  Note: we
	// are called concurrently with other instances of RunFelix so it's important to only
	// read from options.*.
	envVars := map[string]string{
		// Enable core dumps.
		"GOTRACEBACK": "crash",
		"GORACE":      "history_size=2",
		// Tell the wrapper to set the core file name pattern so we can find the dump.
		"SET_CORE_PATTERN": "true",

		"FELIX_LOGSEVERITYSCREEN":        options.FelixLogSeverity,
		"FELIX_PROMETHEUSMETRICSENABLED": "true",
		"FELIX_BPFLOGLEVEL":              "debug",
		"FELIX_USAGEREPORTINGENABLED":    "false",
		"FELIX_IPV6SUPPORT":              ipv6Enabled,
		// Disable log dropping, because it can cause flakes in tests that look for particular logs.
		"FELIX_DEBUGDISABLELOGDROPPING": "true",
	}
	// Collect the volumes for this container.
	volumes := map[string]string{
		"/lib/modules": "/lib/modules",
		"/tmp":         "/tmp",
	}

	containerName := containers.UniqueName(fmt.Sprintf("felix-%d", id))

	if os.Getenv("FELIX_FV_ENABLE_BPF") == "true" {
		if !options.TestManagesBPF {
			log.Info("FELIX_FV_ENABLE_BPF=true, enabling BPF with env var")
			envVars["FELIX_BPFENABLED"] = "true"
		} else {
			log.Info("FELIX_FV_ENABLE_BPF=true but test manages BPF state itself, not using env var")
		}

		// Disable map repinning by default since BPF map names are global and we don't want our simulated instances to
		// share maps.
		envVars["FELIX_DebugBPFMapRepinEnabled"] = "false"

		if CreateCgroupV2 {
			envVars["FELIX_DEBUGBPFCGROUPV2"] = containerName
		}
	}

	if options.DelayFelixStart {
		envVars["DELAY_FELIX_START"] = "true"
	}

	for k, v := range options.ExtraEnvVars {
		envVars[k] = v
	}

	for k, v := range envVars {
		args = append(args, "-e", fmt.Sprintf("%s=%s", k, v))
	}

	// Add in the volumes.
	for k, v := range options.ExtraVolumes {
		volumes[k] = v
	}
	for k, v := range volumes {
		args = append(args, "-v", fmt.Sprintf("%s:%s", k, v))
	}

	args = append(args,
		utils.Config.FelixImage,
	)

	felixOpts := containers.RunOpts{
		AutoRemove: true,
	}
	if options.FelixStopGraceful {
		// Leave StopSignal defaulting to SIGTERM, and allow 10 seconds for Felix
		// to handle that gracefully.
		felixOpts.StopTimeoutSecs = 10
	} else {
		// Use SIGKILL to stop Felix immediately.
		felixOpts.StopSignal = "SIGKILL"
	}
	c := containers.RunWithFixedName(containerName, felixOpts, args...)

	if options.EnableIPv6 {
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.disable_ipv6=0")
		c.Exec("sysctl", "-w", "net.ipv6.conf.default.disable_ipv6=0")
		c.Exec("sysctl", "-w", "net.ipv6.conf.lo.disable_ipv6=0")
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.forwarding=1")
	} else {
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.disable_ipv6=1")
		c.Exec("sysctl", "-w", "net.ipv6.conf.default.disable_ipv6=1")
		c.Exec("sysctl", "-w", "net.ipv6.conf.lo.disable_ipv6=1")
		c.Exec("sysctl", "-w", "net.ipv6.conf.all.forwarding=0")
	}

	// Configure our model host to drop forwarded traffic by default.  Modern
	// Kubernetes/Docker hosts now have this setting, and the consequence is that
	// whenever Calico policy intends to allow a packet, it must explicitly ACCEPT
	// that packet, not just allow it to pass through cali-FORWARD and assume it will
	// be accepted by the rest of the chain.  Establishing that setting in this FV
	// allows us to test that.
	c.Exec("iptables",
		"-w", "10", // Retry this for 10 seconds, e.g. if something else is holding the lock
		"-W", "100000", // How often to probe the lock in microsecs.
		"-P", "FORWARD", "DROP")

	return &Felix{
		Container:      c,
		startupDelayed: options.DelayFelixStart,
	}
}

func (f *Felix) Stop() {
	if CreateCgroupV2 {
		_ = f.ExecMayFail("rmdir", path.Join("/run/calico/cgroup/", f.Name))
	}
	f.Container.Stop()
}

func (f *Felix) Restart() {
	oldPID := f.GetFelixPID()
	f.Exec("kill", "-HUP", fmt.Sprint(oldPID))
	Eventually(f.GetFelixPID, "10s", "100ms").ShouldNot(Equal(oldPID))
}

// AttachTCPDump returns tcpdump attached to the container
func (f *Felix) AttachTCPDump(iface string) *tcpdump.TCPDump {
	return tcpdump.Attach(f.Container.Name, "", iface)
}

func (f *Felix) ProgramIptablesDNAT(serviceIP, targetIP, chain string) {
	f.Exec(
		"iptables",
		"-w", "10", // Retry this for 10 seconds, e.g. if something else is holding the lock
		"-W", "100000", // How often to probe the lock in microsecs.
		"-t", "nat", "-A", chain,
		"--destination", serviceIP,
		"-j", "DNAT", "--to-destination", targetIP,
	)
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Google Inc.
//
// 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 resolve

import (
	"context"
	"fmt"

	"github.com/google/gapid/core/image"
	"github.com/google/gapid/gapis/api"
	"github.com/google/gapid/gapis/database"
	"github.com/google/gapid/gapis/messages"
	"github.com/google/gapid/gapis/service"
	"github.com/google/gapid/gapis/service/path"
)

// Thumbnail resolves and returns the thumbnail from the path p.
func Thumbnail(ctx context.Context, p *path.Thumbnail, r *path.ResolveConfig) (*image.Info, error) {
	switch parent := p.Parent().(type) {
	case *path.Command:
		return CommandThumbnail(ctx, p.DesiredMaxWidth, p.DesiredMaxHeight, p.DesiredFormat, p.DisableOptimization, parent, r)
	case *path.CommandTreeNode:
		return CommandTreeNodeThumbnail(ctx, p.DesiredMaxWidth, p.DesiredMaxHeight, p.DesiredFormat, p.DisableOptimization, parent, r)
	case *path.ResourceData:
		return ResourceDataThumbnail(ctx, p.DesiredMaxWidth, p.DesiredMaxHeight, p.DesiredFormat, parent, r)
	default:
		return nil, fmt.Errorf("Unexpected Thumbnail parent %T", parent)
	}
}

// CommandThumbnail resolves and returns the thumbnail for the framebuffer at p.
func CommandThumbnail(
	ctx context.Context,
	w, h uint32,
	f *image.Format,
	noOpt bool,
	p *path.Command,
	r *path.ResolveConfig) (*image.Info, error) {

	imageInfoPath, err := FramebufferAttachment(ctx,
		&service.ReplaySettings{DisableReplayOptimization: noOpt},
		p,
		api.FramebufferAttachment_Color0,
		&service.RenderSettings{
			MaxWidth:  w,
			MaxHeight: h,
			DrawMode:  service.DrawMode_NORMAL,
		},
		&service.UsageHints{
			Preview: true,
		},
		r,
	)
	if err != nil {
		return nil, err
	}

	var boxedImageInfo interface{}
	if f != nil {
		boxedImageInfo, err = Get(ctx, imageInfoPath.As(f).Path(), r)
	} else {
		boxedImageInfo, err = Get(ctx, imageInfoPath.Path(), r)
	}
	if err != nil {
		return nil, err
	}

	return boxedImageInfo.(*image.Info), nil
}

// CommandTreeNodeThumbnail resolves and returns the thumbnail for the framebuffer at p.
func CommandTreeNodeThumbnail(
	ctx context.Context,
	w, h uint32,
	f *image.Format,
	noOpt bool,
	p *path.CommandTreeNode,
	r *path.ResolveConfig) (*image.Info, error) {

	boxedCmdTree, err := database.Resolve(ctx, p.Tree.ID())
	if err != nil {
		return nil, err
	}

	cmdTree := boxedCmdTree.(*commandTree)

	item, _ := cmdTree.index(p.Indices)
	switch item := item.(type) {
	case api.CmdIDGroup:
		thumbnail := item.Range.Last()
		if userData, ok := item.UserData.(*CmdGroupData); ok {
			thumbnail = userData.Representation
		}
		return CommandThumbnail(ctx, w, h, f, noOpt, cmdTree.path.Capture.Command(uint64(thumbnail)), r)
	case api.SubCmdIdx:
		return CommandThumbnail(ctx, w, h, f, noOpt, cmdTree.path.Capture.Command(uint64(item[0]), item[1:]...), r)
	case api.SubCmdRoot:
		return CommandThumbnail(ctx, w, h, f, noOpt, cmdTree.path.Capture.Command(uint64(item.Id[0]), item.Id[1:]...), r)
	default:
		panic(fmt.Errorf("Unexpected type: %T", item))
	}
}

// ResourceDataThumbnail resolves and returns the thumbnail for the resource at p.
func ResourceDataThumbnail(ctx context.Context, w, h uint32, f *image.Format, p *path.ResourceData, r *path.ResolveConfig) (*image.Info, error) {
	obj, err := ResolveInternal(ctx, p, r)
	if err != nil {
		return nil, err
	}

	t, ok := obj.(image.Thumbnailer)
	if !ok {
		return nil, fmt.Errorf("Type %T does not support thumbnailing", obj)
	}

	img, err := t.Thumbnail(ctx, w, h, 1)
	if err != nil {
		return nil, err
	}

	if img == nil || img.Format == nil || img.Bytes == nil {
		return nil, &service.ErrDataUnavailable{Reason: messages.ErrNoTextureData("")}
	}

	if f != nil {
		// Convert the image to the desired format.
		if img.Format.Key() != f.Key() {
			img, err = img.Convert(ctx, f)
			if err != nil {
				return nil, err
			}
		}
	}

	// Image format supports resizing. See if the image should be.
	scaleX, scaleY := float32(1), float32(1)
	if w > 0 && img.Width > w {
		scaleX = float32(w) / float32(img.Width)
	}
	if h > 0 && img.Height > h {
		scaleY = float32(h) / float32(img.Height)
	}
	scale := scaleX // scale := min(scaleX, scaleY)
	if scale > scaleY {
		scale = scaleY
	}

	targetWidth := uint32(float32(img.Width) * scale)
	targetHeight := uint32(float32(img.Height) * scale)

	// Prevent scaling to zero size.
	if targetWidth == 0 {
		targetWidth = 1
	}
	if targetHeight == 0 {
		targetHeight = 1
	}

	if targetWidth == img.Width && targetHeight == img.Height {
		// Image is already at requested target size.
		return img, err
	}

	return img.Resize(ctx, targetWidth, targetHeight, 1)
}
<commit_msg>gapis: Honor the replay device for thumbnail requests.<commit_after>// Copyright (C) 2017 Google Inc.
//
// 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 resolve

import (
	"context"
	"fmt"

	"github.com/google/gapid/core/image"
	"github.com/google/gapid/gapis/api"
	"github.com/google/gapid/gapis/database"
	"github.com/google/gapid/gapis/messages"
	"github.com/google/gapid/gapis/service"
	"github.com/google/gapid/gapis/service/path"
)

// Thumbnail resolves and returns the thumbnail from the path p.
func Thumbnail(ctx context.Context, p *path.Thumbnail, r *path.ResolveConfig) (*image.Info, error) {
	switch parent := p.Parent().(type) {
	case *path.Command:
		return CommandThumbnail(ctx, p.DesiredMaxWidth, p.DesiredMaxHeight, p.DesiredFormat, p.DisableOptimization, parent, r)
	case *path.CommandTreeNode:
		return CommandTreeNodeThumbnail(ctx, p.DesiredMaxWidth, p.DesiredMaxHeight, p.DesiredFormat, p.DisableOptimization, parent, r)
	case *path.ResourceData:
		return ResourceDataThumbnail(ctx, p.DesiredMaxWidth, p.DesiredMaxHeight, p.DesiredFormat, parent, r)
	default:
		return nil, fmt.Errorf("Unexpected Thumbnail parent %T", parent)
	}
}

// CommandThumbnail resolves and returns the thumbnail for the framebuffer at p.
func CommandThumbnail(
	ctx context.Context,
	w, h uint32,
	f *image.Format,
	noOpt bool,
	p *path.Command,
	r *path.ResolveConfig) (*image.Info, error) {

	imageInfoPath, err := FramebufferAttachment(ctx,
		&service.ReplaySettings{
			DisableReplayOptimization: noOpt,
			Device: r.GetReplayDevice(),
		},
		p,
		api.FramebufferAttachment_Color0,
		&service.RenderSettings{
			MaxWidth:  w,
			MaxHeight: h,
			DrawMode:  service.DrawMode_NORMAL,
		},
		&service.UsageHints{
			Preview: true,
		},
		r,
	)
	if err != nil {
		return nil, err
	}

	var boxedImageInfo interface{}
	if f != nil {
		boxedImageInfo, err = Get(ctx, imageInfoPath.As(f).Path(), r)
	} else {
		boxedImageInfo, err = Get(ctx, imageInfoPath.Path(), r)
	}
	if err != nil {
		return nil, err
	}

	return boxedImageInfo.(*image.Info), nil
}

// CommandTreeNodeThumbnail resolves and returns the thumbnail for the framebuffer at p.
func CommandTreeNodeThumbnail(
	ctx context.Context,
	w, h uint32,
	f *image.Format,
	noOpt bool,
	p *path.CommandTreeNode,
	r *path.ResolveConfig) (*image.Info, error) {

	boxedCmdTree, err := database.Resolve(ctx, p.Tree.ID())
	if err != nil {
		return nil, err
	}

	cmdTree := boxedCmdTree.(*commandTree)

	item, _ := cmdTree.index(p.Indices)
	switch item := item.(type) {
	case api.CmdIDGroup:
		thumbnail := item.Range.Last()
		if userData, ok := item.UserData.(*CmdGroupData); ok {
			thumbnail = userData.Representation
		}
		return CommandThumbnail(ctx, w, h, f, noOpt, cmdTree.path.Capture.Command(uint64(thumbnail)), r)
	case api.SubCmdIdx:
		return CommandThumbnail(ctx, w, h, f, noOpt, cmdTree.path.Capture.Command(uint64(item[0]), item[1:]...), r)
	case api.SubCmdRoot:
		return CommandThumbnail(ctx, w, h, f, noOpt, cmdTree.path.Capture.Command(uint64(item.Id[0]), item.Id[1:]...), r)
	default:
		panic(fmt.Errorf("Unexpected type: %T", item))
	}
}

// ResourceDataThumbnail resolves and returns the thumbnail for the resource at p.
func ResourceDataThumbnail(ctx context.Context, w, h uint32, f *image.Format, p *path.ResourceData, r *path.ResolveConfig) (*image.Info, error) {
	obj, err := ResolveInternal(ctx, p, r)
	if err != nil {
		return nil, err
	}

	t, ok := obj.(image.Thumbnailer)
	if !ok {
		return nil, fmt.Errorf("Type %T does not support thumbnailing", obj)
	}

	img, err := t.Thumbnail(ctx, w, h, 1)
	if err != nil {
		return nil, err
	}

	if img == nil || img.Format == nil || img.Bytes == nil {
		return nil, &service.ErrDataUnavailable{Reason: messages.ErrNoTextureData("")}
	}

	if f != nil {
		// Convert the image to the desired format.
		if img.Format.Key() != f.Key() {
			img, err = img.Convert(ctx, f)
			if err != nil {
				return nil, err
			}
		}
	}

	// Image format supports resizing. See if the image should be.
	scaleX, scaleY := float32(1), float32(1)
	if w > 0 && img.Width > w {
		scaleX = float32(w) / float32(img.Width)
	}
	if h > 0 && img.Height > h {
		scaleY = float32(h) / float32(img.Height)
	}
	scale := scaleX // scale := min(scaleX, scaleY)
	if scale > scaleY {
		scale = scaleY
	}

	targetWidth := uint32(float32(img.Width) * scale)
	targetHeight := uint32(float32(img.Height) * scale)

	// Prevent scaling to zero size.
	if targetWidth == 0 {
		targetWidth = 1
	}
	if targetHeight == 0 {
		targetHeight = 1
	}

	if targetWidth == img.Width && targetHeight == img.Height {
		// Image is already at requested target size.
		return img, err
	}

	return img.Resize(ctx, targetWidth, targetHeight, 1)
}
<|endoftext|>


<commit_before>package test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"sync"
	"syscall"
	"testing"
	"time"

	"github.com/prometheus/client_golang/api/alertmanager"
	"github.com/prometheus/common/model"
	"golang.org/x/net/context"
)

type AcceptanceTest struct {
	*testing.T

	opts *AcceptanceOpts

	ams        []*Alertmanager
	collectors []*Collector

	actions map[float64][]func()
}

type AcceptanceOpts struct {
	baseTime  time.Time
	Tolerance time.Duration

	Config string
}

func (opts *AcceptanceOpts) expandTime(rel float64) time.Time {
	return opts.baseTime.Add(time.Duration(rel * float64(time.Second)))
}

func (opts *AcceptanceOpts) relativeTime(act time.Time) float64 {
	return float64(act.Sub(opts.baseTime)) / float64(time.Second)
}

func NewAcceptanceTest(t *testing.T, opts *AcceptanceOpts) *AcceptanceTest {
	test := &AcceptanceTest{
		T:       t,
		opts:    opts,
		actions: map[float64][]func(){},
	}
	opts.baseTime = time.Now()

	return test
}

func freeAddress() string {
	// Let the OS allocate a free address, close it and hope
	// it is still free when starting Alertmanager.
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		panic(err)
	}
	defer l.Close()

	return l.Addr().String()
}

// Do sets the given function to be executed at the given time.
func (t *AcceptanceTest) Do(at float64, f func()) {
	t.actions[at] = append(t.actions[at], f)
}

// Alertmanager returns a new structure that allows starting an instance
// of Alertmanager on a random port.
func (t *AcceptanceTest) Alertmanager() *Alertmanager {
	am := &Alertmanager{
		t:    t,
		opts: t.opts,
	}

	cf, err := ioutil.TempFile("", "am_config")
	if err != nil {
		t.Fatal(err)
	}
	am.confFile = cf

	if _, err := cf.WriteString(t.opts.Config); err != nil {
		t.Fatal(err)
	}

	am.addr = freeAddress()

	t.Logf("AM on %s", am.addr)

	client, err := alertmanager.New(alertmanager.Config{
		Address: fmt.Sprintf("http://%s", am.addr),
	})
	if err != nil {
		t.Error(err)
	}
	am.client = client

	am.cmd = exec.Command("../../alertmanager",
		"-config.file", cf.Name(),
		"-log.level", "debug",
		"-web.listen-address", am.addr,
	)

	var outb, errb bytes.Buffer
	am.cmd.Stdout = &outb
	am.cmd.Stderr = &errb

	t.ams = append(t.ams, am)

	return am
}

func (t *AcceptanceTest) Collector(name string) *Collector {
	co := &Collector{
		t:         t.T,
		name:      name,
		opts:      t.opts,
		collected: map[float64][]model.Alerts{},
		exepected: map[Interval][]model.Alerts{},
	}
	t.collectors = append(t.collectors, co)

	return co
}

// Run starts all Alertmanagers and runs queries against them. It then checks
// whether all expected notifications have arrived at the expected destination.
func (t *AcceptanceTest) Run() {
	for _, am := range t.ams {
		am.Start()
		defer func(am *Alertmanager) {
			am.Terminate()
			am.cleanup()
		}(am)
	}

	t.runActions()

	var latest float64
	for _, coll := range t.collectors {
		if l := coll.latest(); l > latest {
			latest = l
		}
	}

	deadline := t.opts.expandTime(latest)
	time.Sleep(deadline.Sub(time.Now()))

	for _, coll := range t.collectors {
		report := coll.check()
		t.Log(report)
	}

	for _, am := range t.ams {
		t.Logf("stdout:\n%v", am.cmd.Stdout)
		t.Logf("stderr:\n%v", am.cmd.Stderr)
	}
}

// runActions performs the stored actions at the defined times.
func (t *AcceptanceTest) runActions() {
	var wg sync.WaitGroup

	for at, fs := range t.actions {
		ts := t.opts.expandTime(at)
		wg.Add(len(fs))

		for _, f := range fs {
			go func(f func()) {
				time.Sleep(ts.Sub(time.Now()))
				f()
				wg.Done()
			}(f)
		}
	}

	wg.Wait()
}

// Alertmanager encapsulates an Alertmanager process and allows
// declaring alerts being pushed to it at fixed points in time.
type Alertmanager struct {
	t    *AcceptanceTest
	opts *AcceptanceOpts

	addr     string
	client   alertmanager.Client
	cmd      *exec.Cmd
	confFile *os.File
}

// Start the alertmanager and wait until it is ready to receive.
func (am *Alertmanager) Start() {
	if err := am.cmd.Start(); err != nil {
		am.t.Fatalf("Starting alertmanager failed: %s", err)
	}

	time.Sleep(100 * time.Millisecond)
}

// kill the underlying Alertmanager process and remove intermediate data.
func (am *Alertmanager) Terminate() {
	syscall.Kill(am.cmd.Process.Pid, syscall.SIGTERM)
}

// Reload sends the reloading signal to the Alertmanager process.
func (am *Alertmanager) Reload() {
	syscall.Kill(am.cmd.Process.Pid, syscall.SIGHUP)
}

func (am *Alertmanager) cleanup() {
	os.RemoveAll(am.confFile.Name())
}

// Push declares alerts that are to be pushed to the Alertmanager
// server at a relative point in time.
func (am *Alertmanager) Push(at float64, alerts ...*TestAlert) {
	var nas model.Alerts
	for _, a := range alerts {
		nas = append(nas, a.nativeAlert(am.opts))
	}

	am.t.Do(at, func() {
		var buf bytes.Buffer
		if err := json.NewEncoder(&buf).Encode(nas); err != nil {
			am.t.Error(err)
			return
		}

		resp, err := http.Post(fmt.Sprintf("http://%s/api/v1/alerts", am.addr), "application/json", &buf)
		if err != nil {
			am.t.Error(err)
			return
		}
		resp.Body.Close()
	})
}

// SetSilence updates or creates the given Silence.
func (am *Alertmanager) SetSilence(at float64, sil *TestSilence) {
	silences := alertmanager.NewSilenceAPI(am.client)

	am.t.Do(at, func() {
		sid, err := silences.Set(context.Background(), sil.nativeSilence(am.opts))
		if err != nil {
			am.t.Error(err)
			return
		}
		sil.ID = sid
	})
}

// DelSilence deletes the silence with the sid at the given time.
func (am *Alertmanager) DelSilence(at float64, sil *TestSilence) {
	silences := alertmanager.NewSilenceAPI(am.client)

	am.t.Do(at, func() {
		if err := silences.Del(context.Background(), sil.ID); err != nil {
			am.t.Error(err)
		}
	})
}
<commit_msg>Add acceptance test documentation<commit_after>package test

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"sync"
	"syscall"
	"testing"
	"time"

	"github.com/prometheus/client_golang/api/alertmanager"
	"github.com/prometheus/common/model"
	"golang.org/x/net/context"
)

// AcceptanceTest provides declarative definition of given inputs and expected
// output of an Alertmanager setup.
type AcceptanceTest struct {
	*testing.T

	opts *AcceptanceOpts

	ams        []*Alertmanager
	collectors []*Collector

	actions map[float64][]func()
}

// AcceptanceOpts defines configuration paramters for an acceptance test.
type AcceptanceOpts struct {
	baseTime  time.Time
	Tolerance time.Duration

	Config string
}

// expandTime returns the absolute time for the relative time
// calculated from the test's base time.
func (opts *AcceptanceOpts) expandTime(rel float64) time.Time {
	return opts.baseTime.Add(time.Duration(rel * float64(time.Second)))
}

// expandTime returns the relative time for the given time
// calculated from the test's base time.
func (opts *AcceptanceOpts) relativeTime(act time.Time) float64 {
	return float64(act.Sub(opts.baseTime)) / float64(time.Second)
}

// NewAcceptanceTest returns a new acceptance test with the base time
// set to the current time.
func NewAcceptanceTest(t *testing.T, opts *AcceptanceOpts) *AcceptanceTest {
	test := &AcceptanceTest{
		T:       t,
		opts:    opts,
		actions: map[float64][]func(){},
	}
	opts.baseTime = time.Now()

	return test
}

// freeAddress returns a new listen address not currently in use.
func freeAddress() string {
	// Let the OS allocate a free address, close it and hope
	// it is still free when starting Alertmanager.
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		panic(err)
	}
	defer l.Close()

	return l.Addr().String()
}

// Do sets the given function to be executed at the given time.
func (t *AcceptanceTest) Do(at float64, f func()) {
	t.actions[at] = append(t.actions[at], f)
}

// Alertmanager returns a new structure that allows starting an instance
// of Alertmanager on a random port.
func (t *AcceptanceTest) Alertmanager() *Alertmanager {
	am := &Alertmanager{
		t:    t,
		opts: t.opts,
	}

	cf, err := ioutil.TempFile("", "am_config")
	if err != nil {
		t.Fatal(err)
	}
	am.confFile = cf

	if _, err := cf.WriteString(t.opts.Config); err != nil {
		t.Fatal(err)
	}

	am.addr = freeAddress()

	t.Logf("AM on %s", am.addr)

	client, err := alertmanager.New(alertmanager.Config{
		Address: fmt.Sprintf("http://%s", am.addr),
	})
	if err != nil {
		t.Error(err)
	}
	am.client = client

	am.cmd = exec.Command("../../alertmanager",
		"-config.file", cf.Name(),
		"-log.level", "debug",
		"-web.listen-address", am.addr,
	)

	var outb, errb bytes.Buffer
	am.cmd.Stdout = &outb
	am.cmd.Stderr = &errb

	t.ams = append(t.ams, am)

	return am
}

// Collector returns a new collector bound to the test instance.
func (t *AcceptanceTest) Collector(name string) *Collector {
	co := &Collector{
		t:         t.T,
		name:      name,
		opts:      t.opts,
		collected: map[float64][]model.Alerts{},
		exepected: map[Interval][]model.Alerts{},
	}
	t.collectors = append(t.collectors, co)

	return co
}

// Run starts all Alertmanagers and runs queries against them. It then checks
// whether all expected notifications have arrived at the expected destination.
func (t *AcceptanceTest) Run() {
	for _, am := range t.ams {
		am.Start()
		defer func(am *Alertmanager) {
			am.Terminate()
			am.cleanup()
		}(am)
	}

	t.runActions()

	var latest float64
	for _, coll := range t.collectors {
		if l := coll.latest(); l > latest {
			latest = l
		}
	}

	deadline := t.opts.expandTime(latest)
	time.Sleep(deadline.Sub(time.Now()))

	for _, coll := range t.collectors {
		report := coll.check()
		t.Log(report)
	}

	for _, am := range t.ams {
		t.Logf("stdout:\n%v", am.cmd.Stdout)
		t.Logf("stderr:\n%v", am.cmd.Stderr)
	}
}

// runActions performs the stored actions at the defined times.
func (t *AcceptanceTest) runActions() {
	var wg sync.WaitGroup

	for at, fs := range t.actions {
		ts := t.opts.expandTime(at)
		wg.Add(len(fs))

		for _, f := range fs {
			go func(f func()) {
				time.Sleep(ts.Sub(time.Now()))
				f()
				wg.Done()
			}(f)
		}
	}

	wg.Wait()
}

// Alertmanager encapsulates an Alertmanager process and allows
// declaring alerts being pushed to it at fixed points in time.
type Alertmanager struct {
	t    *AcceptanceTest
	opts *AcceptanceOpts

	addr     string
	client   alertmanager.Client
	cmd      *exec.Cmd
	confFile *os.File
}

// Start the alertmanager and wait until it is ready to receive.
func (am *Alertmanager) Start() {
	if err := am.cmd.Start(); err != nil {
		am.t.Fatalf("Starting alertmanager failed: %s", err)
	}

	time.Sleep(100 * time.Millisecond)
}

// kill the underlying Alertmanager process and remove intermediate data.
func (am *Alertmanager) Terminate() {
	syscall.Kill(am.cmd.Process.Pid, syscall.SIGTERM)
}

// Reload sends the reloading signal to the Alertmanager process.
func (am *Alertmanager) Reload() {
	syscall.Kill(am.cmd.Process.Pid, syscall.SIGHUP)
}

func (am *Alertmanager) cleanup() {
	os.RemoveAll(am.confFile.Name())
}

// Push declares alerts that are to be pushed to the Alertmanager
// server at a relative point in time.
func (am *Alertmanager) Push(at float64, alerts ...*TestAlert) {
	var nas model.Alerts
	for _, a := range alerts {
		nas = append(nas, a.nativeAlert(am.opts))
	}

	am.t.Do(at, func() {
		var buf bytes.Buffer
		if err := json.NewEncoder(&buf).Encode(nas); err != nil {
			am.t.Error(err)
			return
		}

		resp, err := http.Post(fmt.Sprintf("http://%s/api/v1/alerts", am.addr), "application/json", &buf)
		if err != nil {
			am.t.Error(err)
			return
		}
		resp.Body.Close()
	})
}

// SetSilence updates or creates the given Silence.
func (am *Alertmanager) SetSilence(at float64, sil *TestSilence) {
	silences := alertmanager.NewSilenceAPI(am.client)

	am.t.Do(at, func() {
		sid, err := silences.Set(context.Background(), sil.nativeSilence(am.opts))
		if err != nil {
			am.t.Error(err)
			return
		}
		sil.ID = sid
	})
}

// DelSilence deletes the silence with the sid at the given time.
func (am *Alertmanager) DelSilence(at float64, sil *TestSilence) {
	silences := alertmanager.NewSilenceAPI(am.client)

	am.t.Do(at, func() {
		if err := silences.Del(context.Background(), sil.ID); err != nil {
			am.t.Error(err)
		}
	})
}
<|endoftext|>


<commit_before>//  Copyright 2017 Walter Schulze
//
//  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 test

import (
	"fmt"
	"math/rand"
	"reflect"
	"testing"
	"testing/quick"
	"time"
)

var r = rand.New(rand.NewSource(time.Now().UnixNano()))

func equal(this, that interface{}) bool {
	eqMethod := reflect.ValueOf(this).MethodByName("Equal")
	res := eqMethod.Call([]reflect.Value{reflect.ValueOf(that)})
	return res[0].Interface().(bool)
}

func random(this interface{}) interface{} {
	v, ok := quick.Value(reflect.TypeOf(this), r)
	if !ok {
		panic(fmt.Sprintf("unable to generate value for type: %T", this))
	}
	return v.Interface()
}

func TestEqual(t *testing.T) {
	structs := []interface{}{
		&BuiltInTypes{},
		&PtrToBuiltInTypes{},
		&SliceOfBuiltInTypes{},
		&SliceOfPtrToBuiltInTypes{},
		&ArrayOfBuiltInTypes{},
		&ArrayOfPtrToBuiltInTypes{},

		&SomeComplexTypes{},
		&RecursiveType{},
	}
	for _, this := range structs {
		desc := reflect.TypeOf(this).Elem().Name()
		t.Run(desc, func(t *testing.T) {
			for i := 0; i < 100; i++ {
				if !equal(this, this) {
					t.Fatal("empty not equal to itself")
				}
				this = random(this)
				if !equal(this, this) {
					t.Fatal("random not equal to itself")
				}
				that := random(this)
				if equal(this, that) {
					t.Fatalf("random %#v equal to another random %#v", this, that)
				}
			}
		})
	}
}
<commit_msg>fix for semi probable nil == nil random value tests<commit_after>//  Copyright 2017 Walter Schulze
//
//  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 test

import (
	"fmt"
	"math/rand"
	"reflect"
	"testing"
	"testing/quick"
	"time"
)

var r = rand.New(rand.NewSource(time.Now().UnixNano()))

func equal(this, that interface{}) bool {
	eqMethod := reflect.ValueOf(this).MethodByName("Equal")
	res := eqMethod.Call([]reflect.Value{reflect.ValueOf(that)})
	return res[0].Interface().(bool)
}

func random(this interface{}) interface{} {
	v, ok := quick.Value(reflect.TypeOf(this), r)
	if !ok {
		panic(fmt.Sprintf("unable to generate value for type: %T", this))
	}
	return v.Interface()
}

func TestEqual(t *testing.T) {
	structs := []interface{}{
		&BuiltInTypes{},
		&PtrToBuiltInTypes{},
		&SliceOfBuiltInTypes{},
		&SliceOfPtrToBuiltInTypes{},
		&ArrayOfBuiltInTypes{},
		&ArrayOfPtrToBuiltInTypes{},

		&SomeComplexTypes{},
		&RecursiveType{},
	}
	for _, this := range structs {
		desc := reflect.TypeOf(this).Elem().Name()
		t.Run(desc, func(t *testing.T) {
			for i := 0; i < 100; i++ {
				if !equal(this, this) {
					t.Fatal("empty not equal to itself")
				}
				this = random(this)
				if !equal(this, this) {
					t.Fatal("random not equal to itself")
				}
				that := random(this)
				for reflect.ValueOf(that).IsNil() {
					that = random(this)
				}
				if equal(this, that) {
					t.Fatalf("random %#v equal to another random %#v", this, that)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package video

import "github.com/32bitkid/clogo"

var log = clogo.NewLog("mpeg:video")
<commit_msg>renaming clog<commit_after>package video

import "github.com/32bitkid/clog"

var log = clog.NewLog("mpeg:video")
<|endoftext|>


<commit_before>package vm

import (
	"fmt"
	"github.com/st0012/metago"
	"os"
	"os/exec"
	"plugin"
	"reflect"
	"strings"
)

func (vm *VM) initPluginObject(fn string, p *plugin.Plugin) *PluginObject {
	return &PluginObject{fn: fn, plugin: p, baseObj: &baseObj{class: vm.topLevelClass(pluginClass)}}
}

func initPluginClass(vm *VM) {
	pc := vm.initializeClass(pluginClass, false)
	pc.setBuiltInMethods(builtinPluginClassMethods(), true)
	pc.setBuiltInMethods(builtinPluginInstanceMethods(), false)
	vm.objectClass.setClassConstant(pc)

	vm.execGobyLib("plugin.gb")
}

type pluginContext struct {
	pkgs  []*pkg
	funcs []*function
}

func (c *pluginContext) importPkg(prefix, name string) {
	c.pkgs = append(c.pkgs, &pkg{Prefix: prefix, Name: name})
}

func (c *pluginContext) addFunc(prefix, name string) {
	c.funcs = append(c.funcs, &function{Prefix: prefix, Name: name})
}

// PluginObject is a special type that contains a Go's plugin
type PluginObject struct {
	*baseObj
	fn     string
	plugin *plugin.Plugin
}

// Polymorphic helper functions -----------------------------------------
func (p *PluginObject) toString() string {
	return "<Plugin: " + p.fn + ">"
}

func (p *PluginObject) toJSON() string {
	return p.toString()
}

func setPluginContext(context Object) *pluginContext {
	pc := &pluginContext{pkgs: []*pkg{}, funcs: []*function{}}

	funcs, _ := context.instanceVariableGet("@funcs")
	pkgs, _ := context.instanceVariableGet("@pkgs")

	fs := funcs.(*ArrayObject)
	ps := pkgs.(*ArrayObject)

	for _, f := range fs.Elements {
		fInfos := f.(*HashObject)
		prefix := fInfos.Pairs["prefix"].(*StringObject).value
		name := fInfos.Pairs["name"].(*StringObject).value

		pc.addFunc(prefix, name)
	}

	for _, p := range ps.Elements {
		pInfos := p.(*HashObject)
		prefix := pInfos.Pairs["prefix"].(*StringObject).value
		name := pInfos.Pairs["name"].(*StringObject).value

		pc.importPkg(prefix, name)
	}

	return pc
}

func builtinPluginClassMethods() []*BuiltInMethodObject {
	return []*BuiltInMethodObject{
		{
			Name: "new",
			Fn: func(receiver Object) builtinMethodBody {
				return func(t *thread, args []Object, blockFrame *callFrame) Object {
					return &PluginObject{baseObj: &baseObj{class: t.vm.topLevelClass(pluginClass), InstanceVariables: newEnvironment()}}
				}
			},
		},
	}
}

func builtinPluginInstanceMethods() []*BuiltInMethodObject {
	return []*BuiltInMethodObject{
		{
			Name: "compile",
			Fn: func(receiver Object) builtinMethodBody {
				return func(t *thread, args []Object, blockFrame *callFrame) Object {
					context, ok := receiver.instanceVariableGet("@context")

					if !ok {
						return NULL
					}

					pc := setPluginContext(context)
					pluginContent := compilePluginTemplate(pc.pkgs, pc.funcs)

					fn := fmt.Sprintf("./%p", pc)
					file, err := os.Create(fn + ".go")

					if err != nil {
						return t.vm.initErrorObject(InternalError, err.Error())
					}

					file.WriteString(pluginContent)

					soName := fn + ".so"

					// Open plugin first
					p, err := plugin.Open(soName)

					// If there's any issue open a plugin, assume it's not well compiled
					if err != nil {
						cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", soName, file.Name())
						out, err := cmd.CombinedOutput()

						if err != nil {
							return t.vm.initErrorObject(InternalError, "Error: %s from %s", string(out), strings.Join(cmd.Args, " "))
						}

						p, err = plugin.Open(soName)

						if err != nil {
							return t.vm.initErrorObject(InternalError, "Error occurs when open %s package: %s", soName, err.Error())
						}
					}

					r := receiver.(*PluginObject)
					r.fn = fn
					r.plugin = p

					return r
				}
			},
		},
		{
			Name: "send",
			Fn: func(receiver Object) builtinMethodBody {
				return func(t *thread, args []Object, blockFrame *callFrame) Object {
					s, ok := args[0].(*StringObject)

					if !ok {
						return t.vm.initErrorObject(TypeError, WrongArgumentTypeFormat, stringClass, args[0].Class().Name)
					}

					funcName := s.value
					r := receiver.(*PluginObject)
					p := r.plugin
					f, err := p.Lookup(funcName)

					if err != nil {
						return t.vm.initErrorObject(InternalError, err.Error())
					}

					funcArgs, err := convertToGoFuncArgs(args[1:])

					if err != nil {
						t.vm.initErrorObject(TypeError, err.Error())
					}

					funcValue := reflect.ValueOf(f)

					// Check if f is a pointer to function instead of function object
					if funcValue.Type().Kind() == reflect.Ptr {
						ptr := funcValue
						funcValue = ptr.Elem()
					}

					result := reflect.ValueOf(funcValue.Call(metago.WrapArguments(funcArgs...))).Interface()

					return t.vm.initObjectFromGoType(metago.UnwrapReflectValues(result))
				}
			},
		},
	}
}
<commit_msg>Create plugin files in specific directory.<commit_after>package vm

import (
	"fmt"
	"github.com/st0012/metago"
	"os"
	"os/exec"
	"plugin"
	"reflect"
	"strings"
	"syscall"
)

func (vm *VM) initPluginObject(fn string, p *plugin.Plugin) *PluginObject {
	return &PluginObject{fn: fn, plugin: p, baseObj: &baseObj{class: vm.topLevelClass(pluginClass)}}
}

func initPluginClass(vm *VM) {
	pc := vm.initializeClass(pluginClass, false)
	pc.setBuiltInMethods(builtinPluginClassMethods(), true)
	pc.setBuiltInMethods(builtinPluginInstanceMethods(), false)
	vm.objectClass.setClassConstant(pc)

	vm.execGobyLib("plugin.gb")
}

type pluginContext struct {
	pkgs  []*pkg
	funcs []*function
}

func (c *pluginContext) importPkg(prefix, name string) {
	c.pkgs = append(c.pkgs, &pkg{Prefix: prefix, Name: name})
}

func (c *pluginContext) addFunc(prefix, name string) {
	c.funcs = append(c.funcs, &function{Prefix: prefix, Name: name})
}

// PluginObject is a special type that contains a Go's plugin
type PluginObject struct {
	*baseObj
	fn     string
	plugin *plugin.Plugin
}

// Polymorphic helper functions -----------------------------------------
func (p *PluginObject) toString() string {
	return "<Plugin: " + p.fn + ">"
}

func (p *PluginObject) toJSON() string {
	return p.toString()
}

func setPluginContext(context Object) *pluginContext {
	pc := &pluginContext{pkgs: []*pkg{}, funcs: []*function{}}

	funcs, _ := context.instanceVariableGet("@funcs")
	pkgs, _ := context.instanceVariableGet("@pkgs")

	fs := funcs.(*ArrayObject)
	ps := pkgs.(*ArrayObject)

	for _, f := range fs.Elements {
		fInfos := f.(*HashObject)
		prefix := fInfos.Pairs["prefix"].(*StringObject).value
		name := fInfos.Pairs["name"].(*StringObject).value

		pc.addFunc(prefix, name)
	}

	for _, p := range ps.Elements {
		pInfos := p.(*HashObject)
		prefix := pInfos.Pairs["prefix"].(*StringObject).value
		name := pInfos.Pairs["name"].(*StringObject).value

		pc.importPkg(prefix, name)
	}

	return pc
}

// exists returns whether the given file or directory exists or not
func fileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}

func builtinPluginClassMethods() []*BuiltInMethodObject {
	return []*BuiltInMethodObject{
		{
			Name: "new",
			Fn: func(receiver Object) builtinMethodBody {
				return func(t *thread, args []Object, blockFrame *callFrame) Object {
					return &PluginObject{baseObj: &baseObj{class: t.vm.topLevelClass(pluginClass), InstanceVariables: newEnvironment()}}
				}
			},
		},
	}
}

func builtinPluginInstanceMethods() []*BuiltInMethodObject {
	return []*BuiltInMethodObject{
		{
			Name: "compile",
			Fn: func(receiver Object) builtinMethodBody {
				return func(t *thread, args []Object, blockFrame *callFrame) Object {
					context, ok := receiver.instanceVariableGet("@context")

					if !ok {
						return NULL
					}

					pc := setPluginContext(context)
					pluginContent := compilePluginTemplate(pc.pkgs, pc.funcs)

					pluginDir := "./plugins"

					ok, err := fileExists(pluginDir)

					if err != nil {
						return t.vm.initErrorObject(InternalError, err.Error())
					}

					if !ok {
						os.Mkdir(pluginDir, syscall.O_RDWR)
					}

					fn := fmt.Sprintf("%s/%p", pluginDir, pc)
					file, err := os.Create(fn + ".go")

					if err != nil {
						return t.vm.initErrorObject(InternalError, err.Error())
					}

					file.WriteString(pluginContent)

					soName := fn + ".so"

					// Open plugin first
					p, err := plugin.Open(soName)

					// If there's any issue open a plugin, assume it's not well compiled
					if err != nil {
						cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", soName, file.Name())
						out, err := cmd.CombinedOutput()

						if err != nil {
							return t.vm.initErrorObject(InternalError, "Error: %s from %s", string(out), strings.Join(cmd.Args, " "))
						}

						p, err = plugin.Open(soName)

						if err != nil {
							return t.vm.initErrorObject(InternalError, "Error occurs when open %s package: %s", soName, err.Error())
						}
					}

					r := receiver.(*PluginObject)
					r.fn = fn
					r.plugin = p

					return r
				}
			},
		},
		{
			Name: "send",
			Fn: func(receiver Object) builtinMethodBody {
				return func(t *thread, args []Object, blockFrame *callFrame) Object {
					s, ok := args[0].(*StringObject)

					if !ok {
						return t.vm.initErrorObject(TypeError, WrongArgumentTypeFormat, stringClass, args[0].Class().Name)
					}

					funcName := s.value
					r := receiver.(*PluginObject)
					p := r.plugin
					f, err := p.Lookup(funcName)

					if err != nil {
						return t.vm.initErrorObject(InternalError, err.Error())
					}

					funcArgs, err := convertToGoFuncArgs(args[1:])

					if err != nil {
						t.vm.initErrorObject(TypeError, err.Error())
					}

					funcValue := reflect.ValueOf(f)

					// Check if f is a pointer to function instead of function object
					if funcValue.Type().Kind() == reflect.Ptr {
						ptr := funcValue
						funcValue = ptr.Elem()
					}

					result := reflect.ValueOf(funcValue.Call(metago.WrapArguments(funcArgs...))).Interface()

					return t.vm.initObjectFromGoType(metago.UnwrapReflectValues(result))
				}
			},
		},
	}
}
<|endoftext|>


<commit_before>package goose_test

import (
    "testing"
)

func TestConvert(t *testing.T) {
    t.Log("Starting Test")
    str := 4
    if str == 0 {
        t.Log("Error should not be nil", str)
        t.Fail()
    }

    if str == 4 {
        t.Log("Correct answer")
    } else {
        t.Log("Should be 4 but got ", str)
        t.Fail()
    }
}
<commit_msg>Remove test test<commit_after><|endoftext|>


<commit_before>// +build darwin

package memory

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
)

// Get memory statistics
func Get() (*Memory, error) {
	memory, err := collectMemoryStats(newMemoryGenerator())
	if err != nil {
		return nil, err
	}
	swap, err := collectSwapStats(newSwapGenerator())
	if err != nil {
		return nil, err
	}
	memory.SwapTotal = swap.total
	memory.SwapUsed = swap.used
	memory.SwapFree = swap.free
	return memory, nil
}

// Memory represents memory statistics for darwin
type Memory struct {
	Total     uint64
	Used      uint64
	Cached    uint64
	Free      uint64
	Active    uint64
	Inactive  uint64
	SwapTotal uint64
	SwapUsed  uint64
	SwapFree  uint64
}

type memoryGenerator interface {
	Start() error
	Output() (io.Reader, error)
	Finish() error
}

type memoryGeneratorImpl struct {
	cmd *exec.Cmd
}

func newMemoryGenerator() *memoryGeneratorImpl {
	return &memoryGeneratorImpl{cmd: exec.Command("vm_stat")}
}

func (gen memoryGeneratorImpl) Start() error {
	return gen.cmd.Start()
}

func (gen memoryGeneratorImpl) Output() (io.Reader, error) {
	return gen.cmd.StdoutPipe()
}

func (gen memoryGeneratorImpl) Finish() error {
	return gen.cmd.Wait()
}

const (
	freePages        = "Pages free"
	activePages      = "Pages active"
	inactivePages    = "Pages inactive"
	speculativePages = "Pages speculative"
	wiredDownPages   = "Pages wired down"
	purgeablePages   = "Pages purgeable"
	fileBackedPages  = "File-backed pages"
	compressedPages  = "Pages occupied by compressor"
)

// References:
//   - https://support.apple.com/en-us/HT201464#memory
//   - https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemory/Articles/AboutMemory.html
//   - https://opensource.apple.com/source/system_cmds/system_cmds-790/vm_stat.tproj/
func collectMemoryStats(gen memoryGenerator) (*Memory, error) {
	out, err := gen.Output()
	if err != nil {
		return nil, err
	}
	scanner := bufio.NewScanner(out)
	if err := gen.Start(); err != nil {
		return nil, err
	}

	if !scanner.Scan() { // skip the first line
		return nil, fmt.Errorf("failed to scan output of vm_stat")
	}

	stats := make(map[string]uint64, 22)
	pageSize := uint64(4096)
	for scanner.Scan() {
		line := scanner.Text()
		i := strings.IndexRune(line, ':')
		if i < 0 {
			continue
		}
		val := strings.TrimRight(strings.TrimSpace(line[i+1:]), ".")
		if v, err := strconv.ParseUint(val, 10, 64); err == nil {
			stats[line[:i]] = v * pageSize
		}
	}

	wired := stats[wiredDownPages]
	compressed := stats[compressedPages]
	cached := stats[purgeablePages] + stats[fileBackedPages]
	active := stats[activePages]
	inactive := stats[inactivePages]
	used := wired + compressed + active + inactive + stats[speculativePages] - cached
	free := stats[freePages]

	if err := gen.Finish(); err != nil {
		return nil, err
	}

	return &Memory{
		Total:    used + cached + free,
		Used:     used,
		Cached:   cached,
		Free:     free,
		Active:   active,
		Inactive: inactive,
	}, nil
}

type memorySwap struct {
	total uint64
	free  uint64
	used  uint64
}

type swapGenerator interface {
	Start() error
	Output() (io.Reader, error)
	Finish() error
}

type swapGeneratorImpl struct {
	cmd *exec.Cmd
}

func newSwapGenerator() *swapGeneratorImpl {
	return &swapGeneratorImpl{cmd: exec.Command("sysctl", "-n", "vm.swapusage")}
}

func (gen swapGeneratorImpl) Start() error {
	return gen.cmd.Start()
}

func (gen swapGeneratorImpl) Output() (io.Reader, error) {
	return gen.cmd.StdoutPipe()
}

func (gen swapGeneratorImpl) Finish() error {
	return gen.cmd.Wait()
}

func collectSwapStats(gen swapGenerator) (*memorySwap, error) {
	out, err := gen.Output()
	if err != nil {
		return nil, err
	}
	if err := gen.Start(); err != nil {
		return nil, err
	}
	var total, used, free float64
	_, err = fmt.Fscanf(out, "total = %fM used = %fM free = %fM", &total, &used, &free)
	if err := gen.Finish(); err != nil {
		return nil, err
	}
	return &memorySwap{
		total: uint64(total * 1024 * 1024),
		used:  uint64(used * 1024 * 1024),
		free:  uint64(free * 1024 * 1024),
	}, nil
}
<commit_msg>error handling of scanner.Err<commit_after>// +build darwin

package memory

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
)

// Get memory statistics
func Get() (*Memory, error) {
	memory, err := collectMemoryStats(newMemoryGenerator())
	if err != nil {
		return nil, err
	}
	swap, err := collectSwapStats(newSwapGenerator())
	if err != nil {
		return nil, err
	}
	memory.SwapTotal = swap.total
	memory.SwapUsed = swap.used
	memory.SwapFree = swap.free
	return memory, nil
}

// Memory represents memory statistics for darwin
type Memory struct {
	Total     uint64
	Used      uint64
	Cached    uint64
	Free      uint64
	Active    uint64
	Inactive  uint64
	SwapTotal uint64
	SwapUsed  uint64
	SwapFree  uint64
}

type memoryGenerator interface {
	Start() error
	Output() (io.Reader, error)
	Finish() error
}

type memoryGeneratorImpl struct {
	cmd *exec.Cmd
}

func newMemoryGenerator() *memoryGeneratorImpl {
	return &memoryGeneratorImpl{cmd: exec.Command("vm_stat")}
}

func (gen memoryGeneratorImpl) Start() error {
	return gen.cmd.Start()
}

func (gen memoryGeneratorImpl) Output() (io.Reader, error) {
	return gen.cmd.StdoutPipe()
}

func (gen memoryGeneratorImpl) Finish() error {
	return gen.cmd.Wait()
}

const (
	freePages        = "Pages free"
	activePages      = "Pages active"
	inactivePages    = "Pages inactive"
	speculativePages = "Pages speculative"
	wiredDownPages   = "Pages wired down"
	purgeablePages   = "Pages purgeable"
	fileBackedPages  = "File-backed pages"
	compressedPages  = "Pages occupied by compressor"
)

// References:
//   - https://support.apple.com/en-us/HT201464#memory
//   - https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemory/Articles/AboutMemory.html
//   - https://opensource.apple.com/source/system_cmds/system_cmds-790/vm_stat.tproj/
func collectMemoryStats(gen memoryGenerator) (*Memory, error) {
	out, err := gen.Output()
	if err != nil {
		return nil, err
	}
	scanner := bufio.NewScanner(out)
	if err := gen.Start(); err != nil {
		return nil, err
	}

	if !scanner.Scan() { // skip the first line
		return nil, fmt.Errorf("failed to scan output of vm_stat")
	}

	stats := make(map[string]uint64, 22)
	pageSize := uint64(4096)
	for scanner.Scan() {
		line := scanner.Text()
		i := strings.IndexRune(line, ':')
		if i < 0 {
			continue
		}
		val := strings.TrimRight(strings.TrimSpace(line[i+1:]), ".")
		if v, err := strconv.ParseUint(val, 10, 64); err == nil {
			stats[line[:i]] = v * pageSize
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	wired := stats[wiredDownPages]
	compressed := stats[compressedPages]
	cached := stats[purgeablePages] + stats[fileBackedPages]
	active := stats[activePages]
	inactive := stats[inactivePages]
	used := wired + compressed + active + inactive + stats[speculativePages] - cached
	free := stats[freePages]

	if err := gen.Finish(); err != nil {
		return nil, err
	}

	return &Memory{
		Total:    used + cached + free,
		Used:     used,
		Cached:   cached,
		Free:     free,
		Active:   active,
		Inactive: inactive,
	}, nil
}

type memorySwap struct {
	total uint64
	free  uint64
	used  uint64
}

type swapGenerator interface {
	Start() error
	Output() (io.Reader, error)
	Finish() error
}

type swapGeneratorImpl struct {
	cmd *exec.Cmd
}

func newSwapGenerator() *swapGeneratorImpl {
	return &swapGeneratorImpl{cmd: exec.Command("sysctl", "-n", "vm.swapusage")}
}

func (gen swapGeneratorImpl) Start() error {
	return gen.cmd.Start()
}

func (gen swapGeneratorImpl) Output() (io.Reader, error) {
	return gen.cmd.StdoutPipe()
}

func (gen swapGeneratorImpl) Finish() error {
	return gen.cmd.Wait()
}

func collectSwapStats(gen swapGenerator) (*memorySwap, error) {
	out, err := gen.Output()
	if err != nil {
		return nil, err
	}
	if err := gen.Start(); err != nil {
		return nil, err
	}
	var total, used, free float64
	_, err = fmt.Fscanf(out, "total = %fM used = %fM free = %fM", &total, &used, &free)
	if err := gen.Finish(); err != nil {
		return nil, err
	}
	return &memorySwap{
		total: uint64(total * 1024 * 1024),
		used:  uint64(used * 1024 * 1024),
		free:  uint64(free * 1024 * 1024),
	}, nil
}
<|endoftext|>


<commit_before>package scope

import (
	"fmt"

	"github.com/micro/go-micro/v2/store"
)

// Scope extends the store, applying a prefix to each request
type Scope struct {
	store.Store
	prefix string
}

// NewScope returns an initialised scope
func NewScope(s store.Store, prefix string) Scope {
	return Scope{Store: s, prefix: prefix}
}

func (s *Scope) Options() store.Options {
	o := s.Store.Options()
	o.Table = s.prefix
	return o
}

func (s *Scope) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
	key = fmt.Sprintf("%v/%v", s.prefix, key)
	return s.Store.Read(key, opts...)
}

func (s *Scope) Write(r *store.Record, opts ...store.WriteOption) error {
	r.Key = fmt.Sprintf("%v/%v", s.prefix, r.Key)
	return s.Store.Write(r, opts...)
}

func (s *Scope) Delete(key string, opts ...store.DeleteOption) error {
	key = fmt.Sprintf("%v/%v", s.prefix, key)
	return s.Store.Delete(key, opts...)
}

func (s *Scope) List(opts ...store.ListOption) ([]string, error) {
	var lops store.ListOptions
	for _, o := range opts {
		o(&lops)
	}

	key := fmt.Sprintf("%v/%v", s.prefix, lops.Prefix)
	opts = append(opts, store.ListPrefix(key))

	return s.Store.List(opts...)
}
<commit_msg>remove util/scope<commit_after><|endoftext|>


<commit_before>package falconPortal

import (
	"fmt"
	"time"

	"strings"

	"github.com/Cepave/open-falcon-backend/modules/fe/g"
	"github.com/Cepave/open-falcon-backend/modules/fe/model/uic"
	log "github.com/Sirupsen/logrus"
	"github.com/astaxie/beego/orm"
)

//generate status filter SQL templete
func genStatusQueryTemplete(status string, feildsName string) (filterTemplete string) {
	statusList := strings.Split(status, ",")
	var filterTempleteArr []string
	for _, s := range statusList {
		filterTempleteArr = append(filterTempleteArr, fmt.Sprintf("%s = '%s'", feildsName, s))
	}
	filterTemplete = strings.Join(filterTempleteArr, " OR ")
	filterTemplete = fmt.Sprintf("( %s )", filterTemplete)
	return
}

func genSqlFilterTemplete(whereConditions []string) string {
	if len(whereConditions) == 0 {
		return ""
	}
	conditions := strings.Join(whereConditions, " AND ")
	return fmt.Sprintf("WHERE %s", conditions)
}

const SkipFilter = "ALL"

func GetEventCases(includeEvents bool, startTime int64, endTime int64, priority string, status string, progressStatus string, limit int, elimit int, username string, metrics string, caseId string) (result []EventCases, err error) {
	config := g.Config()
	q := orm.NewOrm()
	q.Using("falcon_portal")
	var whereConditions []string
	if limit == 0 || limit > config.FalconPortal.Limit {
		limit = config.FalconPortal.Limit
	}

	isadmin, tplids, err := GetCasePermission(username)
	if tplids == "" {
		tplids = "-1"
	}

	//fot generate sql filter
	if startTime != 0 && endTime != 0 {
		whereConditions = append(whereConditions, fmt.Sprintf("update_at BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", startTime, endTime))
	}
	if priority != "ALL" {
		whereConditions = append(whereConditions, fmt.Sprintf("priority IN (%s) ", priority))
	}
	if status != SkipFilter {
		log.Debug("statis ", status)
		whereConditions = append(whereConditions, genStatusQueryTemplete(status, "status"))
	}
	if progressStatus != SkipFilter {
		whereConditions = append(whereConditions, genStatusQueryTemplete(progressStatus, "process_status"))
	}
	if metrics != SkipFilter {
		whereConditions = append(whereConditions, genStatusQueryTemplete(metrics, "metric"))
	}
	if caseId != "" {
		whereConditions = append(whereConditions, fmt.Sprintf("id = '%s'", caseId))
	}
	//perpare ssql statement
	if !isadmin {
		whereConditions = append(whereConditions, fmt.Sprintf("(tpl_creator = '%s' OR template_id in (%s))", username, tplids))
	}
	_, err = q.Raw(fmt.Sprintf("SELECT * FROM `event_cases` %s limit %d", genSqlFilterTemplete(whereConditions), limit)).QueryRows(&result)

	if len(result) == 0 {
		result = []EventCases{}
		return
	}
	if includeEvents {
		//set default number of event
		var eventLimit int
		if eventLimit = elimit; elimit == 0 {
			eventLimit = 10
		}
		for indx, event := range result {
			var eventArr []*Events
			q.Raw(fmt.Sprintf("SELECT * FROM `events` WHERE event_caseId = '%s' order by timestamp DESC Limit %d", event.Id, eventLimit)).QueryRows(&eventArr)
			if len(eventArr) != 0 {
				event.Events = eventArr
			} else {
				event.Events = []*Events{}
			}
			result[indx] = event
		}
	}
	return
}

func GetEvents(startTime int64, endTime int64, status string, limit int, caseId string) (result []EventsRsp, err error) {

	config := g.Config()
	q := orm.NewOrm()
	q.Using("falcon_portal")

	var whereConditions []string

	if status != SkipFilter {
		if status == "OK" {
			whereConditions = append(whereConditions, fmt.Sprintf("events.status = %d", 1))
		} else if status == "PROBLEM" {
			whereConditions = append(whereConditions, fmt.Sprintf("events.status = %d", 0))
		}
	}

	if startTime != 0 && endTime != 0 {
		whereConditions = append(whereConditions, fmt.Sprintf("events.timestamp BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", startTime, endTime))
	}
	if caseId != "" {
		whereConditions = append(whereConditions, fmt.Sprintf("events.event_caseId = '%s'", caseId))
	}
	if limit == 0 {
		limit = config.FalconPortal.Limit
	}

	_, err = q.Raw(fmt.Sprintf(`SELECT events.id as id,
				events.step as step,
				events.cond as cond,
				events.timestamp as timestamp,
				events.event_caseId as eid,
				event_cases.tpl_creator as tpl_creator,
				event_cases.metric as metric,
				event_cases.endpoint as endpoint
				FROM events LEFT JOIN event_cases on event_cases.id = events.event_caseId
				%s ORDER BY events.timestamp DESC limit %d`, genSqlFilterTemplete(whereConditions), limit)).QueryRows(&result)

	if len(result) == 0 {
		result = []EventsRsp{}
	}
	return
}

func CountNumOfTlp() (c int, err error) {
	var h []Tpl
	q := orm.NewOrm()
	q.Using("falcon_portal")
	_, err = q.Raw("select * from `tpl`").QueryRows(&h)
	c = len(h)
	return
}

func GetNotes(eventCaseId string, limit int, startTime int64, endTime int64, filterIgnored bool) (enotes []EventNote, err error) {
	q := orm.NewOrm()
	q.Using("falcon_portal")
	whereConditions := []string{}
	if eventCaseId != "" {
		whereConditions = append(whereConditions, fmt.Sprintf("event_note.event_caseId = '%s' ", eventCaseId))
	}
	switch {
	//allow api only set the startTime and use the currentTime as the endTime
	case startTime != 0 && endTime == 0:
		endTime = time.Now().Unix()
	case startTime != 0 && endTime != 0:
		tempTime := ""
		q.Raw("SELECT timestamp FROM event_cases WHERE id = ?", eventCaseId).QueryRow(&tempTime)
		if tempTime != "" {
			myzone, _ := time.Now().Zone()
			parsedTime, err := time.Parse("2006-01-02 15:04:05 MST", fmt.Sprintf("%s %s", tempTime, myzone))
			log.Debugf("got time: %v , convertedTime: %v, Unix: %v", fmt.Sprintf("%s %s", tempTime, myzone), parsedTime, parsedTime.Unix())
			if err == nil {
				startTime = parsedTime.Unix()
			} else {
				log.Debug(err.Error())
			}
		}
		endTime = time.Now().Unix()
	}
	if startTime > 0 && endTime > 0 {
		whereConditions = append(whereConditions, fmt.Sprintf("event_note.timestamp BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", startTime, endTime))
	}
	if filterIgnored {
		whereConditions = append(whereConditions, "event_note.status != 'ignored' ")
	}
	limitTemplete := ""
	if limit != 0 {
		limitTemplete = fmt.Sprintf("LIMIT %d", limit)
	}
	sqlTemplete := fmt.Sprintf(`SELECT event_note.id as id,
		event_note.event_caseId as event_caseId,
		event_note.note as note,
		event_note.case_id as case_id,
		event_note.event_caseId as eid,
		event_note.status as status,
		event_note.timestamp as timestamp,
		user.name as user_name
		FROM falcon_portal.event_note as event_note LEFT JOIN uic.user as user on event_note.user_id = user.id
		%s ORDER BY event_note.timestamp DESC %s`, genSqlFilterTemplete(whereConditions), limitTemplete)
	_, err = q.Raw(sqlTemplete).QueryRows(&enotes)
	if len(enotes) == 0 {
		enotes = []EventNote{}
	}
	return
}

func GetNote(noteId int64) (EventNote, error) {
	q := orm.NewOrm()
	q.Using("falcon_portal")
	var eventNote EventNote
	err := q.Raw(`SELECT * from event_note WHERE event_note.id = ?`, noteId).QueryRow(&eventNote)
	if err == nil {
		user := uic.ReadUserById(eventNote.UserId)
		eventNote.UserName = user.Name
	}
	return eventNote, err
}
<commit_msg>add sorting on get alert_cases to solve count of number issue<commit_after>package falconPortal

import (
	"fmt"
	"time"

	"strings"

	"github.com/Cepave/open-falcon-backend/modules/fe/g"
	"github.com/Cepave/open-falcon-backend/modules/fe/model/uic"
	log "github.com/Sirupsen/logrus"
	"github.com/astaxie/beego/orm"
)

//generate status filter SQL templete
func genStatusQueryTemplete(status string, feildsName string) (filterTemplete string) {
	statusList := strings.Split(status, ",")
	var filterTempleteArr []string
	for _, s := range statusList {
		filterTempleteArr = append(filterTempleteArr, fmt.Sprintf("%s = '%s'", feildsName, s))
	}
	filterTemplete = strings.Join(filterTempleteArr, " OR ")
	filterTemplete = fmt.Sprintf("( %s )", filterTemplete)
	return
}

func genSqlFilterTemplete(whereConditions []string) string {
	if len(whereConditions) == 0 {
		return ""
	}
	conditions := strings.Join(whereConditions, " AND ")
	return fmt.Sprintf("WHERE %s", conditions)
}

const SkipFilter = "ALL"

func GetEventCases(includeEvents bool, startTime int64, endTime int64, priority string, status string, progressStatus string, limit int, elimit int, username string, metrics string, caseId string) (result []EventCases, err error) {
	config := g.Config()
	q := orm.NewOrm()
	q.Using("falcon_portal")
	var whereConditions []string
	if limit == 0 || limit > config.FalconPortal.Limit {
		limit = config.FalconPortal.Limit
	}

	isadmin, tplids, err := GetCasePermission(username)
	if tplids == "" {
		tplids = "-1"
	}

	//fot generate sql filter
	if startTime != 0 && endTime != 0 {
		whereConditions = append(whereConditions, fmt.Sprintf("update_at BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", startTime, endTime))
	}
	if priority != "ALL" {
		whereConditions = append(whereConditions, fmt.Sprintf("priority IN (%s) ", priority))
	}
	if status != SkipFilter {
		log.Debug("statis ", status)
		whereConditions = append(whereConditions, genStatusQueryTemplete(status, "status"))
	}
	if progressStatus != SkipFilter {
		whereConditions = append(whereConditions, genStatusQueryTemplete(progressStatus, "process_status"))
	}
	if metrics != SkipFilter {
		whereConditions = append(whereConditions, genStatusQueryTemplete(metrics, "metric"))
	}
	if caseId != "" {
		whereConditions = append(whereConditions, fmt.Sprintf("id = '%s'", caseId))
	}
	//perpare ssql statement
	if !isadmin {
		whereConditions = append(whereConditions, fmt.Sprintf("(tpl_creator = '%s' OR template_id in (%s))", username, tplids))
	}
	_, err = q.Raw(fmt.Sprintf("SELECT * FROM `event_cases` %s ORDER BY update_at DESC limit %d", genSqlFilterTemplete(whereConditions), limit)).QueryRows(&result)

	if len(result) == 0 {
		result = []EventCases{}
		return
	}
	if includeEvents {
		//set default number of event
		var eventLimit int
		if eventLimit = elimit; elimit == 0 {
			eventLimit = 10
		}
		for indx, event := range result {
			var eventArr []*Events
			q.Raw(fmt.Sprintf("SELECT * FROM `events` WHERE event_caseId = '%s' order by timestamp DESC Limit %d", event.Id, eventLimit)).QueryRows(&eventArr)
			if len(eventArr) != 0 {
				event.Events = eventArr
			} else {
				event.Events = []*Events{}
			}
			result[indx] = event
		}
	}
	return
}

func GetEvents(startTime int64, endTime int64, status string, limit int, caseId string) (result []EventsRsp, err error) {

	config := g.Config()
	q := orm.NewOrm()
	q.Using("falcon_portal")

	var whereConditions []string

	if status != SkipFilter {
		if status == "OK" {
			whereConditions = append(whereConditions, fmt.Sprintf("events.status = %d", 1))
		} else if status == "PROBLEM" {
			whereConditions = append(whereConditions, fmt.Sprintf("events.status = %d", 0))
		}
	}

	if startTime != 0 && endTime != 0 {
		whereConditions = append(whereConditions, fmt.Sprintf("events.timestamp BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", startTime, endTime))
	}
	if caseId != "" {
		whereConditions = append(whereConditions, fmt.Sprintf("events.event_caseId = '%s'", caseId))
	}
	if limit == 0 {
		limit = config.FalconPortal.Limit
	}

	_, err = q.Raw(fmt.Sprintf(`SELECT events.id as id,
				events.step as step,
				events.cond as cond,
				events.timestamp as timestamp,
				events.event_caseId as eid,
				event_cases.tpl_creator as tpl_creator,
				event_cases.metric as metric,
				event_cases.endpoint as endpoint
				FROM events LEFT JOIN event_cases on event_cases.id = events.event_caseId
				%s ORDER BY events.timestamp DESC limit %d`, genSqlFilterTemplete(whereConditions), limit)).QueryRows(&result)

	if len(result) == 0 {
		result = []EventsRsp{}
	}
	return
}

func CountNumOfTlp() (c int, err error) {
	var h []Tpl
	q := orm.NewOrm()
	q.Using("falcon_portal")
	_, err = q.Raw("select * from `tpl`").QueryRows(&h)
	c = len(h)
	return
}

func GetNotes(eventCaseId string, limit int, startTime int64, endTime int64, filterIgnored bool) (enotes []EventNote, err error) {
	q := orm.NewOrm()
	q.Using("falcon_portal")
	whereConditions := []string{}
	if eventCaseId != "" {
		whereConditions = append(whereConditions, fmt.Sprintf("event_note.event_caseId = '%s' ", eventCaseId))
	}
	switch {
	//allow api only set the startTime and use the currentTime as the endTime
	case startTime != 0 && endTime == 0:
		endTime = time.Now().Unix()
	case startTime != 0 && endTime != 0:
		tempTime := ""
		q.Raw("SELECT timestamp FROM event_cases WHERE id = ?", eventCaseId).QueryRow(&tempTime)
		if tempTime != "" {
			myzone, _ := time.Now().Zone()
			parsedTime, err := time.Parse("2006-01-02 15:04:05 MST", fmt.Sprintf("%s %s", tempTime, myzone))
			log.Debugf("got time: %v , convertedTime: %v, Unix: %v", fmt.Sprintf("%s %s", tempTime, myzone), parsedTime, parsedTime.Unix())
			if err == nil {
				startTime = parsedTime.Unix()
			} else {
				log.Debug(err.Error())
			}
		}
		endTime = time.Now().Unix()
	}
	if startTime > 0 && endTime > 0 {
		whereConditions = append(whereConditions, fmt.Sprintf("event_note.timestamp BETWEEN FROM_UNIXTIME(%d) AND FROM_UNIXTIME(%d)", startTime, endTime))
	}
	if filterIgnored {
		whereConditions = append(whereConditions, "event_note.status != 'ignored' ")
	}
	limitTemplete := ""
	if limit != 0 {
		limitTemplete = fmt.Sprintf("LIMIT %d", limit)
	}
	sqlTemplete := fmt.Sprintf(`SELECT event_note.id as id,
		event_note.event_caseId as event_caseId,
		event_note.note as note,
		event_note.case_id as case_id,
		event_note.event_caseId as eid,
		event_note.status as status,
		event_note.timestamp as timestamp,
		user.name as user_name
		FROM falcon_portal.event_note as event_note LEFT JOIN uic.user as user on event_note.user_id = user.id
		%s ORDER BY event_note.timestamp DESC %s`, genSqlFilterTemplete(whereConditions), limitTemplete)
	_, err = q.Raw(sqlTemplete).QueryRows(&enotes)
	if len(enotes) == 0 {
		enotes = []EventNote{}
	}
	return
}

func GetNote(noteId int64) (EventNote, error) {
	q := orm.NewOrm()
	q.Using("falcon_portal")
	var eventNote EventNote
	err := q.Raw(`SELECT * from event_note WHERE event_note.id = ?`, noteId).QueryRow(&eventNote)
	if err == nil {
		user := uic.ReadUserById(eventNote.UserId)
		eventNote.UserName = user.Name
	}
	return eventNote, err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

func BuildGenerateCommand() *Command {
	var agouti, noDot, internal bool
	flagSet := flag.NewFlagSet("generate", flag.ExitOnError)
	flagSet.BoolVar(&agouti, "agouti", false, "If set, generate will generate a test file for writing Agouti tests")
	flagSet.BoolVar(&noDot, "nodot", false, "If set, generate will generate a test file that does not . import ginkgo and gomega")
	flagSet.BoolVar(&internal, "internal", false, "If set, generate will generate a test file that uses the regular package name")

	return &Command{
		Name:         "generate",
		FlagSet:      flagSet,
		UsageCommand: "ginkgo generate <filename(s)>",
		Usage: []string{
			"Generate a test file named filename_test.go",
			"If the optional <filenames> argument is omitted, a file named after the package in the current directory will be created.",
			"Accepts the following flags:",
		},
		Command: func(args []string, additionalArgs []string) {
			generateSpec(args, agouti, noDot, internal)
		},
	}
}

var specText = `package {{.Package}}

import (
	{{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}}
	{{if .IncludeImports}}. "github.com/onsi/gomega"{{end}}

	{{if .ImportPackage}}"{{.PackageImportPath}}"{{end}}
)

var _ = Describe("{{.Subject}}", func() {

})
`

var agoutiSpecText = `package {{.Package}}

import (
	{{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}}
	{{if .IncludeImports}}. "github.com/onsi/gomega"{{end}}
	"github.com/sclevine/agouti"
	. "github.com/sclevine/agouti/matchers"

	{{if .ImportPackage}}"{{.PackageImportPath}}"{{end}}
)

var _ = Describe("{{.Subject}}", func() {
	var page *agouti.Page

	BeforeEach(func() {
		var err error
		page, err = agoutiDriver.NewPage()
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		Expect(page.Destroy()).To(Succeed())
	})
})
`

type specData struct {
	Package           string
	Subject           string
	PackageImportPath string
	IncludeImports    bool
	ImportPackage     bool
}

func generateSpec(args []string, agouti, noDot, internal bool) {
	if len(args) == 0 {
		err := generateSpecForSubject("", agouti, noDot, internal)
		if err != nil {
			fmt.Println(err.Error())
			fmt.Println("")
			os.Exit(1)
		}
		fmt.Println("")
		return
	}

	var failed bool
	for _, arg := range args {
		err := generateSpecForSubject(arg, agouti, noDot, internal)
		if err != nil {
			failed = true
			fmt.Println(err.Error())
		}
	}
	fmt.Println("")
	if failed {
		os.Exit(1)
	}
}

func generateSpecForSubject(subject string, agouti, noDot, internal bool) error {
	packageName, specFilePrefix, formattedName := getPackageAndFormattedName()
	if subject != "" {
		specFilePrefix = formatSubject(subject)
		formattedName = prettifyPackageName(specFilePrefix)
	}

	data := specData{
		Package:           determinePackageName(packageName, internal),
		Subject:           formattedName,
		PackageImportPath: getPackageImportPath(),
		IncludeImports:    !noDot,
		ImportPackage:     !internal,
	}

	targetFile := fmt.Sprintf("%s_test.go", specFilePrefix)
	if fileExists(targetFile) {
		return fmt.Errorf("%s already exists.", targetFile)
	} else {
		fmt.Printf("Generating ginkgo test for %s in:\n  %s\n", data.Subject, targetFile)
	}

	f, err := os.Create(targetFile)
	if err != nil {
		return err
	}
	defer f.Close()

	var templateText string
	if agouti {
		templateText = agoutiSpecText
	} else {
		templateText = specText
	}

	specTemplate, err := template.New("spec").Parse(templateText)
	if err != nil {
		return err
	}

	specTemplate.Execute(f, data)
	goFmt(targetFile)
	return nil
}

func formatSubject(name string) string {
	name = strings.Replace(name, "-", "_", -1)
	name = strings.Replace(name, " ", "_", -1)
	name = strings.Split(name, ".go")[0]
	name = strings.Split(name, "_test")[0]
	return name
}

// moduleName returns module name from go.mod from given module root directory
func moduleName(modRoot string) string {
	modFile, err := os.Open(filepath.Join(modRoot, "go.mod"))
	if err != nil {
		return ""
	}

	mod := make([]byte, 128)
	_, err = modFile.Read(mod)
	if err != nil {
		return ""
	}

	slashSlash := []byte("//")
	moduleStr := []byte("module")

	for len(mod) > 0 {
		line := mod
		mod = nil
		if i := bytes.IndexByte(line, '\n'); i >= 0 {
			line, mod = line[:i], line[i+1:]
		}
		if i := bytes.Index(line, slashSlash); i >= 0 {
			line = line[:i]
		}
		line = bytes.TrimSpace(line)
		if !bytes.HasPrefix(line, moduleStr) {
			continue
		}
		line = line[len(moduleStr):]
		n := len(line)
		line = bytes.TrimSpace(line)
		if len(line) == n || len(line) == 0 {
			continue
		}

		if line[0] == '"' || line[0] == '`' {
			p, err := strconv.Unquote(string(line))
			if err != nil {
				return "" // malformed quoted string or multiline module path
			}
			return p
		}

		return string(line)
	}

	return "" // missing module path
}

func findModuleRoot(dir string) (root string) {
	dir = filepath.Clean(dir)

	// Look for enclosing go.mod.
	for {
		if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
			return dir
		}
		d := filepath.Dir(dir)
		if d == dir {
			break
		}
		dir = d
	}
	return ""
}

func getPackageImportPath() string {
	workingDir, err := os.Getwd()
	if err != nil {
		panic(err.Error())
	}

	// Try go.mod file first
	modRoot := findModuleRoot(workingDir)
	if modRoot != "" {
		modName := moduleName(modRoot)
		if modName != "" {
			cd := strings.Replace(workingDir, modRoot, "", -1)
			return modName + cd
		}
	}

	// Fallback to GOPATH structure
	sep := string(filepath.Separator)
	paths := strings.Split(workingDir, sep+"src"+sep)
	if len(paths) == 1 {
		fmt.Printf("\nCouldn't identify package import path.\n\n\tginkgo generate\n\nMust be run within a package directory under $GOPATH/src/...\nYou're going to have to change UNKNOWN_PACKAGE_PATH in the generated file...\n\n")
		return "UNKNOWN_PACKAGE_PATH"
	}
	return filepath.ToSlash(paths[len(paths)-1])
}
<commit_msg>correct handling windows backslash in import path (#721)<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

func BuildGenerateCommand() *Command {
	var agouti, noDot, internal bool
	flagSet := flag.NewFlagSet("generate", flag.ExitOnError)
	flagSet.BoolVar(&agouti, "agouti", false, "If set, generate will generate a test file for writing Agouti tests")
	flagSet.BoolVar(&noDot, "nodot", false, "If set, generate will generate a test file that does not . import ginkgo and gomega")
	flagSet.BoolVar(&internal, "internal", false, "If set, generate will generate a test file that uses the regular package name")

	return &Command{
		Name:         "generate",
		FlagSet:      flagSet,
		UsageCommand: "ginkgo generate <filename(s)>",
		Usage: []string{
			"Generate a test file named filename_test.go",
			"If the optional <filenames> argument is omitted, a file named after the package in the current directory will be created.",
			"Accepts the following flags:",
		},
		Command: func(args []string, additionalArgs []string) {
			generateSpec(args, agouti, noDot, internal)
		},
	}
}

var specText = `package {{.Package}}

import (
	{{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}}
	{{if .IncludeImports}}. "github.com/onsi/gomega"{{end}}

	{{if .ImportPackage}}"{{.PackageImportPath}}"{{end}}
)

var _ = Describe("{{.Subject}}", func() {

})
`

var agoutiSpecText = `package {{.Package}}

import (
	{{if .IncludeImports}}. "github.com/onsi/ginkgo"{{end}}
	{{if .IncludeImports}}. "github.com/onsi/gomega"{{end}}
	"github.com/sclevine/agouti"
	. "github.com/sclevine/agouti/matchers"

	{{if .ImportPackage}}"{{.PackageImportPath}}"{{end}}
)

var _ = Describe("{{.Subject}}", func() {
	var page *agouti.Page

	BeforeEach(func() {
		var err error
		page, err = agoutiDriver.NewPage()
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		Expect(page.Destroy()).To(Succeed())
	})
})
`

type specData struct {
	Package           string
	Subject           string
	PackageImportPath string
	IncludeImports    bool
	ImportPackage     bool
}

func generateSpec(args []string, agouti, noDot, internal bool) {
	if len(args) == 0 {
		err := generateSpecForSubject("", agouti, noDot, internal)
		if err != nil {
			fmt.Println(err.Error())
			fmt.Println("")
			os.Exit(1)
		}
		fmt.Println("")
		return
	}

	var failed bool
	for _, arg := range args {
		err := generateSpecForSubject(arg, agouti, noDot, internal)
		if err != nil {
			failed = true
			fmt.Println(err.Error())
		}
	}
	fmt.Println("")
	if failed {
		os.Exit(1)
	}
}

func generateSpecForSubject(subject string, agouti, noDot, internal bool) error {
	packageName, specFilePrefix, formattedName := getPackageAndFormattedName()
	if subject != "" {
		specFilePrefix = formatSubject(subject)
		formattedName = prettifyPackageName(specFilePrefix)
	}

	data := specData{
		Package:           determinePackageName(packageName, internal),
		Subject:           formattedName,
		PackageImportPath: getPackageImportPath(),
		IncludeImports:    !noDot,
		ImportPackage:     !internal,
	}

	targetFile := fmt.Sprintf("%s_test.go", specFilePrefix)
	if fileExists(targetFile) {
		return fmt.Errorf("%s already exists.", targetFile)
	} else {
		fmt.Printf("Generating ginkgo test for %s in:\n  %s\n", data.Subject, targetFile)
	}

	f, err := os.Create(targetFile)
	if err != nil {
		return err
	}
	defer f.Close()

	var templateText string
	if agouti {
		templateText = agoutiSpecText
	} else {
		templateText = specText
	}

	specTemplate, err := template.New("spec").Parse(templateText)
	if err != nil {
		return err
	}

	specTemplate.Execute(f, data)
	goFmt(targetFile)
	return nil
}

func formatSubject(name string) string {
	name = strings.Replace(name, "-", "_", -1)
	name = strings.Replace(name, " ", "_", -1)
	name = strings.Split(name, ".go")[0]
	name = strings.Split(name, "_test")[0]
	return name
}

// moduleName returns module name from go.mod from given module root directory
func moduleName(modRoot string) string {
	modFile, err := os.Open(filepath.Join(modRoot, "go.mod"))
	if err != nil {
		return ""
	}

	mod := make([]byte, 128)
	_, err = modFile.Read(mod)
	if err != nil {
		return ""
	}

	slashSlash := []byte("//")
	moduleStr := []byte("module")

	for len(mod) > 0 {
		line := mod
		mod = nil
		if i := bytes.IndexByte(line, '\n'); i >= 0 {
			line, mod = line[:i], line[i+1:]
		}
		if i := bytes.Index(line, slashSlash); i >= 0 {
			line = line[:i]
		}
		line = bytes.TrimSpace(line)
		if !bytes.HasPrefix(line, moduleStr) {
			continue
		}
		line = line[len(moduleStr):]
		n := len(line)
		line = bytes.TrimSpace(line)
		if len(line) == n || len(line) == 0 {
			continue
		}

		if line[0] == '"' || line[0] == '`' {
			p, err := strconv.Unquote(string(line))
			if err != nil {
				return "" // malformed quoted string or multiline module path
			}
			return p
		}

		return string(line)
	}

	return "" // missing module path
}

func findModuleRoot(dir string) (root string) {
	dir = filepath.Clean(dir)

	// Look for enclosing go.mod.
	for {
		if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
			return dir
		}
		d := filepath.Dir(dir)
		if d == dir {
			break
		}
		dir = d
	}
	return ""
}

func getPackageImportPath() string {
	workingDir, err := os.Getwd()
	if err != nil {
		panic(err.Error())
	}

	sep := string(filepath.Separator)

	// Try go.mod file first
	modRoot := findModuleRoot(workingDir)
	if modRoot != "" {
		modName := moduleName(modRoot)
		if modName != "" {
			cd := strings.Replace(workingDir, modRoot, "", -1)
			cd = strings.ReplaceAll(cd, sep, "/")
			return modName + cd
		}
	}

	// Fallback to GOPATH structure
	paths := strings.Split(workingDir, sep+"src"+sep)
	if len(paths) == 1 {
		fmt.Printf("\nCouldn't identify package import path.\n\n\tginkgo generate\n\nMust be run within a package directory under $GOPATH/src/...\nYou're going to have to change UNKNOWN_PACKAGE_PATH in the generated file...\n\n")
		return "UNKNOWN_PACKAGE_PATH"
	}
	return filepath.ToSlash(paths[len(paths)-1])
}
<|endoftext|>


<commit_before>package tile

import (
	"math"

	"github.com/paulmach/orb/geo"
	"github.com/paulmach/orb/internal/mercator"
	"github.com/paulmach/orb/planar"
	"github.com/paulmach/orb/project"
)

// Tiles is a set of tiles, later we can add methods to this.
type Tiles []Tile

// Tile is an x, y, z web mercator tile.
type Tile struct {
	X, Y, Z uint32
}

// New creates a tile for the point at the given zoom.
func New(ll geo.Point, z uint32) Tile {
	t := Tile{Z: z}
	t.X, t.Y = project.ScalarMercator.ToPlanar(ll, z)

	return t
}

// FromQuadkey creates the tile from the quadkey.
func FromQuadkey(k uint64, z uint32) Tile {
	t := Tile{Z: z}

	for i := uint32(0); i < z; i++ {
		t.X |= uint32((k & (1 << (2 * i))) >> i)
		t.Y |= uint32((k & (1 << (2*i + 1))) >> (i + 1))
	}

	return t
}

// Valid returns if the tile's x/y are within the range for the tile's zoom.
func (t Tile) Valid() bool {
	maxIndex := uint32(1) << t.Z
	return t.X < maxIndex && t.Z < maxIndex
}

// GeoBound returns the geo bound for the tile.
func (t Tile) GeoBound() geo.Bound {
	lon1, lat1 := mercator.ScalarInverse(t.X, t.Y, t.Z)
	lon2, lat2 := mercator.ScalarInverse(t.X+1, t.Y+1, t.Z)

	return geo.Bound{
		geo.Point{lon1, lat2},
		geo.Point{lon2, lat1},
	}
}

// Center returns the center of the tile.
func (t Tile) Center() geo.Point {
	return t.GeoBound().Center()
}

// Contains returns if the given tile is fully contained (or equal to) the give tile.
func (t Tile) Contains(tile Tile) bool {
	if tile.Z < t.Z {
		return false
	}

	return t == tile.toZoom(t.Z)
}

// Parent returns the parent of the tile.
func (t Tile) Parent() Tile {
	if t.Z == 0 {
		return t
	}

	return Tile{
		X: t.X >> 1,
		Y: t.Y >> 1,
		Z: t.Z - 1,
	}
}

// Fraction returns the precise tile fraction at the given zoom.
func (t Tile) Fraction(ll geo.Point, z uint32) planar.Point {
	var p planar.Point

	factor := uint32(1 << z)
	maxtiles := float64(factor)

	lng := ll[0]/360.0 + 0.5
	p[0] = lng * maxtiles

	// bound it because we have a top of the world problem
	siny := math.Sin(ll[1] * math.Pi / 180.0)

	if siny < -0.9999 {
		p[1] = 0
	} else if siny > 0.9999 {
		p[1] = maxtiles
	} else {
		lat := 0.5 + 0.5*math.Log((1.0+siny)/(1.0-siny))/(-2*math.Pi)
		p[1] = lat * maxtiles
	}

	return p
}

// SharedParent returns the tile that contains both the tiles.
func (t Tile) SharedParent(tile Tile) Tile {
	// bring both tiles to the lowest zoom.
	if t.Z < tile.Z {
		tile = tile.toZoom(t.Z)
	} else {
		t = t.toZoom(tile.Z)
	}

	if t == tile {
		return t
	}

	// move from most significant to least until there isn't a match.
	// TODO: this can be improved using the go1.9 bits package.
	for i := t.Z; i > 0; i-- {
		if t.X&(1<<i) != tile.X&(1<<i) ||
			t.Y&(1<<i) != tile.Y&(1<<i) {
			return Tile{
				t.X >> (t.Z - i),
				t.Y >> (t.Z - i),
				i,
			}
		}
	}

	// if we reach here the tiles are the same, which was checked above.
	panic("unreachable")
}

// Children returns the 4 children of the tile.
func (t Tile) Children() Tiles {
	return Tiles{
		Tile{t.X << 1, t.Y << 1, t.Z + 1},
		Tile{(t.X << 1) + 1, t.Y << 1, t.Z + 1},
		Tile{(t.X << 1) + 1, (t.Y << 1) + 1, t.Z + 1},
		Tile{t.X << 1, (t.Y << 1) + 1, t.Z + 1},
	}
}

// Siblings returns the 4 tiles that share this tile's parent.
func (t Tile) Siblings() Tiles {
	return t.Parent().Children()
}

// Quadkey returns the quad key for the tile.
func (t Tile) Quadkey() uint64 {
	var i, result uint64
	for i = 0; i < uint64(t.Z); i++ {
		result |= (uint64(t.X) & (1 << i)) << i
		result |= (uint64(t.Y) & (1 << i)) << (i + 1)
	}

	return result
}

// Range returns the min and max tile "range" to cover the tile
// at the given zoom.
func (t Tile) Range(z uint32) (min, max Tile) {
	if z < t.Z {
		t = t.toZoom(z)
		return t, t
	}

	offset := z - t.Z
	return Tile{
			X: t.X << offset,
			Y: t.Y << offset,
			Z: z,
		}, Tile{
			X: ((t.X + 1) << offset) - 1,
			Y: ((t.Y + 1) << offset) - 1,
			Z: z,
		}
}

func (t Tile) toZoom(z uint32) Tile {
	if z > t.Z {
		return Tile{
			X: t.X << (z - t.Z),
			Y: t.Y << (z - t.Z),
			Z: z,
		}
	}

	return Tile{
		X: t.X >> (t.Z - z),
		Y: t.Y >> (t.Z - z),
		Z: z,
	}
}
<commit_msg>tile: Fraction is a function not a method<commit_after>package tile

import (
	"math"

	"github.com/paulmach/orb/geo"
	"github.com/paulmach/orb/internal/mercator"
	"github.com/paulmach/orb/planar"
	"github.com/paulmach/orb/project"
)

// Tiles is a set of tiles, later we can add methods to this.
type Tiles []Tile

// Tile is an x, y, z web mercator tile.
type Tile struct {
	X, Y, Z uint32
}

// New creates a tile for the point at the given zoom.
func New(ll geo.Point, z uint32) Tile {
	t := Tile{Z: z}
	t.X, t.Y = project.ScalarMercator.ToPlanar(ll, z)

	return t
}

// FromQuadkey creates the tile from the quadkey.
func FromQuadkey(k uint64, z uint32) Tile {
	t := Tile{Z: z}

	for i := uint32(0); i < z; i++ {
		t.X |= uint32((k & (1 << (2 * i))) >> i)
		t.Y |= uint32((k & (1 << (2*i + 1))) >> (i + 1))
	}

	return t
}

// Valid returns if the tile's x/y are within the range for the tile's zoom.
func (t Tile) Valid() bool {
	maxIndex := uint32(1) << t.Z
	return t.X < maxIndex && t.Z < maxIndex
}

// GeoBound returns the geo bound for the tile.
func (t Tile) GeoBound() geo.Bound {
	lon1, lat1 := mercator.ScalarInverse(t.X, t.Y, t.Z)
	lon2, lat2 := mercator.ScalarInverse(t.X+1, t.Y+1, t.Z)

	return geo.Bound{
		geo.Point{lon1, lat2},
		geo.Point{lon2, lat1},
	}
}

// Center returns the center of the tile.
func (t Tile) Center() geo.Point {
	return t.GeoBound().Center()
}

// Contains returns if the given tile is fully contained (or equal to) the give tile.
func (t Tile) Contains(tile Tile) bool {
	if tile.Z < t.Z {
		return false
	}

	return t == tile.toZoom(t.Z)
}

// Parent returns the parent of the tile.
func (t Tile) Parent() Tile {
	if t.Z == 0 {
		return t
	}

	return Tile{
		X: t.X >> 1,
		Y: t.Y >> 1,
		Z: t.Z - 1,
	}
}

// Fraction returns the precise tile fraction at the given zoom.
func Fraction(ll geo.Point, z uint32) planar.Point {
	var p planar.Point

	factor := uint32(1 << z)
	maxtiles := float64(factor)

	lng := ll[0]/360.0 + 0.5
	p[0] = lng * maxtiles

	// bound it because we have a top of the world problem
	siny := math.Sin(ll[1] * math.Pi / 180.0)

	if siny < -0.9999 {
		p[1] = 0
	} else if siny > 0.9999 {
		p[1] = maxtiles
	} else {
		lat := 0.5 + 0.5*math.Log((1.0+siny)/(1.0-siny))/(-2*math.Pi)
		p[1] = lat * maxtiles
	}

	return p
}

// SharedParent returns the tile that contains both the tiles.
func (t Tile) SharedParent(tile Tile) Tile {
	// bring both tiles to the lowest zoom.
	if t.Z < tile.Z {
		tile = tile.toZoom(t.Z)
	} else {
		t = t.toZoom(tile.Z)
	}

	if t == tile {
		return t
	}

	// move from most significant to least until there isn't a match.
	// TODO: this can be improved using the go1.9 bits package.
	for i := t.Z; i > 0; i-- {
		if t.X&(1<<i) != tile.X&(1<<i) ||
			t.Y&(1<<i) != tile.Y&(1<<i) {
			return Tile{
				t.X >> (t.Z - i),
				t.Y >> (t.Z - i),
				i,
			}
		}
	}

	// if we reach here the tiles are the same, which was checked above.
	panic("unreachable")
}

// Children returns the 4 children of the tile.
func (t Tile) Children() Tiles {
	return Tiles{
		Tile{t.X << 1, t.Y << 1, t.Z + 1},
		Tile{(t.X << 1) + 1, t.Y << 1, t.Z + 1},
		Tile{(t.X << 1) + 1, (t.Y << 1) + 1, t.Z + 1},
		Tile{t.X << 1, (t.Y << 1) + 1, t.Z + 1},
	}
}

// Siblings returns the 4 tiles that share this tile's parent.
func (t Tile) Siblings() Tiles {
	return t.Parent().Children()
}

// Quadkey returns the quad key for the tile.
func (t Tile) Quadkey() uint64 {
	var i, result uint64
	for i = 0; i < uint64(t.Z); i++ {
		result |= (uint64(t.X) & (1 << i)) << i
		result |= (uint64(t.Y) & (1 << i)) << (i + 1)
	}

	return result
}

// Range returns the min and max tile "range" to cover the tile
// at the given zoom.
func (t Tile) Range(z uint32) (min, max Tile) {
	if z < t.Z {
		t = t.toZoom(z)
		return t, t
	}

	offset := z - t.Z
	return Tile{
			X: t.X << offset,
			Y: t.Y << offset,
			Z: z,
		}, Tile{
			X: ((t.X + 1) << offset) - 1,
			Y: ((t.Y + 1) << offset) - 1,
			Z: z,
		}
}

func (t Tile) toZoom(z uint32) Tile {
	if z > t.Z {
		return Tile{
			X: t.X << (z - t.Z),
			Y: t.Y << (z - t.Z),
			Z: z,
		}
	}

	return Tile{
		X: t.X >> (t.Z - z),
		Y: t.Y >> (t.Z - z),
		Z: z,
	}
}
<|endoftext|>