<commit_before>package api

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

	"github.com/af83/edwig/core"
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type StopVisitController struct {
	referential *core.Referential
}

func NewStopVisitController(referential *core.Referential) ControllerInterface {
	return &Controller{
		restfulRessource: &StopVisitController{
			referential: referential,
		},
	}
}

func (controller *StopVisitController) findStopVisit(tx *model.Transaction, identifier string) (model.StopVisit, bool) {
	idRegexp := "([0-9a-zA-Z-]+):([0-9a-zA-Z-:]+)"
	pattern := regexp.MustCompile(idRegexp)
	foundStrings := pattern.FindStringSubmatch(identifier)
	if foundStrings != nil {
		objectid := model.NewObjectID(foundStrings[1], foundStrings[2])
		return tx.Model().StopVisits().FindByObjectId(objectid)
	}
	return tx.Model().StopVisits().Find(model.StopVisitId(identifier))
}

func (controller *StopVisitController) Index(response http.ResponseWriter) {
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	logger.Log.Debugf("StopVisits Index")

	jsonBytes, _ := json.Marshal(tx.Model().StopVisits().FindAll())
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Show(response http.ResponseWriter, identifier string) {
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	stopVisit, ok := controller.findStopVisit(tx, identifier)
	if !ok {
		http.Error(response, fmt.Sprintf("Stop visit not found: %s", identifier), 500)
		return
	}
	logger.Log.Debugf("Get stopVisit %s", identifier)

	jsonBytes, _ := stopVisit.MarshalJSON()
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Delete(response http.ResponseWriter, identifier string) {
	// New transaction
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	stopVisit, ok := controller.findStopVisit(tx, identifier)
	if !ok {
		http.Error(response, fmt.Sprintf("Stop visit not found: %s", identifier), 500)
		return
	}
	logger.Log.Debugf("Delete stopVisit %s", identifier)

	jsonBytes, _ := stopVisit.MarshalJSON()
	tx.Model().StopVisits().Delete(&stopVisit)
	err := tx.Commit()
	if err != nil {
		logger.Log.Debugf("Transaction error: %v", err)
		http.Error(response, "Internal error", 500)
		return
	}
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Update(response http.ResponseWriter, identifier string, body []byte) {
	// New transaction
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	stopVisit, ok := controller.findStopVisit(tx, identifier)
	if !ok {
		http.Error(response, fmt.Sprintf("Stop visit not found: %s", identifier), 500)
		return
	}

	logger.Log.Debugf("Update stopVisit %s: %s", identifier, string(body))

	err := json.Unmarshal(body, &stopVisit)
	if err != nil {
		http.Error(response, fmt.Sprintf("Invalid request: can't parse request body: %v", err), 400)
		return
	}

	tx.Model().StopVisits().Save(&stopVisit)
	err = tx.Commit()
	if err != nil {
		logger.Log.Debugf("Transaction error: %v", err)
		http.Error(response, "Internal error", 500)
		return
	}

	jsonBytes, _ := stopVisit.MarshalJSON()
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Create(response http.ResponseWriter, body []byte) {
	// New transaction
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	logger.Log.Debugf("Create stopVisit: %s", string(body))

	stopVisit := tx.Model().StopVisits().New()

	err := json.Unmarshal(body, &stopVisit)
	if err != nil {
		http.Error(response, fmt.Sprintf("Invalid request: can't parse request body: %v", err), 400)
		return
	}
	if stopVisit.Id() != "" {
		http.Error(response, "Invalid request", 400)
		return
	}

	tx.Model().StopVisits().Save(&stopVisit)
	err = tx.Commit()
	if err != nil {
		logger.Log.Debugf("Transaction error: %v", err)
		http.Error(response, "Internal error", 500)
		return
	}
	jsonBytes, _ := stopVisit.MarshalJSON()
	response.Write(jsonBytes)
}
<commit_msg>Return 404 error when StopVisit isn't found in StopVisitController#Show. Refs #3829<commit_after>package api

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

	"github.com/af83/edwig/core"
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type StopVisitController struct {
	referential *core.Referential
}

func NewStopVisitController(referential *core.Referential) ControllerInterface {
	return &Controller{
		restfulRessource: &StopVisitController{
			referential: referential,
		},
	}
}

func (controller *StopVisitController) findStopVisit(tx *model.Transaction, identifier string) (model.StopVisit, bool) {
	idRegexp := "([0-9a-zA-Z-]+):([0-9a-zA-Z-:]+)"
	pattern := regexp.MustCompile(idRegexp)
	foundStrings := pattern.FindStringSubmatch(identifier)
	if foundStrings != nil {
		objectid := model.NewObjectID(foundStrings[1], foundStrings[2])
		return tx.Model().StopVisits().FindByObjectId(objectid)
	}
	return tx.Model().StopVisits().Find(model.StopVisitId(identifier))
}

func (controller *StopVisitController) Index(response http.ResponseWriter) {
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	logger.Log.Debugf("StopVisits Index")

	jsonBytes, _ := json.Marshal(tx.Model().StopVisits().FindAll())
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Show(response http.ResponseWriter, identifier string) {
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	stopVisit, ok := controller.findStopVisit(tx, identifier)
	if !ok {
		http.Error(response, fmt.Sprintf("Stop visit not found: %s", identifier), 404)
		return
	}
	logger.Log.Debugf("Get stopVisit %s", identifier)

	jsonBytes, _ := stopVisit.MarshalJSON()
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Delete(response http.ResponseWriter, identifier string) {
	// New transaction
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	stopVisit, ok := controller.findStopVisit(tx, identifier)
	if !ok {
		http.Error(response, fmt.Sprintf("Stop visit not found: %s", identifier), 500)
		return
	}
	logger.Log.Debugf("Delete stopVisit %s", identifier)

	jsonBytes, _ := stopVisit.MarshalJSON()
	tx.Model().StopVisits().Delete(&stopVisit)
	err := tx.Commit()
	if err != nil {
		logger.Log.Debugf("Transaction error: %v", err)
		http.Error(response, "Internal error", 500)
		return
	}
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Update(response http.ResponseWriter, identifier string, body []byte) {
	// New transaction
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	stopVisit, ok := controller.findStopVisit(tx, identifier)
	if !ok {
		http.Error(response, fmt.Sprintf("Stop visit not found: %s", identifier), 500)
		return
	}

	logger.Log.Debugf("Update stopVisit %s: %s", identifier, string(body))

	err := json.Unmarshal(body, &stopVisit)
	if err != nil {
		http.Error(response, fmt.Sprintf("Invalid request: can't parse request body: %v", err), 400)
		return
	}

	tx.Model().StopVisits().Save(&stopVisit)
	err = tx.Commit()
	if err != nil {
		logger.Log.Debugf("Transaction error: %v", err)
		http.Error(response, "Internal error", 500)
		return
	}

	jsonBytes, _ := stopVisit.MarshalJSON()
	response.Write(jsonBytes)
}

func (controller *StopVisitController) Create(response http.ResponseWriter, body []byte) {
	// New transaction
	tx := controller.referential.NewTransaction()
	defer tx.Close()

	logger.Log.Debugf("Create stopVisit: %s", string(body))

	stopVisit := tx.Model().StopVisits().New()

	err := json.Unmarshal(body, &stopVisit)
	if err != nil {
		http.Error(response, fmt.Sprintf("Invalid request: can't parse request body: %v", err), 400)
		return
	}
	if stopVisit.Id() != "" {
		http.Error(response, "Invalid request", 400)
		return
	}

	tx.Model().StopVisits().Save(&stopVisit)
	err = tx.Commit()
	if err != nil {
		logger.Log.Debugf("Transaction error: %v", err)
		http.Error(response, "Internal error", 500)
		return
	}
	jsonBytes, _ := stopVisit.MarshalJSON()
	response.Write(jsonBytes)
}
<|endoftext|>


<commit_before>package tests_test

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/flags"
)

const (
	uploadProxyService   = "svc/cdi-uploadproxy"
	uploadProxyPort      = 443
	localUploadProxyPort = 18443
	imagePath            = "/tmp/alpine.iso"
)

var _ = Describe("[Serial]ImageUpload", func() {
	var kubectlCmd *exec.Cmd

	namespace := tests.NamespaceTestDefault
	pvcSize := "100Mi"

	var virtClient kubecli.KubevirtClient

	BeforeEach(func() {
		var err error

		virtClient, err = kubecli.GetKubevirtClient()
		tests.PanicOnError(err)
	})

	BeforeEach(func() {
		By("Getting CDI HTTP import server pod")
		pods, err := virtClient.CoreV1().Pods(flags.KubeVirtInstallNamespace).List(metav1.ListOptions{LabelSelector: "kubevirt.io=cdi-http-import-server"})
		Expect(err).ToNot(HaveOccurred())
		Expect(pods.Items).ToNot(BeEmpty())

		stopChan := make(chan struct{})
		err = tests.ForwardPorts(&pods.Items[0], []string{"65432:80"}, stopChan, 10*time.Second)
		Expect(err).ToNot(HaveOccurred())

		By("Downloading alpine image")
		r, err := http.Get("http://localhost:65432/images/alpine.iso")
		Expect(err).ToNot(HaveOccurred())
		defer r.Body.Close()

		file, err := os.Create(imagePath)
		Expect(err).ToNot(HaveOccurred())
		defer file.Close()

		_, err = io.Copy(file, r.Body)
		Expect(err).ToNot(HaveOccurred())

		close(stopChan)

		By("Setting up port forwarding")
		portMapping := fmt.Sprintf("%d:%d", localUploadProxyPort, uploadProxyPort)
		_, kubectlCmd, err = tests.CreateCommandWithNS(flags.ContainerizedDataImporterNamespace, "kubectl", "port-forward", uploadProxyService, portMapping)
		Expect(err).ToNot(HaveOccurred())

		err = kubectlCmd.Start()
		Expect(err).ToNot(HaveOccurred())
	})

	validateDataVolume := func(targetName string) {
		By("Get DataVolume")
		_, err := virtClient.CdiClient().CdiV1alpha1().DataVolumes(namespace).Get(targetName, metav1.GetOptions{})
		Expect(err).ToNot(HaveOccurred())
	}

	deletePVC := func(targetName string) {
		err := virtClient.CoreV1().PersistentVolumeClaims(namespace).Delete(targetName, &metav1.DeleteOptions{})
		if errors.IsNotFound(err) {
			return
		}
		Expect(err).ToNot(HaveOccurred())

		Eventually(func() bool {
			_, err = virtClient.CoreV1().PersistentVolumeClaims(namespace).Get(targetName, metav1.GetOptions{})
			if errors.IsNotFound(err) {
				return true
			}
			Expect(err).ToNot(HaveOccurred())
			return false
		}, 90*time.Second, 2*time.Second).Should(BeTrue())
	}

	deleteDataVolume := func(targetName string) {
		err := virtClient.CdiClient().CdiV1alpha1().DataVolumes(namespace).Delete(targetName, &metav1.DeleteOptions{})
		if errors.IsNotFound(err) {
			return
		}
		Expect(err).ToNot(HaveOccurred())

		Eventually(func() bool {
			_, err = virtClient.CdiClient().CdiV1alpha1().DataVolumes(namespace).Get(targetName, metav1.GetOptions{})
			if errors.IsNotFound(err) {
				return true
			}
			Expect(err).ToNot(HaveOccurred())
			return false
		}, 90*time.Second, 2*time.Second).Should(BeTrue())

		deletePVC(targetName)
	}

	validatePVC := func(targetName string) {
		By("Don't DataVolume")
		_, err := virtClient.CdiClient().CdiV1alpha1().DataVolumes(namespace).Get(targetName, metav1.GetOptions{})
		Expect(errors.IsNotFound(err)).To(BeTrue())

		By("Get PVC")
		pvc, err := virtClient.CoreV1().PersistentVolumeClaims(namespace).Get(targetName, metav1.GetOptions{})
		Expect(err).ToNot(HaveOccurred())
		Expect(*pvc.Spec.StorageClassName).To(Equal(tests.Config.StorageClassLocal))
	}

	Context("Upload an image and start a VMI with PVC", func() {
		DescribeTable("[test_id:4621] Should succeed", func(resource, targetName string, validateFunc, deleteFunc func(string), startVM bool) {
			defer deleteFunc(targetName)

			By("Upload image")
			virtctlCmd := tests.NewRepeatableVirtctlCommand("image-upload",
				resource, targetName,
				"--namespace", namespace,
				"--image-path", imagePath,
				"--size", pvcSize,
				"--uploadproxy-url", fmt.Sprintf("https://127.0.0.1:%d", localUploadProxyPort),
				"--wait-secs", "30",
				"--storage-class", tests.Config.StorageClassLocal,
				"--insecure")
			err := virtctlCmd()
			if err != nil {
				fmt.Printf("UploadImage Error: %+v\n", err)
				Expect(err).ToNot(HaveOccurred())
			}

			validateFunc(targetName)

			if startVM {
				By("Start VM")
				vmi := tests.NewRandomVMIWithDataVolume(targetName)
				vmi, err = virtClient.VirtualMachineInstance(namespace).Create(vmi)
				Expect(err).ToNot(HaveOccurred())
				defer func() {
					err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Delete(vmi.Name, &metav1.DeleteOptions{})
					Expect(err).ToNot(HaveOccurred())
				}()
				tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
				vmi, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmi.Name, &metav1.GetOptions{})
				Expect(err).ToNot(HaveOccurred())
			}
		},
			Entry("DataVolume", "dv", "alpine-dv", validateDataVolume, deleteDataVolume, true),
			Entry("PVC", "pvc", "alpine-pvc", validatePVC, deletePVC, false),
		)
	})

	AfterEach(func() {
		if kubectlCmd != nil {
			kubectlCmd.Process.Kill()
			kubectlCmd.Wait()
		}

		err := os.Remove(imagePath)
		Expect(err).ToNot(HaveOccurred())
	})
})
<commit_msg>Reference the default namespace directly<commit_after>package tests_test

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/flags"
)

const (
	uploadProxyService   = "svc/cdi-uploadproxy"
	uploadProxyPort      = 443
	localUploadProxyPort = 18443
	imagePath            = "/tmp/alpine.iso"
)

var _ = Describe("[Serial]ImageUpload", func() {
	var kubectlCmd *exec.Cmd

	pvcSize := "100Mi"

	var virtClient kubecli.KubevirtClient

	BeforeEach(func() {
		var err error

		virtClient, err = kubecli.GetKubevirtClient()
		tests.PanicOnError(err)
	})

	BeforeEach(func() {
		By("Getting CDI HTTP import server pod")
		pods, err := virtClient.CoreV1().Pods(flags.KubeVirtInstallNamespace).List(metav1.ListOptions{LabelSelector: "kubevirt.io=cdi-http-import-server"})
		Expect(err).ToNot(HaveOccurred())
		Expect(pods.Items).ToNot(BeEmpty())

		stopChan := make(chan struct{})
		err = tests.ForwardPorts(&pods.Items[0], []string{"65432:80"}, stopChan, 10*time.Second)
		Expect(err).ToNot(HaveOccurred())

		By("Downloading alpine image")
		r, err := http.Get("http://localhost:65432/images/alpine.iso")
		Expect(err).ToNot(HaveOccurred())
		defer r.Body.Close()

		file, err := os.Create(imagePath)
		Expect(err).ToNot(HaveOccurred())
		defer file.Close()

		_, err = io.Copy(file, r.Body)
		Expect(err).ToNot(HaveOccurred())

		close(stopChan)

		By("Setting up port forwarding")
		portMapping := fmt.Sprintf("%d:%d", localUploadProxyPort, uploadProxyPort)
		_, kubectlCmd, err = tests.CreateCommandWithNS(flags.ContainerizedDataImporterNamespace, "kubectl", "port-forward", uploadProxyService, portMapping)
		Expect(err).ToNot(HaveOccurred())

		err = kubectlCmd.Start()
		Expect(err).ToNot(HaveOccurred())
	})

	validateDataVolume := func(targetName string) {
		By("Get DataVolume")
		_, err := virtClient.CdiClient().CdiV1alpha1().DataVolumes(tests.NamespaceTestDefault).Get(targetName, metav1.GetOptions{})
		Expect(err).ToNot(HaveOccurred())
	}

	deletePVC := func(targetName string) {
		err := virtClient.CoreV1().PersistentVolumeClaims(tests.NamespaceTestDefault).Delete(targetName, &metav1.DeleteOptions{})
		if errors.IsNotFound(err) {
			return
		}
		Expect(err).ToNot(HaveOccurred())

		Eventually(func() bool {
			_, err = virtClient.CoreV1().PersistentVolumeClaims(tests.NamespaceTestDefault).Get(targetName, metav1.GetOptions{})
			if errors.IsNotFound(err) {
				return true
			}
			Expect(err).ToNot(HaveOccurred())
			return false
		}, 90*time.Second, 2*time.Second).Should(BeTrue())
	}

	deleteDataVolume := func(targetName string) {
		err := virtClient.CdiClient().CdiV1alpha1().DataVolumes(tests.NamespaceTestDefault).Delete(targetName, &metav1.DeleteOptions{})
		if errors.IsNotFound(err) {
			return
		}
		Expect(err).ToNot(HaveOccurred())

		Eventually(func() bool {
			_, err = virtClient.CdiClient().CdiV1alpha1().DataVolumes(tests.NamespaceTestDefault).Get(targetName, metav1.GetOptions{})
			if errors.IsNotFound(err) {
				return true
			}
			Expect(err).ToNot(HaveOccurred())
			return false
		}, 90*time.Second, 2*time.Second).Should(BeTrue())

		deletePVC(targetName)
	}

	validatePVC := func(targetName string) {
		By("Don't DataVolume")
		_, err := virtClient.CdiClient().CdiV1alpha1().DataVolumes(tests.NamespaceTestDefault).Get(targetName, metav1.GetOptions{})
		Expect(errors.IsNotFound(err)).To(BeTrue())

		By("Get PVC")
		pvc, err := virtClient.CoreV1().PersistentVolumeClaims(tests.NamespaceTestDefault).Get(targetName, metav1.GetOptions{})
		Expect(err).ToNot(HaveOccurred())
		Expect(*pvc.Spec.StorageClassName).To(Equal(tests.Config.StorageClassLocal))
	}

	Context("Upload an image and start a VMI with PVC", func() {
		DescribeTable("[test_id:4621] Should succeed", func(resource, targetName string, validateFunc, deleteFunc func(string), startVM bool) {
			defer deleteFunc(targetName)

			By("Upload image")
			virtctlCmd := tests.NewRepeatableVirtctlCommand("image-upload",
				resource, targetName,
				"--namespace", tests.NamespaceTestDefault,
				"--image-path", imagePath,
				"--size", pvcSize,
				"--uploadproxy-url", fmt.Sprintf("https://127.0.0.1:%d", localUploadProxyPort),
				"--wait-secs", "30",
				"--storage-class", tests.Config.StorageClassLocal,
				"--insecure")
			err := virtctlCmd()
			if err != nil {
				fmt.Printf("UploadImage Error: %+v\n", err)
				Expect(err).ToNot(HaveOccurred())
			}

			validateFunc(targetName)

			if startVM {
				By("Start VM")
				vmi := tests.NewRandomVMIWithDataVolume(targetName)
				vmi, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Create(vmi)
				Expect(err).ToNot(HaveOccurred())
				defer func() {
					err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Delete(vmi.Name, &metav1.DeleteOptions{})
					Expect(err).ToNot(HaveOccurred())
				}()
				tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
				vmi, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Get(vmi.Name, &metav1.GetOptions{})
				Expect(err).ToNot(HaveOccurred())
			}
		},
			Entry("DataVolume", "dv", "alpine-dv", validateDataVolume, deleteDataVolume, true),
			Entry("PVC", "pvc", "alpine-pvc", validatePVC, deletePVC, false),
		)
	})

	AfterEach(func() {
		if kubectlCmd != nil {
			kubectlCmd.Process.Kill()
			kubectlCmd.Wait()
		}

		err := os.Remove(imagePath)
		Expect(err).ToNot(HaveOccurred())
	})
})
<|endoftext|>


<commit_before>package pipeline

import (
	"io"

	"github.com/fsouza/go-dockerclient"
)

var DefaultConfig = docker.Config{
	AttachStdin:  true,
	AttachStdout: true,
	AttachStderr: true,
	OpenStdin:    true,
	StdinOnce:    true,
}

func startContainer(opts docker.CreateContainerOptions) (string, error) {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return "", err
	}
	container, err := client.CreateContainer(opts)
	if err != nil {
		return "", err
	}
	err = client.StartContainer(container.ID, opts.HostConfig)
	if err != nil {
		return "", err
	}

	return container.ID, nil
}

func stopContainer(id string) error {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	return client.StopContainer(id, 5)
}

func pullImage(image string) error {
	repository, tag := docker.ParseRepositoryTag(image)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	opts := docker.PullImageOptions{Repository: repository, Tag: "latest"}
	if tag != "" {
		opts.Tag = tag
	}
	return client.PullImage(opts, docker.AuthConfiguration{})
}

func pipeToStdin(id string, in io.Reader) error {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	return client.AttachToContainer(docker.AttachToContainerOptions{
		Container:   id,
		InputStream: in,
		Stdin:       true,
		Stream:      true,
	})
}

func containerLogs(id string, out io.Writer) error {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	return client.AttachToContainer(docker.AttachToContainerOptions{
		Container:    id,
		OutputStream: out,
		ErrorStream:  out,
		Stdout:       true,
		Stderr:       true,
		Logs:         true,
	})
}

func waitContainer(id string) (int, error) {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return 0, err
	}

	return client.WaitContainer(id)
}

func isImageLocal(image string) (bool, error) {
	repository, _ := docker.ParseRepositoryTag(image)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return false, err
	}
	images, err := client.ListImages(docker.ListImagesOptions{All: true, Digests: false})
	if err != nil {
		return false, err
	}
	for _, image := range images {
		if image.ID == repository {
			return true, nil
		}
	}
	return false, nil
}
<commit_msg>Fix going throught the images tags<commit_after>package pipeline

import (
	"fmt"
	"io"

	"github.com/fsouza/go-dockerclient"
)

var DefaultConfig = docker.Config{
	AttachStdin:  true,
	AttachStdout: true,
	AttachStderr: true,
	OpenStdin:    true,
	StdinOnce:    true,
}

func startContainer(opts docker.CreateContainerOptions) (string, error) {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return "", err
	}
	container, err := client.CreateContainer(opts)
	if err != nil {
		return "", err
	}
	err = client.StartContainer(container.ID, opts.HostConfig)
	if err != nil {
		return "", err
	}

	return container.ID, nil
}

