<commit_before>package storage

import (
	"context"
	"time"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"kubevirt.io/client-go/kubecli"

	"kubevirt.io/kubevirt/pkg/virtctl/guestfs"
	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/clientcmd"
	"kubevirt.io/kubevirt/tests/libstorage"
	"kubevirt.io/kubevirt/tests/util"
)

const libguestsTools = "libguestfs-tools-"

type fakeAttacher struct {
	done chan bool
}

// fakeCreateAttacher simulates the attacher to the pod console. It has to block until the test terminates.
func (f *fakeAttacher) fakeCreateAttacher(client *guestfs.K8sClient, p *corev1.Pod, command string) error {
	<-f.done
	return nil
}

func (f *fakeAttacher) closeChannel() {
	f.done <- true
}

var _ = SIGDescribe("[rfe_id:6364][[Serial]Guestfs", func() {
	var (
		virtClient kubecli.KubevirtClient
		pvcClaim   string
		setGroup   bool
		testGroup  string
	)
	execCommandLibguestfsPod := func(podName string, c []string) (string, string, error) {
		pod, err := virtClient.CoreV1().Pods(util.NamespaceTestDefault).Get(context.Background(), podName, metav1.GetOptions{})
		Expect(err).ToNot(HaveOccurred())
		return tests.ExecuteCommandOnPodV2(virtClient, pod, "libguestfs", c)
	}

	createPVCFilesystem := func(name string) {
		quantity, _ := resource.ParseQuantity("500Mi")
		_, err := virtClient.CoreV1().PersistentVolumeClaims(util.NamespaceTestDefault).Create(context.Background(), &corev1.PersistentVolumeClaim{
			ObjectMeta: metav1.ObjectMeta{Name: name},
			Spec: corev1.PersistentVolumeClaimSpec{
				AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
				Resources: corev1.ResourceRequirements{
					Requests: corev1.ResourceList{
						"storage": quantity,
					},
				},
			},
		}, metav1.CreateOptions{})
		Expect(err).ToNot(HaveOccurred())

	}

	createFakeAttacher := func() *fakeAttacher {
		f := &fakeAttacher{}
		f.done = make(chan bool, 1)
		guestfs.SetAttacher(f.fakeCreateAttacher)
		return f
	}

	runGuestfsOnPVC := func(pvcClaim string, options ...string) {
		podName := libguestsTools + pvcClaim
		o := append([]string{"guestfs", pvcClaim, "--namespace", util.NamespaceTestDefault}, options...)
		if setGroup {
			o = append(o, "--group", testGroup)
		}
		guestfsCmd := clientcmd.NewVirtctlCommand(o...)
		go func() {
			defer GinkgoRecover()
			Expect(guestfsCmd.Execute()).ToNot(HaveOccurred())
		}()
		// Waiting until the libguestfs pod is running
		Eventually(func() bool {
			pod, _ := virtClient.CoreV1().Pods(util.NamespaceTestDefault).Get(context.Background(), podName, metav1.GetOptions{})
			ready := false
			for _, status := range pod.Status.ContainerStatuses {
				if status.State.Running != nil {
					return true
				}
			}
			return ready

		}, 90*time.Second, 2*time.Second).Should(BeTrue())
		// Verify that the appliance has been extracted before running any tests by checking the done file
		Eventually(func() bool {
			_, _, err := execCommandLibguestfsPod(podName, []string{"ls", "/usr/local/lib/guestfs/appliance/done"})
			if err != nil {
				return false
			}
			return true
		}, 30*time.Second, 2*time.Second).Should(BeTrue())

	}

	verifyCanRunOnFSPVC := func(podName string) {
		stdout, stderr, err := execCommandLibguestfsPod(podName, []string{"qemu-img", "create", "/disk/disk.img", "500M"})
		Expect(stderr).To(Equal(""))
		Expect(stdout).To(ContainSubstring("Formatting"))
		Expect(err).ToNot(HaveOccurred())
		stdout, stderr, err = execCommandLibguestfsPod(podName, []string{"guestfish", "-a", "/disk/disk.img", "run"})
		Expect(stderr).To(BeEmpty())
		Expect(stdout).To(BeEmpty())
		Expect(err).ToNot(HaveOccurred())

	}

	Context("Run libguestfs on PVCs", func() {
		BeforeEach(func() {
			var err error
			virtClient, err = kubecli.GetKubevirtClient()
			Expect(err).ToNot(HaveOccurred())
			// TODO: Always setGroup to true until we have the ability to control how virtctl guestfs is run
			setGroup = true
			testGroup = "2000"
		})

		AfterEach(func() {
			err := virtClient.CoreV1().PersistentVolumeClaims(util.NamespaceTestDefault).Delete(context.Background(), pvcClaim, metav1.DeleteOptions{})
			Expect(err).ToNot(HaveOccurred())
		})

		// libguestfs-test-tool verifies the setup to run libguestfs-tools
		It("Should successfully run libguestfs-test-tool", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-verify"
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim)
			output, _, err := execCommandLibguestfsPod(libguestsTools+pvcClaim, []string{"libguestfs-test-tool"})
			Expect(err).ToNot(HaveOccurred())
			Expect(output).To(ContainSubstring("===== TEST FINISHED OK ====="))

		})

		It("[posneg:positive][test_id:6480]Should successfully run guestfs command on a filesystem-based PVC", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fs"
			podName := libguestsTools + pvcClaim
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim)
			verifyCanRunOnFSPVC(podName)
		})

		It("[posneg:negative][test_id:6480]Should fail to run the guestfs command on a PVC in use", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fail-to-run-twice"
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim)
			guestfsCmd := clientcmd.NewVirtctlCommand("guestfs",
				pvcClaim,
				"--namespace", util.NamespaceTestDefault)
			Expect(guestfsCmd.Execute()).To(HaveOccurred())
		})

		It("[posneg:positive][test_id:6479]Should successfully run guestfs command on a block-based PVC", func() {
			f := createFakeAttacher()
			defer f.closeChannel()

			pvcClaim = "pvc-block"
			podName := libguestsTools + pvcClaim
			libstorage.CreateBlockPVC(pvcClaim, "500Mi")
			runGuestfsOnPVC(pvcClaim)
			stdout, stderr, err := execCommandLibguestfsPod(podName, []string{"guestfish", "-a", "/dev/vda", "run"})
			Expect(stderr).To(Equal(""))
			Expect(stdout).To(Equal(""))
			Expect(err).ToNot(HaveOccurred())

		})
		It("Should successfully run guestfs command on a filesystem-based PVC setting the uid", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fs-with-different-uid"
			podName := libguestsTools + pvcClaim
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim, "--uid", "1002")
			verifyCanRunOnFSPVC(podName)
		})
	})
	Context("Run libguestfs on PVCs with root", func() {
		BeforeEach(func() {
			var err error
			virtClient, err = kubecli.GetKubevirtClient()
			Expect(err).ToNot(HaveOccurred())
			setGroup = false
		})

		AfterEach(func() {
			err := virtClient.CoreV1().PersistentVolumeClaims(util.NamespaceTestDefault).Delete(context.Background(), pvcClaim, metav1.DeleteOptions{})
			Expect(err).ToNot(HaveOccurred())
		})
		It("Should successfully run guestfs command on a filesystem-based PVC with root", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fs-with-different-uid"
			podName := libguestsTools + pvcClaim
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim, "--root")
			verifyCanRunOnFSPVC(podName)
		})
	})

})
<commit_msg>fix fsgrouo flag in the test case<commit_after>package storage

import (
	"context"
	"time"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"kubevirt.io/client-go/kubecli"

	"kubevirt.io/kubevirt/pkg/virtctl/guestfs"
	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/clientcmd"
	"kubevirt.io/kubevirt/tests/libstorage"
	"kubevirt.io/kubevirt/tests/util"
)

const libguestsTools = "libguestfs-tools-"

type fakeAttacher struct {
	done chan bool
}

// fakeCreateAttacher simulates the attacher to the pod console. It has to block until the test terminates.
func (f *fakeAttacher) fakeCreateAttacher(client *guestfs.K8sClient, p *corev1.Pod, command string) error {
	<-f.done
	return nil
}

func (f *fakeAttacher) closeChannel() {
	f.done <- true
}

var _ = SIGDescribe("[rfe_id:6364][[Serial]Guestfs", func() {
	var (
		virtClient kubecli.KubevirtClient
		pvcClaim   string
		setGroup   bool
		testGroup  string
	)
	execCommandLibguestfsPod := func(podName string, c []string) (string, string, error) {
		pod, err := virtClient.CoreV1().Pods(util.NamespaceTestDefault).Get(context.Background(), podName, metav1.GetOptions{})
		Expect(err).ToNot(HaveOccurred())
		return tests.ExecuteCommandOnPodV2(virtClient, pod, "libguestfs", c)
	}

	createPVCFilesystem := func(name string) {
		quantity, _ := resource.ParseQuantity("500Mi")
		_, err := virtClient.CoreV1().PersistentVolumeClaims(util.NamespaceTestDefault).Create(context.Background(), &corev1.PersistentVolumeClaim{
			ObjectMeta: metav1.ObjectMeta{Name: name},
			Spec: corev1.PersistentVolumeClaimSpec{
				AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
				Resources: corev1.ResourceRequirements{
					Requests: corev1.ResourceList{
						"storage": quantity,
					},
				},
			},
		}, metav1.CreateOptions{})
		Expect(err).ToNot(HaveOccurred())

	}

	createFakeAttacher := func() *fakeAttacher {
		f := &fakeAttacher{}
		f.done = make(chan bool, 1)
		guestfs.SetAttacher(f.fakeCreateAttacher)
		return f
	}

	runGuestfsOnPVC := func(pvcClaim string, options ...string) {
		podName := libguestsTools + pvcClaim
		o := append([]string{"guestfs", pvcClaim, "--namespace", util.NamespaceTestDefault}, options...)
		if setGroup {
			o = append(o, "--fsGroup", testGroup)
		}
		guestfsCmd := clientcmd.NewVirtctlCommand(o...)
		go func() {
			defer GinkgoRecover()
			Expect(guestfsCmd.Execute()).ToNot(HaveOccurred())
		}()
		// Waiting until the libguestfs pod is running
		Eventually(func() bool {
			pod, _ := virtClient.CoreV1().Pods(util.NamespaceTestDefault).Get(context.Background(), podName, metav1.GetOptions{})
			ready := false
			for _, status := range pod.Status.ContainerStatuses {
				if status.State.Running != nil {
					return true
				}
			}
			return ready

		}, 90*time.Second, 2*time.Second).Should(BeTrue())
		// Verify that the appliance has been extracted before running any tests by checking the done file
		Eventually(func() bool {
			_, _, err := execCommandLibguestfsPod(podName, []string{"ls", "/usr/local/lib/guestfs/appliance/done"})
			if err != nil {
				return false
			}
			return true
		}, 30*time.Second, 2*time.Second).Should(BeTrue())

	}

	verifyCanRunOnFSPVC := func(podName string) {
		stdout, stderr, err := execCommandLibguestfsPod(podName, []string{"qemu-img", "create", "/disk/disk.img", "500M"})
		Expect(stderr).To(Equal(""))
		Expect(stdout).To(ContainSubstring("Formatting"))
		Expect(err).ToNot(HaveOccurred())
		stdout, stderr, err = execCommandLibguestfsPod(podName, []string{"guestfish", "-a", "/disk/disk.img", "run"})
		Expect(stderr).To(BeEmpty())
		Expect(stdout).To(BeEmpty())
		Expect(err).ToNot(HaveOccurred())

	}

	Context("Run libguestfs on PVCs", func() {
		BeforeEach(func() {
			var err error
			virtClient, err = kubecli.GetKubevirtClient()
			Expect(err).ToNot(HaveOccurred())
			// TODO: Always setGroup to true until we have the ability to control how virtctl guestfs is run
			setGroup = true
			testGroup = "2000"
		})

		AfterEach(func() {
			err := virtClient.CoreV1().PersistentVolumeClaims(util.NamespaceTestDefault).Delete(context.Background(), pvcClaim, metav1.DeleteOptions{})
			Expect(err).ToNot(HaveOccurred())
		})

		// libguestfs-test-tool verifies the setup to run libguestfs-tools
		It("Should successfully run libguestfs-test-tool", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-verify"
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim)
			output, _, err := execCommandLibguestfsPod(libguestsTools+pvcClaim, []string{"libguestfs-test-tool"})
			Expect(err).ToNot(HaveOccurred())
			Expect(output).To(ContainSubstring("===== TEST FINISHED OK ====="))

		})

		It("[posneg:positive][test_id:6480]Should successfully run guestfs command on a filesystem-based PVC", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fs"
			podName := libguestsTools + pvcClaim
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim)
			verifyCanRunOnFSPVC(podName)
		})

		It("[posneg:negative][test_id:6480]Should fail to run the guestfs command on a PVC in use", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fail-to-run-twice"
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim)
			guestfsCmd := clientcmd.NewVirtctlCommand("guestfs",
				pvcClaim,
				"--namespace", util.NamespaceTestDefault)
			Expect(guestfsCmd.Execute()).To(HaveOccurred())
		})

		It("[posneg:positive][test_id:6479]Should successfully run guestfs command on a block-based PVC", func() {
			f := createFakeAttacher()
			defer f.closeChannel()

			pvcClaim = "pvc-block"
			podName := libguestsTools + pvcClaim
			libstorage.CreateBlockPVC(pvcClaim, "500Mi")
			runGuestfsOnPVC(pvcClaim)
			stdout, stderr, err := execCommandLibguestfsPod(podName, []string{"guestfish", "-a", "/dev/vda", "run"})
			Expect(stderr).To(Equal(""))
			Expect(stdout).To(Equal(""))
			Expect(err).ToNot(HaveOccurred())

		})
		It("Should successfully run guestfs command on a filesystem-based PVC setting the uid", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fs-with-different-uid"
			podName := libguestsTools + pvcClaim
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim, "--uid", "1002")
			verifyCanRunOnFSPVC(podName)
		})
	})
	Context("Run libguestfs on PVCs with root", func() {
		BeforeEach(func() {
			var err error
			virtClient, err = kubecli.GetKubevirtClient()
			Expect(err).ToNot(HaveOccurred())
			setGroup = false
		})

		AfterEach(func() {
			err := virtClient.CoreV1().PersistentVolumeClaims(util.NamespaceTestDefault).Delete(context.Background(), pvcClaim, metav1.DeleteOptions{})
			Expect(err).ToNot(HaveOccurred())
		})
		It("Should successfully run guestfs command on a filesystem-based PVC with root", func() {
			f := createFakeAttacher()
			defer f.closeChannel()
			pvcClaim = "pvc-fs-with-different-uid"
			podName := libguestsTools + pvcClaim
			createPVCFilesystem(pvcClaim)
			runGuestfsOnPVC(pvcClaim, "--root")
			verifyCanRunOnFSPVC(podName)
		})
	})

})
<|endoftext|>


