<commit_before>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/moovweb/gokogiri"
	"github.com/moovweb/gokogiri/xml"
	"github.com/moovweb/gokogiri/xpath"
	"io/ioutil"
	"launchpad.net/goyaml"
	"net/http"
	"os"
	"strconv"
	"strings"
)

var opts struct {
	Products string `short:"p" long:"products" description:"A YAML file with product data" required:"true"`
	Stores   string `short:"s" long:"stores" description:"A YAML file with store data" required:"true"`
}

var storeList []Store
var productList []Product

type Store struct {
	Name          string
	Domain        string
	XPath         string
	compiledXPath *xpath.Expression
}

type StorePrice struct {
	Store *Store
	Price float64
}

type Product struct {
	Name string
	URLs []string
}

func (p *Product) GetPrices(stores []Store) (store_prices []StorePrice) {
	store_prices = make([]StorePrice, len(p.URLs))

	for i, url := range p.URLs {
		for j, store := range stores {
			if !strings.Contains(url, store.Domain) {
				continue
			}

			resp, err := http.Get(url)
			if err != nil {
				continue
			}

			defer resp.Body.Close()

			body, err := ioutil.ReadAll(resp.Body)

			if err != nil {
				continue
			}

			doc, err := gokogiri.ParseHtml(body)

			if err != nil {
				continue
			}

			nxpath := xpath.NewXPath(doc.DocPtr())
			nodes, err := nxpath.Evaluate(doc.DocPtr(), store.compiledXPath)

			if err != nil {
				continue
			}

			if len(nodes) == 0 {
				fmt.Printf("Check XPath correctness (not found) for domain: %s\n", store.Domain)
				continue
			}

			price_raw := xml.NewNode(nodes[0], doc).InnerHtml()
			price_raw = strings.Trim(price_raw, "$ \n\r")
			price, err := strconv.ParseFloat(price_raw, 64)

			if err != nil {
				fmt.Printf("Check XPath correctness (not monetary) for domain: %s\n", store.Domain)
				continue
			}

			store_prices[i] = StorePrice{Store: &stores[j], Price: price}
		}
	}
	return
}

func main() {
	// Parse options
	_, err := flags.Parse(&opts)

	if err != nil {
		fmt.Println("Error: Check options")
		return
	}

	// Open, parse YAML data
	f, _ := os.Open(opts.Products)
	products := make([]byte, 10000)
	count, _ := f.Read(products)
	err = goyaml.Unmarshal(products[:count], &productList)

	if err != nil {
		fmt.Println("Error: Check YAML file of product data")
		return
	}

	f, _ = os.Open(opts.Stores)
	stores := make([]byte, 10000)
	count, _ = f.Read(stores)
	err = goyaml.Unmarshal(stores[:count], &storeList)

	if err != nil {
		fmt.Println("Error: Check YAML file of store data")
		return
	}

	// Compile XPaths
	for i, store := range storeList {
		storeList[i].compiledXPath = xpath.Compile(store.XPath)
	}

	// Loop through products
	for _, product := range productList {
		store_prices := product.GetPrices(storeList)
		fmt.Printf("%s\n", strings.ToUpper(product.Name))

		// Get prices
		for _, store_price := range store_prices {
			fmt.Printf("\t%s: \t$%s\n", store_price.Store.Name, strconv.FormatFloat(store_price.Price, 'f', 2, 32))
		}
	}
}
<commit_msg>Added concurrency<commit_after>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/moovweb/gokogiri"
	"github.com/moovweb/gokogiri/xml"
	"github.com/moovweb/gokogiri/xpath"
	"io/ioutil"
	"launchpad.net/goyaml"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

var opts struct {
	Products string `short:"p" long:"products" description:"A YAML file with product data" required:"true"`
	Stores   string `short:"s" long:"stores" description:"A YAML file with store data" required:"true"`
}

var storeList []Store
var productList []Product

type Store struct {
	Name          string
	Domain        string
	XPath         string
	compiledXPath *xpath.Expression
}

type StorePrice struct {
	Store *Store
	Price float64
}

type Product struct {
	Name string
	URLs []string
	StoreCount int
	StorePrices []StorePrice
}

func (store *Store) LoadPrice(url string) (price float64, err error) {
	resp, err := http.Get(url)
	if err != nil {
		return
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return
	}

	doc, err := gokogiri.ParseHtml(body)

	if err != nil {
		return
	}

	nxpath := xpath.NewXPath(doc.DocPtr())
	nodes, err := nxpath.Evaluate(doc.DocPtr(), store.compiledXPath)

	if err != nil {
		return
	}

	if len(nodes) == 0 {
		fmt.Printf("Check XPath correctness (not found) for domain: %s\n", store.Domain)
		return
	}

	price_raw := xml.NewNode(nodes[0], doc).InnerHtml()
	price_raw = strings.Trim(price_raw, "$ \n\r")
	price, err = strconv.ParseFloat(price_raw, 64)

	if err != nil {
		fmt.Printf("Check XPath correctness (not monetary) for domain: %s\n", store.Domain)
		return
	}

	return
}

func (product *Product) GetPrices(stores []Store) {
	product.StorePrices = make([]StorePrice, len(product.URLs))
	store_count := 0

	for i, url := range product.URLs {
		for j, store := range stores {
			if !strings.Contains(url, store.Domain) {
				continue
			}

			store_count += 1

			price, _ := store.LoadPrice(url)
			product.StorePrices[i] = StorePrice{Store: &stores[j], Price: price}
		}
	}
	product.StoreCount = store_count
	return
}

func main() {
	// Parse options
	_, err := flags.Parse(&opts)

	if err != nil {
		fmt.Println("Error: Check options")
		return
	}

	// Open, parse YAML data
	f, _ := os.Open(opts.Products)
	products := make([]byte, 10000)
	count, _ := f.Read(products)
	err = goyaml.Unmarshal(products[:count], &productList)

	if err != nil {
		fmt.Println("Error: Check YAML file of product data")
		return
	}

	f, _ = os.Open(opts.Stores)
	stores := make([]byte, 10000)
	count, _ = f.Read(stores)
	err = goyaml.Unmarshal(stores[:count], &storeList)

	if err != nil {
		fmt.Println("Error: Check YAML file of store data")
		return
	}

	// Compile XPaths
	for i, store := range storeList {
		storeList[i].compiledXPath = xpath.Compile(store.XPath)
	}

	// Loop through products
	for i, _ := range productList {
		productList[i].StoreCount = -1
		go productList[i].GetPrices(storeList)
	}

	for {
		complete := true
		for _, product := range productList {
			if product.StoreCount == -1 {
				complete = false
			}
		}
		if complete == true {
			break
		}
		time.Sleep(100 * time.Millisecond)
	}

	for _, product := range productList {
		fmt.Printf("\033[1m%s\033[0m\n", product.Name)

		// Get prices
		for _, store_price := range product.StorePrices {
			fmt.Printf(" - %s: \t$%s\n", store_price.Store.Name, strconv.FormatFloat(store_price.Price, 'f', 2, 32))
		}
	}
}
<|endoftext|>


<commit_before>/*
 * This file is part of the kubevirt project
 *
 * 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.
 *
 * Copyright 2021 Red Hat, Inc.
 *
 */

package network

import (
	"context"
	"fmt"

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

	expect "github.com/google/goexpect"
	k8sv1 "k8s.io/api/core/v1"
	k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/console"
	"kubevirt.io/kubevirt/tests/libnet"
	netservice "kubevirt.io/kubevirt/tests/libnet/service"
	"kubevirt.io/kubevirt/tests/libvmi"
	"kubevirt.io/kubevirt/tests/util"
)

var _ = SIGDescribe("Subdomain", func() {
	var virtClient kubecli.KubevirtClient

	const (
		subdomain          = "testsubdomain"
		selectorLabelKey   = "expose"
		selectorLabelValue = "this"
	)

	BeforeEach(func() {
		var err error
		virtClient, err = kubecli.GetKubevirtClient()
		Expect(err).NotTo(HaveOccurred(), "Should successfully initialize an API client")

		tests.BeforeTestCleanup()
	})

	Context("with a headless service given", func() {
		const servicePort = 22

		BeforeEach(func() {
			serviceName := subdomain
			service := netservice.BuildHeadlessSpec(serviceName, servicePort, servicePort, selectorLabelKey, selectorLabelValue)
			_, err := virtClient.CoreV1().Services(util.NamespaceTestDefault).Create(context.Background(), service, k8smetav1.CreateOptions{})
			Expect(err).ToNot(HaveOccurred())
		})

		table.DescribeTable("VMI should have the expected FQDN", func(f func() *v1.VirtualMachineInstance, subdom string) {
			vmiSpec := f()
			var expectedFQDN string
			if subdom != "" {
				vmiSpec.Spec.Subdomain = subdom
				expectedFQDN = fmt.Sprintf("%s.%s.%s.svc.cluster.local", vmiSpec.Name, subdom, util.NamespaceTestDefault)
			} else {
				expectedFQDN = vmiSpec.Name
			}
			vmiSpec.Labels = map[string]string{selectorLabelKey: selectorLabelValue}

			vmi, err := virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmiSpec)
			Expect(err).ToNot(HaveOccurred())
			vmi = tests.WaitUntilVMIReady(vmi, console.LoginToFedora)

			Expect(assertFQDNinGuest(vmi, expectedFQDN)).To(Succeed(), "failed to get expected FQDN")
		},
			table.Entry("with Masquerade binding and subdomain", fedoraMasqueradeVMI, subdomain),
			table.Entry("with Bridge binding and subdomain", fedoraBridgeBindingVMI, subdomain),
			table.Entry("with Masquerade binding without subdomain", fedoraMasqueradeVMI, ""),
			table.Entry("with Bridge binding without subdomain", fedoraBridgeBindingVMI, ""),
		)

		It("VMI with custom DNSPolicy should have the expected FQDN", func() {
			vmiSpec := fedoraBridgeBindingVMI()
			vmiSpec.Spec.Subdomain = subdomain
			expectedFQDN := fmt.Sprintf("%s.%s.%s.svc.cluster.local", vmiSpec.Name, subdomain, util.NamespaceTestDefault)
			vmiSpec.Labels = map[string]string{selectorLabelKey: selectorLabelValue}

			dnsServerIP, err := libnet.ClusterDNSServiceIP()
			Expect(err).ToNot(HaveOccurred())

			vmiSpec.Spec.DNSPolicy = "None"
			vmiSpec.Spec.DNSConfig = &k8sv1.PodDNSConfig{
				Nameservers: []string{dnsServerIP},
				Searches: []string{util.NamespaceTestDefault + ".svc.cluster.local",
					"svc.cluster.local", "cluster.local", util.NamespaceTestDefault + ".this.is.just.a.very.long.dummy"},
			}

			vmi, err := virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmiSpec)
			Expect(err).ToNot(HaveOccurred())
			vmi = tests.WaitUntilVMIReady(vmi, console.LoginToFedora)

			Expect(assertFQDNinGuest(vmi, expectedFQDN)).To(Succeed(), "failed to get expected FQDN")
		})
	})

	It("VMI with custom DNSPolicy, a subdomain and no service entry, should not include the subdomain in the searchlist", func() {
		vmiSpec := fedoraBridgeBindingVMI()
		vmiSpec.Spec.Subdomain = subdomain
		expectedFQDN := fmt.Sprintf("%s.%s.%s.svc.cluster.local", vmiSpec.Name, subdomain, util.NamespaceTestDefault)
		vmiSpec.Labels = map[string]string{selectorLabelKey: selectorLabelValue}

		dnsServerIP, err := libnet.ClusterDNSServiceIP()
		Expect(err).ToNot(HaveOccurred())

		vmiSpec.Spec.DNSPolicy = "None"
		vmiSpec.Spec.DNSConfig = &k8sv1.PodDNSConfig{
			Nameservers: []string{dnsServerIP},
			Searches:    []string{"example.com"},
		}

		vmi, err := virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmiSpec)
		Expect(err).ToNot(HaveOccurred())
		vmi = tests.WaitUntilVMIReady(vmi, console.LoginToFedora)

		Expect(assertFQDNinGuest(vmi, expectedFQDN)).To(Not(Succeed()), "found unexpected FQDN")
		Expect(assertSearchEntriesinGuest(vmi, "search example.com")).To(Succeed(), "failed to get expected search entries")
	})
})