func stopContainer(id string) error {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	return client.StopContainer(id, 5)
}

func pullImage(image string) error {
	repository, tag := docker.ParseRepositoryTag(image)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	opts := docker.PullImageOptions{Repository: repository, Tag: "latest"}
	if tag != "" {
		opts.Tag = tag
	}
	return client.PullImage(opts, docker.AuthConfiguration{})
}

func pipeToStdin(id string, in io.Reader) error {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	return client.AttachToContainer(docker.AttachToContainerOptions{
		Container:   id,
		InputStream: in,
		Stdin:       true,
		Stream:      true,
	})
}

func containerLogs(id string, out io.Writer) error {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return err
	}
	return client.AttachToContainer(docker.AttachToContainerOptions{
		Container:    id,
		OutputStream: out,
		ErrorStream:  out,
		Stdout:       true,
		Stderr:       true,
		Logs:         true,
	})
}

func waitContainer(id string) (int, error) {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return 0, err
	}

	return client.WaitContainer(id)
}

func isImageLocal(image string) (bool, error) {
	repository, tag := docker.ParseRepositoryTag(image)
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return false, err
	}
	images, err := client.ListImages(docker.ListImagesOptions{All: true, Digests: false})
	if err != nil {
		return false, err
	}
	expectedRepoTag := fmt.Sprintf("%s:%s", repository, tag)
	for _, image := range images {
		for _, repoTag := range image.RepoTags {
			if repoTag == expectedRepoTag {
				return true, nil
			}
		}
	}
	return false, nil
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go 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 rpc