<commit_before>package pool

import "net"

//Pool interface describes a connection pool.
type Pool interface {
	//Get returns an available(new or reused) connection from the pool.
	//It blocks when no connection is available.
	//Closing a connection puts the connection back to the pool.
	//Duplicated close is endurable as the second close is ignored.
	Get() (net.Conn, error)

	//Close closes the pool and all its connections.
	//Call Get() when the pool is closed is counted as an error.
	Close()

	//Len returns the current number of connections in the pool,
	//including those that are in use or free.
	Len() int
}
<commit_msg>update doc of Get()<commit_after>package pool

import "net"

//Pool interface describes a connection pool.
type Pool interface {
	//Get returns an available(new or reused) connection from the pool.
	//It blocks when no connection is available.
	//Closing a connection puts the connection back to the pool.
	//Duplicated close of a connection is endurable as the second close is ignored.
	Get() (net.Conn, error)

	//Close closes the pool and all its connections.
	//Call Get() when the pool is closed is counted as an error.
	Close()

	//Len returns the current number of connections in the pool,
	//including those that are in use or free.
	Len() int
}
<|endoftext|>


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

package kubernetes

import (
	"fmt"
	"io"
	"strings"

	"github.com/pkg/errors"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/mgo.v2/bson"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/client/restclient"
	client "k8s.io/kubernetes/pkg/client/unversioned"
)

const (
	provisionerName = "kubernetes"
)

var errNotImplemented = errors.New("not implemented")

type kubernetesProvisioner struct{}

func init() {
	provision.Register(provisionerName, func() (provision.Provisioner, error) {
		return &kubernetesProvisioner{}, nil
	})
}

func (p *kubernetesProvisioner) GetName() string {
	return provisionerName
}

func (p *kubernetesProvisioner) Provision(provision.App) error {
	return nil
}

func (p *kubernetesProvisioner) Destroy(provision.App) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) AddUnits(provision.App, uint, string, io.Writer) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RemoveUnits(provision.App, uint, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) SetUnitStatus(provision.Unit, provision.Status) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Restart(provision.App, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Start(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Stop(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Units(app provision.App) ([]provision.Unit, error) {
	return nil, nil
}

func (p *kubernetesProvisioner) RoutableUnits(app provision.App) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RegisterUnit(unit provision.Unit, customData map[string]interface{}) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ListNodes(addressFilter []string) ([]provision.Node, error) {
	coll, err := nodeAddrCollection()
	if err != nil {
		return nil, err
	}
	defer coll.Close()
	var data kubernetesNodeWrapper
	err = coll.FindId(uniqueDocumentID).One(&data)
	if err != nil {
		return []provision.Node{}, nil
	}
	if len(addressFilter) > 0 {
		for _, addr := range addressFilter {
			if addr == data.Address() {
				return []provision.Node{&data}, nil
			}
		}
		return []provision.Node{}, nil
	}
	return []provision.Node{&data}, nil
}

func (p *kubernetesProvisioner) GetNode(address string) (provision.Node, error) {
	nodes, err := p.ListNodes(nil)
	if err != nil {
		return nil, err
	}
	for _, n := range nodes {
		if address == n.Address() {
			return n, nil
		}
	}
	return nil, provision.ErrNodeNotFound
}

func (p *kubernetesProvisioner) AddNode(opts provision.AddNodeOptions) error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	token, err := config.GetString("kubernetes:token")
	if err != nil {
		return err
	}
	_, err = client.New(&restclient.Config{
		Host:        opts.Address,
		Insecure:    true,
		BearerToken: token,
	})
	if err != nil {
		return err
	}
	addrs := []string{opts.Address}
	_, err = coll.UpsertId(uniqueDocumentID, bson.M{"$set": bson.M{"addresses": addrs}})
	if err != nil {
		return errors.Wrap(err, "")
	}
	return nil
}

func (p *kubernetesProvisioner) RemoveNode(opts provision.RemoveNodeOptions) error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	err = coll.RemoveId(uniqueDocumentID)
	return err
}

func (p *kubernetesProvisioner) UpdateNode(provision.UpdateNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ArchiveDeploy(app provision.App, archiveURL string, evt *event.Event) (imgID string, err error) {
	return "", errNotImplemented
}

func (p *kubernetesProvisioner) ImageDeploy(a provision.App, imgID string, evt *event.Event) (string, error) {
	hosts, err := p.ListNodes(nil)
	if err != nil {
		return "", err
	}
	token, err := config.GetString("kubernetes:token")
	if err != nil {
		return "", err
	}
	client, err := client.New(&restclient.Config{
		Host:        hosts[0].Address(),
		Insecure:    true,
		BearerToken: token,
	})
	if err != nil {
		return "", err
	}
	if !strings.Contains(imgID, ":") {
		imgID = fmt.Sprintf("%s:latest", imgID)
	}
	deployment := extensions.Deployment{
		ObjectMeta: api.ObjectMeta{
			Name: a.GetName(),
		},
		Spec: extensions.DeploymentSpec{
			Replicas: 1,
			Template: api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name: a.GetName(),
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{Name: a.GetName(), Image: imgID},
					},
				},
			},
		},
	}
	_, err = client.Deployments("default").Create(&deployment)
	return "", err
}
<commit_msg>kubernetes: add label metadata<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package kubernetes

import (
	"fmt"
	"io"
	"strings"

	"github.com/pkg/errors"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/mgo.v2/bson"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/client/restclient"
	client "k8s.io/kubernetes/pkg/client/unversioned"
)

const (
	provisionerName = "kubernetes"
)

var errNotImplemented = errors.New("not implemented")

type kubernetesProvisioner struct{}

func init() {
	provision.Register(provisionerName, func() (provision.Provisioner, error) {
		return &kubernetesProvisioner{}, nil
	})
}

func (p *kubernetesProvisioner) GetName() string {
	return provisionerName
}

func (p *kubernetesProvisioner) Provision(provision.App) error {
	return nil
}

func (p *kubernetesProvisioner) Destroy(provision.App) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) AddUnits(provision.App, uint, string, io.Writer) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RemoveUnits(provision.App, uint, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) SetUnitStatus(provision.Unit, provision.Status) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Restart(provision.App, string, io.Writer) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Start(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Stop(provision.App, string) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) Units(app provision.App) ([]provision.Unit, error) {
	return nil, nil
}

func (p *kubernetesProvisioner) RoutableUnits(app provision.App) ([]provision.Unit, error) {
	return nil, errNotImplemented
}

func (p *kubernetesProvisioner) RegisterUnit(unit provision.Unit, customData map[string]interface{}) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ListNodes(addressFilter []string) ([]provision.Node, error) {
	coll, err := nodeAddrCollection()
	if err != nil {
		return nil, err
	}
	defer coll.Close()
	var data kubernetesNodeWrapper
	err = coll.FindId(uniqueDocumentID).One(&data)
	if err != nil {
		return []provision.Node{}, nil
	}
	if len(addressFilter) > 0 {
		for _, addr := range addressFilter {
			if addr == data.Address() {
				return []provision.Node{&data}, nil
			}
		}
		return []provision.Node{}, nil
	}
	return []provision.Node{&data}, nil
}

func (p *kubernetesProvisioner) GetNode(address string) (provision.Node, error) {
	nodes, err := p.ListNodes(nil)
	if err != nil {
		return nil, err
	}
	for _, n := range nodes {
		if address == n.Address() {
			return n, nil
		}
	}
	return nil, provision.ErrNodeNotFound
}

func (p *kubernetesProvisioner) AddNode(opts provision.AddNodeOptions) error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	token, err := config.GetString("kubernetes:token")
	if err != nil {
		return err
	}
	_, err = client.New(&restclient.Config{
		Host:        opts.Address,
		Insecure:    true,
		BearerToken: token,
	})
	if err != nil {
		return err
	}
	addrs := []string{opts.Address}
	_, err = coll.UpsertId(uniqueDocumentID, bson.M{"$set": bson.M{"addresses": addrs}})
	if err != nil {
		return errors.Wrap(err, "")
	}
	return nil
}

func (p *kubernetesProvisioner) RemoveNode(opts provision.RemoveNodeOptions) error {
	coll, err := nodeAddrCollection()
	if err != nil {
		return err
	}
	defer coll.Close()
	err = coll.RemoveId(uniqueDocumentID)
	return err
}

func (p *kubernetesProvisioner) UpdateNode(provision.UpdateNodeOptions) error {
	return errNotImplemented
}

func (p *kubernetesProvisioner) ArchiveDeploy(app provision.App, archiveURL string, evt *event.Event) (imgID string, err error) {
	return "", errNotImplemented
}