func fedoraMasqueradeVMI() *v1.VirtualMachineInstance {
	return libvmi.NewFedora(
		libvmi.WithInterface(libvmi.InterfaceDeviceWithMasqueradeBinding()),
		libvmi.WithNetwork(v1.DefaultPodNetwork()))
}

func fedoraBridgeBindingVMI() *v1.VirtualMachineInstance {
	return libvmi.NewFedora(
		libvmi.WithInterface(libvmi.InterfaceDeviceWithBridgeBinding(libvmi.DefaultInterfaceName)),
		libvmi.WithNetwork(v1.DefaultPodNetwork()))
}

func assertFQDNinGuest(vmi *v1.VirtualMachineInstance, expectedFQDN string) error {
	return console.SafeExpectBatch(vmi, []expect.Batcher{
		&expect.BSnd{S: "\n"},
		&expect.BExp{R: console.PromptExpression},
		&expect.BSnd{S: "hostname -f\n"},
		&expect.BExp{R: expectedFQDN},
	}, 10)
}

func assertSearchEntriesinGuest(vmi *v1.VirtualMachineInstance, expectedSearch string) error {
	return console.SafeExpectBatch(vmi, []expect.Batcher{
		&expect.BSnd{S: "\n"},
		&expect.BExp{R: console.PromptExpression},
		&expect.BSnd{S: "cat /etc/resolv.conf\n"},
		&expect.BExp{R: expectedSearch + console.CRLF},
	}, 20)
}
<commit_msg>tests, single stack ipv6: skip tests that are not supported with no RA<commit_after>/*
 * This file is part of the kubevirt project
 *
 * 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.
 *
 * Copyright 2021 Red Hat, Inc.
 *
 */

package network

import (
	"context"
	"fmt"

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

	expect "github.com/google/goexpect"
	k8sv1 "k8s.io/api/core/v1"
	k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/kubecli"
	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/console"
	"kubevirt.io/kubevirt/tests/libnet"
	netservice "kubevirt.io/kubevirt/tests/libnet/service"
	"kubevirt.io/kubevirt/tests/libvmi"
	"kubevirt.io/kubevirt/tests/util"
)

var _ = SIGDescribe("Subdomain", func() {
	var virtClient kubecli.KubevirtClient

	const (
		subdomain          = "testsubdomain"
		selectorLabelKey   = "expose"
		selectorLabelValue = "this"
	)

	BeforeEach(func() {
		var err error
		virtClient, err = kubecli.GetKubevirtClient()
		Expect(err).NotTo(HaveOccurred(), "Should successfully initialize an API client")

		// Should be skipped as long as masquerade binding doesn't have dhcpv6 + ra (issue- https://github.com/kubevirt/kubevirt/issues/7184)
		libnet.SkipWhenClusterNotSupportIpv4(virtClient)

		tests.BeforeTestCleanup()
	})

	Context("with a headless service given", func() {
		const servicePort = 22

		BeforeEach(func() {
			serviceName := subdomain
			service := netservice.BuildHeadlessSpec(serviceName, servicePort, servicePort, selectorLabelKey, selectorLabelValue)
			_, err := virtClient.CoreV1().Services(util.NamespaceTestDefault).Create(context.Background(), service, k8smetav1.CreateOptions{})
			Expect(err).ToNot(HaveOccurred())
		})

		table.DescribeTable("VMI should have the expected FQDN", func(f func() *v1.VirtualMachineInstance, subdom string) {
			vmiSpec := f()
			var expectedFQDN string
			if subdom != "" {
				vmiSpec.Spec.Subdomain = subdom
				expectedFQDN = fmt.Sprintf("%s.%s.%s.svc.cluster.local", vmiSpec.Name, subdom, util.NamespaceTestDefault)
			} else {
				expectedFQDN = vmiSpec.Name
			}
			vmiSpec.Labels = map[string]string{selectorLabelKey: selectorLabelValue}

			vmi, err := virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmiSpec)
			Expect(err).ToNot(HaveOccurred())
			vmi = tests.WaitUntilVMIReady(vmi, console.LoginToFedora)

			Expect(assertFQDNinGuest(vmi, expectedFQDN)).To(Succeed(), "failed to get expected FQDN")
		},
			table.Entry("with Masquerade binding and subdomain", fedoraMasqueradeVMI, subdomain),
			table.Entry("with Bridge binding and subdomain", fedoraBridgeBindingVMI, subdomain),
			table.Entry("with Masquerade binding without subdomain", fedoraMasqueradeVMI, ""),
			table.Entry("with Bridge binding without subdomain", fedoraBridgeBindingVMI, ""),
		)

		It("VMI with custom DNSPolicy should have the expected FQDN", func() {
			vmiSpec := fedoraBridgeBindingVMI()
			vmiSpec.Spec.Subdomain = subdomain
			expectedFQDN := fmt.Sprintf("%s.%s.%s.svc.cluster.local", vmiSpec.Name, subdomain, util.NamespaceTestDefault)
			vmiSpec.Labels = map[string]string{selectorLabelKey: selectorLabelValue}

			dnsServerIP, err := libnet.ClusterDNSServiceIP()
			Expect(err).ToNot(HaveOccurred())

			vmiSpec.Spec.DNSPolicy = "None"
			vmiSpec.Spec.DNSConfig = &k8sv1.PodDNSConfig{
				Nameservers: []string{dnsServerIP},
				Searches: []string{util.NamespaceTestDefault + ".svc.cluster.local",
					"svc.cluster.local", "cluster.local", util.NamespaceTestDefault + ".this.is.just.a.very.long.dummy"},
			}

			vmi, err := virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmiSpec)
			Expect(err).ToNot(HaveOccurred())
			vmi = tests.WaitUntilVMIReady(vmi, console.LoginToFedora)

			Expect(assertFQDNinGuest(vmi, expectedFQDN)).To(Succeed(), "failed to get expected FQDN")
		})
	})

	It("VMI with custom DNSPolicy, a subdomain and no service entry, should not include the subdomain in the searchlist", func() {
		vmiSpec := fedoraBridgeBindingVMI()
		vmiSpec.Spec.Subdomain = subdomain
		expectedFQDN := fmt.Sprintf("%s.%s.%s.svc.cluster.local", vmiSpec.Name, subdomain, util.NamespaceTestDefault)
		vmiSpec.Labels = map[string]string{selectorLabelKey: selectorLabelValue}

		dnsServerIP, err := libnet.ClusterDNSServiceIP()
		Expect(err).ToNot(HaveOccurred())

		vmiSpec.Spec.DNSPolicy = "None"
		vmiSpec.Spec.DNSConfig = &k8sv1.PodDNSConfig{
			Nameservers: []string{dnsServerIP},
			Searches:    []string{"example.com"},
		}

		vmi, err := virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmiSpec)
		Expect(err).ToNot(HaveOccurred())
		vmi = tests.WaitUntilVMIReady(vmi, console.LoginToFedora)

		Expect(assertFQDNinGuest(vmi, expectedFQDN)).To(Not(Succeed()), "found unexpected FQDN")
		Expect(assertSearchEntriesinGuest(vmi, "search example.com")).To(Succeed(), "failed to get expected search entries")
	})
})

func fedoraMasqueradeVMI() *v1.VirtualMachineInstance {
	return libvmi.NewFedora(
		libvmi.WithInterface(libvmi.InterfaceDeviceWithMasqueradeBinding()),
		libvmi.WithNetwork(v1.DefaultPodNetwork()))
}

func fedoraBridgeBindingVMI() *v1.VirtualMachineInstance {
	return libvmi.NewFedora(
		libvmi.WithInterface(libvmi.InterfaceDeviceWithBridgeBinding(libvmi.DefaultInterfaceName)),
		libvmi.WithNetwork(v1.DefaultPodNetwork()))
}

func assertFQDNinGuest(vmi *v1.VirtualMachineInstance, expectedFQDN string) error {
	return console.SafeExpectBatch(vmi, []expect.Batcher{
		&expect.BSnd{S: "\n"},
		&expect.BExp{R: console.PromptExpression},
		&expect.BSnd{S: "hostname -f\n"},
		&expect.BExp{R: expectedFQDN},
	}, 10)
}

func assertSearchEntriesinGuest(vmi *v1.VirtualMachineInstance, expectedSearch string) error {
	return console.SafeExpectBatch(vmi, []expect.Batcher{
		&expect.BSnd{S: "\n"},
		&expect.BExp{R: console.PromptExpression},
		&expect.BSnd{S: "cat /etc/resolv.conf\n"},
		&expect.BExp{R: expectedSearch + console.CRLF},
	}, 20)
}
<|endoftext|>


<commit_before>package envcfg

import (
    "testing"
    "os"
    "reflect"
    _ "fmt"
)

func init() {
    os.Clearenv()
}

func setEnv(t *testing.T, k string, v string) {
    err := os.Setenv(k, v)
    if err != nil {
        t.Fatal("error when setting env")
    }
}

func TestEnvironNames(t *testing.T) {

    names, err := getAllEnvironNames([]string{"key1=val", "key2=", "key1=anotherval"})
    if err != nil {
        t.FailNow()
    }
    want := map[string]struct{}{"key1":struct{}{}, "key2":struct{}{}}
    if !reflect.DeepEqual(names, want) {
        t.FailNow()
    }

    names, err = getAllEnvironNames([]string{"key1=val", "key2"})
    if err == nil && names != nil {
        t.FailNow()
    }
}

func TestNewEnviron(t *testing.T) {
    setEnv(t, "key1", "val")
    setEnv(t, "key2", "")
    setEnv(t, "key3", "")
    setEnv(t, "key3", "val3")
    defer os.Clearenv()

    env, err := newEnviron()
    if err != nil {
        t.Fatal("error when calling newEnviron")
    }
    want := environ{"key1": "val", "key2": "", "key3": "val3"}
    if !reflect.DeepEqual(want, env) {
        t.Fatalf("env not eq to want %#v compared to have %#v", want, env)
    }
}

type cfgValid1 struct {
    STRING string
    INT int
    BOOL bool
    STRING_SLICE []string
    INT_SLICE []int
    BOOL_SLICE []bool
}

type validType int
type cfgValid2 struct {
    INT_SLICE []validType
    INT validType
}

type cfgInvalid1 struct {
    FLOAT float64
}

type cfgInvalid2 struct {
    FLOAT_SLICE []float64
}

func TestUnmarshalValidateType(t *testing.T) {

    var i int
    if err := Unmarshal(i); err == nil {
        t.Fatal("should fail if we don't pass addressable value")
    }

    var p *cfgValid1
    if err := Unmarshal(p); err == nil {
        t.Fatal("pointer type: should fail if we don't pass addressable value")
    }
    if err := Unmarshal(&p); err != nil {
        t.Fatal("pointer type: should not fail since passed an addressable value")
    }

    var v cfgValid1
    if err := Unmarshal(&v); err != nil {
        t.Fatal("should not fail since we passed a valid value addressable")
    }
    if err := Unmarshal(v); err == nil {
        t.Fatal("should fail since we did not pass an addressable value")
    }

    var v1 cfgValid2
    if err := Unmarshal(&v1); err != nil {
        t.Fatal("should not fail since we passed another valid value")
    }

    var inv1 cfgInvalid1
    if err := Unmarshal(&inv1); err == nil {
        t.Log(err)
        t.Fatal("should fail due to invalid struct type")
    }

    var inv2 cfgInvalid2
    if err := Unmarshal(&inv2); err == nil {
        t.Log(err)
        t.Fatal("should fail due to invalid struct type - second case")
    }
}