import (
	"bufio"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
)

// ServerError represents an error that has been returned from
// the remote side of the RPC connection.
type ServerError string

func (e ServerError) Error() string {
	return string(e)
}

var ErrShutdown = errors.New("connection is shut down")

// Call represents an active RPC.
type Call struct {
	ServiceMethod string      // The name of the service and method to call.
	Args          interface{} // The argument to the function (*struct).
	Reply         interface{} // The reply from the function (*struct).
	Error         error       // After completion, the error status.
	Done          chan *Call  // Strobes when call is complete.
}

// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
	mutex    sync.Mutex // protects pending, seq, request
	sending  sync.Mutex
	request  Request
	seq      uint64
	codec    ClientCodec
	pending  map[uint64]*Call
	closing  bool
	shutdown bool
}

// A ClientCodec implements writing of RPC requests and
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
// to read responses.  The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error

	Close() error
}

func (client *Client) send(call *Call) {
	client.sending.Lock()
	defer client.sending.Unlock()

	// Register this call.
	client.mutex.Lock()
	if client.shutdown {
		call.Error = ErrShutdown
		client.mutex.Unlock()
		call.done()
		return
	}
	seq := client.seq
	client.seq++
	client.pending[seq] = call
	client.mutex.Unlock()

	// Encode and send the request.
	client.request.Seq = seq
	client.request.ServiceMethod = call.ServiceMethod
	err := client.codec.WriteRequest(&client.request, call.Args)
	if err != nil {
		client.mutex.Lock()
		call = client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()
		if call != nil {
			call.Error = err
			call.done()
		}
	}
}

func (client *Client) input() {
	var err error
	var response Response
	for err == nil {
		response = Response{}
		err = client.codec.ReadResponseHeader(&response)
		if err != nil {
			if err == io.EOF && !client.closing {
				err = io.ErrUnexpectedEOF
			}
			break
		}
		seq := response.Seq
		client.mutex.Lock()
		call := client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()

		if call == nil || response.Error != "" {
			// We've got an error response. Give this to the request;
			// any subsequent requests will get the ReadResponseBody
			// error if there is one.
			if call != nil {
				call.Error = ServerError(response.Error)
			}
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
		} else if response.Error == "" {
			err = client.codec.ReadResponseBody(call.Reply)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			}
		}
		if call != nil {
			call.done()
		}
	}
	// Terminate pending calls.
	client.sending.Lock()
	client.mutex.Lock()
	client.shutdown = true
	closing := client.closing
	for _, call := range client.pending {
		call.Error = err
		call.done()
	}
	client.mutex.Unlock()
	client.sending.Unlock()
	if err != io.EOF && !closing {
		log.Println("rpc: client protocol error:", err)
	}
}

func (call *Call) done() {
	select {
	case call.Done <- call:
		// ok
	default:
		// We don't want to block here.  It is the caller's responsibility to make
		// sure the channel has enough buffer space. See comment in Go().
		log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
	}
}

// NewClient returns a new Client to handle requests to the
// set of services at the other end of the connection.
// It adds a buffer to the write side of the connection so
// the header and payload are sent as a unit.
func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

// NewClientWithCodec is like NewClient but uses the specified
// codec to encode requests and decode responses.
func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,
		pending: make(map[uint64]*Call),
	}
	go client.input()
	return client
}

type gobClientCodec struct {
	rwc    io.ReadWriteCloser
	dec    *gob.Decoder
	enc    *gob.Encoder
	encBuf *bufio.Writer
}

func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
	if err = c.enc.Encode(r); err != nil {
		return
	}
	if err = c.enc.Encode(body); err != nil {
		return
	}
	return c.encBuf.Flush()
}

func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
	return c.dec.Decode(r)
}

func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
	return c.dec.Decode(body)
}

func (c *gobClientCodec) Close() error {
	return c.rwc.Close()
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, error) {
	return DialHTTPPath(network, address, DefaultRPCPath)
}

// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, error) {
	var err error
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn), nil
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	conn.Close()
	return nil, &net.OpError{
		Op:   "dial-http",
		Net:  network + " " + address,
		Addr: nil,
		Err:  err,
	}
}

// Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), nil
}

func (client *Client) Close() error {
	client.mutex.Lock()
	if client.shutdown || client.closing {
		client.mutex.Unlock()
		return ErrShutdown
	}
	client.closing = true
	client.mutex.Unlock()
	return client.codec.Close()
}

// Go invokes the function asynchronously.  It returns the Call structure representing
// the invocation.  The done channel will signal when the call is complete by returning
// the same Call object.  If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
	call := new(Call)
	call.ServiceMethod = serviceMethod
	call.Args = args
	call.Reply = reply
	if done == nil {
		done = make(chan *Call, 10) // buffered.
	} else {
		// If caller passes done != nil, it must arrange that
		// done has enough buffer for the number of simultaneous
		// RPCs that will be using that channel.  If the channel
		// is totally unbuffered, it's best not to run at all.
		if cap(done) == 0 {
			log.Panic("rpc: done channel is unbuffered")
		}
	}
	call.Done = done
	client.send(call)
	return call
}

// Call invokes the named function, waits for it to complete, and returns its error status.
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
	call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
	return call.Error
}
<commit_msg>net/rpc: improve response reading logic<commit_after>// Copyright 2009 The Go 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 rpc

import (
	"bufio"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"sync"
)

// ServerError represents an error that has been returned from
// the remote side of the RPC connection.
type ServerError string

func (e ServerError) Error() string {
	return string(e)
}

var ErrShutdown = errors.New("connection is shut down")

// Call represents an active RPC.
type Call struct {
	ServiceMethod string      // The name of the service and method to call.
	Args          interface{} // The argument to the function (*struct).
	Reply         interface{} // The reply from the function (*struct).
	Error         error       // After completion, the error status.
	Done          chan *Call  // Strobes when call is complete.
}

// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
	mutex    sync.Mutex // protects pending, seq, request
	sending  sync.Mutex
	request  Request
	seq      uint64
	codec    ClientCodec
	pending  map[uint64]*Call
	closing  bool
	shutdown bool
}

// A ClientCodec implements writing of RPC requests and
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
// to read responses.  The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error

	Close() error
}

func (client *Client) send(call *Call) {
	client.sending.Lock()
	defer client.sending.Unlock()

	// Register this call.
	client.mutex.Lock()
	if client.shutdown {
		call.Error = ErrShutdown
		client.mutex.Unlock()
		call.done()
		return
	}
	seq := client.seq
	client.seq++
	client.pending[seq] = call
	client.mutex.Unlock()

	// Encode and send the request.
	client.request.Seq = seq
	client.request.ServiceMethod = call.ServiceMethod
	err := client.codec.WriteRequest(&client.request, call.Args)
	if err != nil {
		client.mutex.Lock()
		call = client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()
		if call != nil {
			call.Error = err
			call.done()
		}
	}
}

func (client *Client) input() {
	var err error
	var response Response
	for err == nil {
		response = Response{}
		err = client.codec.ReadResponseHeader(&response)
		if err != nil {
			if err == io.EOF && !client.closing {
				err = io.ErrUnexpectedEOF
			}
			break
		}
		seq := response.Seq
		client.mutex.Lock()
		call := client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()

		switch {
		case call == nil:
			// We've got no pending call. That usually means that
			// WriteRequest partially failed, and call was already
			// removed; response is a server telling us about an
			// error reading request body. We should still attempt
			// to read error body, but there's no one to give it to.
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
		case response.Error != "":
			// We've got an error response. Give this to the request;
			// any subsequent requests will get the ReadResponseBody
			// error if there is one.
			call.Error = ServerError(response.Error)
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
			call.done()
		default:
			err = client.codec.ReadResponseBody(call.Reply)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			}
			call.done()
		}
	}
	// Terminate pending calls.
	client.sending.Lock()
	client.mutex.Lock()
	client.shutdown = true
	closing := client.closing
	for _, call := range client.pending {
		call.Error = err
		call.done()
	}
	client.mutex.Unlock()
	client.sending.Unlock()
	if err != io.EOF && !closing {
		log.Println("rpc: client protocol error:", err)
	}
}

func (call *Call) done() {
	select {
	case call.Done <- call:
		// ok
	default:
		// We don't want to block here.  It is the caller's responsibility to make
		// sure the channel has enough buffer space. See comment in Go().
		log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
	}
}

// NewClient returns a new Client to handle requests to the
// set of services at the other end of the connection.
// It adds a buffer to the write side of the connection so
// the header and payload are sent as a unit.
func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

// NewClientWithCodec is like NewClient but uses the specified
// codec to encode requests and decode responses.
func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,
		pending: make(map[uint64]*Call),
	}
	go client.input()
	return client
}

type gobClientCodec struct {
	rwc    io.ReadWriteCloser
	dec    *gob.Decoder
	enc    *gob.Encoder
	encBuf *bufio.Writer
}

func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
	if err = c.enc.Encode(r); err != nil {
		return
	}
	if err = c.enc.Encode(body); err != nil {
		return
	}
	return c.encBuf.Flush()
}

func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
	return c.dec.Decode(r)
}

func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
	return c.dec.Decode(body)
}

func (c *gobClientCodec) Close() error {
	return c.rwc.Close()
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, error) {
	return DialHTTPPath(network, address, DefaultRPCPath)
}

// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, error) {
	var err error
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn), nil
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	conn.Close()
	return nil, &net.OpError{
		Op:   "dial-http",
		Net:  network + " " + address,
		Addr: nil,
		Err:  err,
	}
}

// Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), nil
}

func (client *Client) Close() error {
	client.mutex.Lock()
	if client.shutdown || client.closing {
		client.mutex.Unlock()
		return ErrShutdown
	}
	client.closing = true
	client.mutex.Unlock()
	return client.codec.Close()
}

// Go invokes the function asynchronously.  It returns the Call structure representing
// the invocation.  The done channel will signal when the call is complete by returning
// the same Call object.  If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
	call := new(Call)
	call.ServiceMethod = serviceMethod
	call.Args = args
	call.Reply = reply
	if done == nil {
		done = make(chan *Call, 10) // buffered.
	} else {
		// If caller passes done != nil, it must arrange that
		// done has enough buffer for the number of simultaneous
		// RPCs that will be using that channel.  If the channel
		// is totally unbuffered, it's best not to run at all.
		if cap(done) == 0 {
			log.Panic("rpc: done channel is unbuffered")
		}
	}
	call.Done = done
	client.send(call)
	return call
}