func (p *kubernetesProvisioner) ImageDeploy(a provision.App, imgID string, evt *event.Event) (string, error) {
	hosts, err := p.ListNodes(nil)
	if err != nil {
		return "", err
	}
	token, err := config.GetString("kubernetes:token")
	if err != nil {
		return "", err
	}
	client, err := client.New(&restclient.Config{
		Host:        hosts[0].Address(),
		Insecure:    true,
		BearerToken: token,
	})
	if err != nil {
		return "", err
	}
	if !strings.Contains(imgID, ":") {
		imgID = fmt.Sprintf("%s:latest", imgID)
	}
	deployment := extensions.Deployment{
		ObjectMeta: api.ObjectMeta{
			Name: a.GetName(),
		},
		Spec: extensions.DeploymentSpec{
			Replicas: 1,
			Template: api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name: a.GetName(),
					Labels: map[string]string{
						"name": a.GetName(),
					},
				},
				Spec: api.PodSpec{
					Containers: []api.Container{
						{Name: a.GetName(), Image: imgID},
					},
				},
			},
		},
	}
	_, err = client.Deployments("default").Create(&deployment)
	return "", err
}
<|endoftext|>


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

package main

import (
	"image"
	"math"

	"github.com/thinkofdeath/steven/type/direction"
)

type processedModel struct {
	faces            []processedFace
	ambientOcclusion bool
}

type processedFace struct {
	cullFace  direction.Type
	facing    direction.Type
	vertices  []chunkVertex
	shade     bool
	tintIndex int
}

func precomputeModel(bm *blockModel) *processedModel {
	p := &processedModel{}
	p.ambientOcclusion = bm.ambientOcclusion
	for ei := range bm.elements {
		// Render the last element first so that
		// grass's overlay works correctly.
		el := bm.elements[len(bm.elements)-1-ei]
		for i, face := range el.faces {
			faceID := i
			if face == nil {
				continue
			}
			pFace := processedFace{}
			cullFace := face.cullFace
			if bm.y > 0 {
				if cullFace >= 2 {
					var pos int
					for di, d := range faceRotation {
						if d == cullFace {
							pos = di
							break
						}
					}
					cullFace = faceRotation[(pos+(int(bm.y)/90))%len(faceRotation)]
				}
				if faceID >= 2 {
					var pos int
					for di, d := range faceRotation {
						if d == direction.Type(faceID) {
							pos = di
							break
						}
					}
					faceID = int(faceRotation[(pos+(int(bm.y)/90))%len(faceRotation)])
				}
			}
			pFace.cullFace = cullFace
			pFace.facing = direction.Type(faceID)
			pFace.tintIndex = face.tintIndex
			pFace.shade = el.shade

			vert := faceVertices[i]
			tex := bm.lookupTexture(face.texture)

			ux1 := int16(face.uv[0] * tex.Width)
			ux2 := int16(face.uv[2] * tex.Width)
			uy1 := int16(face.uv[1] * tex.Height)
			uy2 := int16(face.uv[3] * tex.Height)

			var minX, minY, minZ int16 = math.MaxInt16, math.MaxInt16, math.MaxInt16
			var maxX, maxY, maxZ int16 = math.MinInt16, math.MinInt16, math.MinInt16

			for v := range vert {
				vert[v].TX = uint16(tex.X)
				vert[v].TY = uint16(tex.Y + tex.Atlas*1024.0)
				vert[v].TW = uint16(tex.Width)
				vert[v].TH = uint16(tex.Height)

				if vert[v].X == 0 {
					vert[v].X = int16(el.from[0] * 16)
				} else {
					vert[v].X = int16(el.to[0] * 16)
				}
				if vert[v].Y == 0 {
					vert[v].Y = int16(el.from[1] * 16)
				} else {
					vert[v].Y = int16(el.to[1] * 16)
				}
				if vert[v].Z == 0 {
					vert[v].Z = int16(el.from[2] * 16)
				} else {
					vert[v].Z = int16(el.to[2] * 16)
				}

				if bm.y > 0 {
					rotY := bm.y * (math.Pi / 180)
					c := int16(math.Cos(rotY))
					s := int16(math.Sin(rotY))
					x := vert[v].X - 8*16
					z := vert[v].Z - 8*16
					vert[v].X = 8*16 + int16(x*c-z*s)
					vert[v].Z = 8*16 + int16(z*c+x*s)
				}

				if el.rotation != nil {
					r := el.rotation
					switch r.axis {
					case "y":
						rotY := r.angle * (math.Pi / 180)
						c := math.Cos(rotY)
						s := math.Sin(rotY)
						x := float64(vert[v].X) - r.origin[0]*16
						z := float64(vert[v].Z) - r.origin[2]*16
						vert[v].X = int16(r.origin[0] + (x*c - z*s))
						vert[v].Z = int16(r.origin[2] + (z*c + x*s))
					}
				}

				if vert[v].TOffsetX == 0 {
					vert[v].TOffsetX = int16(ux1)
				} else {
					vert[v].TOffsetX = int16(ux2)
				}
				if vert[v].TOffsetY == 0 {
					vert[v].TOffsetY = int16(uy1)
				} else {
					vert[v].TOffsetY = int16(uy2)
				}

				if face.rotation > 0 {
					rotY := float64(face.rotation) * (math.Pi / 180)
					c := int16(math.Cos(rotY))
					s := int16(math.Sin(rotY))
					x := vert[v].TOffsetX - 8*16
					y := vert[v].TOffsetY - 8*16
					vert[v].TOffsetX = 8*16 + int16(x*c-y*s)
					vert[v].TOffsetY = 8*16 + int16(y*c+x*s)
				}

				if el.rotation != nil && el.rotation.rescale {
					if vert[v].X < minX {
						minX = vert[v].X
					} else if vert[v].X > maxX {
						maxX = vert[v].X
					}
					if vert[v].Y < minY {
						minY = vert[v].Y
					} else if vert[v].Y > maxY {
						maxY = vert[v].Y
					}
					if vert[v].Z < minZ {
						minZ = vert[v].Z
					} else if vert[v].Z > maxZ {
						maxZ = vert[v].Z
					}
				}
			}

			if el.rotation != nil && el.rotation.rescale {
				diffX := float64(maxX - minX)
				diffY := float64(maxY - minY)
				diffZ := float64(maxZ - minZ)
				for v := range vert {
					vert[v].X = int16((float64(vert[v].X-minX) / diffX) * 256)
					vert[v].Y = int16((float64(vert[v].Y-minY) / diffY) * 256)
					vert[v].Z = int16((float64(vert[v].Z-minZ) / diffZ) * 256)
				}
			}

			pFace.vertices = vert[:]

			p.faces = append(p.faces, pFace)
		}
	}
	return p
}

func (p processedModel) Render(x, y, z int, bs *blocksSnapshot) []chunkVertex {
	var out []chunkVertex
	this := bs.block(x, y, z)
	for _, f := range p.faces {
		if f.cullFace != direction.Invalid {
			ox, oy, oz := f.cullFace.Offset()
			if b := bs.block(x+ox, y+oy, z+oz); b.ShouldCullAgainst() || b == this {
				continue
			}
		}

		off := len(out)
		out = append(out, f.vertices...)
		verts := out[off:]

		var cr, cg, cb byte
		cr = 255
		cg = 255
		cb = 255
		if this.TintImage() != nil {
			switch f.tintIndex {
			case 0:
				cr, cg, cb = calculateBiome(bs, x, z, this.TintImage())
			}
		}
		if f.facing == direction.West || f.facing == direction.East {
			cr = byte(float64(cr) * 0.8)
			cg = byte(float64(cg) * 0.8)
			cb = byte(float64(cb) * 0.8)
		}

		for i := range verts {
			verts[i].R = cr
			verts[i].G = cg
			verts[i].B = cb

			verts[i].X += int16(x * 256)
			verts[i].Y += int16(y * 256)
			verts[i].Z += int16(z * 256)

			verts[i].BlockLight, verts[i].SkyLight = calculateLight(
				bs,
				x, y, z,
				float64(verts[i].X)/256.0,
				float64(verts[i].Y)/256.0,
				float64(verts[i].Z)/256.0,
				int(f.facing), p.ambientOcclusion, this.ForceShade(),
			)
		}
	}
	return out
}

// Takes an average of the biome colors of the surrounding area
func calculateBiome(bs *blocksSnapshot, x, z int, img *image.NRGBA) (byte, byte, byte) {
	count := 0
	var r, g, b int
	for xx := -2; xx <= 2; xx++ {
		for zz := -2; zz <= 2; zz++ {
			biome := bs.biome(x+xx, z+zz)
			ix := biome.ColorIndex & 0xFF
			iy := biome.ColorIndex >> 8
			col := img.NRGBAAt(ix, iy)
			r += int(col.R)
			g += int(col.G)
			b += int(col.B)
			count++
		}
	}
	return byte(r / count), byte(g / count), byte(b / count)
}

func calculateLight(bs *blocksSnapshot, origX, origY, origZ int,
	x, y, z float64, face int, smooth, force bool) (byte, byte) {
	blockLight := bs.blockLight(origX, origY, origZ)
	skyLight := bs.skyLight(origX, origY, origZ)
	if !smooth {
		return blockLight, skyLight
	}
	count := 1

	// TODO(Think) Document/cleanup this
	// it was taken from and older renderer of mine
	// (thinkmap).

	var pox, poy, poz, nox, noy, noz int

	switch face {
	case 0: // Up
		poz, pox = 0, 0
		noz, nox = -1, -1
		poy = 1
		noy = 0
	case 1: // Down
		poz, pox = 0, 0
		noz, nox = -1, -1
		poy = -1
		noy = -2
	case 2: // North
		poy, pox = 0, 0
		noy, nox = -1, -1
		poz = -1
		noz = -2
	case 3: // South
		poy, pox = 0, 0
		noy, nox = -1, -1
		poz = 1
		noz = 0
	case 4: // West
		poz, poy = 0, 0
		noz, noy = -1, -1
		pox = -1
		nox = -2
	case 5: // East
		poz, poy = 0, 0
		noz, noy = -1, -1
		pox = 1
		nox = 0
	}
	for ox := nox; ox <= pox; ox++ {
		for oy := noy; oy <= poy; oy++ {
			for oz := noz; oz <= poz; oz++ {
				bx := round(x + float64(ox))
				by := round(y + float64(oy))
				bz := round(z + float64(oz))
				count++
				blockLight += bs.blockLight(bx, by, bz)
				if !force {
					skyLight += bs.skyLight(bx, by, bz)
				} else if bl := bs.block(bx, by, bz); bl.Is(BlockAir) {
					skyLight += 15
				}
			}
		}

	}

	return blockLight / byte(count), skyLight / byte(count)
}

func round(f float64) int {
	return int(f + math.Copysign(0.5, f))
}
<commit_msg>/: support x and z rotation<commit_after>// Copyright 2015 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"image"
	"math"

	"github.com/thinkofdeath/steven/type/direction"
)

type processedModel struct {
	faces            []processedFace
	ambientOcclusion bool
}

type processedFace struct {
	cullFace  direction.Type
	facing    direction.Type
	vertices  []chunkVertex
	shade     bool
	tintIndex int
}