func TestUnmarshalInit(t *testing.T) {
    var p *cfgValid1
    Unmarshal(&p)
    if !reflect.DeepEqual(p, new(cfgValid1)) {
        t.Fatal("should be initialized")
    }

    var v cfgValid1
    Unmarshal(&v) // shouldn't panic
}

type IntType struct {
    INT int
    INT_1 int
    INT_2 int `envcfg:""`
    INT_3 int `envcfg:"LABEL_INT"`
    INT_4 int `envcfg:"LABEL_INT"`
}

func TestUnmarshalSetInt(t *testing.T) {
    setEnv(t, "INT_1", "1")
    setEnv(t, "INT_2", "2")
    setEnv(t, "LABEL_INT", "3")
    defer os.Clearenv()

    var i IntType
    Unmarshal(&i)
    if !reflect.DeepEqual(IntType{0, 1, 2, 3, 3}, i) {
        t.Fatal("should be eq")
    }

    var p *IntType
    Unmarshal(&p)
    if !reflect.DeepEqual(&IntType{0, 1, 2, 3, 3}, p) {
        t.Fatal("should be eq")
    }

    setEnv(t, "INT_1", "invalid")
    if err := Unmarshal(&i); err == nil {
        t.Fatal("should throw an error since we passed an invalid int value")
    }
}

type StringType struct {
    STR string
    STR_1 string
    STR_2 string `envcfg:""`
    STR_3 string `envcfg:"LABEL_STR"`
    STR_4 string `envcfg:"LABEL_STR"`
}

func TestUnmarshalString(t *testing.T) {
    setEnv(t, "STR_1", "s1")
    setEnv(t, "STR_2", "s2")
    setEnv(t, "LABEL_STR", "s3")
    defer os.Clearenv()

    var s StringType
    Unmarshal(&s)
    if !reflect.DeepEqual(StringType{"", "s1","s2","s3", "s3"},s) {
        t.Fatal("should be equal")
    }
}

type BoolType struct {
    BOOL bool
    BOOL_1 bool
    BOOL_2 bool `envcfg:"LABEL_BOOL"`
}

func TestUnmarshalBool(t *testing.T) {
    setEnv(t, "BOOL_1", "true")
    setEnv(t, "LABEL_BOOL", "true")
    defer os.Clearenv()

    var b BoolType
    Unmarshal(&b)
    if !reflect.DeepEqual(BoolType{false, true, true}, b) {
        t.Log(b)
        t.Fatal("should be equal")
    }

    setEnv(t, "LABEL_BOOL", "invalid")
    if err := Unmarshal(&b); err == nil {
        t.Fatal("should fail")
    }
}

type SliceType struct {
    SLICE_STR []string
    SLICE_INT []int
    SLICE_BOOL []bool
}

func TestUnmarshalSlice(t *testing.T) {
    setEnv(t, "SLICE_STR_1", "foo")
    setEnv(t, "SLICE_STR_2", "bar")
    setEnv(t, "SLICE_INT_1", "1")
    setEnv(t, "SLICE_INT_2", "2")
    setEnv(t, "SLICE_BOOL_1", "true")
    setEnv(t, "SLICE_BOOL_2", "false")
    defer os.Clearenv()

    var s SliceType
    Unmarshal(&s)
    if !reflect.DeepEqual(s, SliceType{[]string{"foo", "bar"}, []int{1, 2}, []bool{true, false}}) {
        t.Fatal("should be equal")
    }
}

func TestUnmarshalSliceFail(t *testing.T) {
    defer os.Clearenv()
    setEnv(t, "SLICE_BOOL_1", "true")
    setEnv(t, "SLICE_BOOL_2", "invalid")
    var s SliceType

    if err := Unmarshal(&s); err == nil {
        t.Fatal("should fail on an invalid bool value")
    }
    os.Clearenv()

    setEnv(t, "SLICE_INT_1", "invalid")
    if err := Unmarshal(&s); err == nil {
        t.Fatal("shoud fail on invalid int")
    }
}

type GeneralTest struct {
    some_int int // unexported - will not be set
    SOME_INT int

    SOME_STR string

    SOME_BOOL bool

    SOME_SLICE_BOOL []bool
    SOME_SLICE_INT []int
    SOME_SLICE_STRING []string

    SOME_UNSET_FIELD string
}

func TestGeneral(t *testing.T) {
    t.FailNow()
    defer os.Clearenv()
    setEnv(t, "some_int", "1")
    setEnv(t, "SOME_INT", "1")
    setEnv(t, "SOME_STR", "1")
    setEnv(t, "SOME_BOOL", "true")
    setEnv(t, "SOME_SLICE_BOOL_a", "true")
    setEnv(t, "SOME_SLICE_INT", "1")
    setEnv(t, "SOME_SLICE_INT_1", "1")
    setEnv(t, "SOME_SLICE_INT_2", "5")
    setEnv(t, "SOME_SLICE_STRING", "foo")

    var gt GeneralTest
    if err := Unmarshal(&gt); err != nil {
        t.Fatal("should not fail")
    }
    want := GeneralTest{
        SOME_INT : 1,
        SOME_STR : "1",
        SOME_BOOL: true,
        SOME_SLICE_BOOL: []bool{true},
        SOME_SLICE_INT: []int{1,1,5},
        SOME_SLICE_STRING: []string{"foo"},
    }
    if !reflect.DeepEqual(gt, want) {
        t.Fatal("should be eq")
    }

}
<commit_msg>fix test<commit_after>package envcfg

import (
    "testing"
    "os"
    "reflect"
    _ "fmt"
)

func init() {
    os.Clearenv()
}

func setEnv(t *testing.T, k string, v string) {
    err := os.Setenv(k, v)
    if err != nil {
        t.Fatal("error when setting env")
    }
}

func TestEnvironNames(t *testing.T) {

    names, err := getAllEnvironNames([]string{"key1=val", "key2=", "key1=anotherval"})
    if err != nil {
        t.FailNow()
    }
    want := map[string]struct{}{"key1":struct{}{}, "key2":struct{}{}}
    if !reflect.DeepEqual(names, want) {
        t.FailNow()
    }

    names, err = getAllEnvironNames([]string{"key1=val", "key2"})
    if err == nil && names != nil {
        t.FailNow()
    }
}

func TestNewEnviron(t *testing.T) {
    setEnv(t, "key1", "val")
    setEnv(t, "key2", "")
    setEnv(t, "key3", "")
    setEnv(t, "key3", "val3")
    defer os.Clearenv()

    env, err := newEnviron()
    if err != nil {
        t.Fatal("error when calling newEnviron")
    }
    want := environ{"key1": "val", "key2": "", "key3": "val3"}
    if !reflect.DeepEqual(want, env) {
        t.Fatalf("env not eq to want %#v compared to have %#v", want, env)
    }
}

type cfgValid1 struct {
    STRING string
    INT int
    BOOL bool
    STRING_SLICE []string
    INT_SLICE []int
    BOOL_SLICE []bool
}

type validType int
type cfgValid2 struct {
    INT_SLICE []validType
    INT validType
}

type cfgInvalid1 struct {
    FLOAT float64
}

type cfgInvalid2 struct {
    FLOAT_SLICE []float64
}

func TestUnmarshalValidateType(t *testing.T) {

    var i int
    if err := Unmarshal(i); err == nil {
        t.Fatal("should fail if we don't pass addressable value")
    }

    var p *cfgValid1
    if err := Unmarshal(p); err == nil {
        t.Fatal("pointer type: should fail if we don't pass addressable value")
    }
    if err := Unmarshal(&p); err != nil {
        t.Fatal("pointer type: should not fail since passed an addressable value")
    }

    var v cfgValid1
    if err := Unmarshal(&v); err != nil {
        t.Fatal("should not fail since we passed a valid value addressable")
    }
    if err := Unmarshal(v); err == nil {
        t.Fatal("should fail since we did not pass an addressable value")
    }

    var v1 cfgValid2
    if err := Unmarshal(&v1); err != nil {
        t.Fatal("should not fail since we passed another valid value")
    }

    var inv1 cfgInvalid1
    if err := Unmarshal(&inv1); err == nil {
        t.Log(err)
        t.Fatal("should fail due to invalid struct type")
    }

    var inv2 cfgInvalid2
    if err := Unmarshal(&inv2); err == nil {
        t.Log(err)
        t.Fatal("should fail due to invalid struct type - second case")
    }
}

func TestUnmarshalInit(t *testing.T) {
    var p *cfgValid1
    Unmarshal(&p)
    if !reflect.DeepEqual(p, new(cfgValid1)) {
        t.Fatal("should be initialized")
    }

    var v cfgValid1
    Unmarshal(&v) // shouldn't panic
}

type IntType struct {
    INT int
    INT_1 int
    INT_2 int `envcfg:""`
    INT_3 int `envcfg:"LABEL_INT"`
    INT_4 int `envcfg:"LABEL_INT"`
}

func TestUnmarshalSetInt(t *testing.T) {
    setEnv(t, "INT_1", "1")
    setEnv(t, "INT_2", "2")
    setEnv(t, "LABEL_INT", "3")
    defer os.Clearenv()

    var i IntType
    Unmarshal(&i)
    if !reflect.DeepEqual(IntType{0, 1, 2, 3, 3}, i) {
        t.Fatal("should be eq")
    }

    var p *IntType
    Unmarshal(&p)
    if !reflect.DeepEqual(&IntType{0, 1, 2, 3, 3}, p) {
        t.Fatal("should be eq")
    }

    setEnv(t, "INT_1", "invalid")
    if err := Unmarshal(&i); err == nil {
        t.Fatal("should throw an error since we passed an invalid int value")
    }
}

type StringType struct {
    STR string
    STR_1 string
    STR_2 string `envcfg:""`
    STR_3 string `envcfg:"LABEL_STR"`
    STR_4 string `envcfg:"LABEL_STR"`
}

func TestUnmarshalString(t *testing.T) {
    setEnv(t, "STR_1", "s1")
    setEnv(t, "STR_2", "s2")
    setEnv(t, "LABEL_STR", "s3")
    defer os.Clearenv()

    var s StringType
    Unmarshal(&s)
    if !reflect.DeepEqual(StringType{"", "s1","s2","s3", "s3"},s) {
        t.Fatal("should be equal")
    }
}

type BoolType struct {
    BOOL bool
    BOOL_1 bool
    BOOL_2 bool `envcfg:"LABEL_BOOL"`
}

func TestUnmarshalBool(t *testing.T) {
    setEnv(t, "BOOL_1", "true")
    setEnv(t, "LABEL_BOOL", "true")
    defer os.Clearenv()

    var b BoolType
    Unmarshal(&b)
    if !reflect.DeepEqual(BoolType{false, true, true}, b) {
        t.Log(b)
        t.Fatal("should be equal")
    }

    setEnv(t, "LABEL_BOOL", "invalid")
    if err := Unmarshal(&b); err == nil {
        t.Fatal("should fail")
    }
}

type SliceType struct {
    SLICE_STR []string
    SLICE_INT []int
    SLICE_BOOL []bool
}

func TestUnmarshalSlice(t *testing.T) {
    setEnv(t, "SLICE_STR_1", "foo")
    setEnv(t, "SLICE_STR_2", "bar")
    setEnv(t, "SLICE_INT_1", "1")
    setEnv(t, "SLICE_INT_2", "2")
    setEnv(t, "SLICE_BOOL_1", "true")
    setEnv(t, "SLICE_BOOL_2", "false")
    defer os.Clearenv()

    var s SliceType
    Unmarshal(&s)
    if !reflect.DeepEqual(s, SliceType{[]string{"foo", "bar"}, []int{1, 2}, []bool{true, false}}) {
        t.Fatal("should be equal")
    }
}