// Call invokes the named function, waits for it to complete, and returns its error status.
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
	call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
	return call.Error
}
<|endoftext|>


<commit_before>// Copyright Project Harbor 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 dao

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/goharbor/harbor/src/lib/orm"
	"github.com/goharbor/harbor/src/lib/q"
	"github.com/goharbor/harbor/src/pkg/quota/types"
)

var (
	quotaOrderMap = map[string]string{
		"creation_time":  "b.creation_time asc",
		"+creation_time": "b.creation_time asc",
		"-creation_time": "b.creation_time desc",
		"update_time":    "b.update_time asc",
		"+update_time":   "b.update_time asc",
		"-update_time":   "b.update_time desc",
	}
)

type listQuery struct {
	ID           int64    `json:"id"`
	Reference    string   `json:"reference"`
	ReferenceID  string   `json:"reference_id"`
	ReferenceIDs []string `json:"reference_ids"`
}

func listConditions(query *q.Query) (string, []interface{}) {
	params := []interface{}{}
	sql := ""
	if query == nil {
		return sql, params
	}

	sql += `WHERE 1=1 `

	var q listQuery

	bytes, err := json.Marshal(query.Keywords)
	if err == nil {
		json.Unmarshal(bytes, &q)
	}

	if q.ID != 0 {
		sql += `AND a.id = ? `
		params = append(params, q.ID)
	}
	if q.Reference != "" {
		sql += `AND a.reference = ? `
		params = append(params, q.Reference)
	}
	if q.ReferenceID != "" {
		sql += `AND a.reference_id = ? `
		params = append(params, q.ReferenceID)
	}

	if len(q.ReferenceIDs) != 0 {
		sql += fmt.Sprintf(`AND a.reference_id IN (%s) `, orm.ParamPlaceholderForIn(len(q.ReferenceIDs)))
		params = append(params, q.ReferenceIDs)
	}

	return sql, params
}

func castQuantity(field string) string {
	// cast -1 to max int64 when order by field
	return fmt.Sprintf("CAST( (CASE WHEN (%[1]s) IS NULL THEN '0' WHEN (%[1]s) = '-1' THEN '9223372036854775807' ELSE (%[1]s) END) AS BIGINT )", field)
}

func listOrderBy(query *q.Query) string {
	orderBy := "b.creation_time DESC"

	if query != nil && query.Sorting != "" {
		if val, ok := quotaOrderMap[query.Sorting]; ok {
			orderBy = val
		} else {
			sort := query.Sorting

			order := "ASC"
			if sort[0] == '-' {
				order = "DESC"
				sort = sort[1:]
			}

			prefixes := []string{"hard.", "used."}
			for _, prefix := range prefixes {
				if strings.HasPrefix(sort, prefix) {
					resource := strings.TrimPrefix(sort, prefix)
					if types.IsValidResource(types.ResourceName(resource)) {
						field := fmt.Sprintf("%s->>'%s'", strings.TrimSuffix(prefix, "."), resource)
						orderBy = fmt.Sprintf("(%s) %s", castQuantity(field), order)
						break
					}
				}
			}
		}
	}

	return orderBy
}
<commit_msg>fix quota dao sql injection<commit_after>// Copyright Project Harbor 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 dao

import (
	"encoding/json"
	"fmt"
	"github.com/lib/pq"
	"strings"

	"github.com/goharbor/harbor/src/lib/orm"
	"github.com/goharbor/harbor/src/lib/q"
	"github.com/goharbor/harbor/src/pkg/quota/types"
)

var (
	quotaOrderMap = map[string]string{
		"creation_time":  "b.creation_time asc",
		"+creation_time": "b.creation_time asc",
		"-creation_time": "b.creation_time desc",
		"update_time":    "b.update_time asc",
		"+update_time":   "b.update_time asc",
		"-update_time":   "b.update_time desc",
	}
)

type listQuery struct {
	ID           int64    `json:"id"`
	Reference    string   `json:"reference"`
	ReferenceID  string   `json:"reference_id"`
	ReferenceIDs []string `json:"reference_ids"`
}

func listConditions(query *q.Query) (string, []interface{}) {
	params := []interface{}{}
	sql := ""
	if query == nil {
		return sql, params
	}

	sql += `WHERE 1=1 `

	var q listQuery

	bytes, err := json.Marshal(query.Keywords)
	if err == nil {
		json.Unmarshal(bytes, &q)
	}

	if q.ID != 0 {
		sql += `AND a.id = ? `
		params = append(params, q.ID)
	}
	if q.Reference != "" {
		sql += `AND a.reference = ? `
		params = append(params, q.Reference)
	}
	if q.ReferenceID != "" {
		sql += `AND a.reference_id = ? `
		params = append(params, q.ReferenceID)
	}

	if len(q.ReferenceIDs) != 0 {
		sql += fmt.Sprintf(`AND a.reference_id IN (%s) `, orm.ParamPlaceholderForIn(len(q.ReferenceIDs)))
		params = append(params, q.ReferenceIDs)
	}

	return sql, params
}

func castQuantity(field string) string {
	// cast -1 to max int64 when order by field
	return fmt.Sprintf("CAST( (CASE WHEN (%[1]s) IS NULL THEN '0' WHEN (%[1]s) = '-1' THEN '9223372036854775807' ELSE (%[1]s) END) AS BIGINT )", field)
}

func listOrderBy(query *q.Query) string {
	orderBy := "b.creation_time DESC"

	if query != nil && query.Sorting != "" {
		if val, ok := quotaOrderMap[query.Sorting]; ok {
			orderBy = val
		} else {
			sort := query.Sorting

			order := "ASC"
			if sort[0] == '-' {
				order = "DESC"
				sort = sort[1:]
			}

			prefixes := []string{"hard.", "used."}
			for _, prefix := range prefixes {
				if strings.HasPrefix(sort, prefix) {
					resource := strings.TrimPrefix(sort, prefix)
					if types.IsValidResource(types.ResourceName(resource)) {
						field := fmt.Sprintf("%s->>%s", strings.TrimSuffix(prefix, "."), pq.QuoteLiteral(resource))
						orderBy = fmt.Sprintf("(%s) %s", castQuantity(field), order)
						break
					}
				}
			}
		}
	}

	return orderBy
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go 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 utf8_test

import (
	"bytes";
	"strings";
	"testing";
	. "utf8";
)

type Utf8Map struct {
	rune	int;
	str	string;
}

var utf8map = []Utf8Map{
	Utf8Map{0x0000, "\x00"},
	Utf8Map{0x0001, "\x01"},
	Utf8Map{0x007e, "\x7e"},
	Utf8Map{0x007f, "\x7f"},
	Utf8Map{0x0080, "\xc2\x80"},
	Utf8Map{0x0081, "\xc2\x81"},
	Utf8Map{0x00bf, "\xc2\xbf"},
	Utf8Map{0x00c0, "\xc3\x80"},
	Utf8Map{0x00c1, "\xc3\x81"},
	Utf8Map{0x00c8, "\xc3\x88"},
	Utf8Map{0x00d0, "\xc3\x90"},
	Utf8Map{0x00e0, "\xc3\xa0"},
	Utf8Map{0x00f0, "\xc3\xb0"},
	Utf8Map{0x00f8, "\xc3\xb8"},
	Utf8Map{0x00ff, "\xc3\xbf"},
	Utf8Map{0x0100, "\xc4\x80"},
	Utf8Map{0x07ff, "\xdf\xbf"},
	Utf8Map{0x0800, "\xe0\xa0\x80"},
	Utf8Map{0x0801, "\xe0\xa0\x81"},
	Utf8Map{0xfffe, "\xef\xbf\xbe"},
	Utf8Map{0xffff, "\xef\xbf\xbf"},
	Utf8Map{0x10000, "\xf0\x90\x80\x80"},
	Utf8Map{0x10001, "\xf0\x90\x80\x81"},
	Utf8Map{0x10fffe, "\xf4\x8f\xbf\xbe"},
	Utf8Map{0x10ffff, "\xf4\x8f\xbf\xbf"},
}

// strings.Bytes with one extra byte at end
func makeBytes(s string) []byte {
	s += "\x00";
	b := strings.Bytes(s);
	return b[0 : len(s)-1];
}

func TestFullRune(t *testing.T) {
	for i := 0; i < len(utf8map); i++ {
		m := utf8map[i];
		b := makeBytes(m.str);
		if !FullRune(b) {
			t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune)
		}
		s := m.str;
		if !FullRuneInString(s) {
			t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune)
		}
		b1 := b[0 : len(b)-1];
		if FullRune(b1) {
			t.Errorf("FullRune(%q) = true, want false", b1)
		}
		s1 := string(b1);
		if FullRuneInString(s1) {
			t.Errorf("FullRune(%q) = true, want false", s1)
		}
	}
}

func TestEncodeRune(t *testing.T) {
	for i := 0; i < len(utf8map); i++ {
		m := utf8map[i];
		b := makeBytes(m.str);
		var buf [10]byte;
		n := EncodeRune(m.rune, &buf);
		b1 := buf[0:n];
		if !bytes.Equal(b, b1) {
			t.Errorf("EncodeRune(0x%04x) = %q want %q", m.rune, b1, b)
		}
	}
}

func TestDecodeRune(t *testing.T) {
	for i := 0; i < len(utf8map); i++ {
		m := utf8map[i];
		b := makeBytes(m.str);
		rune, size := DecodeRune(b);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b))
		}
		s := m.str;
		rune, size = DecodeRuneInString(s);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b))
		}

		// there's an extra byte that bytes left behind - make sure trailing byte works
		rune, size = DecodeRune(b[0:cap(b)]);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b))
		}
		s = m.str + "\x00";
		rune, size = DecodeRuneInString(s);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b))
		}

		// make sure missing bytes fail
		wantsize := 1;
		if wantsize >= len(b) {
			wantsize = 0
		}
		rune, size = DecodeRune(b[0 : len(b)-1]);
		if rune != RuneError || size != wantsize {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
		}
		s = m.str[0 : len(m.str)-1];
		rune, size = DecodeRuneInString(s);
		if rune != RuneError || size != wantsize {
			t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, wantsize)
		}

		// make sure bad sequences fail
		if len(b) == 1 {
			b[0] = 0x80
		} else {
			b[len(b)-1] = 0x7F
		}
		rune, size = DecodeRune(b);
		if rune != RuneError || size != 1 {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, RuneError, 1)
		}
		s = string(b);
		rune, size = DecodeRune(b);
		if rune != RuneError || size != 1 {
			t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, 1)
		}
	}
}

type RuneCountTest struct {
	in	string;
	out	int;
}

var runecounttests = []RuneCountTest{
	RuneCountTest{"abcd", 4},
	RuneCountTest{"☺☻☹", 3},
	RuneCountTest{"1,2,3,4", 7},
	RuneCountTest{"\xe2\x00", 2},
}

func TestRuneCount(t *testing.T) {
	for i := 0; i < len(runecounttests); i++ {
		tt := runecounttests[i];
		if out := RuneCountInString(tt.in); out != tt.out {
			t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
		}
		if out := RuneCount(makeBytes(tt.in)); out != tt.out {
			t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
		}
	}
}
<commit_msg>a few utf8 benchmarks. on my mac:<commit_after>// Copyright 2009 The Go 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 utf8_test

import (
	"bytes";
	"strings";
	"testing";
	. "utf8";
)

type Utf8Map struct {
	rune	int;
	str	string;
}