func precomputeModel(bm *blockModel) *processedModel {
	p := &processedModel{}
	p.ambientOcclusion = bm.ambientOcclusion
	for ei := range bm.elements {
		// Render the last element first so that
		// grass's overlay works correctly.
		el := bm.elements[len(bm.elements)-1-ei]
		for i, face := range el.faces {
			faceID := i
			if face == nil {
				continue
			}
			pFace := processedFace{}
			cullFace := face.cullFace
			if bm.y > 0 {
				if cullFace >= 2 {
					var pos int
					for di, d := range faceRotation {
						if d == cullFace {
							pos = di
							break
						}
					}
					cullFace = faceRotation[(pos+(int(bm.y)/90))%len(faceRotation)]
				}
				if faceID >= 2 {
					var pos int
					for di, d := range faceRotation {
						if d == direction.Type(faceID) {
							pos = di
							break
						}
					}
					faceID = int(faceRotation[(pos+(int(bm.y)/90))%len(faceRotation)])
				}
			}
			pFace.cullFace = cullFace
			pFace.facing = direction.Type(faceID)
			pFace.tintIndex = face.tintIndex
			pFace.shade = el.shade

			vert := faceVertices[i]
			tex := bm.lookupTexture(face.texture)

			ux1 := int16(face.uv[0] * tex.Width)
			ux2 := int16(face.uv[2] * tex.Width)
			uy1 := int16(face.uv[1] * tex.Height)
			uy2 := int16(face.uv[3] * tex.Height)

			var minX, minY, minZ int16 = math.MaxInt16, math.MaxInt16, math.MaxInt16
			var maxX, maxY, maxZ int16 = math.MinInt16, math.MinInt16, math.MinInt16

			for v := range vert {
				vert[v].TX = uint16(tex.X)
				vert[v].TY = uint16(tex.Y + tex.Atlas*1024.0)
				vert[v].TW = uint16(tex.Width)
				vert[v].TH = uint16(tex.Height)

				if vert[v].X == 0 {
					vert[v].X = int16(el.from[0] * 16)
				} else {
					vert[v].X = int16(el.to[0] * 16)
				}
				if vert[v].Y == 0 {
					vert[v].Y = int16(el.from[1] * 16)
				} else {
					vert[v].Y = int16(el.to[1] * 16)
				}
				if vert[v].Z == 0 {
					vert[v].Z = int16(el.from[2] * 16)
				} else {
					vert[v].Z = int16(el.to[2] * 16)
				}

				if bm.y > 0 {
					rotY := bm.y * (math.Pi / 180)
					c := int16(math.Cos(rotY))
					s := int16(math.Sin(rotY))
					x := vert[v].X - 8*16
					z := vert[v].Z - 8*16
					vert[v].X = 8*16 + int16(x*c-z*s)
					vert[v].Z = 8*16 + int16(z*c+x*s)
				}

				if el.rotation != nil {
					r := el.rotation
					switch r.axis {
					case "y":
						rotY := r.angle * (math.Pi / 180)
						c := math.Cos(rotY)
						s := math.Sin(rotY)
						x := float64(vert[v].X) - r.origin[0]*16
						z := float64(vert[v].Z) - r.origin[2]*16
						vert[v].X = int16(r.origin[0] + (x*c - z*s))
						vert[v].Z = int16(r.origin[2] + (z*c + x*s))
					case "x":
						rotX := r.angle * (math.Pi / 180)
						c := math.Cos(-rotX)
						s := math.Sin(-rotX)
						z := float64(vert[v].Z) - r.origin[1]*16
						y := float64(vert[v].Y) - r.origin[1]*16
						vert[v].Z = int16(r.origin[2] + (z*c - y*s))
						vert[v].Y = int16(r.origin[1] + (y*c + z*s))
					case "z":
						rotZ := r.angle * (math.Pi / 180)
						c := math.Cos(-rotZ)
						s := math.Sin(-rotZ)
						x := float64(vert[v].X) - r.origin[0]*16
						y := float64(vert[v].Y) - r.origin[1]*16
						vert[v].X = int16(r.origin[0] + (x*c - y*s))
						vert[v].Y = int16(r.origin[1] + (y*c + x*s))
					}
				}

				if vert[v].TOffsetX == 0 {
					vert[v].TOffsetX = int16(ux1)
				} else {
					vert[v].TOffsetX = int16(ux2)
				}
				if vert[v].TOffsetY == 0 {
					vert[v].TOffsetY = int16(uy1)
				} else {
					vert[v].TOffsetY = int16(uy2)
				}

				if face.rotation > 0 {
					rotY := float64(face.rotation) * (math.Pi / 180)
					c := int16(math.Cos(rotY))
					s := int16(math.Sin(rotY))
					x := vert[v].TOffsetX - 8*16
					y := vert[v].TOffsetY - 8*16
					vert[v].TOffsetX = 8*16 + int16(x*c-y*s)
					vert[v].TOffsetY = 8*16 + int16(y*c+x*s)
				}

				if el.rotation != nil && el.rotation.rescale {
					if vert[v].X < minX {
						minX = vert[v].X
					} else if vert[v].X > maxX {
						maxX = vert[v].X
					}
					if vert[v].Y < minY {
						minY = vert[v].Y
					} else if vert[v].Y > maxY {
						maxY = vert[v].Y
					}
					if vert[v].Z < minZ {
						minZ = vert[v].Z
					} else if vert[v].Z > maxZ {
						maxZ = vert[v].Z
					}
				}
			}

			if el.rotation != nil && el.rotation.rescale {
				diffX := float64(maxX - minX)
				diffY := float64(maxY - minY)
				diffZ := float64(maxZ - minZ)
				for v := range vert {
					vert[v].X = int16((float64(vert[v].X-minX) / diffX) * 256)
					vert[v].Y = int16((float64(vert[v].Y-minY) / diffY) * 256)
					vert[v].Z = int16((float64(vert[v].Z-minZ) / diffZ) * 256)
				}
			}

			pFace.vertices = vert[:]

			p.faces = append(p.faces, pFace)
		}
	}
	return p
}

func (p processedModel) Render(x, y, z int, bs *blocksSnapshot) []chunkVertex {
	var out []chunkVertex
	this := bs.block(x, y, z)
	for _, f := range p.faces {
		if f.cullFace != direction.Invalid {
			ox, oy, oz := f.cullFace.Offset()
			if b := bs.block(x+ox, y+oy, z+oz); b.ShouldCullAgainst() || b == this {
				continue
			}
		}

		off := len(out)
		out = append(out, f.vertices...)
		verts := out[off:]

		var cr, cg, cb byte
		cr = 255
		cg = 255
		cb = 255
		if this.TintImage() != nil {
			switch f.tintIndex {
			case 0:
				cr, cg, cb = calculateBiome(bs, x, z, this.TintImage())
			}
		}
		if f.facing == direction.West || f.facing == direction.East {
			cr = byte(float64(cr) * 0.8)
			cg = byte(float64(cg) * 0.8)
			cb = byte(float64(cb) * 0.8)
		}

		for i := range verts {
			verts[i].R = cr
			verts[i].G = cg
			verts[i].B = cb

			verts[i].X += int16(x * 256)
			verts[i].Y += int16(y * 256)
			verts[i].Z += int16(z * 256)

			verts[i].BlockLight, verts[i].SkyLight = calculateLight(
				bs,
				x, y, z,
				float64(verts[i].X)/256.0,
				float64(verts[i].Y)/256.0,
				float64(verts[i].Z)/256.0,
				int(f.facing), p.ambientOcclusion, this.ForceShade(),
			)
		}
	}
	return out
}

// Takes an average of the biome colors of the surrounding area
func calculateBiome(bs *blocksSnapshot, x, z int, img *image.NRGBA) (byte, byte, byte) {
	count := 0
	var r, g, b int
	for xx := -2; xx <= 2; xx++ {
		for zz := -2; zz <= 2; zz++ {
			biome := bs.biome(x+xx, z+zz)
			ix := biome.ColorIndex & 0xFF
			iy := biome.ColorIndex >> 8
			col := img.NRGBAAt(ix, iy)
			r += int(col.R)
			g += int(col.G)
			b += int(col.B)
			count++
		}
	}
	return byte(r / count), byte(g / count), byte(b / count)
}

func calculateLight(bs *blocksSnapshot, origX, origY, origZ int,
	x, y, z float64, face int, smooth, force bool) (byte, byte) {
	blockLight := bs.blockLight(origX, origY, origZ)
	skyLight := bs.skyLight(origX, origY, origZ)
	if !smooth {
		return blockLight, skyLight
	}
	count := 1

	// TODO(Think) Document/cleanup this
	// it was taken from and older renderer of mine
	// (thinkmap).

	var pox, poy, poz, nox, noy, noz int

	switch face {
	case 0: // Up
		poz, pox = 0, 0
		noz, nox = -1, -1
		poy = 1
		noy = 0
	case 1: // Down
		poz, pox = 0, 0
		noz, nox = -1, -1
		poy = -1
		noy = -2
	case 2: // North
		poy, pox = 0, 0
		noy, nox = -1, -1
		poz = -1
		noz = -2
	case 3: // South
		poy, pox = 0, 0
		noy, nox = -1, -1
		poz = 1
		noz = 0
	case 4: // West
		poz, poy = 0, 0
		noz, noy = -1, -1
		pox = -1
		nox = -2
	case 5: // East
		poz, poy = 0, 0
		noz, noy = -1, -1
		pox = 1
		nox = 0
	}
	for ox := nox; ox <= pox; ox++ {
		for oy := noy; oy <= poy; oy++ {
			for oz := noz; oz <= poz; oz++ {
				bx := round(x + float64(ox))
				by := round(y + float64(oy))
				bz := round(z + float64(oz))
				count++
				blockLight += bs.blockLight(bx, by, bz)
				if !force {
					skyLight += bs.skyLight(bx, by, bz)
				} else if bl := bs.block(bx, by, bz); bl.Is(BlockAir) {
					skyLight += 15
				}
			}
		}

	}

	return blockLight / byte(count), skyLight / byte(count)
}

func round(f float64) int {
	return int(f + math.Copysign(0.5, f))
}
<|endoftext|>


<commit_before>package ethutil

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math/big"
	"strings"
)

// Number to bytes
//
// Returns the number in bytes with the specified base
func NumberToBytes(num interface{}, bits int) []byte {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, num)
	if err != nil {
		fmt.Println("NumberToBytes failed:", err)
	}

	return buf.Bytes()[buf.Len()-(bits/8):]
}

// Bytes to number
//
// Attempts to cast a byte slice to a unsigned integer
func BytesToNumber(b []byte) uint64 {
	var number uint64

	// Make sure the buffer is 64bits
	data := make([]byte, 8)
	data = append(data[:len(b)], b...)

	buf := bytes.NewReader(data)
	err := binary.Read(buf, binary.BigEndian, &number)
	if err != nil {
		fmt.Println("BytesToNumber failed:", err)
	}

	return number
}

// Read variable int
//
// Read a variable length number in big endian byte order
func ReadVarint(reader *bytes.Reader) (ret uint64) {
	if reader.Len() == 8 {
		var num uint64
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	} else if reader.Len() == 4 {
		var num uint32
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	} else if reader.Len() == 2 {
		var num uint16
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	} else {
		var num uint8
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	}

	return ret
}

// Binary length
//
// Returns the true binary length of the given number
func BinaryLength(num int) int {
	if num == 0 {
		return 0
	}

	return 1 + BinaryLength(num>>8)
}

// Copy bytes
//
// Returns an exact copy of the provided bytes
func CopyBytes(b []byte) (copiedBytes []byte) {
	copiedBytes = make([]byte, len(b))
	copy(copiedBytes, b)

	return
}

func IsHex(str string) bool {
	l := len(str)
	return l >= 4 && l%2 == 0 && str[0:2] == "0x"
}

func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
	if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") {
		ret = FromHex(str[2:])
	} else {
		ret = cb(str)
	}

	return
}

func FormatData(data string) []byte {
	if len(data) == 0 {
		return nil
	}
	// Simple stupid
	d := new(big.Int)
	if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
		d.SetBytes([]byte(data[1 : len(data)-1]))
	} else if len(data) > 1 && data[:2] == "0x" {
		d.SetBytes(FromHex(data[2:]))
	} else {
		d.SetString(data, 0)
	}

	return BigToBytes(d, 256)
}
<commit_msg>move ethutil hex conversion functions to bytes<commit_after>package ethutil

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"math/big"
	"strings"
)