func TestUnmarshalSliceFail(t *testing.T) {
    defer os.Clearenv()
    setEnv(t, "SLICE_BOOL_1", "true")
    setEnv(t, "SLICE_BOOL_2", "invalid")
    var s SliceType

    if err := Unmarshal(&s); err == nil {
        t.Fatal("should fail on an invalid bool value")
    }
    os.Clearenv()

    setEnv(t, "SLICE_INT_1", "invalid")
    if err := Unmarshal(&s); err == nil {
        t.Fatal("shoud fail on invalid int")
    }
}

type GeneralTest struct {
    some_int int // unexported - will not be set
    SOME_INT int

    SOME_STR string

    SOME_BOOL bool

    SOME_SLICE_BOOL []bool
    SOME_SLICE_INT []int
    SOME_SLICE_STRING []string

    SOME_UNSET_FIELD string
}

func TestGeneral(t *testing.T) {
    defer os.Clearenv()
    setEnv(t, "some_int", "1")
    setEnv(t, "SOME_INT", "1")
    setEnv(t, "SOME_STR", "1")
    setEnv(t, "SOME_BOOL", "true")
    setEnv(t, "SOME_SLICE_BOOL_a", "true")
    setEnv(t, "SOME_SLICE_INT", "1")
    setEnv(t, "SOME_SLICE_INT_1", "1")
    setEnv(t, "SOME_SLICE_INT_2", "5")
    setEnv(t, "SOME_SLICE_STRING", "foo")

    var gt GeneralTest
    if err := Unmarshal(&gt); err != nil {
        t.Fatal("should not fail")
    }
    want := GeneralTest{
        SOME_INT : 1,
        SOME_STR : "1",
        SOME_BOOL: true,
        SOME_SLICE_BOOL: []bool{true},
        SOME_SLICE_INT: []int{1,1,5},
        SOME_SLICE_STRING: []string{"foo"},
    }
    if !reflect.DeepEqual(gt, want) {
        t.Fatal("should be eq")
    }

}
<|endoftext|>


<commit_before>package app

// ChangeEvent represents the data passed in a change event.
type ChangeEvent struct {
	Value string
}

// MouseEvent represents data fired when interacting with a pointing device
// (such as a mouse).
type MouseEvent struct {
	ClientX  float64
	ClientY  float64
	PageX    float64
	PageY    float64
	ScreenX  float64
	ScreenY  float64
	Button   int
	Detail   int
	AltKey   bool
	CtrlKey  bool
	MetaKey  bool
	ShiftKey bool
}

// WheelEvent represents data fired when a wheel button of a pointing device
// (usually a mouse) is rotated.
type WheelEvent struct {
	DeltaX    float64
	DeltaY    float64
	DeltaZ    float64
	DeltaMode DeltaMode
}

// DeltaMode is an indication of the units of measurement for a delta value.
type DeltaMode uint64

// KeyboardEvent represents data fired when the keyboard is used.
type KeyboardEvent struct {
	CharCode rune
	KeyCode  KeyCode
	Location KeyLocation
	AltKey   bool
	CtrlKey  bool
	MetaKey  bool
	ShiftKey bool
}
<commit_msg>fix key<commit_after>package app

import (
	"github.com/murlokswarm/app/key"
)

// ChangeEvent represents the data passed in a change event.
type ChangeEvent struct {
	Value string
}

// MouseEvent represents data fired when interacting with a pointing device
// (such as a mouse).
type MouseEvent struct {
	ClientX  float64
	ClientY  float64
	PageX    float64
	PageY    float64
	ScreenX  float64
	ScreenY  float64
	Button   int
	Detail   int
	AltKey   bool
	CtrlKey  bool
	MetaKey  bool
	ShiftKey bool
}

// WheelEvent represents data fired when a wheel button of a pointing device
// (usually a mouse) is rotated.
type WheelEvent struct {
	DeltaX    float64
	DeltaY    float64
	DeltaZ    float64
	DeltaMode DeltaMode
}

// DeltaMode is an indication of the units of measurement for a delta value.
type DeltaMode uint64

// KeyboardEvent represents data fired when the keyboard is used.
type KeyboardEvent struct {
	CharCode rune
	KeyCode  key.Code
	Location key.Location
	AltKey   bool
	CtrlKey  bool
	MetaKey  bool
	ShiftKey bool
}
<|endoftext|>


<commit_before>package route

import (
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_registry"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
	cliFlags "github.com/simonleung8/flags/flag"
)

type UnmapRoute struct {
	ui        terminal.UI
	config    core_config.Reader
	routeRepo api.RouteRepository
	appReq    requirements.ApplicationRequirement
	domainReq requirements.DomainRequirement
}

func init() {
	command_registry.Register(&UnmapRoute{})
}

func (cmd *UnmapRoute) MetaData() command_registry.CommandMetadata {
	fs := make(map[string]flags.FlagSet)
	fs["hostname"] = &cliFlags.StringFlag{Name: "hostname", ShortName: "n", Usage: T("Hostname")}

	return command_registry.CommandMetadata{
		Name:        "unmap-route",
		Description: T("Remove a url route from an app"),
		Usage:       T("CF_NAME unmap-route APP_NAME DOMAIN [--hostname HOSTNAME]"),
		Flags:       fs,
	}
}

func (cmd *UnmapRoute) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) (reqs []requirements.Requirement, err error) {
	if len(fc.Args()) != 2 {
		cmd.ui.Failed(T("Incorrect Usage. Requires app_name, domain_name as arguments\n\n") + command_registry.Commands.CommandUsage("unmap-route"))
	}

	domainName := fc.Args()[1]

	cmd.appReq = requirementsFactory.NewApplicationRequirement(fc.Args()[0])
	cmd.domainReq = requirementsFactory.NewDomainRequirement(domainName)

	reqs = []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
		cmd.appReq,
		cmd.domainReq,
	}
	return
}

func (cmd *UnmapRoute) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command {
	cmd.ui = deps.Ui
	cmd.config = deps.Config
	cmd.routeRepo = deps.RepoLocator.GetRouteRepository()
	return cmd
}

func (cmd *UnmapRoute) Execute(c flags.FlagContext) {
	hostName := c.String("n")
	domain := cmd.domainReq.GetDomain()
	app := cmd.appReq.GetApplication()

	route, apiErr := cmd.routeRepo.FindByHostAndDomain(hostName, domain)
	if apiErr != nil {
		cmd.ui.Failed(apiErr.Error())
	}
	cmd.ui.Say(T("Removing route {{.URL}} from app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...",
		map[string]interface{}{
			"URL":       terminal.EntityNameColor(route.URL()),
			"AppName":   terminal.EntityNameColor(app.Name),
			"OrgName":   terminal.EntityNameColor(cmd.config.OrganizationFields().Name),
			"SpaceName": terminal.EntityNameColor(cmd.config.SpaceFields().Name),
			"Username":  terminal.EntityNameColor(cmd.config.Username())}))

	var routeFound bool
	for _, routeApp := range route.Apps {
		if routeApp.Guid == app.Guid {
			routeFound = true
			apiErr = cmd.routeRepo.Unbind(route.Guid, app.Guid)
			if apiErr != nil {
				cmd.ui.Failed(apiErr.Error())
				return
			}
		}
	}
	cmd.ui.Ok()

	if !routeFound {
		cmd.ui.Warn(T("\nRoute to be unmapped is not currently mapped to the application."))
	}

}
<commit_msg>Update unmap-route<commit_after>package route

import (
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_registry"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
	cliFlags "github.com/simonleung8/flags/flag"
)

type UnmapRoute struct {
	ui        terminal.UI
	config    core_config.Reader
	routeRepo api.RouteRepository
	appReq    requirements.ApplicationRequirement
	domainReq requirements.DomainRequirement
}

func init() {
	command_registry.Register(&UnmapRoute{})
}

func (cmd *UnmapRoute) MetaData() command_registry.CommandMetadata {
	fs := make(map[string]flags.FlagSet)
	fs["hostname"] = &cliFlags.StringFlag{Name: "hostname", ShortName: "n", Usage: T("Hostname")}

	return command_registry.CommandMetadata{
		Name:        "unmap-route",
		Description: T("Remove a url route from an app"),
		Usage:       T("CF_NAME unmap-route APP_NAME DOMAIN [--hostname HOSTNAME]"),
		Flags:       fs,
	}
}

func (cmd *UnmapRoute) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) (reqs []requirements.Requirement, err error) {
	if len(fc.Args()) != 2 {
		cmd.ui.Failed(T("Incorrect Usage. Requires app_name, domain_name as arguments\n\n") + command_registry.Commands.CommandUsage("unmap-route"))
	}

	domainName := fc.Args()[1]

	cmd.appReq = requirementsFactory.NewApplicationRequirement(fc.Args()[0])
	cmd.domainReq = requirementsFactory.NewDomainRequirement(domainName)

	reqs = []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
		cmd.appReq,
		cmd.domainReq,
	}
	return
}

func (cmd *UnmapRoute) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command {
	cmd.ui = deps.Ui
	cmd.config = deps.Config
	cmd.routeRepo = deps.RepoLocator.GetRouteRepository()
	return cmd
}

func (cmd *UnmapRoute) Execute(c flags.FlagContext) {
	hostName := c.String("n")
	domain := cmd.domainReq.GetDomain()
	app := cmd.appReq.GetApplication()

	route, err := cmd.routeRepo.FindByHostAndDomain(hostName, domain)
	if err != nil {
		cmd.ui.Failed(err.Error())
	}

	cmd.ui.Say(T("Removing route {{.URL}} from app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...",
		map[string]interface{}{
			"URL":       terminal.EntityNameColor(route.URL()),
			"AppName":   terminal.EntityNameColor(app.Name),
			"OrgName":   terminal.EntityNameColor(cmd.config.OrganizationFields().Name),
			"SpaceName": terminal.EntityNameColor(cmd.config.SpaceFields().Name),
			"Username":  terminal.EntityNameColor(cmd.config.Username())}))

	var routeFound bool
	for _, routeApp := range route.Apps {
		if routeApp.Guid == app.Guid {
			routeFound = true
			err = cmd.routeRepo.Unbind(route.Guid, app.Guid)
			if err != nil {
				cmd.ui.Failed(err.Error())
			}
			break
		}
	}

	cmd.ui.Ok()

	if !routeFound {
		cmd.ui.Warn(T("\nRoute to be unmapped is not currently mapped to the application."))
	}
}
<|endoftext|>


<commit_before>// +build linux

package systemd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	systemd "github.com/coreos/go-systemd/dbus"
	"github.com/docker/libcontainer/cgroups"
	"github.com/docker/libcontainer/cgroups/fs"
	"github.com/docker/libcontainer/configs"
	"github.com/godbus/dbus"
)

type Manager struct {
	Cgroups *configs.Cgroup
	Paths   map[string]string
}

type subsystem interface {
	// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
	GetStats(path string, stats *cgroups.Stats) error
	// Set the cgroup represented by cgroup.
	Set(path string, cgroup *configs.Cgroup) error
}

var subsystems = map[string]subsystem{
	"devices":    &fs.DevicesGroup{},
	"memory":     &fs.MemoryGroup{},
	"cpu":        &fs.CpuGroup{},
	"cpuset":     &fs.CpusetGroup{},
	"cpuacct":    &fs.CpuacctGroup{},
	"blkio":      &fs.BlkioGroup{},
	"perf_event": &fs.PerfEventGroup{},
	"freezer":    &fs.FreezerGroup{},
}

const (
	testScopeWait = 4
)

var (
	connLock                        sync.Mutex
	theConn                         *systemd.Conn
	hasStartTransientUnit           bool
	hasTransientDefaultDependencies bool
)

func newProp(name string, units interface{}) systemd.Property {
	return systemd.Property{
		Name:  name,
		Value: dbus.MakeVariant(units),
	}
}