var utf8map = []Utf8Map{
	Utf8Map{0x0000, "\x00"},
	Utf8Map{0x0001, "\x01"},
	Utf8Map{0x007e, "\x7e"},
	Utf8Map{0x007f, "\x7f"},
	Utf8Map{0x0080, "\xc2\x80"},
	Utf8Map{0x0081, "\xc2\x81"},
	Utf8Map{0x00bf, "\xc2\xbf"},
	Utf8Map{0x00c0, "\xc3\x80"},
	Utf8Map{0x00c1, "\xc3\x81"},
	Utf8Map{0x00c8, "\xc3\x88"},
	Utf8Map{0x00d0, "\xc3\x90"},
	Utf8Map{0x00e0, "\xc3\xa0"},
	Utf8Map{0x00f0, "\xc3\xb0"},
	Utf8Map{0x00f8, "\xc3\xb8"},
	Utf8Map{0x00ff, "\xc3\xbf"},
	Utf8Map{0x0100, "\xc4\x80"},
	Utf8Map{0x07ff, "\xdf\xbf"},
	Utf8Map{0x0800, "\xe0\xa0\x80"},
	Utf8Map{0x0801, "\xe0\xa0\x81"},
	Utf8Map{0xfffe, "\xef\xbf\xbe"},
	Utf8Map{0xffff, "\xef\xbf\xbf"},
	Utf8Map{0x10000, "\xf0\x90\x80\x80"},
	Utf8Map{0x10001, "\xf0\x90\x80\x81"},
	Utf8Map{0x10fffe, "\xf4\x8f\xbf\xbe"},
	Utf8Map{0x10ffff, "\xf4\x8f\xbf\xbf"},
}

// strings.Bytes with one extra byte at end
func makeBytes(s string) []byte {
	s += "\x00";
	b := strings.Bytes(s);
	return b[0 : len(s)-1];
}

func TestFullRune(t *testing.T) {
	for i := 0; i < len(utf8map); i++ {
		m := utf8map[i];
		b := makeBytes(m.str);
		if !FullRune(b) {
			t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune)
		}
		s := m.str;
		if !FullRuneInString(s) {
			t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune)
		}
		b1 := b[0 : len(b)-1];
		if FullRune(b1) {
			t.Errorf("FullRune(%q) = true, want false", b1)
		}
		s1 := string(b1);
		if FullRuneInString(s1) {
			t.Errorf("FullRune(%q) = true, want false", s1)
		}
	}
}

func TestEncodeRune(t *testing.T) {
	for i := 0; i < len(utf8map); i++ {
		m := utf8map[i];
		b := makeBytes(m.str);
		var buf [10]byte;
		n := EncodeRune(m.rune, &buf);
		b1 := buf[0:n];
		if !bytes.Equal(b, b1) {
			t.Errorf("EncodeRune(0x%04x) = %q want %q", m.rune, b1, b)
		}
	}
}

func TestDecodeRune(t *testing.T) {
	for i := 0; i < len(utf8map); i++ {
		m := utf8map[i];
		b := makeBytes(m.str);
		rune, size := DecodeRune(b);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b))
		}
		s := m.str;
		rune, size = DecodeRuneInString(s);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b))
		}

		// there's an extra byte that bytes left behind - make sure trailing byte works
		rune, size = DecodeRune(b[0:cap(b)]);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b))
		}
		s = m.str + "\x00";
		rune, size = DecodeRuneInString(s);
		if rune != m.rune || size != len(b) {
			t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b))
		}

		// make sure missing bytes fail
		wantsize := 1;
		if wantsize >= len(b) {
			wantsize = 0
		}
		rune, size = DecodeRune(b[0 : len(b)-1]);
		if rune != RuneError || size != wantsize {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
		}
		s = m.str[0 : len(m.str)-1];
		rune, size = DecodeRuneInString(s);
		if rune != RuneError || size != wantsize {
			t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, wantsize)
		}

		// make sure bad sequences fail
		if len(b) == 1 {
			b[0] = 0x80
		} else {
			b[len(b)-1] = 0x7F
		}
		rune, size = DecodeRune(b);
		if rune != RuneError || size != 1 {
			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, RuneError, 1)
		}
		s = string(b);
		rune, size = DecodeRune(b);
		if rune != RuneError || size != 1 {
			t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, 1)
		}
	}
}

type RuneCountTest struct {
	in	string;
	out	int;
}

var runecounttests = []RuneCountTest{
	RuneCountTest{"abcd", 4},
	RuneCountTest{"☺☻☹", 3},
	RuneCountTest{"1,2,3,4", 7},
	RuneCountTest{"\xe2\x00", 2},
}

func TestRuneCount(t *testing.T) {
	for i := 0; i < len(runecounttests); i++ {
		tt := runecounttests[i];
		if out := RuneCountInString(tt.in); out != tt.out {
			t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
		}
		if out := RuneCount(makeBytes(tt.in)); out != tt.out {
			t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
		}
	}
}

func BenchmarkRuneCountTenASCIIChars(b *testing.B) {
	for i := 0; i < b.N; i++ {
		RuneCountInString("0123456789")
	}
}

func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
	for i := 0; i < b.N; i++ {
		RuneCountInString("日本語日本語日本語日")
	}
}

func BenchmarkEncodeASCIIRune(b *testing.B) {
	buf := make([]byte, UTFMax);
	for i := 0; i < b.N; i++ {
		EncodeRune('a', buf)
	}
}

func BenchmarkEncodeJapaneseRune(b *testing.B) {
	buf := make([]byte, UTFMax);
	for i := 0; i < b.N; i++ {
		EncodeRune('本', buf)
	}
}

func BenchmarkDecodeASCIIRune(b *testing.B) {
	a := []byte{'a'};
	for i := 0; i < b.N; i++ {
		DecodeRune(a)
	}
}

func BenchmarkDecodeJapaneseRune(b *testing.B) {
	nihon := strings.Bytes("本");
	for i := 0; i < b.N; i++ {
		DecodeRune(nihon)
	}
}
<|endoftext|>


<commit_before>package convert

import (
	"fmt"
	"os"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/swarm"
	servicecli "github.com/docker/docker/cli/command/service"
	composetypes "github.com/docker/docker/cli/compose/types"
	"github.com/docker/docker/client"
	"github.com/docker/docker/opts"
	runconfigopts "github.com/docker/docker/runconfig/opts"
	"github.com/docker/go-connections/nat"
)

// Services from compose-file types to engine API types
// TODO: fix secrets API so that SecretAPIClient is not required here
func Services(
	namespace Namespace,
	config *composetypes.Config,
	client client.SecretAPIClient,
) (map[string]swarm.ServiceSpec, error) {
	result := make(map[string]swarm.ServiceSpec)

	services := config.Services
	volumes := config.Volumes
	networks := config.Networks

	for _, service := range services {

		secrets, err := convertServiceSecrets(client, namespace, service.Secrets, config.Secrets)
		if err != nil {
			return nil, err
		}
		serviceSpec, err := convertService(namespace, service, networks, volumes, secrets)
		if err != nil {
			return nil, err
		}
		result[service.Name] = serviceSpec
	}

	return result, nil
}

func convertService(
	namespace Namespace,
	service composetypes.ServiceConfig,
	networkConfigs map[string]composetypes.NetworkConfig,
	volumes map[string]composetypes.VolumeConfig,
	secrets []*swarm.SecretReference,
) (swarm.ServiceSpec, error) {
	name := namespace.Scope(service.Name)

	endpoint, err := convertEndpointSpec(service.Ports)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	mode, err := convertDeployMode(service.Deploy.Mode, service.Deploy.Replicas)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	mounts, err := Volumes(service.Volumes, volumes, namespace)
	if err != nil {
		// TODO: better error message (include service name)
		return swarm.ServiceSpec{}, err
	}

	resources, err := convertResources(service.Deploy.Resources)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	restartPolicy, err := convertRestartPolicy(
		service.Restart, service.Deploy.RestartPolicy)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	healthcheck, err := convertHealthcheck(service.HealthCheck)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	networks, err := convertServiceNetworks(service.Networks, networkConfigs, namespace, service.Name)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	var logDriver *swarm.Driver
	if service.Logging != nil {
		logDriver = &swarm.Driver{
			Name:    service.Logging.Driver,
			Options: service.Logging.Options,
		}
	}

	serviceSpec := swarm.ServiceSpec{
		Annotations: swarm.Annotations{
			Name:   name,
			Labels: AddStackLabel(namespace, service.Deploy.Labels),
		},
		TaskTemplate: swarm.TaskSpec{
			ContainerSpec: swarm.ContainerSpec{
				Image:           service.Image,
				Command:         service.Entrypoint,
				Args:            service.Command,
				Hostname:        service.Hostname,
				Hosts:           convertExtraHosts(service.ExtraHosts),
				Healthcheck:     healthcheck,
				Env:             convertEnvironment(service.Environment),
				Labels:          AddStackLabel(namespace, service.Labels),
				Dir:             service.WorkingDir,
				User:            service.User,
				Mounts:          mounts,
				StopGracePeriod: service.StopGracePeriod,
				TTY:             service.Tty,
				OpenStdin:       service.StdinOpen,
				Secrets:         secrets,
			},
			LogDriver:     logDriver,
			Resources:     resources,
			RestartPolicy: restartPolicy,
			Placement: &swarm.Placement{
				Constraints: service.Deploy.Placement.Constraints,
			},
		},
		EndpointSpec: endpoint,
		Mode:         mode,
		Networks:     networks,
		UpdateConfig: convertUpdateConfig(service.Deploy.UpdateConfig),
	}

	return serviceSpec, nil
}

func convertServiceNetworks(
	networks map[string]*composetypes.ServiceNetworkConfig,
	networkConfigs networkMap,
	namespace Namespace,
	name string,
) ([]swarm.NetworkAttachmentConfig, error) {
	if len(networks) == 0 {
		return []swarm.NetworkAttachmentConfig{
			{
				Target:  namespace.Scope("default"),
				Aliases: []string{name},
			},
		}, nil
	}

	nets := []swarm.NetworkAttachmentConfig{}
	for networkName, network := range networks {
		networkConfig, ok := networkConfigs[networkName]
		if !ok {
			return []swarm.NetworkAttachmentConfig{}, fmt.Errorf(
				"service %q references network %q, which is not declared", name, networkName)
		}
		var aliases []string
		if network != nil {
			aliases = network.Aliases
		}
		target := namespace.Scope(networkName)
		if networkConfig.External.External {
			target = networkConfig.External.Name
		}
		nets = append(nets, swarm.NetworkAttachmentConfig{
			Target:  target,
			Aliases: append(aliases, name),
		})
	}
	return nets, nil
}

// TODO: fix secrets API so that SecretAPIClient is not required here
func convertServiceSecrets(
	client client.SecretAPIClient,
	namespace Namespace,
	secrets []composetypes.ServiceSecretConfig,
	secretSpecs map[string]composetypes.SecretConfig,
) ([]*swarm.SecretReference, error) {
	opts := []*types.SecretRequestOption{}
	for _, secret := range secrets {
		target := secret.Target
		if target == "" {
			target = secret.Source
		}

		source := namespace.Scope(secret.Source)
		secretSpec := secretSpecs[secret.Source]
		if secretSpec.External.External {
			source = secretSpec.External.Name
		}

		opts = append(opts, &types.SecretRequestOption{
			Source: source,
			Target: target,
			UID:    secret.UID,
			GID:    secret.GID,
			Mode:   os.FileMode(secret.Mode),
		})
	}

	return servicecli.ParseSecrets(client, opts)
}