// Number to bytes
//
// Returns the number in bytes with the specified base
func NumberToBytes(num interface{}, bits int) []byte {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, num)
	if err != nil {
		fmt.Println("NumberToBytes failed:", err)
	}

	return buf.Bytes()[buf.Len()-(bits/8):]
}

// Bytes to number
//
// Attempts to cast a byte slice to a unsigned integer
func BytesToNumber(b []byte) uint64 {
	var number uint64

	// Make sure the buffer is 64bits
	data := make([]byte, 8)
	data = append(data[:len(b)], b...)

	buf := bytes.NewReader(data)
	err := binary.Read(buf, binary.BigEndian, &number)
	if err != nil {
		fmt.Println("BytesToNumber failed:", err)
	}

	return number
}

// Read variable int
//
// Read a variable length number in big endian byte order
func ReadVarint(reader *bytes.Reader) (ret uint64) {
	if reader.Len() == 8 {
		var num uint64
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	} else if reader.Len() == 4 {
		var num uint32
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	} else if reader.Len() == 2 {
		var num uint16
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	} else {
		var num uint8
		binary.Read(reader, binary.BigEndian, &num)
		ret = uint64(num)
	}

	return ret
}

// Binary length
//
// Returns the true binary length of the given number
func BinaryLength(num int) int {
	if num == 0 {
		return 0
	}

	return 1 + BinaryLength(num>>8)
}

// Copy bytes
//
// Returns an exact copy of the provided bytes
func CopyBytes(b []byte) (copiedBytes []byte) {
	copiedBytes = make([]byte, len(b))
	copy(copiedBytes, b)

	return
}

func IsHex(str string) bool {
	l := len(str)
	return l >= 4 && l%2 == 0 && str[0:2] == "0x"
}

func Bytes2Hex(d []byte) string {
	return hex.EncodeToString(d)
}

func Hex2Bytes(str string) []byte {
	h, _ := hex.DecodeString(str)
	return h
}

func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) {
	if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") {
		ret = Hex2Bytes(str[2:])
	} else {
		ret = cb(str)
	}

	return
}

func FormatData(data string) []byte {
	if len(data) == 0 {
		return nil
	}
	// Simple stupid
	d := new(big.Int)
	if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
		d.SetBytes([]byte(data[1 : len(data)-1]))
	} else if len(data) > 1 && data[:2] == "0x" {
		d.SetBytes(Hex2Bytes(data[2:]))
	} else {
		d.SetString(data, 0)
	}

	return BigToBytes(d, 256)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/hashicorp/errwrap"

	"github.com/advanderveer/timer/model"
)

var Version = "0.0.0"
var Build = "gobuild"

var mbu = flag.Duration("mbu", time.Minute*6, "The minimal billable unit")
var bind = flag.String("bind", ":0", "Address to bind the Daemon to")

func main() {
	flag.Parse()

	timer := NewTimer(*mbu)
	svr, err := NewServer(*bind, timer)
	if err != nil {
		log.Fatal(err)
	}

	dir, err := os.Getwd()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed to fetch current working dir: {{err}}", err))
	}

	m := model.New(dir)
	info := model.NewDeamon(dir, svr.Addr())
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	go func() {
		<-sig
		svr.Stop()
	}()

	log.Printf("Listening on '%s'", svr.Addr())
	err = svr.Start()
	if err != nil && !strings.Contains(err.Error(), "closed network connection") {
		log.Fatal(err)
	}

	log.Printf("Writing information to database...")
	info.Addr = ""
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	log.Printf("Done")
}
<commit_msg>basic prevention for starting two daemons at the same time<commit_after>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/hashicorp/errwrap"

	"github.com/advanderveer/timer/model"
)

var Version = "0.0.0"
var Build = "gobuild"

var mbu = flag.Duration("mbu", time.Minute*6, "The minimal billable unit")
var bind = flag.String("bind", ":0", "Address to bind the Daemon to")
var force = flag.Bool("force", false, "Force start the Daemon")

func main() {
	flag.Parse()

	timer := NewTimer(*mbu)
	svr, err := NewServer(*bind, timer)
	if err != nil {
		log.Fatal(err)
	}

	dir, err := os.Getwd()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed to fetch current working dir: {{err}}", err))
	}

	m := model.New(dir)
	info, err := m.ReadDaemonInfo()
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed read Daemon info: {{err}}", err))
	}

	if info.Addr != "" && !*force {
		log.Fatal("It appears another Daemon is already running or a previous instance didn't shutdown properly, use -force to force start.")
	}

	info = model.NewDeamon(dir, svr.Addr())
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)
	go func() {
		<-sig
		svr.Stop()
	}()

	log.Printf("Listening on '%s'", svr.Addr())
	err = svr.Start()
	if err != nil && !strings.Contains(err.Error(), "closed network connection") {
		log.Fatal(err)
	}

	log.Printf("Writing information to database...")
	info.Addr = ""
	err = m.UpsertDaemonInfo(info)
	if err != nil {
		log.Fatal(errwrap.Wrapf("Failed write Daemon info: {{err}}", err))
	}

	log.Printf("Done")
}
<|endoftext|>


<commit_before>// This file is part of *kellner*
//
// Copyright (C) 2016, Travelping GmbH <copyright@travelping.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode"
)

// recursively scan through a list of directories and find
// packages. per package (and architecture) keep only the
// most recent version.
// output the list (plan: create zip) of resultant packages
func condensePackages(roots []string, nworkers int, output string, archsubdirs bool) error {
	var (
		scanner = packageScanner{
			doMD5:  false,
			doSHA1: false,
		}
		now = time.Now()
	)
	for _, root := range roots {
		werr := filepath.Walk(root, func(path string, fi os.FileInfo, walkerr error) error {
			if fi == nil {
				log.Printf("no such file or directory: %s\n", path)
				return nil
			}
			if !fi.IsDir() {
				return nil
			}
			log.Println("condensing packages from", path)

			if err := scanner.scan(path, nworkers); err != nil {
				return fmt.Errorf("error: %v\n", err)
			}
			return nil
		})
		if werr != nil {
			return werr
		}
	}
	if scanner.packages == nil {
		log.Printf("no packages found.\n")
		return fmt.Errorf("no packages found.")
	}

	// and now to the act of condensing...
	log.Printf("condensing a set of %d packages\n", scanner.packages.Len())
	condensate := &packageIndex{Entries: make(map[string]*ipkArchive)} // key is Package+Architecture
	for pkgname, pkg := range scanner.packages.Entries {

		// slight paranoia check (control data ./. pkgname):
		epochless_version := pkg.Header["Version"]
		if idx := strings.Index(pkg.Header["Version"], ":"); idx > 0 {
			epochless_version = pkg.Header["Version"][idx+1:]
		}
		synthetic_pkgname := fmt.Sprintf("%s_%s_%s.ipk",
			pkg.Header["Package"], epochless_version, pkg.Header["Architecture"])
		if synthetic_pkgname != pkgname {
			return fmt.Errorf("package %s has mismatching control-information \"%s\"",
				pkgname, synthetic_pkgname)
		}
		cname := pkg.Header["Architecture"] + pkg.Header["Package"] // condense-key
		if prev, ok := condensate.Entries[cname]; ok {
			// compare version
			cmp := compareVersion(pkg.Header["Version"], prev.Header["Version"])
			if cmp > 0 { // new finding wins
				fmt.Printf("%s: %s (old: %s)\n", pkg.Header["Package"],
					pkg.Header["Version"], prev.Header["Version"])
				condensate.Add(cname, pkg)
			}
		} else {
			// first finding
			condensate.Add(cname, pkg)
		}

		fmt.Printf("%s: (%s / %s)\n", pkgname, pkg.Header["Package"], pkg.Header["Version"])
	}
	if output == "-" {
		fmt.Printf("sorted names: {%s}\n", strings.Join(condensate.SortedNames(), "\n"))
	} else if strings.HasSuffix(output, ".zip") {
		zipfile, err := os.Create(output)
		if err != nil {
			return err
		}
		defer zipfile.Close()

		zipper := zip.NewWriter(zipfile)
		defer zipper.Close()

		for _, pkg := range condensate.Entries {
			header := &zip.FileHeader{Name: pkg.Name}
			if archsubdirs {
				header.Name = filepath.Join(pkg.Header["Architecture"], header.Name)
			}
			header.SetModTime(now)
			writer, zwerr := zipper.CreateHeader(header)
			if zwerr != nil {
				return zwerr
			}
			sourcepkg, srcerr := os.Open(pkg.ScanLocation)
			if srcerr != nil {
				return srcerr
			}
			_, cperr := io.Copy(writer, sourcepkg)
			sourcepkg.Close()
			if cperr != nil {
				return cperr
			}
		}
	}
	log.Printf("condensed %d into %d packages. done after %s\n",
		scanner.packages.Len(), condensate.Len(), time.Since(now))
	return nil
}

func compareVersion(v1 string, v2 string) int {
	v1ord := versionStringToOrdinals(v1)
	v2ord := versionStringToOrdinals(v2)

	// make them equal in length, append zeros to the shorter one:
	lendiff := len(v1ord) - len(v2ord)
	if lendiff < 0 {
		v1ord = append(v1ord, make([]int, (-1*lendiff))...)
	} else if lendiff > 0 {
		v2ord = append(v2ord, make([]int, (lendiff))...)
	}

	for i := range v1ord {
		if v1ord[i] < v2ord[i] {
			return -1
		}
		if v1ord[i] > v2ord[i] {
			return 1
		}
	}
	return 0
}

func versionStringToOrdinals(version_string string) []int {
	ord := ""
	ordarray := []int{}
	addComponent := func() {
		if len(ord) > 0 {
			i, _ := strconv.Atoi(ord) // error is unlikely with all digits
			ordarray = append(ordarray, i)
			ord = ""
		}
	}
	for _, c := range version_string {
		if !unicode.IsDigit(c) {
			addComponent()
			continue
		}
		ord += string(c)
	}
	addComponent()
	return ordarray
}
<commit_msg>cosmetics/comments<commit_after>// This file is part of *kellner*
//
// Copyright (C) 2016, Travelping GmbH <copyright@travelping.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode"
)