func UseSystemd() bool {
	s, err := os.Stat("/run/systemd/system")
	if err != nil || !s.IsDir() {
		return false
	}

	connLock.Lock()
	defer connLock.Unlock()

	if theConn == nil {
		var err error
		theConn, err = systemd.New()
		if err != nil {
			return false
		}

		// Assume we have StartTransientUnit
		hasStartTransientUnit = true

		// But if we get UnknownMethod error we don't
		if _, err := theConn.StartTransientUnit("test.scope", "invalid"); err != nil {
			if dbusError, ok := err.(dbus.Error); ok {
				if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
					hasStartTransientUnit = false
					return hasStartTransientUnit
				}
			}
		}

		// Ensure the scope name we use doesn't exist. Use the Pid to
		// avoid collisions between multiple libcontainer users on a
		// single host.
		scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
		testScopeExists := true
		for i := 0; i <= testScopeWait; i++ {
			if _, err := theConn.StopUnit(scope, "replace"); err != nil {
				if dbusError, ok := err.(dbus.Error); ok {
					if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
						testScopeExists = false
						break
					}
				}
			}
			time.Sleep(time.Millisecond)
		}

		// Bail out if we can't kill this scope without testing for DefaultDependencies
		if testScopeExists {
			return hasStartTransientUnit
		}

		// Assume StartTransientUnit on a scope allows DefaultDependencies
		hasTransientDefaultDependencies = true
		ddf := newProp("DefaultDependencies", false)
		if _, err := theConn.StartTransientUnit(scope, "replace", ddf); err != nil {
			if dbusError, ok := err.(dbus.Error); ok {
				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
					hasTransientDefaultDependencies = false
				}
			}
		}

		// Not critical because of the stop unit logic above.
		theConn.StopUnit(scope, "replace")
	}
	return hasStartTransientUnit
}

func getIfaceForUnit(unitName string) string {
	if strings.HasSuffix(unitName, ".scope") {
		return "Scope"
	}
	if strings.HasSuffix(unitName, ".service") {
		return "Service"
	}
	return "Unit"
}

func (m *Manager) Apply(pid int) error {
	var (
		c          = m.Cgroups
		unitName   = getUnitName(c)
		slice      = "system.slice"
		properties []systemd.Property
	)

	if c.Slice != "" {
		slice = c.Slice
	}

	properties = append(properties,
		systemd.PropSlice(slice),
		systemd.PropDescription("docker container "+c.Name),
		newProp("PIDs", []uint32{uint32(pid)}),
	)

	// Always enable accounting, this gets us the same behaviour as the fs implementation,
	// plus the kernel has some problems with joining the memory cgroup at a later time.
	properties = append(properties,
		newProp("MemoryAccounting", true),
		newProp("CPUAccounting", true),
		newProp("BlockIOAccounting", true))

	if hasTransientDefaultDependencies {
		properties = append(properties,
			newProp("DefaultDependencies", false))
	}

	if c.Memory != 0 {
		properties = append(properties,
			newProp("MemoryLimit", uint64(c.Memory)))
	}
	// TODO: MemoryReservation and MemorySwap not available in systemd

	if c.CpuShares != 0 {
		properties = append(properties,
			newProp("CPUShares", uint64(c.CpuShares)))
	}

	if c.BlkioWeight != 0 {
		properties = append(properties,
			newProp("BlockIOWeight", uint64(c.BlkioWeight)))
	}

	if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
		return err
	}

	if err := joinDevices(c, pid); err != nil {
		return err
	}

	// TODO: CpuQuota and CpuPeriod not available in systemd
	// we need to manually join the cpu.cfs_quota_us and cpu.cfs_period_us
	if err := joinCpu(c, pid); err != nil {
		return err
	}

	// -1 disables memorySwap
	if c.MemorySwap >= 0 && c.Memory != 0 {
		if err := joinMemory(c, pid); err != nil {
			return err
		}

	}

	// we need to manually join the freezer and cpuset cgroup in systemd
	// because it does not currently support it via the dbus api.
	if err := joinFreezer(c, pid); err != nil {
		return err
	}

	if err := joinCpuset(c, pid); err != nil {
		return err
	}

	paths := make(map[string]string)
	for sysname := range subsystems {
		subsystemPath, err := getSubsystemPath(m.Cgroups, sysname)
		if err != nil {
			// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
			if cgroups.IsNotFound(err) {
				continue
			}
			return err
		}
		paths[sysname] = subsystemPath
	}

	m.Paths = paths

	return nil
}

func (m *Manager) Destroy() error {
	return cgroups.RemovePaths(m.Paths)
}

func (m *Manager) GetPaths() map[string]string {
	return m.Paths
}

func writeFile(dir, file, data string) error {
	return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
}

func joinCpu(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "cpu")
	if err != nil {
		return err
	}
	if c.CpuQuota != 0 {
		if err = ioutil.WriteFile(filepath.Join(path, "cpu.cfs_quota_us"), []byte(strconv.FormatInt(c.CpuQuota, 10)), 0700); err != nil {
			return err
		}
	}
	if c.CpuPeriod != 0 {
		if err = ioutil.WriteFile(filepath.Join(path, "cpu.cfs_period_us"), []byte(strconv.FormatInt(c.CpuPeriod, 10)), 0700); err != nil {
			return err
		}
	}
	return nil
}

func joinFreezer(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "freezer")
	if err != nil {
		return err
	}

	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700)
}

func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
	mountpoint, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return "", err
	}

	initPath, err := cgroups.GetInitCgroupDir(subsystem)
	if err != nil {
		return "", err
	}

	slice := "system.slice"
	if c.Slice != "" {
		slice = c.Slice
	}

	return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
}

func (m *Manager) Freeze(state configs.FreezerState) error {
	path, err := getSubsystemPath(m.Cgroups, "freezer")
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(filepath.Join(path, "freezer.state"), []byte(state), 0); err != nil {
		return err
	}
	for {
		state_, err := ioutil.ReadFile(filepath.Join(path, "freezer.state"))
		if err != nil {
			return err
		}
		if string(state) == string(bytes.TrimSpace(state_)) {
			break
		}
		time.Sleep(1 * time.Millisecond)
	}

	m.Cgroups.Freezer = state

	return nil
}

func (m *Manager) GetPids() ([]int, error) {
	path, err := getSubsystemPath(m.Cgroups, "cpu")
	if err != nil {
		return nil, err
	}

	return cgroups.ReadProcsFile(path)
}

func (m *Manager) GetStats() (*cgroups.Stats, error) {
	stats := cgroups.NewStats()
	for name, path := range m.Paths {
		sys, ok := subsystems[name]
		if !ok || !cgroups.PathExists(path) {
			continue
		}
		if err := sys.GetStats(path, stats); err != nil {
			return nil, err
		}
	}

	return stats, nil
}

func (m *Manager) Set(container *configs.Config) error {
	panic("not implemented")
}

func getUnitName(c *configs.Cgroup) string {
	return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name)
}

// Atm we can't use the systemd device support because of two missing things:
// * Support for wildcards to allow mknod on any device
// * Support for wildcards to allow /dev/pts support
//
// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
// in wide use. When both these are availalable we will be able to switch, but need to keep the old
// implementation for backwards compat.
//
// Note: we can't use systemd to set up the initial limits, and then change the cgroup
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
// This happens at least for v208 when any sibling unit is started.
func joinDevices(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "devices")
	if err != nil {
		return err
	}

	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
		return err
	}

	if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
		return err
	}

	if !c.AllowAllDevices {
		if err := writeFile(path, "devices.deny", "a"); err != nil {
			return err
		}
	}
	for _, dev := range c.AllowedDevices {
		if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
			return err
		}
	}
	return nil
}

// Symmetrical public function to update device based cgroups.  Also available
// in the fs implementation.
func ApplyDevices(c *configs.Cgroup, pid int) error {
	return joinDevices(c, pid)
}

func joinMemory(c *configs.Cgroup, pid int) error {
	memorySwap := c.MemorySwap

	if memorySwap == 0 {
		// By default, MemorySwap is set to twice the size of RAM.
		memorySwap = c.Memory * 2
	}

	path, err := getSubsystemPath(c, "memory")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filepath.Join(path, "memory.memsw.limit_in_bytes"), []byte(strconv.FormatInt(memorySwap, 10)), 0700)
}

// systemd does not atm set up the cpuset controller, so we must manually
// join it. Additionally that is a very finicky controller where each
// level must have a full setup as the default for a new directory is "no cpus"
func joinCpuset(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "cpuset")
	if err != nil {
		return err
	}

	s := &fs.CpusetGroup{}

	return s.ApplyDir(path, c, pid)
}
<commit_msg>add Set support for systemd based cgroup<commit_after>// +build linux

package systemd

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	systemd "github.com/coreos/go-systemd/dbus"
	"github.com/docker/libcontainer/cgroups"
	"github.com/docker/libcontainer/cgroups/fs"
	"github.com/docker/libcontainer/configs"
	"github.com/godbus/dbus"
)

type Manager struct {
	Cgroups *configs.Cgroup
	Paths   map[string]string
}

type subsystem interface {
	// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
	GetStats(path string, stats *cgroups.Stats) error
	// Set the cgroup represented by cgroup.
	Set(path string, cgroup *configs.Cgroup) error
}

var subsystems = map[string]subsystem{
	"devices":    &fs.DevicesGroup{},
	"memory":     &fs.MemoryGroup{},
	"cpu":        &fs.CpuGroup{},
	"cpuset":     &fs.CpusetGroup{},
	"cpuacct":    &fs.CpuacctGroup{},
	"blkio":      &fs.BlkioGroup{},
	"perf_event": &fs.PerfEventGroup{},
	"freezer":    &fs.FreezerGroup{},
}

const (
	testScopeWait = 4
)

var (
	connLock                        sync.Mutex
	theConn                         *systemd.Conn
	hasStartTransientUnit           bool
	hasTransientDefaultDependencies bool
)

func newProp(name string, units interface{}) systemd.Property {
	return systemd.Property{
		Name:  name,
		Value: dbus.MakeVariant(units),
	}
}

func UseSystemd() bool {
	s, err := os.Stat("/run/systemd/system")
	if err != nil || !s.IsDir() {
		return false
	}

	connLock.Lock()
	defer connLock.Unlock()

	if theConn == nil {
		var err error
		theConn, err = systemd.New()
		if err != nil {
			return false
		}

		// Assume we have StartTransientUnit
		hasStartTransientUnit = true

		// But if we get UnknownMethod error we don't
		if _, err := theConn.StartTransientUnit("test.scope", "invalid"); err != nil {
			if dbusError, ok := err.(dbus.Error); ok {
				if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
					hasStartTransientUnit = false
					return hasStartTransientUnit
				}
			}
		}

		// Ensure the scope name we use doesn't exist. Use the Pid to
		// avoid collisions between multiple libcontainer users on a
		// single host.
		scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
		testScopeExists := true
		for i := 0; i <= testScopeWait; i++ {
			if _, err := theConn.StopUnit(scope, "replace"); err != nil {
				if dbusError, ok := err.(dbus.Error); ok {
					if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
						testScopeExists = false
						break
					}
				}
			}
			time.Sleep(time.Millisecond)
		}

		// Bail out if we can't kill this scope without testing for DefaultDependencies
		if testScopeExists {
			return hasStartTransientUnit
		}

		// Assume StartTransientUnit on a scope allows DefaultDependencies
		hasTransientDefaultDependencies = true
		ddf := newProp("DefaultDependencies", false)
		if _, err := theConn.StartTransientUnit(scope, "replace", ddf); err != nil {
			if dbusError, ok := err.(dbus.Error); ok {
				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
					hasTransientDefaultDependencies = false
				}
			}
		}

		// Not critical because of the stop unit logic above.
		theConn.StopUnit(scope, "replace")
	}
	return hasStartTransientUnit
}

func getIfaceForUnit(unitName string) string {
	if strings.HasSuffix(unitName, ".scope") {
		return "Scope"
	}
	if strings.HasSuffix(unitName, ".service") {
		return "Service"
	}
	return "Unit"
}