func convertExtraHosts(extraHosts map[string]string) []string {
	hosts := []string{}
	for host, ip := range extraHosts {
		hosts = append(hosts, fmt.Sprintf("%s %s", ip, host))
	}
	return hosts
}

func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container.HealthConfig, error) {
	if healthcheck == nil {
		return nil, nil
	}
	var (
		err               error
		timeout, interval time.Duration
		retries           int
	)
	if healthcheck.Disable {
		if len(healthcheck.Test) != 0 {
			return nil, fmt.Errorf("test and disable can't be set at the same time")
		}
		return &container.HealthConfig{
			Test: []string{"NONE"},
		}, nil

	}
	if healthcheck.Timeout != "" {
		timeout, err = time.ParseDuration(healthcheck.Timeout)
		if err != nil {
			return nil, err
		}
	}
	if healthcheck.Interval != "" {
		interval, err = time.ParseDuration(healthcheck.Interval)
		if err != nil {
			return nil, err
		}
	}
	if healthcheck.Retries != nil {
		retries = int(*healthcheck.Retries)
	}
	return &container.HealthConfig{
		Test:     healthcheck.Test,
		Timeout:  timeout,
		Interval: interval,
		Retries:  retries,
	}, nil
}

func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*swarm.RestartPolicy, error) {
	// TODO: log if restart is being ignored
	if source == nil {
		policy, err := runconfigopts.ParseRestartPolicy(restart)
		if err != nil {
			return nil, err
		}
		switch {
		case policy.IsNone():
			return nil, nil
		case policy.IsAlways(), policy.IsUnlessStopped():
			return &swarm.RestartPolicy{
				Condition: swarm.RestartPolicyConditionAny,
			}, nil
		case policy.IsOnFailure():
			attempts := uint64(policy.MaximumRetryCount)
			return &swarm.RestartPolicy{
				Condition:   swarm.RestartPolicyConditionOnFailure,
				MaxAttempts: &attempts,
			}, nil
		default:
			return nil, fmt.Errorf("unknown restart policy: %s", restart)
		}
	}
	return &swarm.RestartPolicy{
		Condition:   swarm.RestartPolicyCondition(source.Condition),
		Delay:       source.Delay,
		MaxAttempts: source.MaxAttempts,
		Window:      source.Window,
	}, nil
}

func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig {
	if source == nil {
		return nil
	}
	parallel := uint64(1)
	if source.Parallelism != nil {
		parallel = *source.Parallelism
	}
	return &swarm.UpdateConfig{
		Parallelism:     parallel,
		Delay:           source.Delay,
		FailureAction:   source.FailureAction,
		Monitor:         source.Monitor,
		MaxFailureRatio: source.MaxFailureRatio,
	}
}

func convertResources(source composetypes.Resources) (*swarm.ResourceRequirements, error) {
	resources := &swarm.ResourceRequirements{}
	var err error
	if source.Limits != nil {
		var cpus int64
		if source.Limits.NanoCPUs != "" {
			cpus, err = opts.ParseCPUs(source.Limits.NanoCPUs)
			if err != nil {
				return nil, err
			}
		}
		resources.Limits = &swarm.Resources{
			NanoCPUs:    cpus,
			MemoryBytes: int64(source.Limits.MemoryBytes),
		}
	}
	if source.Reservations != nil {
		var cpus int64
		if source.Reservations.NanoCPUs != "" {
			cpus, err = opts.ParseCPUs(source.Reservations.NanoCPUs)
			if err != nil {
				return nil, err
			}
		}
		resources.Reservations = &swarm.Resources{
			NanoCPUs:    cpus,
			MemoryBytes: int64(source.Reservations.MemoryBytes),
		}
	}
	return resources, nil
}

func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
	portConfigs := []swarm.PortConfig{}
	ports, portBindings, err := nat.ParsePortSpecs(source)
	if err != nil {
		return nil, err
	}

	for port := range ports {
		portConfig, err := opts.ConvertPortToPortConfig(port, portBindings)
		if err != nil {
			return nil, err
		}
		portConfigs = append(portConfigs, portConfig...)
	}

	return &swarm.EndpointSpec{Ports: portConfigs}, nil
}

func convertEnvironment(source map[string]string) []string {
	var output []string

	for name, value := range source {
		output = append(output, fmt.Sprintf("%s=%s", name, value))
	}

	return output
}

func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) {
	serviceMode := swarm.ServiceMode{}

	switch mode {
	case "global":
		if replicas != nil {
			return serviceMode, fmt.Errorf("replicas can only be used with replicated mode")
		}
		serviceMode.Global = &swarm.GlobalService{}
	case "replicated", "":
		serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas}
	default:
		return serviceMode, fmt.Errorf("Unknown mode: %s", mode)
	}
	return serviceMode, nil
}
<commit_msg>Set default values for uid and gid to prevent errors when starting a service.<commit_after>package convert

import (
	"fmt"
	"os"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/swarm"
	servicecli "github.com/docker/docker/cli/command/service"
	composetypes "github.com/docker/docker/cli/compose/types"
	"github.com/docker/docker/client"
	"github.com/docker/docker/opts"
	runconfigopts "github.com/docker/docker/runconfig/opts"
	"github.com/docker/go-connections/nat"
)

// Services from compose-file types to engine API types
// TODO: fix secrets API so that SecretAPIClient is not required here
func Services(
	namespace Namespace,
	config *composetypes.Config,
	client client.SecretAPIClient,
) (map[string]swarm.ServiceSpec, error) {
	result := make(map[string]swarm.ServiceSpec)

	services := config.Services
	volumes := config.Volumes
	networks := config.Networks

	for _, service := range services {

		secrets, err := convertServiceSecrets(client, namespace, service.Secrets, config.Secrets)
		if err != nil {
			return nil, err
		}
		serviceSpec, err := convertService(namespace, service, networks, volumes, secrets)
		if err != nil {
			return nil, err
		}
		result[service.Name] = serviceSpec
	}

	return result, nil
}

func convertService(
	namespace Namespace,
	service composetypes.ServiceConfig,
	networkConfigs map[string]composetypes.NetworkConfig,
	volumes map[string]composetypes.VolumeConfig,
	secrets []*swarm.SecretReference,
) (swarm.ServiceSpec, error) {
	name := namespace.Scope(service.Name)

	endpoint, err := convertEndpointSpec(service.Ports)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	mode, err := convertDeployMode(service.Deploy.Mode, service.Deploy.Replicas)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	mounts, err := Volumes(service.Volumes, volumes, namespace)
	if err != nil {
		// TODO: better error message (include service name)
		return swarm.ServiceSpec{}, err
	}

	resources, err := convertResources(service.Deploy.Resources)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	restartPolicy, err := convertRestartPolicy(
		service.Restart, service.Deploy.RestartPolicy)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	healthcheck, err := convertHealthcheck(service.HealthCheck)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	networks, err := convertServiceNetworks(service.Networks, networkConfigs, namespace, service.Name)
	if err != nil {
		return swarm.ServiceSpec{}, err
	}

	var logDriver *swarm.Driver
	if service.Logging != nil {
		logDriver = &swarm.Driver{
			Name:    service.Logging.Driver,
			Options: service.Logging.Options,
		}
	}

	serviceSpec := swarm.ServiceSpec{
		Annotations: swarm.Annotations{
			Name:   name,
			Labels: AddStackLabel(namespace, service.Deploy.Labels),
		},
		TaskTemplate: swarm.TaskSpec{
			ContainerSpec: swarm.ContainerSpec{
				Image:           service.Image,
				Command:         service.Entrypoint,
				Args:            service.Command,
				Hostname:        service.Hostname,
				Hosts:           convertExtraHosts(service.ExtraHosts),
				Healthcheck:     healthcheck,
				Env:             convertEnvironment(service.Environment),
				Labels:          AddStackLabel(namespace, service.Labels),
				Dir:             service.WorkingDir,
				User:            service.User,
				Mounts:          mounts,
				StopGracePeriod: service.StopGracePeriod,
				TTY:             service.Tty,
				OpenStdin:       service.StdinOpen,
				Secrets:         secrets,
			},
			LogDriver:     logDriver,
			Resources:     resources,
			RestartPolicy: restartPolicy,
			Placement: &swarm.Placement{
				Constraints: service.Deploy.Placement.Constraints,
			},
		},
		EndpointSpec: endpoint,
		Mode:         mode,
		Networks:     networks,
		UpdateConfig: convertUpdateConfig(service.Deploy.UpdateConfig),
	}

	return serviceSpec, nil
}

func convertServiceNetworks(
	networks map[string]*composetypes.ServiceNetworkConfig,
	networkConfigs networkMap,
	namespace Namespace,
	name string,
) ([]swarm.NetworkAttachmentConfig, error) {
	if len(networks) == 0 {
		return []swarm.NetworkAttachmentConfig{
			{
				Target:  namespace.Scope("default"),
				Aliases: []string{name},
			},
		}, nil
	}

	nets := []swarm.NetworkAttachmentConfig{}
	for networkName, network := range networks {
		networkConfig, ok := networkConfigs[networkName]
		if !ok {
			return []swarm.NetworkAttachmentConfig{}, fmt.Errorf(
				"service %q references network %q, which is not declared", name, networkName)
		}
		var aliases []string
		if network != nil {
			aliases = network.Aliases
		}
		target := namespace.Scope(networkName)
		if networkConfig.External.External {
			target = networkConfig.External.Name
		}
		nets = append(nets, swarm.NetworkAttachmentConfig{
			Target:  target,
			Aliases: append(aliases, name),
		})
	}
	return nets, nil
}

// TODO: fix secrets API so that SecretAPIClient is not required here
func convertServiceSecrets(
	client client.SecretAPIClient,
	namespace Namespace,
	secrets []composetypes.ServiceSecretConfig,
	secretSpecs map[string]composetypes.SecretConfig,
) ([]*swarm.SecretReference, error) {
	opts := []*types.SecretRequestOption{}
	for _, secret := range secrets {
		target := secret.Target
		if target == "" {
			target = secret.Source
		}

		source := namespace.Scope(secret.Source)
		secretSpec := secretSpecs[secret.Source]
		if secretSpec.External.External {
			source = secretSpec.External.Name
		}

		uid := secret.UID
		gid := secret.GID
		if uid == "" {
			uid = "0"
		}
		if gid == "" {
			gid = "0"
		}

		opts = append(opts, &types.SecretRequestOption{
			Source: source,
			Target: target,
			UID:    uid,
			GID:    gid,
			Mode:   os.FileMode(secret.Mode),
		})
	}

	return servicecli.ParseSecrets(client, opts)
}

func convertExtraHosts(extraHosts map[string]string) []string {
	hosts := []string{}
	for host, ip := range extraHosts {
		hosts = append(hosts, fmt.Sprintf("%s %s", ip, host))
	}
	return hosts
}

func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container.HealthConfig, error) {
	if healthcheck == nil {
		return nil, nil
	}
	var (
		err               error
		timeout, interval time.Duration
		retries           int
	)
	if healthcheck.Disable {
		if len(healthcheck.Test) != 0 {
			return nil, fmt.Errorf("test and disable can't be set at the same time")
		}
		return &container.HealthConfig{
			Test: []string{"NONE"},
		}, nil

	}
	if healthcheck.Timeout != "" {
		timeout, err = time.ParseDuration(healthcheck.Timeout)
		if err != nil {
			return nil, err
		}
	}
	if healthcheck.Interval != "" {
		interval, err = time.ParseDuration(healthcheck.Interval)
		if err != nil {
			return nil, err
		}
	}
	if healthcheck.Retries != nil {
		retries = int(*healthcheck.Retries)
	}
	return &container.HealthConfig{
		Test:     healthcheck.Test,
		Timeout:  timeout,
		Interval: interval,
		Retries:  retries,
	}, nil
}