// recursively scan through a list of directories and find
// packages. per package (and architecture) keep only the
// most recent version.
// output the list (plan: create zip) of resultant packages
func condensePackages(roots []string, nworkers int, output string, archsubdirs bool) error {
	var (
		scanner = packageScanner{
			doMD5:  false,
			doSHA1: false,
		}
		now = time.Now()
	)
	for _, root := range roots {
		werr := filepath.Walk(root, func(path string, fi os.FileInfo, walkerr error) error {
			if fi == nil {
				log.Printf("no such file or directory: %s\n", path)
				return nil
			}
			if !fi.IsDir() {
				return nil
			}
			log.Println("condensing packages from", path)

			if err := scanner.scan(path, nworkers); err != nil {
				return fmt.Errorf("error: %v\n", err)
			}
			return nil
		})
		if werr != nil {
			return werr
		}
	}
	if scanner.packages == nil {
		log.Printf("no packages found.\n")
		return fmt.Errorf("no packages found.")
	}

	// and now to the act of condensing...
	log.Printf("condensing a set of %d packages\n", scanner.packages.Len())
	condensate := &packageIndex{Entries: make(map[string]*ipkArchive)} // key is Package+Architecture
	for pkgname, pkg := range scanner.packages.Entries {

		// slight paranoia check (control data ./. pkgname):
		epochless_version := pkg.Header["Version"]
		if idx := strings.Index(pkg.Header["Version"], ":"); idx > 0 {
			epochless_version = pkg.Header["Version"][idx+1:]
		}
		synthetic_pkgname := fmt.Sprintf("%s_%s_%s.ipk",
			pkg.Header["Package"], epochless_version, pkg.Header["Architecture"])
		if synthetic_pkgname != pkgname {
			return fmt.Errorf("package %s has mismatching control-information \"%s\"",
				pkgname, synthetic_pkgname)
		}
		cname := pkg.Header["Architecture"] + pkg.Header["Package"] // condense-key
		if prev, ok := condensate.Entries[cname]; ok {
			// compare version
			cmp := compareVersion(pkg.Header["Version"], prev.Header["Version"])
			if cmp > 0 { // new finding wins
				fmt.Printf("%s: %s replaced: %s\n", pkg.Header["Package"],
					pkg.Header["Version"], prev.Header["Version"])
				condensate.Add(cname, pkg)
			}
		} else {
			// first finding
			condensate.Add(cname, pkg)
		}
	}

	// now let us create a zipfile with the condensated files
	if output == "-" {
		// this is more a debugging thing,
		// output filenames to stdout
		fmt.Printf("sorted names:\n%s\n", strings.Join(condensate.SortedNames(), "\n"))
	} else if strings.HasSuffix(output, ".zip") {
		zipfile, err := os.Create(output)
		if err != nil {
			return err
		}
		defer zipfile.Close()

		zipper := zip.NewWriter(zipfile)
		defer zipper.Close()

		for _, pkg := range condensate.Entries {
			header := &zip.FileHeader{Name: pkg.Name}
			if archsubdirs {
				header.Name = filepath.Join(pkg.Header["Architecture"], header.Name)
			}
			header.SetModTime(now)
			writer, zwerr := zipper.CreateHeader(header)
			if zwerr != nil {
				return zwerr
			}
			// read scanned package from original location
			sourcepkg, srcerr := os.Open(pkg.ScanLocation)
			if srcerr != nil {
				return srcerr
			}
			// and write bytes into the zip/bundle
			_, cperr := io.Copy(writer, sourcepkg)
			sourcepkg.Close()
			if cperr != nil {
				return cperr
			}
		}
	}
	log.Printf("condensed %d into %d packages. done after %s\n",
		scanner.packages.Len(), condensate.Len(), time.Since(now))
	return nil
}

// compare to versions,
// return 0 when equal or 1/-1 when different
func compareVersion(v1 string, v2 string) int {
	v1ord := versionStringToOrdinals(v1)
	v2ord := versionStringToOrdinals(v2)

	// make them equal in length, append zeros to the shorter one:
	lendiff := len(v1ord) - len(v2ord)
	if lendiff < 0 {
		v1ord = append(v1ord, make([]int, (-1*lendiff))...)
	} else if lendiff > 0 {
		v2ord = append(v2ord, make([]int, (lendiff))...)
	}

	for i := range v1ord {
		if v1ord[i] < v2ord[i] {
			return -1
		}
		if v1ord[i] > v2ord[i] {
			return 1
		}
	}
	return 0
}

// convert a string into an array of numbers parsed from
// all occurances of consecutive digits
// "foo123bar321" --> [123, 321]
// "version-1.0.7-rc3.3" --> [1,0,7,3,3]
func versionStringToOrdinals(version_string string) []int {
	ord := ""
	ordarray := []int{}
	addComponent := func() {
		if len(ord) > 0 {
			i, _ := strconv.Atoi(ord) // error is unlikely with all digits
			ordarray = append(ordarray, i)
			ord = ""
		}
	}
	for _, c := range version_string {
		if !unicode.IsDigit(c) {
			addComponent()
			continue
		}
		ord += string(c)
	}
	addComponent()
	return ordarray
}
<|endoftext|>


<commit_before>package event

import (
	"time"

	"bitbucket.org/oakmoundstudio/oak/timing"
)

// Trigger an event, but only
// for one ID. Use case example:
// on onHit event
func (id CID) Trigger(eventName string, data interface{}) {

	go func(eventName string, data interface{}) {
		eb := GetBus()
		mutex.RLock()
		if idMap, ok := eb.bindingMap[eventName]; ok {
			if bs, ok := idMap[int(id)]; ok {
				for i := bs.highIndex - 1; i >= 0; i-- {
					for j, bnd := range (*bs.highPriority[i]).sl {
						handleBindable(bnd, int(id), data, j, eventName)
					}
				}
				triggerDefault((bs.defaultPriority).sl, int(id), eventName, data)

				for i := 0; i < bs.lowIndex; i++ {
					for j, bnd := range (*bs.lowPriority[i]).sl {
						handleBindable(bnd, int(id), data, j, eventName)
					}
				}
			}
		}
		mutex.RUnlock()
	}(eventName, data)
}

// TriggerAfter will trigger the given event after d time.
func (id CID) TriggerAfter(d time.Duration, eventName string, data interface{}) {
	go func() {
		timing.DoAfter(d, func() {
			id.Trigger(eventName, data)
		})
	}()
}

// Trigger is equivalent to bus.Trigger(...)
func Trigger(eventName string, data interface{}) {
	thisBus.Trigger(eventName, data)
}

// TriggerBack is equivalent to bus.TriggerBack(...)
func TriggerBack(eventName string, data interface{}) chan bool {
	return thisBus.TriggerBack(eventName, data)
}

// TriggerBack is a version of Trigger which returns a channel that
// informs on when all bindables have been called and returned from
// the input event. It is dangerous to use this unless you have a
// very good idea how things will synchronize, as if a triggered
// bindable itself makes a TriggerBack call, this will cause the engine to freeze,
// as the function will never end because the first TriggerBack has control of
// the lock for the event bus, and the first TriggerBack won't give up that lock
// until the function ends.
//
// This inherently means that when you call Trigger, the event will almost
// almost never be immediately triggered but rather will be triggered sometime
// soon in the future.
//
// TriggerBack is right now used by the primary logic loop to dictate logical
// framerate, so EnterFrame events are called through TriggerBack.
func (eb *Bus) TriggerBack(eventName string, data interface{}) chan bool {

	ch := make(chan bool)
	go func(ch chan bool, eb *Bus, eventName string, data interface{}) {
		ebtrigger(eb, eventName, data)
		ch <- true
	}(ch, eb, eventName, data)

	return ch
}

// Trigger will scan through the event bus and call all bindables found attached
// to the given event, with the passed in data.
func (eb *Bus) Trigger(eventName string, data interface{}) {
	go func(eb *Bus, eventName string, data interface{}) {
		ebtrigger(eb, eventName, data)
	}(eb, eventName, data)
}

func ebtrigger(eb *Bus, eventName string, data interface{}) {
	mutex.RLock()
	// Loop through all bindableStores for this eventName
	for id, bs := range (*eb).bindingMap[eventName] {
		// Top to bottom, high priority
		for i := bs.highIndex - 1; i >= 0; i-- {
			for j, bnd := range (*bs.highPriority[i]).sl {
				handleBindable(bnd, id, data, j, eventName)
			}
		}
	}

	for id, bs := range (*eb).bindingMap[eventName] {
		if bs != nil && bs.defaultPriority != nil {
			triggerDefault((bs.defaultPriority).sl, id, eventName, data)
		}
	}

	for id, bs := range (*eb).bindingMap[eventName] {
		// Bottom to top, low priority
		for i := 0; i < bs.lowIndex; i++ {
			for j, bnd := range (*bs.lowPriority[i]).sl {
				handleBindable(bnd, id, data, j, eventName)
			}
		}
	}
	mutex.RUnlock()
}

func triggerDefault(sl []Bindable, id int, eventName string, data interface{}) {
	progCh := make(chan bool)
	for i, bnd := range sl {
		go func(bnd Bindable, id int, eventName string, data interface{}, progCh chan bool, index int) {
			handleBindable(bnd, id, data, index, eventName)
			progCh <- true
		}(bnd, id, eventName, data, progCh, i)
	}
	for range sl {
		<-progCh
	}
}

func handleBindable(bnd Bindable, id int, data interface{}, index int, eventName string) {
	if bnd != nil {
		if id == 0 || GetEntity(id) != nil {
			response := bnd(id, data)
			switch response {
			case UnbindEvent:
				UnbindAll(BindingOption{
					Event{
						eventName,
						id,
					},
					0,
				})
			case UnbindSingle:
				Binding{
					BindingOption{
						Event{
							eventName,
							id,
						},
						0,
					},
					index,
				}.Unbind()
			}
		}
	}
}
<commit_msg>Listing of events in event/trigger<commit_after>package event

import (
	"time"

	"bitbucket.org/oakmoundstudio/oak/timing"
)

// Oak uses the following built in events:
//
// - EnterFrame: the beginning of every logical frame.
//   Payload: (int) frames passed since this scene started
//
// - CollisionStart/Stop: when a PhaseCollision entity starts/stops touching some label.
//   Payload: (collision.Label) the label the entity has started/stopped touching
//
// - MouseCollisionStart/Stop: as above, for mouse collision
//   Payload: (mouse.Event)
//
// - KeyDown/Up: when a key is pressed down / lifted up.
//   Payload: (string) the key pressed
//
// - Mouse events: MousePress, MouseRelease, MouseScrollDown, MouseScrollUp, MouseDrag
//   Payload: (mouse.Event) details on the mouse event
//
// - AnimationEnd: Triggered on animations CIDs when they loop from the last to the first frame
//   Payload: nil
//
// - ViewportUpdate: Triggered when the viewport changes.
//   Payload: []float64{viewportX, viewportY}

// Trigger an event, but only
// for one ID. Use case example:
// on onHit event
func (id CID) Trigger(eventName string, data interface{}) {

	go func(eventName string, data interface{}) {
		eb := GetBus()
		mutex.RLock()
		if idMap, ok := eb.bindingMap[eventName]; ok {
			if bs, ok := idMap[int(id)]; ok {
				for i := bs.highIndex - 1; i >= 0; i-- {
					for j, bnd := range (*bs.highPriority[i]).sl {
						handleBindable(bnd, int(id), data, j, eventName)
					}
				}
				triggerDefault((bs.defaultPriority).sl, int(id), eventName, data)

				for i := 0; i < bs.lowIndex; i++ {
					for j, bnd := range (*bs.lowPriority[i]).sl {
						handleBindable(bnd, int(id), data, j, eventName)
					}
				}
			}
		}
		mutex.RUnlock()
	}(eventName, data)
}

// TriggerAfter will trigger the given event after d time.
func (id CID) TriggerAfter(d time.Duration, eventName string, data interface{}) {
	go func() {
		timing.DoAfter(d, func() {
			id.Trigger(eventName, data)
		})
	}()
}

// Trigger is equivalent to bus.Trigger(...)
func Trigger(eventName string, data interface{}) {
	thisBus.Trigger(eventName, data)
}

// TriggerBack is equivalent to bus.TriggerBack(...)
func TriggerBack(eventName string, data interface{}) chan bool {
	return thisBus.TriggerBack(eventName, data)
}

// TriggerBack is a version of Trigger which returns a channel that
// informs on when all bindables have been called and returned from
// the input event. It is dangerous to use this unless you have a
// very good idea how things will synchronize, as if a triggered
// bindable itself makes a TriggerBack call, this will cause the engine to freeze,
// as the function will never end because the first TriggerBack has control of
// the lock for the event bus, and the first TriggerBack won't give up that lock
// until the function ends.
//
// This inherently means that when you call Trigger, the event will almost
// almost never be immediately triggered but rather will be triggered sometime
// soon in the future.
//
// TriggerBack is right now used by the primary logic loop to dictate logical
// framerate, so EnterFrame events are called through TriggerBack.
func (eb *Bus) TriggerBack(eventName string, data interface{}) chan bool {

	ch := make(chan bool)
	go func(ch chan bool, eb *Bus, eventName string, data interface{}) {
		ebtrigger(eb, eventName, data)
		ch <- true
	}(ch, eb, eventName, data)

	return ch
}

// Trigger will scan through the event bus and call all bindables found attached
// to the given event, with the passed in data.
func (eb *Bus) Trigger(eventName string, data interface{}) {
	go func(eb *Bus, eventName string, data interface{}) {
		ebtrigger(eb, eventName, data)
	}(eb, eventName, data)
}