func (m *Manager) Apply(pid int) error {
	var (
		c          = m.Cgroups
		unitName   = getUnitName(c)
		slice      = "system.slice"
		properties []systemd.Property
	)

	if c.Slice != "" {
		slice = c.Slice
	}

	properties = append(properties,
		systemd.PropSlice(slice),
		systemd.PropDescription("docker container "+c.Name),
		newProp("PIDs", []uint32{uint32(pid)}),
	)

	// Always enable accounting, this gets us the same behaviour as the fs implementation,
	// plus the kernel has some problems with joining the memory cgroup at a later time.
	properties = append(properties,
		newProp("MemoryAccounting", true),
		newProp("CPUAccounting", true),
		newProp("BlockIOAccounting", true))

	if hasTransientDefaultDependencies {
		properties = append(properties,
			newProp("DefaultDependencies", false))
	}

	if c.Memory != 0 {
		properties = append(properties,
			newProp("MemoryLimit", uint64(c.Memory)))
	}
	// TODO: MemoryReservation and MemorySwap not available in systemd

	if c.CpuShares != 0 {
		properties = append(properties,
			newProp("CPUShares", uint64(c.CpuShares)))
	}

	if c.BlkioWeight != 0 {
		properties = append(properties,
			newProp("BlockIOWeight", uint64(c.BlkioWeight)))
	}

	if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
		return err
	}

	if err := joinDevices(c, pid); err != nil {
		return err
	}

	// TODO: CpuQuota and CpuPeriod not available in systemd
	// we need to manually join the cpu.cfs_quota_us and cpu.cfs_period_us
	if err := joinCpu(c, pid); err != nil {
		return err
	}

	// -1 disables memorySwap
	if c.MemorySwap >= 0 && c.Memory != 0 {
		if err := joinMemory(c, pid); err != nil {
			return err
		}

	}

	// we need to manually join the freezer and cpuset cgroup in systemd
	// because it does not currently support it via the dbus api.
	if err := joinFreezer(c, pid); err != nil {
		return err
	}

	if err := joinCpuset(c, pid); err != nil {
		return err
	}

	paths := make(map[string]string)
	for sysname := range subsystems {
		subsystemPath, err := getSubsystemPath(m.Cgroups, sysname)
		if err != nil {
			// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
			if cgroups.IsNotFound(err) {
				continue
			}
			return err
		}
		paths[sysname] = subsystemPath
	}

	m.Paths = paths

	return nil
}

func (m *Manager) Destroy() error {
	return cgroups.RemovePaths(m.Paths)
}

func (m *Manager) GetPaths() map[string]string {
	return m.Paths
}

func writeFile(dir, file, data string) error {
	return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
}

func joinCpu(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "cpu")
	if err != nil {
		return err
	}
	if c.CpuQuota != 0 {
		if err = ioutil.WriteFile(filepath.Join(path, "cpu.cfs_quota_us"), []byte(strconv.FormatInt(c.CpuQuota, 10)), 0700); err != nil {
			return err
		}
	}
	if c.CpuPeriod != 0 {
		if err = ioutil.WriteFile(filepath.Join(path, "cpu.cfs_period_us"), []byte(strconv.FormatInt(c.CpuPeriod, 10)), 0700); err != nil {
			return err
		}
	}
	return nil
}

func joinFreezer(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "freezer")
	if err != nil {
		return err
	}

	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
		return err
	}

	return ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700)
}

func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
	mountpoint, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return "", err
	}

	initPath, err := cgroups.GetInitCgroupDir(subsystem)
	if err != nil {
		return "", err
	}

	slice := "system.slice"
	if c.Slice != "" {
		slice = c.Slice
	}

	return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
}

func (m *Manager) Freeze(state configs.FreezerState) error {
	path, err := getSubsystemPath(m.Cgroups, "freezer")
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(filepath.Join(path, "freezer.state"), []byte(state), 0); err != nil {
		return err
	}
	for {
		state_, err := ioutil.ReadFile(filepath.Join(path, "freezer.state"))
		if err != nil {
			return err
		}
		if string(state) == string(bytes.TrimSpace(state_)) {
			break
		}
		time.Sleep(1 * time.Millisecond)
	}

	m.Cgroups.Freezer = state

	return nil
}

func (m *Manager) GetPids() ([]int, error) {
	path, err := getSubsystemPath(m.Cgroups, "cpu")
	if err != nil {
		return nil, err
	}

	return cgroups.ReadProcsFile(path)
}

func (m *Manager) GetStats() (*cgroups.Stats, error) {
	stats := cgroups.NewStats()
	for name, path := range m.Paths {
		sys, ok := subsystems[name]
		if !ok || !cgroups.PathExists(path) {
			continue
		}
		if err := sys.GetStats(path, stats); err != nil {
			return nil, err
		}
	}

	return stats, nil
}

func (m *Manager) Set(container *configs.Config) error {
	for name, path := range m.Paths {
		sys, ok := subsystems[name]
		if !ok || !cgroups.PathExists(path) {
			continue
		}
		if err := sys.Set(path, container.Cgroups); err != nil {
			return err
		}
	}

	return nil
}

func getUnitName(c *configs.Cgroup) string {
	return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name)
}

// Atm we can't use the systemd device support because of two missing things:
// * Support for wildcards to allow mknod on any device
// * Support for wildcards to allow /dev/pts support
//
// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
// in wide use. When both these are availalable we will be able to switch, but need to keep the old
// implementation for backwards compat.
//
// Note: we can't use systemd to set up the initial limits, and then change the cgroup
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
// This happens at least for v208 when any sibling unit is started.
func joinDevices(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "devices")
	if err != nil {
		return err
	}

	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
		return err
	}

	if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
		return err
	}

	if !c.AllowAllDevices {
		if err := writeFile(path, "devices.deny", "a"); err != nil {
			return err
		}
	}
	for _, dev := range c.AllowedDevices {
		if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
			return err
		}
	}
	return nil
}

// Symmetrical public function to update device based cgroups.  Also available
// in the fs implementation.
func ApplyDevices(c *configs.Cgroup, pid int) error {
	return joinDevices(c, pid)
}

func joinMemory(c *configs.Cgroup, pid int) error {
	memorySwap := c.MemorySwap

	if memorySwap == 0 {
		// By default, MemorySwap is set to twice the size of RAM.
		memorySwap = c.Memory * 2
	}

	path, err := getSubsystemPath(c, "memory")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filepath.Join(path, "memory.memsw.limit_in_bytes"), []byte(strconv.FormatInt(memorySwap, 10)), 0700)
}

// systemd does not atm set up the cpuset controller, so we must manually
// join it. Additionally that is a very finicky controller where each
// level must have a full setup as the default for a new directory is "no cpus"
func joinCpuset(c *configs.Cgroup, pid int) error {
	path, err := getSubsystemPath(c, "cpuset")
	if err != nil {
		return err
	}

	s := &fs.CpusetGroup{}

	return s.ApplyDir(path, c, pid)
}
<|endoftext|>


<commit_before>package bootstrap

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/tinzenite/model"
	"github.com/tinzenite/shared"
)

type chaninterface struct {
	// reference back to Bootstrap
	boot *Bootstrap
	// model reference NOTE: once created it means that a bootstrap is in progress! Also it is CORRECT and DESIRED that the model is not stored between runs.
	model *model.Model
	// we need to remember all update messages so that we can apply them when received
	messages map[string]*shared.UpdateMessage
}

func createChanInterface(boot *Bootstrap) *chaninterface {
	return &chaninterface{
		boot:     boot,
		model:    nil,
		messages: make(map[string]*shared.UpdateMessage)}
}

func (c *chaninterface) OnFriendRequest(address, message string) {
	log.Println("NewConnection:", address[:8], "ignoring!")
}

func (c *chaninterface) OnMessage(address, message string) {
	log.Println("Bootstrap received message from", address[:8], ":", message)
}

func (c *chaninterface) OnAllowFile(address, name string) (bool, string) {
	filename := address + "." + name
	return true, c.boot.path + "/" + shared.TINZENITEDIR + "/" + shared.RECEIVINGDIR + "/" + filename
}

func (c *chaninterface) OnFileReceived(address, path, name string) {
	// split filename to get identification
	check := strings.Split(name, ".")[0]
	identification := strings.Split(name, ".")[1]
	if check != address {
		log.Println("Filename is mismatched!")
		return
	}
	// whether we allow accepting a file or model depends on whether we already have a model here...
	if c.model != nil {
		// safe guard
		if len(c.messages) == 0 {
			log.Println("No update messages available! Ignoring file.")
			return
		}
		err := c.onFile(path, identification)
		if err != nil {
			log.Println("onFile:", err)
		}
	} else {
		// safe guard
		if identification != shared.IDMODEL {
			log.Println("Expecting model! Ignoring file.")
			return
		}
		log.Println("Receiving model!") // <-- should only be called once!
		// no need to keep sending check in backgronud
		c.boot.stop <- false
		// go due it
		err := c.onModel(address, path)
		if err != nil {
			log.Println("onModel:", err)
		}
	}
}

func (c *chaninterface) OnFileCanceled(address, path string) {
	log.Println("File transfer was canceled by " + address[:8] + "!")
}

func (c *chaninterface) OnConnected(address string) {
	log.Println("Connected:", address[:8])
}

// ---------------------- NO CALLBACKS BEYOND THIS POINT -----------------------

func (c *chaninterface) onModel(address, path string) error {
	// read model file and remove it
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	err = os.Remove(path)
	if err != nil {
		log.Println("Failed to remove temp model file:", err)
		// not strictly critical so no return here
	}
	// unmarshal
	foreignModel := &shared.ObjectInfo{}
	err = json.Unmarshal(data, foreignModel)
	if err != nil {
		return err
	}
	// make a model of the local stuff
	m, err := model.Create(c.boot.path, c.boot.peer.Identification)
	if err != nil {
		return err
	}
	c.model = m
	// apply what is already here
	err = c.model.Update()
	if err != nil {
		return err
	}
	// get difference in updates
	var updateLists []*shared.UpdateMessage
	updateLists, err = c.model.Bootstrap(foreignModel)
	if err != nil {
		return err
	}
	log.Println("Need to apply", len(updateLists), "updates.")
	// pretend that the updatemessage came from outside here
	for _, um := range updateLists {
		// directories can be applied directly
		if um.Object.Directory {
			dirPath := m.Root + "/" + um.Object.Path
			// if the dir doesn't exist, make it
			if exists, _ := shared.DirectoryExists(dirPath); !exists {
				err := shared.MakeDirectory(dirPath)
				if err != nil {
					log.Println("Failed applying dir:", err)
				}
			}
			// apply to model
			err = c.model.ApplyUpdateMessage(um)
			// ignore merge conflicts as they are to be overwritten anyway
			if err != nil && err != shared.ErrConflict {
				return err
			}
			continue
		}
		// files must be fetched first, so:
		// we have to remember the update messages because we'll need to apply them
		c.messages[um.Object.Identification] = um
		// create & modify must first fetch file
		rm := shared.CreateRequestMessage(shared.ReObject, um.Object.Identification)
		// request file and apply update on success
		c.boot.channel.Send(address, rm.JSON())
	}
	return nil
}