func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*swarm.RestartPolicy, error) {
	// TODO: log if restart is being ignored
	if source == nil {
		policy, err := runconfigopts.ParseRestartPolicy(restart)
		if err != nil {
			return nil, err
		}
		switch {
		case policy.IsNone():
			return nil, nil
		case policy.IsAlways(), policy.IsUnlessStopped():
			return &swarm.RestartPolicy{
				Condition: swarm.RestartPolicyConditionAny,
			}, nil
		case policy.IsOnFailure():
			attempts := uint64(policy.MaximumRetryCount)
			return &swarm.RestartPolicy{
				Condition:   swarm.RestartPolicyConditionOnFailure,
				MaxAttempts: &attempts,
			}, nil
		default:
			return nil, fmt.Errorf("unknown restart policy: %s", restart)
		}
	}
	return &swarm.RestartPolicy{
		Condition:   swarm.RestartPolicyCondition(source.Condition),
		Delay:       source.Delay,
		MaxAttempts: source.MaxAttempts,
		Window:      source.Window,
	}, nil
}

func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig {
	if source == nil {
		return nil
	}
	parallel := uint64(1)
	if source.Parallelism != nil {
		parallel = *source.Parallelism
	}
	return &swarm.UpdateConfig{
		Parallelism:     parallel,
		Delay:           source.Delay,
		FailureAction:   source.FailureAction,
		Monitor:         source.Monitor,
		MaxFailureRatio: source.MaxFailureRatio,
	}
}

func convertResources(source composetypes.Resources) (*swarm.ResourceRequirements, error) {
	resources := &swarm.ResourceRequirements{}
	var err error
	if source.Limits != nil {
		var cpus int64
		if source.Limits.NanoCPUs != "" {
			cpus, err = opts.ParseCPUs(source.Limits.NanoCPUs)
			if err != nil {
				return nil, err
			}
		}
		resources.Limits = &swarm.Resources{
			NanoCPUs:    cpus,
			MemoryBytes: int64(source.Limits.MemoryBytes),
		}
	}
	if source.Reservations != nil {
		var cpus int64
		if source.Reservations.NanoCPUs != "" {
			cpus, err = opts.ParseCPUs(source.Reservations.NanoCPUs)
			if err != nil {
				return nil, err
			}
		}
		resources.Reservations = &swarm.Resources{
			NanoCPUs:    cpus,
			MemoryBytes: int64(source.Reservations.MemoryBytes),
		}
	}
	return resources, nil
}

func convertEndpointSpec(source []string) (*swarm.EndpointSpec, error) {
	portConfigs := []swarm.PortConfig{}
	ports, portBindings, err := nat.ParsePortSpecs(source)
	if err != nil {
		return nil, err
	}

	for port := range ports {
		portConfig, err := opts.ConvertPortToPortConfig(port, portBindings)
		if err != nil {
			return nil, err
		}
		portConfigs = append(portConfigs, portConfig...)
	}

	return &swarm.EndpointSpec{Ports: portConfigs}, nil
}

func convertEnvironment(source map[string]string) []string {
	var output []string

	for name, value := range source {
		output = append(output, fmt.Sprintf("%s=%s", name, value))
	}

	return output
}

func convertDeployMode(mode string, replicas *uint64) (swarm.ServiceMode, error) {
	serviceMode := swarm.ServiceMode{}

	switch mode {
	case "global":
		if replicas != nil {
			return serviceMode, fmt.Errorf("replicas can only be used with replicated mode")
		}
		serviceMode.Global = &swarm.GlobalService{}
	case "replicated", "":
		serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas}
	default:
		return serviceMode, fmt.Errorf("Unknown mode: %s", mode)
	}
	return serviceMode, nil
}
<|endoftext|>


<commit_before>// Package timeout is for handling timeout invocation of external command
package timeout

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"runtime"

	"syscall"
	"time"

	"github.com/Songmu/wrapcommander"
)

// Timeout is main struct of timeout package
type Timeout struct {
	Duration   time.Duration
	KillAfter  time.Duration
	Signal     os.Signal
	Foreground bool
	Cmd        *exec.Cmd
}

var defaultSignal os.Signal

func init() {
	switch runtime.GOOS {
	case "windows":
		defaultSignal = os.Interrupt
	default:
		defaultSignal = syscall.SIGTERM
	}
}

// exit statuses are same with GNU timeout
const (
	exitNormal     = 0
	exitTimedOut   = 124
	exitUnknownErr = 125
	exitKilled     = 137
)

// Error is error of timeout
type Error struct {
	ExitCode int
	Err      error
}

func (err *Error) Error() string {
	return fmt.Sprintf("exit code: %d, %s", err.ExitCode, err.Err.Error())
}

// ExitStatus stores exit information of the command
type ExitStatus struct {
	Code     int
	typ      exitType
}

// IsTimedOut returns the command timed out or not
func (ex ExitStatus) IsTimedOut() bool {
	return ex.typ == exitTypeTimedOut || ex.typ == exitTypeKilled
}

// IsKilled returns the command is killed or not
func (ex ExitStatus) IsKilled() bool {
	return ex.typ == exitTypeKilled
}

// GetExitCode gets the exit code for command line tools
func (ex ExitStatus) GetExitCode() int {
	switch {
	case ex.IsKilled():
		return exitKilled
	case ex.IsTimedOut():
		return exitTimedOut
	default:
		return ex.Code
	}
}

// GetChildExitCode gets the exit code of the Cmd itself
func (ex ExitStatus) GetChildExitCode() int {
	return ex.Code
}

type exitType int

// exit types
const (
	exitTypeNormal exitType = iota + 1
	exitTypeTimedOut
	exitTypeKilled
)

func (tio *Timeout) signal() os.Signal {
	if tio.Signal == nil {
		return defaultSignal
	}
	return tio.Signal
}

// Run is synchronous interface of executing command and returning information
func (tio *Timeout) Run() (ExitStatus, string, string, error) {
	cmd := tio.getCmd()
	var outBuffer, errBuffer bytes.Buffer
	cmd.Stdout = &outBuffer
	cmd.Stderr = &errBuffer

	ch, err := tio.RunCommand()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return ExitStatus{}, string(outBuffer.Bytes()), string(errBuffer.Bytes()), err
	}
	exitSt := <-ch
	return exitSt, string(outBuffer.Bytes()), string(errBuffer.Bytes()), nil
}

// RunSimple executes command and only returns integer as exit code. It is mainly for go-timeout command
func (tio *Timeout) RunSimple(preserveStatus bool) int {
	cmd := tio.getCmd()

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return exitUnknownErr
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return exitUnknownErr
	}

	ch, err := tio.RunCommand()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return getExitCodeFromErr(err)
	}

	go func() {
		defer stdoutPipe.Close()
		io.Copy(os.Stdout, stdoutPipe)
	}()

	go func() {
		defer stderrPipe.Close()
		io.Copy(os.Stderr, stderrPipe)
	}()

	exitSt := <-ch
	if preserveStatus {
		return exitSt.GetChildExitCode()
	}
	return exitSt.GetExitCode()
}

func getExitCodeFromErr(err error) int {
	if err != nil {
		if tmerr, ok := err.(*Error); ok {
			return tmerr.ExitCode
		}
		return -1
	}
	return exitNormal
}

// RunCommand is executing the command and handling timeout. This is primitive interface of Timeout
func (tio *Timeout) RunCommand() (chan ExitStatus, error) {
	cmd := tio.getCmd()

	if err := cmd.Start(); err != nil {
		return nil, &Error{
			ExitCode: wrapcommander.ResolveExitCode(err),
			Err:      err,
		}
	}

	exitChan := make(chan ExitStatus)
	go func() {
		exitChan <- tio.handleTimeout()
	}()

	return exitChan, nil
}

func (tio *Timeout) handleTimeout() (ex ExitStatus) {
	cmd := tio.getCmd()
	exitChan := getExitChan(cmd)
	select {
	case st := <-exitChan:
		ex.Code = wrapcommander.WaitStatusToExitCode(st)
		ex.typ = exitTypeNormal
		return ex
	case <-time.After(tio.Duration):
		tio.terminate()
		ex.typ = exitTypeTimedOut
	}

	if tio.KillAfter > 0 {
		select {
		case st := <-exitChan:
			ex.Code = wrapcommander.WaitStatusToExitCode(st)
		case <-time.After(tio.KillAfter):
			tio.killall()
			// just to make sure
			cmd.Process.Kill()
			ex.Code = exitKilled
			ex.typ = exitTypeKilled
		}
	} else {
		st := <-exitChan
		ex.Code = wrapcommander.WaitStatusToExitCode(st)
	}

	return ex
}

func getExitChan(cmd *exec.Cmd) chan syscall.WaitStatus {
	ch := make(chan syscall.WaitStatus)
	go func() {
		err := cmd.Wait()
		st, _ := wrapcommander.ErrorToWaitStatus(err)
		ch <- st
	}()
	return ch
}
<commit_msg>use reflect.SelectCase for simplify code. (but it's magical...)<commit_after>// Package timeout is for handling timeout invocation of external command
package timeout

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"reflect"
	"runtime"

	"syscall"
	"time"

	"github.com/Songmu/wrapcommander"
)

// Timeout is main struct of timeout package
type Timeout struct {
	Duration   time.Duration
	KillAfter  time.Duration
	Signal     os.Signal
	Foreground bool
	Cmd        *exec.Cmd
}

var defaultSignal os.Signal

func init() {
	switch runtime.GOOS {
	case "windows":
		defaultSignal = os.Interrupt
	default:
		defaultSignal = syscall.SIGTERM
	}
}

// exit statuses are same with GNU timeout
const (
	exitNormal     = 0
	exitTimedOut   = 124
	exitUnknownErr = 125
	exitKilled     = 137
)

// Error is error of timeout
type Error struct {
	ExitCode int
	Err      error
}

func (err *Error) Error() string {
	return fmt.Sprintf("exit code: %d, %s", err.ExitCode, err.Err.Error())
}

// ExitStatus stores exit information of the command
type ExitStatus struct {
	Code int
	typ  exitType
}

// IsTimedOut returns the command timed out or not
func (ex ExitStatus) IsTimedOut() bool {
	return ex.typ == exitTypeTimedOut || ex.typ == exitTypeKilled
}

// IsKilled returns the command is killed or not
func (ex ExitStatus) IsKilled() bool {
	return ex.typ == exitTypeKilled
}

// GetExitCode gets the exit code for command line tools
func (ex ExitStatus) GetExitCode() int {
	switch {
	case ex.IsKilled():
		return exitKilled
	case ex.IsTimedOut():
		return exitTimedOut
	default:
		return ex.Code
	}
}

// GetChildExitCode gets the exit code of the Cmd itself
func (ex ExitStatus) GetChildExitCode() int {
	return ex.Code
}

type exitType int

// exit types
const (
	exitTypeNormal exitType = iota
	exitTypeTimedOut
	exitTypeKilled
)

func (tio *Timeout) signal() os.Signal {
	if tio.Signal == nil {
		return defaultSignal
	}
	return tio.Signal
}