func ebtrigger(eb *Bus, eventName string, data interface{}) {
	mutex.RLock()
	// Loop through all bindableStores for this eventName
	for id, bs := range (*eb).bindingMap[eventName] {
		// Top to bottom, high priority
		for i := bs.highIndex - 1; i >= 0; i-- {
			for j, bnd := range (*bs.highPriority[i]).sl {
				handleBindable(bnd, id, data, j, eventName)
			}
		}
	}

	for id, bs := range (*eb).bindingMap[eventName] {
		if bs != nil && bs.defaultPriority != nil {
			triggerDefault((bs.defaultPriority).sl, id, eventName, data)
		}
	}

	for id, bs := range (*eb).bindingMap[eventName] {
		// Bottom to top, low priority
		for i := 0; i < bs.lowIndex; i++ {
			for j, bnd := range (*bs.lowPriority[i]).sl {
				handleBindable(bnd, id, data, j, eventName)
			}
		}
	}
	mutex.RUnlock()
}

func triggerDefault(sl []Bindable, id int, eventName string, data interface{}) {
	progCh := make(chan bool)
	for i, bnd := range sl {
		go func(bnd Bindable, id int, eventName string, data interface{}, progCh chan bool, index int) {
			handleBindable(bnd, id, data, index, eventName)
			progCh <- true
		}(bnd, id, eventName, data, progCh, i)
	}
	for range sl {
		<-progCh
	}
}

func handleBindable(bnd Bindable, id int, data interface{}, index int, eventName string) {
	if bnd != nil {
		if id == 0 || GetEntity(id) != nil {
			response := bnd(id, data)
			switch response {
			case UnbindEvent:
				UnbindAll(BindingOption{
					Event{
						eventName,
						id,
					},
					0,
				})
			case UnbindSingle:
				Binding{
					BindingOption{
						Event{
							eventName,
							id,
						},
						0,
					},
					index,
				}.Unbind()
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package clientcmd

import (
	"fmt"
	"testing"

	"k8s.io/kubernetes/pkg/client/restclient"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

type testLoader struct {
	ClientConfigLoader

	called bool
	config *clientcmdapi.Config
	err    error
}

func (l *testLoader) Load() (*clientcmdapi.Config, error) {
	l.called = true
	return l.config, l.err
}

type testClientConfig struct {
	config *restclient.Config
	err    error
}

func (c *testClientConfig) RawConfig() (clientcmdapi.Config, error) {
	return clientcmdapi.Config{}, fmt.Errorf("unexpected call")
}
func (c *testClientConfig) ClientConfig() (*restclient.Config, error) {
	return c.config, c.err
}
func (c *testClientConfig) Namespace() (string, bool, error) {
	return "", false, fmt.Errorf("unexpected call")
}
func (c *testClientConfig) ConfigAccess() ConfigAccess {
	return nil
}

type testICC struct {
	testClientConfig

	possible bool
	called   bool
}

func (icc *testICC) Possible() bool {
	icc.called = true
	return icc.possible
}

func TestInClusterConfig(t *testing.T) {
	// override direct client config for this run
	originalDefault := DefaultClientConfig
	defer func() {
		DefaultClientConfig = originalDefault
	}()

	baseDefault := &DirectClientConfig{
		overrides: &ConfigOverrides{},
	}
	default1 := &DirectClientConfig{
		config:      *createValidTestConfig(),
		contextName: "clean",
		overrides:   &ConfigOverrides{},
	}
	config1, err := default1.ClientConfig()
	if err != nil {
		t.Fatal(err)
	}
	config2 := &restclient.Config{Host: "config2"}
	err1 := fmt.Errorf("unique error")

	testCases := map[string]struct {
		clientConfig  *testClientConfig
		icc           *testICC
		defaultConfig *DirectClientConfig

		checkedICC bool
		result     *restclient.Config
		err        error
	}{
		"in-cluster checked on other error": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc:          &testICC{},

			checkedICC: true,
			result:     nil,
			err:        ErrEmptyConfig,
		},

		"in-cluster not checked on non-empty error": {
			clientConfig: &testClientConfig{err: ErrEmptyCluster},
			icc:          &testICC{},

			checkedICC: false,
			result:     nil,
			err:        ErrEmptyCluster,
		},

		"in-cluster checked when config is default": {
			defaultConfig: default1,
			clientConfig:  &testClientConfig{config: config1},
			icc:           &testICC{},

			checkedICC: true,
			result:     config1,
			err:        nil,
		},

		"in-cluster not checked when config is not equal to default": {
			defaultConfig: default1,
			clientConfig:  &testClientConfig{config: config2},
			icc:           &testICC{},

			checkedICC: false,
			result:     config2,
			err:        nil,
		},

		"in-cluster checked when config is not equal to default and error is empty": {
			clientConfig: &testClientConfig{config: config2, err: ErrEmptyConfig},
			icc:          &testICC{},

			checkedICC: true,
			result:     config2,
			err:        ErrEmptyConfig,
		},

		"in-cluster error returned when config is empty": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc: &testICC{
				possible: true,
				testClientConfig: testClientConfig{
					err: err1,
				},
			},

			checkedICC: true,
			result:     nil,
			err:        err1,
		},

		"in-cluster config returned when config is empty": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc: &testICC{
				possible: true,
				testClientConfig: testClientConfig{
					config: config2,
				},
			},

			checkedICC: true,
			result:     config2,
			err:        nil,
		},
	}

	for name, test := range testCases {
		if test.defaultConfig != nil {
			DefaultClientConfig = *test.defaultConfig
		} else {
			DefaultClientConfig = *baseDefault
		}
		c := &DeferredLoadingClientConfig{icc: test.icc}
		c.clientConfig = test.clientConfig

		cfg, err := c.ClientConfig()
		if test.icc.called != test.checkedICC {
			t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called)
		}
		if err != test.err || cfg != test.result {
			t.Errorf("%s: unexpected result: %v %#v", name, err, cfg)
		}
	}
}
<commit_msg>Add a test to verify that the client config is returned when default config is invalid.<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package clientcmd

import (
	"fmt"
	"testing"

	"k8s.io/kubernetes/pkg/client/restclient"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

type testLoader struct {
	ClientConfigLoader

	called bool
	config *clientcmdapi.Config
	err    error
}

func (l *testLoader) Load() (*clientcmdapi.Config, error) {
	l.called = true
	return l.config, l.err
}

type testClientConfig struct {
	config *restclient.Config
	err    error
}

func (c *testClientConfig) RawConfig() (clientcmdapi.Config, error) {
	return clientcmdapi.Config{}, fmt.Errorf("unexpected call")
}
func (c *testClientConfig) ClientConfig() (*restclient.Config, error) {
	return c.config, c.err
}
func (c *testClientConfig) Namespace() (string, bool, error) {
	return "", false, fmt.Errorf("unexpected call")
}
func (c *testClientConfig) ConfigAccess() ConfigAccess {
	return nil
}

type testICC struct {
	testClientConfig

	possible bool
	called   bool
}

func (icc *testICC) Possible() bool {
	icc.called = true
	return icc.possible
}

func TestInClusterConfig(t *testing.T) {
	// override direct client config for this run
	originalDefault := DefaultClientConfig
	defer func() {
		DefaultClientConfig = originalDefault
	}()

	baseDefault := &DirectClientConfig{
		overrides: &ConfigOverrides{},
	}
	default1 := &DirectClientConfig{
		config:      *createValidTestConfig(),
		contextName: "clean",
		overrides:   &ConfigOverrides{},
	}
	config1, err := default1.ClientConfig()
	if err != nil {
		t.Fatal(err)
	}
	config2 := &restclient.Config{Host: "config2"}
	err1 := fmt.Errorf("unique error")

	testCases := map[string]struct {
		clientConfig  *testClientConfig
		icc           *testICC
		defaultConfig *DirectClientConfig

		checkedICC bool
		result     *restclient.Config
		err        error
	}{
		"in-cluster checked on other error": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc:          &testICC{},

			checkedICC: true,
			result:     nil,
			err:        ErrEmptyConfig,
		},

		"in-cluster not checked on non-empty error": {
			clientConfig: &testClientConfig{err: ErrEmptyCluster},
			icc:          &testICC{},

			checkedICC: false,
			result:     nil,
			err:        ErrEmptyCluster,
		},

		"in-cluster checked when config is default": {
			defaultConfig: default1,
			clientConfig:  &testClientConfig{config: config1},
			icc:           &testICC{},

			checkedICC: true,
			result:     config1,
			err:        nil,
		},

		"in-cluster not checked when config is not equal to default": {
			defaultConfig: default1,
			clientConfig:  &testClientConfig{config: config2},
			icc:           &testICC{},

			checkedICC: false,
			result:     config2,
			err:        nil,
		},

		"in-cluster checked when config is not equal to default and error is empty": {
			clientConfig: &testClientConfig{config: config2, err: ErrEmptyConfig},
			icc:          &testICC{},

			checkedICC: true,
			result:     config2,
			err:        ErrEmptyConfig,
		},

		"in-cluster error returned when config is empty": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc: &testICC{
				possible: true,
				testClientConfig: testClientConfig{
					err: err1,
				},
			},

			checkedICC: true,
			result:     nil,
			err:        err1,
		},

		"in-cluster config returned when config is empty": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc: &testICC{
				possible: true,
				testClientConfig: testClientConfig{
					config: config2,
				},
			},

			checkedICC: true,
			result:     config2,
			err:        nil,
		},

		"in-cluster not checked when default is invalid": {
			defaultConfig: &DefaultClientConfig,
			clientConfig:  &testClientConfig{config: config2},
			icc:           &testICC{},

			checkedICC: false,
			result:     config2,
			err:        nil,
		},
	}

	for name, test := range testCases {
		if test.defaultConfig != nil {
			DefaultClientConfig = *test.defaultConfig
		} else {
			DefaultClientConfig = *baseDefault
		}
		c := &DeferredLoadingClientConfig{icc: test.icc}
		c.clientConfig = test.clientConfig

		cfg, err := c.ClientConfig()
		if test.icc.called != test.checkedICC {
			t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called)
		}
		if err != test.err || cfg != test.result {
			t.Errorf("%s: unexpected result: %v %#v", name, err, cfg)
		}
	}
}
<|endoftext|>


<commit_before>package graval

import (
	"os"
	"time"
)

type ftpFileInfo struct {
	name  string
	bytes int64
	mode  os.FileMode
}

func (info *ftpFileInfo) Name() string {
	return info.name
}

func (info *ftpFileInfo) Size() int64 {
	return info.bytes
}

func (info *ftpFileInfo) Mode() os.FileMode {
	return info.mode
}

func (info *ftpFileInfo) ModTime() time.Time {
	return time.Now()
}

func (info *ftpFileInfo) IsDir() bool {
	return (info.mode | os.ModeDir) == os.ModeDir
}

func (info *ftpFileInfo) Sys() interface{} {
	return nil
}

// NewDirItem creates a new os.FileInfo that represents a single diretory. Use
// this function to build the response to DirContents() in your FTPDriver
// implementation.
func NewDirItem(name string) os.FileInfo {
	d := new(ftpFileInfo)
	d.name = name
	d.bytes = int64(0)
	d.mode = os.ModeDir | 666
	return d
}

// NewFileItem creates a new os.FileInfo that represents a single file. Use
// this function to build the response to DirContents() in your FTPDriver
// implementation.
func NewFileItem(name string, bytes int) os.FileInfo {
	f := new(ftpFileInfo)
	f.name = name
	f.bytes = int64(bytes)
	f.mode = 666
	return f
}
<commit_msg>FileItem modtime, changed time to UTC, fixed file mode<commit_after>package graval

import (
	"os"
	"time"
)

type ftpFileInfo struct {
	name    string
	bytes   int64
	mode    os.FileMode
	modtime time.Time
}