func (c *chaninterface) onFile(path, identification string) error {
	// see if we have a corresponding update message
	um, exists := c.messages[identification]
	if !exists {
		log.Println("Can not apply file", identification, "!")
		return os.Remove(path)
	}
	// remove from list since we're applying it
	delete(c.messages, identification)
	// rename to correct name for model
	err := os.Rename(path, c.boot.path+"/"+shared.TINZENITEDIR+"/"+shared.TEMPDIR+"/"+identification)
	if err != nil {
		return err
	}
	// apply
	err = c.model.ApplyUpdateMessage(um)
	// ignore merge conflicts as they are to be overwritten anyway
	if err != nil && err != shared.ErrConflict {
		return err
	}
	// detect when done to call success callback
	if len(c.messages) == 0 {
		// write directory to DIRECTORYLIST because it is now a valid TINZENITEDIR
		err := shared.WriteDirectoryList(c.boot.path)
		if err != nil {
			log.Println("Failed to write path to", shared.DIRECTORYLIST, "!")
			// not a critical error but log in case clients can't find the dir
		}
		// notify of done
		if c.boot.onDone != nil {
			c.boot.onDone()
		} else {
			log.Println("onDone is nil!")
		}
		/* NOTE: it is important that if the bootstrap was successful, DO NOT
		CALL boot.Close() from within this method! */
		// done so return nil
		return nil
	}
	return nil
}
<commit_msg>adapted model storage path<commit_after>package bootstrap

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/tinzenite/model"
	"github.com/tinzenite/shared"
)

type chaninterface struct {
	// reference back to Bootstrap
	boot *Bootstrap
	// model reference NOTE: once created it means that a bootstrap is in progress! Also it is CORRECT and DESIRED that the model is not stored between runs.
	model *model.Model
	// we need to remember all update messages so that we can apply them when received
	messages map[string]*shared.UpdateMessage
}

func createChanInterface(boot *Bootstrap) *chaninterface {
	return &chaninterface{
		boot:     boot,
		model:    nil,
		messages: make(map[string]*shared.UpdateMessage)}
}

func (c *chaninterface) OnFriendRequest(address, message string) {
	log.Println("NewConnection:", address[:8], "ignoring!")
}

func (c *chaninterface) OnMessage(address, message string) {
	log.Println("Bootstrap received message from", address[:8], ":", message)
}

func (c *chaninterface) OnAllowFile(address, name string) (bool, string) {
	filename := address + "." + name
	return true, c.boot.path + "/" + shared.TINZENITEDIR + "/" + shared.RECEIVINGDIR + "/" + filename
}

func (c *chaninterface) OnFileReceived(address, path, name string) {
	// split filename to get identification
	check := strings.Split(name, ".")[0]
	identification := strings.Split(name, ".")[1]
	if check != address {
		log.Println("Filename is mismatched!")
		return
	}
	// whether we allow accepting a file or model depends on whether we already have a model here...
	if c.model != nil {
		// safe guard
		if len(c.messages) == 0 {
			log.Println("No update messages available! Ignoring file.")
			return
		}
		err := c.onFile(path, identification)
		if err != nil {
			log.Println("onFile:", err)
		}
	} else {
		// safe guard
		if identification != shared.IDMODEL {
			log.Println("Expecting model! Ignoring file.")
			return
		}
		log.Println("Receiving model!") // <-- should only be called once!
		// no need to keep sending check in backgronud
		c.boot.stop <- false
		// go due it
		err := c.onModel(address, path)
		if err != nil {
			log.Println("onModel:", err)
		}
	}
}

func (c *chaninterface) OnFileCanceled(address, path string) {
	log.Println("File transfer was canceled by " + address[:8] + "!")
}

func (c *chaninterface) OnConnected(address string) {
	log.Println("Connected:", address[:8])
}

// ---------------------- NO CALLBACKS BEYOND THIS POINT -----------------------

func (c *chaninterface) onModel(address, path string) error {
	// read model file and remove it
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	err = os.Remove(path)
	if err != nil {
		log.Println("Failed to remove temp model file:", err)
		// not strictly critical so no return here
	}
	// unmarshal
	foreignModel := &shared.ObjectInfo{}
	err = json.Unmarshal(data, foreignModel)
	if err != nil {
		return err
	}
	// make a model of the local stuff
	storePath := c.boot.path + "/" + shared.TINZENITEDIR + "/" + shared.LOCALDIR + "/" + shared.MODELJSON
	m, err := model.Create(c.boot.path, c.boot.peer.Identification, storePath)
	if err != nil {
		return err
	}
	c.model = m
	// apply what is already here
	err = c.model.Update()
	if err != nil {
		return err
	}
	// get difference in updates
	var updateLists []*shared.UpdateMessage
	updateLists, err = c.model.Bootstrap(foreignModel)
	if err != nil {
		return err
	}
	log.Println("Need to apply", len(updateLists), "updates.")
	// pretend that the updatemessage came from outside here
	for _, um := range updateLists {
		// directories can be applied directly
		if um.Object.Directory {
			dirPath := m.Root + "/" + um.Object.Path
			// if the dir doesn't exist, make it
			if exists, _ := shared.DirectoryExists(dirPath); !exists {
				err := shared.MakeDirectory(dirPath)
				if err != nil {
					log.Println("Failed applying dir:", err)
				}
			}
			// apply to model
			err = c.model.ApplyUpdateMessage(um)
			// ignore merge conflicts as they are to be overwritten anyway
			if err != nil && err != shared.ErrConflict {
				return err
			}
			continue
		}
		// files must be fetched first, so:
		// we have to remember the update messages because we'll need to apply them
		c.messages[um.Object.Identification] = um
		// create & modify must first fetch file
		rm := shared.CreateRequestMessage(shared.ReObject, um.Object.Identification)
		// request file and apply update on success
		c.boot.channel.Send(address, rm.JSON())
	}
	return nil
}

func (c *chaninterface) onFile(path, identification string) error {
	// see if we have a corresponding update message
	um, exists := c.messages[identification]
	if !exists {
		log.Println("Can not apply file", identification, "!")
		return os.Remove(path)
	}
	// remove from list since we're applying it
	delete(c.messages, identification)
	// rename to correct name for model
	err := os.Rename(path, c.boot.path+"/"+shared.TINZENITEDIR+"/"+shared.TEMPDIR+"/"+identification)
	if err != nil {
		return err
	}
	// apply
	err = c.model.ApplyUpdateMessage(um)
	// ignore merge conflicts as they are to be overwritten anyway
	if err != nil && err != shared.ErrConflict {
		return err
	}
	// detect when done to call success callback
	if len(c.messages) == 0 {
		// write directory to DIRECTORYLIST because it is now a valid TINZENITEDIR
		err := shared.WriteDirectoryList(c.boot.path)
		if err != nil {
			log.Println("Failed to write path to", shared.DIRECTORYLIST, "!")
			// not a critical error but log in case clients can't find the dir
		}
		// notify of done
		if c.boot.onDone != nil {
			c.boot.onDone()
		} else {
			log.Println("onDone is nil!")
		}
		/* NOTE: it is important that if the bootstrap was successful, DO NOT
		CALL boot.Close() from within this method! */
		// done so return nil
		return nil
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package mqtt

import (
	"time"

	"github.com/TheThingsNetwork/ttn/core/types"
)

// JSONTime is a time.Time that marshals to/from RFC3339Nano format
type JSONTime time.Time

// MarshalText implements the encoding.TextMarshaler interface
func (t JSONTime) MarshalText() ([]byte, error) {
	if time.Time(t).IsZero() || time.Time(t).Unix() == 0 {
		return []byte{}, nil
	}
	stamp := time.Time(t).UTC().Format(time.RFC3339Nano)
	return []byte(stamp), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface
func (t *JSONTime) UnmarshalText(text []byte) error {
	if len(text) == 0 {
		*t = JSONTime{}
		return nil
	}
	time, err := time.Parse(time.RFC3339Nano, string(text))
	if err != nil {
		return err
	}
	*t = JSONTime(time)
	return nil
}

// BuildTime builds a new JSONTime
func BuildTime(unixNano int64) JSONTime {
	if unixNano == 0 {
		return JSONTime{}
	}
	return JSONTime(time.Unix(0, 0).Add(time.Duration(unixNano)).UTC())
}

// LocationMetadata contains GPS coordinates
type LocationMetadata struct {
	Altitude  int32   `json:"altitude,omitempty"`
	Longitude float32 `json:"longitude,omitempty"`
	Latitude  float32 `json:"latitude,omitempty"`
}

// GatewayMetadata contains metadata for each gateway that received a message
type GatewayMetadata struct {
	GtwID     string   `json:"gtw_id,omitempty"`
	Timestamp uint32   `json:"timestamp,omitempty"`
	Time      JSONTime `json:"time,omitempty"`
	Channel   uint32   `json:"channel,omitempty"`
	RSSI      float32  `json:"rssi,omitempty"`
	SNR       float32  `json:"snr,omitempty"`
	RFChain   uint32   `json:"rf_chain,omitempty"`
	LocationMetadata
}

// Metadata contains metadata of a message
type Metadata struct {
	Time       JSONTime          `json:"time,omitempty,omitempty"`
	Frequency  float32           `json:"frequency,omitempty"`
	Modulation string            `json:"modulation,omitempty"`
	DataRate   string            `json:"data_rate,omitempty"`
	Bitrate    uint32            `json:"bit_rate,omitempty"`
	CodingRate string            `json:"coding_rate,omitempty"`
	Gateways   []GatewayMetadata `json:"gateways,omitempty"`
	LocationMetadata
}

// UplinkMessage represents an application-layer uplink message
type UplinkMessage struct {
	AppID         string                 `json:"app_id,omitempty"`
	DevID         string                 `json:"dev_id,omitempty"`
	FPort         uint8                  `json:"port"`
	FCnt          uint32                 `json:"counter"`
	PayloadRaw    []byte                 `json:"payload_raw"`
	PayloadFields map[string]interface{} `json:"payload_fields,omitempty"`
	Metadata      Metadata               `json:"metadata,omitempty"`
}

// DownlinkMessage represents an application-layer downlink message
type DownlinkMessage struct {
	AppID         string                 `json:"app_id,omitempty"`
	DevID         string                 `json:"dev_id,omitempty"`
	FPort         uint8                  `json:"port"`
	PayloadRaw    []byte                 `json:"payload_raw,omitempty"`
	PayloadFields map[string]interface{} `json:"payload_fields,omitempty"`
}

// Activation messages are used to notify application of a device activation
type Activation struct {
	AppID    string        `json:"app_id,omitempty"`
	DevID    string        `json:"dev_id,omitempty"`
	AppEUI   types.AppEUI  `json:"app_eui,omitempty"`
	DevEUI   types.DevEUI  `json:"dev_eui,omitempty"`
	DevAddr  types.DevAddr `json:"dev_addr,omitempty"`
	Metadata Metadata      `json:"metadata,omitempty"`
}
<commit_msg>Resolve #307<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package mqtt

import (
	"time"

	"github.com/TheThingsNetwork/ttn/core/types"
)

// JSONTime is a time.Time that marshals to/from RFC3339Nano format
type JSONTime time.Time

// MarshalText implements the encoding.TextMarshaler interface
func (t JSONTime) MarshalText() ([]byte, error) {
	if time.Time(t).IsZero() || time.Time(t).Unix() == 0 {
		return []byte{}, nil
	}
	stamp := time.Time(t).UTC().Format(time.RFC3339Nano)
	return []byte(stamp), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface
func (t *JSONTime) UnmarshalText(text []byte) error {
	if len(text) == 0 {
		*t = JSONTime{}
		return nil
	}
	time, err := time.Parse(time.RFC3339Nano, string(text))
	if err != nil {
		return err
	}
	*t = JSONTime(time)
	return nil
}

// BuildTime builds a new JSONTime
func BuildTime(unixNano int64) JSONTime {
	if unixNano == 0 {
		return JSONTime{}
	}
	return JSONTime(time.Unix(0, 0).Add(time.Duration(unixNano)).UTC())
}

// LocationMetadata contains GPS coordinates
type LocationMetadata struct {
	Altitude  int32   `json:"altitude,omitempty"`
	Longitude float32 `json:"longitude,omitempty"`
	Latitude  float32 `json:"latitude,omitempty"`
}

// GatewayMetadata contains metadata for each gateway that received a message
type GatewayMetadata struct {
	GtwID     string   `json:"gtw_id,omitempty"`
	Timestamp uint32   `json:"timestamp,omitempty"`
	Time      JSONTime `json:"time,omitempty"`
	Channel   uint32   `json:"channel"`
	RSSI      float32  `json:"rssi,omitempty"`
	SNR       float32  `json:"snr,omitempty"`
	RFChain   uint32   `json:"rf_chain,omitempty"`
	LocationMetadata
}

// Metadata contains metadata of a message
type Metadata struct {
	Time       JSONTime          `json:"time,omitempty,omitempty"`
	Frequency  float32           `json:"frequency,omitempty"`
	Modulation string            `json:"modulation,omitempty"`
	DataRate   string            `json:"data_rate,omitempty"`
	Bitrate    uint32            `json:"bit_rate,omitempty"`
	CodingRate string            `json:"coding_rate,omitempty"`
	Gateways   []GatewayMetadata `json:"gateways,omitempty"`
	LocationMetadata
}

// UplinkMessage represents an application-layer uplink message
type UplinkMessage struct {
	AppID         string                 `json:"app_id,omitempty"`
	DevID         string                 `json:"dev_id,omitempty"`
	FPort         uint8                  `json:"port"`
	FCnt          uint32                 `json:"counter"`
	PayloadRaw    []byte                 `json:"payload_raw"`
	PayloadFields map[string]interface{} `json:"payload_fields,omitempty"`
	Metadata      Metadata               `json:"metadata,omitempty"`
}

// DownlinkMessage represents an application-layer downlink message
type DownlinkMessage struct {
	AppID         string                 `json:"app_id,omitempty"`
	DevID         string                 `json:"dev_id,omitempty"`
	FPort         uint8                  `json:"port"`
	PayloadRaw    []byte                 `json:"payload_raw,omitempty"`
	PayloadFields map[string]interface{} `json:"payload_fields,omitempty"`
}

// Activation messages are used to notify application of a device activation
type Activation struct {
	AppID    string        `json:"app_id,omitempty"`
	DevID    string        `json:"dev_id,omitempty"`
	AppEUI   types.AppEUI  `json:"app_eui,omitempty"`
	DevEUI   types.DevEUI  `json:"dev_eui,omitempty"`
	DevAddr  types.DevAddr `json:"dev_addr,omitempty"`
	Metadata Metadata      `json:"metadata,omitempty"`
}
<|endoftext|>


<commit_before>package pop

// Query is the main value that is used to build up a query
// to be executed against the `Connection`.
type Query struct {
	RawSQL                  *clause
	limitResults            int
	whereClauses            clauses
	orderClauses            clauses
	fromClauses             fromClauses
	belongsToThroughClauses belongsToThroughClauses
	joinClauses             joinClauses
	Paginator               *Paginator
	Connection              *Connection
}

// RawQuery will override the query building feature of Pop and will use
// whatever query you want to execute against the `Connection`. You can continue
// to use the `?` argument syntax.
//
//	c.RawQuery("select * from foo where id = ?", 1)
func (c *Connection) RawQuery(stmt string, args ...interface{}) *Query {
	return Q(c).RawQuery(stmt, args...)
}

// RawQuery will override the query building feature of Pop and will use
// whatever query you want to execute against the `Connection`. You can continue
// to use the `?` argument syntax.
//
//	q.RawQuery("select * from foo where id = ?", 1)
func (q *Query) RawQuery(stmt string, args ...interface{}) *Query {
	q.RawSQL = &clause{stmt, args}
	return q
}

func (q *Query) Order(stmt string) *Query {
	q.orderClauses = append(q.orderClauses, clause{stmt, []interface{}{}})
	return q
}

func (q *Query) Join(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"JOIN", table, as, on, args})
	return q
}

func (q *Query) LeftJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"LEFT JOIN", table, as, on, args})
	return q
}