// Run is synchronous interface of executing command and returning information
func (tio *Timeout) Run() (ExitStatus, string, string, error) {
	cmd := tio.getCmd()
	var outBuffer, errBuffer bytes.Buffer
	cmd.Stdout = &outBuffer
	cmd.Stderr = &errBuffer

	ch, err := tio.RunCommand()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return ExitStatus{}, string(outBuffer.Bytes()), string(errBuffer.Bytes()), err
	}
	exitSt := <-ch
	return exitSt, string(outBuffer.Bytes()), string(errBuffer.Bytes()), nil
}

// RunSimple executes command and only returns integer as exit code. It is mainly for go-timeout command
func (tio *Timeout) RunSimple(preserveStatus bool) int {
	cmd := tio.getCmd()

	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return exitUnknownErr
	}
	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return exitUnknownErr
	}

	ch, err := tio.RunCommand()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return getExitCodeFromErr(err)
	}

	go func() {
		defer stdoutPipe.Close()
		io.Copy(os.Stdout, stdoutPipe)
	}()

	go func() {
		defer stderrPipe.Close()
		io.Copy(os.Stderr, stderrPipe)
	}()

	exitSt := <-ch
	if preserveStatus {
		return exitSt.GetChildExitCode()
	}
	return exitSt.GetExitCode()
}

func getExitCodeFromErr(err error) int {
	if err != nil {
		if tmerr, ok := err.(*Error); ok {
			return tmerr.ExitCode
		}
		return -1
	}
	return exitNormal
}

// RunCommand is executing the command and handling timeout. This is primitive interface of Timeout
func (tio *Timeout) RunCommand() (chan ExitStatus, error) {
	cmd := tio.getCmd()

	if err := cmd.Start(); err != nil {
		return nil, &Error{
			ExitCode: wrapcommander.ResolveExitCode(err),
			Err:      err,
		}
	}

	exitChan := make(chan ExitStatus)
	go func() {
		exitChan <- tio.handleTimeout()
	}()

	return exitChan, nil
}

func (tio *Timeout) handleTimeout() (ex ExitStatus) {
	cmd := tio.getCmd()
	exitChan := getExitChan(cmd)
	cases := []reflect.SelectCase{
		{ // 0: command exit
			Chan: reflect.ValueOf(exitChan),
			Dir:  reflect.SelectRecv,
		},
		{ // 1: timed out and send signal
			Chan: reflect.ValueOf(time.After(tio.Duration)),
			Dir:  reflect.SelectRecv,
		},
	}
	if tio.KillAfter > 0 {
		// 2: send KILL signal
		cases = append(cases, reflect.SelectCase{
			Chan: reflect.ValueOf(time.After(tio.Duration + tio.KillAfter)),
			Dir:  reflect.SelectRecv,
		})
	}
	for {
		chosen, recv, _ := reflect.Select(cases)
		switch chosen {
		case 0:
			st := recv.Interface().(syscall.WaitStatus)
			ex.Code = wrapcommander.WaitStatusToExitCode(st)
			return ex
		case 1:
			tio.terminate()
			ex.typ = exitTypeTimedOut
		case 2:
			tio.killall()
			// just to make sure
			cmd.Process.Kill()
			ex.typ = exitTypeKilled
		}
	}
	return ex
}

func getExitChan(cmd *exec.Cmd) chan syscall.WaitStatus {
	ch := make(chan syscall.WaitStatus)
	go func() {
		err := cmd.Wait()
		st, _ := wrapcommander.ErrorToWaitStatus(err)
		ch <- st
	}()
	return ch
}
<|endoftext|>


<commit_before>package toJson

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/serenize/snaker"
	"net/http"
	"reflect"
	"strings"
)

type jsonWriter interface {
	ToJson() interface{}
}

type JsonWriter jsonWriter

var Debug bool = false

var TypeError = errors.New("Could not get type")
var UnsupportedDatatype = errors.New("Unsupported Datatype")
var ReflectTypeError = errors.New("Got passed reflect.Type")
var ReflectValueError = errors.New("Got passed reflect.Value")

func fieldName(field reflect.StructField) (name string) {
	value := field.Tag.Get("json")
	fields := strings.Split(value, ",")

	// The format of the json tag is "<field>,<options>", with fields possibly being
	// empty
	if len(fields) > 0 && fields[0] != "" {
		return fields[0]
	}

	return snaker.CamelToSnake(field.Name)
}

func ToJson(i interface{}) (interface{}, error) {
	var err error

	_, ok := i.(reflect.Value)

	if ok {
		return nil, ReflectValueError
	}
	_, ok = i.(reflect.Type)

	if ok {
		return nil, ReflectValueError
	}

	t := reflect.TypeOf(i)

	if t == nil {
		return nil, nil
	}

	value := reflect.ValueOf(i)

	writer, ok := i.(jsonWriter)

	if ok {
		if Debug {
			fmt.Printf("Processing %T with ToJson()\n", i)
		}
		return ToJson(writer.ToJson())
	}

	marshaler, ok := i.(json.Marshaler)

	if ok {
		if Debug {
			fmt.Printf("Processing %T with MarshalJson()\n", i)
		}
		return marshaler, nil
	}

	errorer, ok := i.(error)
	if ok {
		if Debug {
			fmt.Printf("Processing %T with Error()\n", i)
		}

		return errorer.Error(), nil
	}

	switch t.Kind() {
	case reflect.Struct:
		if Debug {
			fmt.Printf("Processing %T as Struct\n", i)
		}
		x := make(map[string]interface{})

		for idx := 0; idx < t.NumField(); idx++ {
			def := t.Field(idx)
			val := value.Field(idx)

			// do not try and render unexported fields
			if !val.CanInterface() {
				continue
			}

			res, err := ToJson(val.Interface())

			if err != nil {
				return nil, err
			}

			name := fieldName(def)

			x[name] = res
		}

		return x, nil
	case reflect.Map:
		if Debug {
			fmt.Printf("Processing %T as Map\n", i)
		}
		input, ok := i.(map[string]interface{})
		x := make(map[string]interface{})
		if ok {
			for key, value := range input {
				x[key], err = ToJson(value)

				if err != nil {
					return nil, err
				}
			}
		} else {
			keys := value.MapKeys()

			for _, key := range keys {
				keyval := value.MapIndex(key)
				x[fmt.Sprintf("%v", key.Interface())], err = ToJson(keyval.Interface())

				if err != nil {
					return nil, err
				}
			}
		}

		return x, nil
	case reflect.Slice:
		if Debug {
			fmt.Printf("Processing %T as Slice\n", i)
		}
		var x []interface{} = make([]interface{}, 0)
		for idx := 0; idx < value.Len(); idx++ {
			v := value.Index(idx)
			o, err := ToJson(v.Interface())
			if err != nil {
				return nil, err
			}
			x = append(x, o)
		}

		return x, nil
	case reflect.Ptr:
		if Debug {
			fmt.Printf("Processing %T as Pointer\n", i)
		}

		return ToJson(reflect.Indirect(value).Interface())
	default:
		if Debug {
			fmt.Printf("Processing %T as default\n", i)
		}
		return i, nil
	}
}

func WriteToJson(w http.ResponseWriter, obj interface{}) error {
	o, err := ToJson(obj)
	if err != nil {
		return err
	}
	return WriteJson(w, &o)
}

func WriteJson(w http.ResponseWriter, obj interface{}) error {
	w.Header().Add("Content-Type", "application/json")
	marshalled, err := json.MarshalIndent(map[string]interface{}{"result": obj}, "", "  ")
	if err != nil {
		return err
	}
	w.Write([]byte(fmt.Sprintf("%s\n", marshalled)))

	return nil
}
<commit_msg>always replace the header, otherwise we'll have overlap<commit_after>package toJson

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/serenize/snaker"
	"net/http"
	"reflect"
	"strings"
)

type jsonWriter interface {
	ToJson() interface{}
}

type JsonWriter jsonWriter

var Debug bool = false

var TypeError = errors.New("Could not get type")
var UnsupportedDatatype = errors.New("Unsupported Datatype")
var ReflectTypeError = errors.New("Got passed reflect.Type")
var ReflectValueError = errors.New("Got passed reflect.Value")

func fieldName(field reflect.StructField) (name string) {
	value := field.Tag.Get("json")
	fields := strings.Split(value, ",")

	// The format of the json tag is "<field>,<options>", with fields possibly being
	// empty
	if len(fields) > 0 && fields[0] != "" {
		return fields[0]
	}

	return snaker.CamelToSnake(field.Name)
}

func ToJson(i interface{}) (interface{}, error) {
	var err error

	_, ok := i.(reflect.Value)

	if ok {
		return nil, ReflectValueError
	}
	_, ok = i.(reflect.Type)

	if ok {
		return nil, ReflectValueError
	}

	t := reflect.TypeOf(i)

	if t == nil {
		return nil, nil
	}

	value := reflect.ValueOf(i)

	writer, ok := i.(jsonWriter)

	if ok {
		if Debug {
			fmt.Printf("Processing %T with ToJson()\n", i)
		}
		return ToJson(writer.ToJson())
	}

	marshaler, ok := i.(json.Marshaler)

	if ok {
		if Debug {
			fmt.Printf("Processing %T with MarshalJson()\n", i)
		}
		return marshaler, nil
	}

	errorer, ok := i.(error)
	if ok {
		if Debug {
			fmt.Printf("Processing %T with Error()\n", i)
		}

		return errorer.Error(), nil
	}

	switch t.Kind() {
	case reflect.Struct:
		if Debug {
			fmt.Printf("Processing %T as Struct\n", i)
		}
		x := make(map[string]interface{})

		for idx := 0; idx < t.NumField(); idx++ {
			def := t.Field(idx)
			val := value.Field(idx)

			// do not try and render unexported fields
			if !val.CanInterface() {
				continue
			}

			res, err := ToJson(val.Interface())

			if err != nil {
				return nil, err
			}

			name := fieldName(def)

			x[name] = res
		}

		return x, nil
	case reflect.Map:
		if Debug {
			fmt.Printf("Processing %T as Map\n", i)
		}
		input, ok := i.(map[string]interface{})
		x := make(map[string]interface{})
		if ok {
			for key, value := range input {
				x[key], err = ToJson(value)

				if err != nil {
					return nil, err
				}
			}
		} else {
			keys := value.MapKeys()

			for _, key := range keys {
				keyval := value.MapIndex(key)
				x[fmt.Sprintf("%v", key.Interface())], err = ToJson(keyval.Interface())

				if err != nil {
					return nil, err
				}
			}
		}

		return x, nil
	case reflect.Slice:
		if Debug {
			fmt.Printf("Processing %T as Slice\n", i)
		}
		var x []interface{} = make([]interface{}, 0)
		for idx := 0; idx < value.Len(); idx++ {
			v := value.Index(idx)
			o, err := ToJson(v.Interface())
			if err != nil {
				return nil, err
			}
			x = append(x, o)
		}

		return x, nil
	case reflect.Ptr:
		if Debug {
			fmt.Printf("Processing %T as Pointer\n", i)
		}

		return ToJson(reflect.Indirect(value).Interface())
	default:
		if Debug {
			fmt.Printf("Processing %T as default\n", i)
		}
		return i, nil
	}
}

func WriteToJson(w http.ResponseWriter, obj interface{}) error {
	o, err := ToJson(obj)
	if err != nil {
		return err
	}
	return WriteJson(w, &o)
}

func WriteJson(w http.ResponseWriter, obj interface{}) error {
	w.Header().Set("Content-Type", "application/json")
	marshalled, err := json.MarshalIndent(map[string]interface{}{"result": obj}, "", "  ")
	if err != nil {
		return err
	}
	w.Write([]byte(fmt.Sprintf("%s\n", marshalled)))

	return nil
}
<|endoftext|>