func (info *ftpFileInfo) Name() string {
	return info.name
}

func (info *ftpFileInfo) Size() int64 {
	return info.bytes
}

func (info *ftpFileInfo) Mode() os.FileMode {
	return info.mode
}

func (info *ftpFileInfo) ModTime() time.Time {
	return info.modtime
}

func (info *ftpFileInfo) IsDir() bool {
	return (info.mode | os.ModeDir) == os.ModeDir
}

func (info *ftpFileInfo) Sys() interface{} {
	return nil
}

// NewDirItem creates a new os.FileInfo that represents a single diretory. Use
// this function to build the response to DirContents() in your FTPDriver
// implementation.
func NewDirItem(name string) os.FileInfo {
	d := new(ftpFileInfo)
	d.name = name
	d.bytes = int64(0)
	d.mode = os.ModeDir | 0666
	d.modtime = time.Now().UTC()
	return d
}

// NewFileItem creates a new os.FileInfo that represents a single file. Use
// this function to build the response to DirContents() in your FTPDriver
// implementation.
func NewFileItem(name string, bytes int64, modtime time.Time) os.FileInfo {
	f := new(ftpFileInfo)
	f.name = name
	f.bytes = int64(bytes)
	f.mode = 0666
	f.modtime = modtime
	return f
}
<|endoftext|>


<commit_before>package app

import (
	"github.com/moncho/dry/appui"
	termbox "github.com/nsf/termbox-go"
)

type stacksScreenEventHandler struct {
	baseEventHandler
}

func (h *stacksScreenEventHandler) widget() appui.AppWidget {
	return h.dry.widgetRegistry.Stacks
}

func (h *stacksScreenEventHandler) handle(event termbox.Event) {
	if h.forwardingEvents {
		h.eventChan <- event
		return
	}
	focus := true
	handled := false
	switch event.Key {
	case termbox.KeyF1: //sort
		handled = true
		h.dry.widgetRegistry.Stacks.Sort()
	case termbox.KeyF5: // refresh
		handled = true
		h.dry.appmessage("Refreshing stack list")
		h.widget().Unmount()

	case termbox.KeyEnter: //inspect
		handled = true
		showTasks := func(stack string) error {
			h.dry.ShowStackTasks(stack)
			return refreshScreen()
		}
		h.widget().OnEvent(showTasks)

	}
	if !handled {
		switch event.Ch {
		case '6':
			//already in stack screen
			handled = true
		case '%':
			handled = true
			showFilterInput(h)
		}
	}
	if handled {
		h.setFocus(focus)
		if h.hasFocus() {
			refreshScreen()
		}
	} else {
		h.baseEventHandler.handle(event)
	}
}
<commit_msg>Remove a stack by pressing Ctrl+r on the stack list screen<commit_after>package app

import (
	"fmt"

	"github.com/moncho/dry/appui"
	"github.com/moncho/dry/ui"
	termbox "github.com/nsf/termbox-go"
)

type stacksScreenEventHandler struct {
	baseEventHandler
}

func (h *stacksScreenEventHandler) widget() appui.AppWidget {
	return h.dry.widgetRegistry.Stacks
}

func (h *stacksScreenEventHandler) handle(event termbox.Event) {
	if h.forwardingEvents {
		h.eventChan <- event
		return
	}
	focus := true
	handled := false
	switch event.Key {
	case termbox.KeyF1: //sort
		handled = true
		h.dry.widgetRegistry.Stacks.Sort()
	case termbox.KeyF5: // refresh
		handled = true
		h.dry.appmessage("Refreshing stack list")
		h.widget().Unmount()

	case termbox.KeyEnter: //inspect
		handled = true
		showTasks := func(stack string) error {
			h.dry.ShowStackTasks(stack)
			return refreshScreen()
		}
		h.widget().OnEvent(showTasks)
	case termbox.KeyCtrlR: //remove stack
		rw := appui.NewPrompt("The selected stack will be removed. Do you want to proceed? y/N")
		h.setForwardEvents(true)
		handled = true
		h.dry.widgetRegistry.add(rw)
		go func() {
			events := ui.EventSource{
				Events: h.eventChan,
				EventHandledCallback: func(e termbox.Event) error {
					return refreshScreen()
				},
			}
			rw.OnFocus(events)
			h.dry.widgetRegistry.remove(rw)
			confirmation, canceled := rw.Text()
			h.setForwardEvents(false)
			if canceled || (confirmation != "y" && confirmation != "Y") {
				return
			}
			removeStack := func(stack string) error {
				err := h.dry.dockerDaemon.StackRemove(stack)
				if err == nil {
					h.dry.appmessage(fmt.Sprintf("Stack %s removed", stack))
				}
				refreshScreen()
				return err
			}
			if err := h.widget().OnEvent(removeStack); err != nil {
				h.dry.appmessage("There was an error removing the stack: " + err.Error())
			}
		}()
	}
	if !handled {
		switch event.Ch {
		case '6':
			//already in stack screen
			handled = true
		case '%':
			handled = true
			showFilterInput(h)
		}
	}
	if handled {
		h.setFocus(focus)
		if h.hasFocus() {
			refreshScreen()
		}
	} else {
		h.baseEventHandler.handle(event)
	}
}
<|endoftext|>


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

package gitlab

import (
	"fmt"
	"net/http"
	"time"
)

// ProjectMirrorService handles communication with the project mirror
// related methods of the GitLab API.
//
// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html
type ProjectMirrorService struct {
	client *Client
}

// ProjectMirror represents a project mirror configuration.
//
// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html
type ProjectMirror struct {
	Enabled                bool       `json:"enabled"`
	ID                     int        `json:"id"`
	LastError              string     `json:"last_error"`
	LastSuccessfulUpdateAt *time.Time `json:"last_successful_update_at"`
	LastUpdateAt           *time.Time `json:"last_update_at"`
	LastUpdateStartedAt    *time.Time `json:"last_update_started_at"`
	OnlyProtectedBranches  bool       `json:"only_protected_branches"`
	KeepDivergentRefs      bool       `json:"keep_divergent_refs"`
	UpdateStatus           string     `json:"update_status"`
	URL                    string     `json:"url"`
}

// ListProjectMirrorOptions represents the available ListProjectMirror() options.
type ListProjectMirrorOptions ListOptions

// ListProjectMirror gets a list of mirrors configured on the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#list-a-projects-remote-mirrors
func (s *ProjectMirrorService) ListProjectMirror(pid interface{}, opt *ListProjectMirrorOptions, options ...RequestOptionFunc) ([]*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors", PathEscape(project))

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

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

	return pm, resp, err
}

// GetProjectMirror gets a single mirrors configured on the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/remote_mirrors.html#get-a-single-projects-remote-mirror
func (s *ProjectMirrorService) GetProjectMirror(pid interface{}, mirror int, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors/%d", PathEscape(project), mirror)

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

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

	return pm, resp, err
}

// AddProjectMirrorOptions contains the properties requires to create
// a new project mirror.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror
type AddProjectMirrorOptions struct {
	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
	Enabled               *bool   `url:"enabled,omitempty" json:"enabled,omitempty"`
	OnlyProtectedBranches *bool   `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"`
	KeepDivergentRefs     *bool   `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"`
}

// AddProjectMirror creates a new mirror on the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror
func (s *ProjectMirrorService) AddProjectMirror(pid interface{}, opt *AddProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors", PathEscape(project))

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

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

	return pm, resp, err
}

// EditProjectMirrorOptions contains the properties requires to edit
// an existing project mirror.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes
type EditProjectMirrorOptions struct {
	Enabled               *bool `url:"enabled,omitempty" json:"enabled,omitempty"`
	OnlyProtectedBranches *bool `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"`
	KeepDivergentRefs     *bool `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"`
}

// EditProjectMirror updates a project team member to a specified access level..
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes
func (s *ProjectMirrorService) EditProjectMirror(pid interface{}, mirror int, opt *EditProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors/%d", PathEscape(project), mirror)

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

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

	return pm, resp, err
}

// DeleteProjectMirror deletes a project mirror.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/remote_mirrors.html#delete-a-remote-mirror
func (s *ProjectMirrorService) DeleteProjectMirror(pid interface{}, mirror int, options ...RequestOptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors/%d", PathEscape(project), mirror)

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

	return s.client.Do(req, nil)
}
<commit_msg>Update project_mirror.go<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package gitlab

import (
	"fmt"
	"net/http"
	"time"
)

// ProjectMirrorService handles communication with the project mirror
// related methods of the GitLab API.
//
// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html
type ProjectMirrorService struct {
	client *Client
}

// ProjectMirror represents a project mirror configuration.
//
// GitLAb API docs: https://docs.gitlab.com/ce/api/remote_mirrors.html
type ProjectMirror struct {
	Enabled                bool       `json:"enabled"`
	ID                     int        `json:"id"`
	LastError              string     `json:"last_error"`
	LastSuccessfulUpdateAt *time.Time `json:"last_successful_update_at"`
	LastUpdateAt           *time.Time `json:"last_update_at"`
	LastUpdateStartedAt    *time.Time `json:"last_update_started_at"`
	OnlyProtectedBranches  bool       `json:"only_protected_branches"`
	KeepDivergentRefs      bool       `json:"keep_divergent_refs"`
	UpdateStatus           string     `json:"update_status"`
	URL                    string     `json:"url"`
}

// ListProjectMirrorOptions represents the available ListProjectMirror() options.
type ListProjectMirrorOptions ListOptions

// ListProjectMirror gets a list of mirrors configured on the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#list-a-projects-remote-mirrors
func (s *ProjectMirrorService) ListProjectMirror(pid interface{}, opt *ListProjectMirrorOptions, options ...RequestOptionFunc) ([]*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors", PathEscape(project))

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

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

	return pm, resp, err
}

// GetProjectMirror gets a single mirror configured on the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/remote_mirrors.html#get-a-single-projects-remote-mirror
func (s *ProjectMirrorService) GetProjectMirror(pid interface{}, mirror int, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors/%d", PathEscape(project), mirror)

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

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

	return pm, resp, err
}

// AddProjectMirrorOptions contains the properties requires to create
// a new project mirror.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror
type AddProjectMirrorOptions struct {
	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
	Enabled               *bool   `url:"enabled,omitempty" json:"enabled,omitempty"`
	OnlyProtectedBranches *bool   `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"`
	KeepDivergentRefs     *bool   `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"`
}

// AddProjectMirror creates a new mirror on the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#create-a-remote-mirror
func (s *ProjectMirrorService) AddProjectMirror(pid interface{}, opt *AddProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors", PathEscape(project))

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

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

	return pm, resp, err
}

// EditProjectMirrorOptions contains the properties requires to edit
// an existing project mirror.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes
type EditProjectMirrorOptions struct {
	Enabled               *bool `url:"enabled,omitempty" json:"enabled,omitempty"`
	OnlyProtectedBranches *bool `url:"only_protected_branches,omitempty" json:"only_protected_branches,omitempty"`
	KeepDivergentRefs     *bool `url:"keep_divergent_refs,omitempty" json:"keep_divergent_refs,omitempty"`
}

// EditProjectMirror updates a project team member to a specified access level..
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/remote_mirrors.html#update-a-remote-mirrors-attributes
func (s *ProjectMirrorService) EditProjectMirror(pid interface{}, mirror int, opt *EditProjectMirrorOptions, options ...RequestOptionFunc) (*ProjectMirror, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors/%d", PathEscape(project), mirror)

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

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

	return pm, resp, err
}

// DeleteProjectMirror deletes a project mirror.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/remote_mirrors.html#delete-a-remote-mirror
func (s *ProjectMirrorService) DeleteProjectMirror(pid interface{}, mirror int, options ...RequestOptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/remote_mirrors/%d", PathEscape(project), mirror)

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

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