func (q *Query) RightJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"RIGHT JOIN", table, as, on, args})
	return q
}

func (q *Query) LeftOuterJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"LEFT OUTER JOIN", table, as, on, args})
	return q
}

func (q *Query) RightOuterJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"RIGHT OUTER JOIN", table, as, on, args})
	return q
}

func (q *Query) LeftInnerJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"LEFT INNER JOIN", table, as, on, args})
	return q
}

func (q *Query) RightInnerJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"RIGHT INNER JOIN", table, as, on, args})
	return q
}

// Where will append a where clause to the query. You may use `?` in place of
// arguments.
//
// 	c.Where("id = ?", 1)
func (c *Connection) Where(stmt string, args ...interface{}) *Query {
	return Q(c).Where(stmt, args...)
}

// Where will append a where clause to the query. You may use `?` in place of
// arguments.
//
// 	q.Where("id = ?", 1)
func (q *Query) Where(stmt string, args ...interface{}) *Query {
	q.whereClauses = append(q.whereClauses, clause{stmt, args})
	return q
}

// Order will append an order clause to the query.
//
// 	c.Order("name desc")
func (c *Connection) Order(stmt string) *Query {
	return Q(c).Order(stmt)
}

// Order will append an order clause to the query.
//
// 	q.Order("name desc")

// Limit will add a limit clause to the query.
func (c *Connection) Limit(limit int) *Query {
	return Q(c).Limit(limit)
}

// Limit will add a limit clause to the query.
func (q *Query) Limit(limit int) *Query {
	q.limitResults = limit
	return q
}

// Q will create a new "empty" query from the current connection.
func Q(c *Connection) *Query {
	return &Query{
		RawSQL:     &clause{},
		Connection: c,
	}
}

// ToSQL will generate SQL and the appropriate arguments for that SQL
// from the `Model` passed in.
func (q Query) ToSQL(model *Model, addColumns ...string) (string, []interface{}) {
	sb := q.toSQLBuilder(model, addColumns...)
	return sb.String(), sb.Args()
}

// ToSQLBuilder returns a new `SQLBuilder` that can be used to generate SQL,
// get arguments, and more.
func (q Query) toSQLBuilder(model *Model, addColumns ...string) *sqlBuilder {
	return newSQLBuilder(q, model, addColumns...)
}
<commit_msg>realign code<commit_after>package pop

// Query is the main value that is used to build up a query
// to be executed against the `Connection`.
type Query struct {
	RawSQL                  *clause
	limitResults            int
	whereClauses            clauses
	orderClauses            clauses
	fromClauses             fromClauses
	belongsToThroughClauses belongsToThroughClauses
	joinClauses             joinClauses
	Paginator               *Paginator
	Connection              *Connection
}

// RawQuery will override the query building feature of Pop and will use
// whatever query you want to execute against the `Connection`. You can continue
// to use the `?` argument syntax.
//
//	c.RawQuery("select * from foo where id = ?", 1)
func (c *Connection) RawQuery(stmt string, args ...interface{}) *Query {
	return Q(c).RawQuery(stmt, args...)
}

// RawQuery will override the query building feature of Pop and will use
// whatever query you want to execute against the `Connection`. You can continue
// to use the `?` argument syntax.
//
//	q.RawQuery("select * from foo where id = ?", 1)
func (q *Query) RawQuery(stmt string, args ...interface{}) *Query {
	q.RawSQL = &clause{stmt, args}
	return q
}

func (q *Query) Join(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"JOIN", table, as, on, args})
	return q
}

func (q *Query) LeftJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"LEFT JOIN", table, as, on, args})
	return q
}

func (q *Query) RightJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"RIGHT JOIN", table, as, on, args})
	return q
}

func (q *Query) LeftOuterJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"LEFT OUTER JOIN", table, as, on, args})
	return q
}

func (q *Query) RightOuterJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"RIGHT OUTER JOIN", table, as, on, args})
	return q
}

func (q *Query) LeftInnerJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"LEFT INNER JOIN", table, as, on, args})
	return q
}

func (q *Query) RightInnerJoin(table string, as string, on []string, args ...interface{}) *Query {
	q.joinClauses = append(q.joinClauses, joinClause{"RIGHT INNER JOIN", table, as, on, args})
	return q
}

// Where will append a where clause to the query. You may use `?` in place of
// arguments.
//
// 	c.Where("id = ?", 1)
func (c *Connection) Where(stmt string, args ...interface{}) *Query {
	return Q(c).Where(stmt, args...)
}

// Where will append a where clause to the query. You may use `?` in place of
// arguments.
//
// 	q.Where("id = ?", 1)
func (q *Query) Where(stmt string, args ...interface{}) *Query {
	q.whereClauses = append(q.whereClauses, clause{stmt, args})
	return q
}

// Order will append an order clause to the query.
//
// 	c.Order("name desc")
func (c *Connection) Order(stmt string) *Query {
	return Q(c).Order(stmt)
}

// 	q.Order("name desc")
func (q *Query) Order(stmt string) *Query {
	q.orderClauses = append(q.orderClauses, clause{stmt, []interface{}{}})
	return q
}

// Limit will add a limit clause to the query.
func (c *Connection) Limit(limit int) *Query {
	return Q(c).Limit(limit)
}

// Limit will add a limit clause to the query.
func (q *Query) Limit(limit int) *Query {
	q.limitResults = limit
	return q
}

// Q will create a new "empty" query from the current connection.
func Q(c *Connection) *Query {
	return &Query{
		RawSQL:     &clause{},
		Connection: c,
	}
}

// ToSQL will generate SQL and the appropriate arguments for that SQL
// from the `Model` passed in.
func (q Query) ToSQL(model *Model, addColumns ...string) (string, []interface{}) {
	sb := q.toSQLBuilder(model, addColumns...)
	return sb.String(), sb.Args()
}

// ToSQLBuilder returns a new `SQLBuilder` that can be used to generate SQL,
// get arguments, and more.
func (q Query) toSQLBuilder(model *Model, addColumns ...string) *sqlBuilder {
	return newSQLBuilder(q, model, addColumns...)
}
<|endoftext|>


<commit_before>package kip

import "gopkg.in/mgo.v2"

type Query struct {
	mgo_query *mgo.Query
}

func (q *Query) Limit(n int) *Query {
	q.mgo_query = q.mgo_query.Limit(n)
	return q
}

func (q *Query) Select(selector interface{}) *Query {
	q.mgo_query = q.mgo_query.Select(selector)
	return q
}

func (q *Query) Skip(n int) *Query {
	q.mgo_query = q.mgo_query.Skip(n)
	return q
}

func (q *Query) Snapshot() *Query {
	q.mgo_query = q.mgo_query.Snapshot()
	return q
}

func (q *Query) Sort(fields ...string) *Query {
	q.mgo_query = q.mgo_query.Sort(fields...)
	return q
}

// Finalizers
func (q *Query) All(result interface{}) error {
	return q.mgo_query.All(result)
}

func (q *Query) Count() (n int, err error) {
	return q.mgo_query.Count()
}

func (q *Query) Iter() {
	// TODO!
}

func (q *Query) One() {
	// TODO!
	// Already implemented by Instance
}
<commit_msg>Implement query.Iter<commit_after>package kip

import "gopkg.in/mgo.v2"

type Query struct {
	mgo_query *mgo.Query
}

func (q *Query) Limit(n int) *Query {
	q.mgo_query = q.mgo_query.Limit(n)
	return q
}

func (q *Query) Select(selector interface{}) *Query {
	q.mgo_query = q.mgo_query.Select(selector)
	return q
}

func (q *Query) Skip(n int) *Query {
	q.mgo_query = q.mgo_query.Skip(n)
	return q
}

func (q *Query) Snapshot() *Query {
	q.mgo_query = q.mgo_query.Snapshot()
	return q
}

func (q *Query) Sort(fields ...string) *Query {
	q.mgo_query = q.mgo_query.Sort(fields...)
	return q
}

// Finalizers
func (q *Query) All(result interface{}) error {
	return q.mgo_query.All(result)
}

func (q *Query) Count() (n int, err error) {
	return q.mgo_query.Count()
}

func (q *Query) Iter() *mgo.Iter {
	return q.mgo_query.Iter()
}

func (q *Query) One() {
	// TODO!
	// Already implemented by Instance
}
<|endoftext|>