<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"

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

const (
	nautilusImage            = "gcr.io/google_containers/update-demo:nautilus"
	kittenImage              = "gcr.io/google_containers/update-demo:kitten"
	updateDemoSelector       = "name=update-demo"
	updateDemoContainer      = "update-demo"
	frontendSelector         = "name=frontend"
	redisMasterSelector      = "name=redis-master"
	redisSlaveSelector       = "name=redis-slave"
	kubectlProxyPort         = 8011
	guestbookStartupTimeout  = 10 * time.Minute
	guestbookResponseTimeout = 3 * time.Minute
	simplePodSelector        = "name=nginx"
	simplePodName            = "nginx"
	nginxDefaultOutput       = "Welcome to nginx!"
	simplePodPort            = 80
)

var (
	portForwardRegexp = regexp.MustCompile("Forwarding from 127.0.0.1:([0-9]+) -> 80")
)

var _ = Describe("Kubectl client", func() {
	defer GinkgoRecover()
	var c *client.Client
	var ns string
	var testingNs *api.Namespace
	BeforeEach(func() {
		var err error
		c, err = loadClient()
		expectNoError(err)
		testingNs, err = createTestingNS("kubectl", c)
		ns = testingNs.Name
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		By(fmt.Sprintf("Destroying namespace for this suite %v", ns))
		if err := c.Namespaces().Delete(ns); err != nil {
			Failf("Couldn't delete ns %s", err)
		}
	})

	Describe("Update Demo", func() {
		var updateDemoRoot, nautilusPath, kittenPath string
		BeforeEach(func() {
			updateDemoRoot = filepath.Join(testContext.RepoRoot, "examples/update-demo")
			nautilusPath = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
			kittenPath = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
		})

		It("should create and stop a replication controller", func() {
			defer cleanup(nautilusPath, ns, updateDemoSelector)

			By("creating a replication controller")
			runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
		})

		It("should scale a replication controller", func() {
			defer cleanup(nautilusPath, ns, updateDemoSelector)

			By("creating a replication controller")
			runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
			By("scaling down the replication controller")
			runKubectl("scale", "rc", "update-demo-nautilus", "--replicas=1", fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 1, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
			By("scaling up the replication controller")
			runKubectl("scale", "rc", "update-demo-nautilus", "--replicas=2", fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
		})

		It("should do a rolling update of a replication controller", func() {
			By("creating the initial replication controller")
			runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
			By("rolling-update to new replication controller")
			runKubectl("rolling-update", "update-demo-nautilus", "--update-period=1s", "-f", kittenPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, kittenImage, 2, "update-demo", updateDemoSelector, getUDData("kitten.jpg", ns), ns)
			// Everything will hopefully be cleaned up when the namespace is deleted.
		})
	})

	Describe("Guestbook application", func() {
		var guestbookPath string

		BeforeEach(func() {
			guestbookPath = filepath.Join(testContext.RepoRoot, "examples/guestbook")

			// requires ExternalLoadBalancer support
			SkipUnlessProviderIs("gce", "gke", "aws")
		})

		It("should create and stop a working application", func() {
			defer cleanup(guestbookPath, ns, frontendSelector, redisMasterSelector, redisSlaveSelector)

			By("creating all guestbook components")
			runKubectl("create", "-f", guestbookPath, fmt.Sprintf("--namespace=%v", ns))

			By("validating guestbook app")
			validateGuestbookApp(c, ns)
		})
	})

	Describe("Simple pod", func() {
		var podPath string

		BeforeEach(func() {
			podPath = filepath.Join(testContext.RepoRoot, "examples/pod.yaml")
			By("creating the pod")
			runKubectl("create", "-f", podPath, fmt.Sprintf("--namespace=%v", ns))
			checkPodsRunningReady(c, ns, []string{simplePodName}, podStartTimeout)

		})
		AfterEach(func() {
			cleanup(podPath, ns, simplePodSelector)
		})

		It("should support exec", func() {
			By("executing a command in the container")
			execOutput := runKubectl("exec", fmt.Sprintf("--namespace=%v", ns), simplePodName, "echo", "running", "in", "container")
			expectedExecOutput := "running in container"
			if execOutput != expectedExecOutput {
				Failf("Unexpected kubectl exec output. Wanted '%s', got '%s'", execOutput, expectedExecOutput)
			}
		})
		It("should support port-forward", func() {
			By("forwarding the container port to a local port")
			cmd := kubectlCmd("port-forward", fmt.Sprintf("--namespace=%v", ns), "-p", simplePodName, fmt.Sprintf(":%d", simplePodPort))
			defer func() {
				if err := cmd.Process.Kill(); err != nil {
					Logf("ERROR failed to kill kubectl port-forward command! The process may leak")
				}
			}()
			// This is somewhat ugly but is the only way to retrieve the port that was picked
			// by the port-forward command. We don't want to hard code the port as we have no
			// way of guaranteeing we can pick one that isn't in use, particularly on Jenkins.
			Logf("starting port-forward command and streaming output")
			stdout, stderr, err := startCmdAndStreamOutput(cmd)
			if err != nil {
				Failf("Failed to start port-forward command: %v", err)
			}
			defer stdout.Close()
			defer stderr.Close()

			buf := make([]byte, 128)
			var n int
			Logf("reading from `kubectl port-forward` command's stderr")
			if n, err = stderr.Read(buf); err != nil {
				Failf("Failed to read from kubectl port-forward stderr: %v", err)
			}
			portForwardOutput := string(buf[:n])
			match := portForwardRegexp.FindStringSubmatch(portForwardOutput)
			if len(match) != 2 {
				Failf("Failed to parse kubectl port-forward output: %s", portForwardOutput)
			}
			By("curling local port output")
			localAddr := fmt.Sprintf("http://localhost:%s", match[1])
			body, err := curl(localAddr)
			if err != nil {
				Failf("Failed http.Get of forwarded port (%s): %v", localAddr, err)
			}
			if !strings.Contains(body, nginxDefaultOutput) {
				Failf("Container port output missing expected value. Wanted:'%s', got: %s", nginxDefaultOutput, body)
			}
		})
	})

	Describe("Kubectl label", func() {
		var podPath string
		var nsFlag string
		BeforeEach(func() {
			podPath = filepath.Join(testContext.RepoRoot, "examples/pod.yaml")
			By("creating the pod")
			nsFlag = fmt.Sprintf("--namespace=%v", ns)
			runKubectl("create", "-f", podPath, nsFlag)
			checkPodsRunningReady(c, ns, []string{simplePodName}, podStartTimeout)
		})
		AfterEach(func() {
			cleanup(podPath, ns, simplePodSelector)
		})

		It("should update the label on a resource", func() {
			labelName := "testing-label"
			labelValue := "testing-label-value"

			By("adding the label " + labelName + " with value " + labelValue + " to a pod")
			runKubectl("label", "pods", simplePodName, labelName+"="+labelValue, nsFlag)
			By("verifying the pod has the label " + labelName + " with the value " + labelValue)
			output := runKubectl("get", "pod", simplePodName, "-L", labelName, nsFlag)
			if !strings.Contains(output, labelValue) {
				Failf("Failed updating label " + labelName + " to the pod " + simplePodName)
			}

			By("removing the label " + labelName + " of a pod")
			runKubectl("label", "pods", simplePodName, labelName+"-", nsFlag)
			By("verifying the pod doesn't have the label " + labelName)
			output = runKubectl("get", "pod", simplePodName, "-L", labelName, nsFlag)
			if strings.Contains(output, labelValue) {
				Failf("Failed removing label " + labelName + " of the pod " + simplePodName)
			}
		})
	})

})

func curl(addr string) (string, error) {
	resp, err := http.Get(addr)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body[:]), nil
}

func validateGuestbookApp(c *client.Client, ns string) {
	Logf("Waiting for frontend to serve content.")
	if !waitForGuestbookResponse(c, "get", "", `{"data": ""}`, guestbookStartupTimeout, ns) {
		Failf("Frontend service did not start serving content in %v seconds.", guestbookStartupTimeout.Seconds())
	}

	Logf("Trying to add a new entry to the guestbook.")
	if !waitForGuestbookResponse(c, "set", "TestEntry", `{"message": "Updated"}`, guestbookResponseTimeout, ns) {
		Failf("Cannot added new entry in %v seconds.", guestbookResponseTimeout.Seconds())
	}

	Logf("Verifying that added entry can be retrieved.")
	if !waitForGuestbookResponse(c, "get", "", `{"data": "TestEntry"}`, guestbookResponseTimeout, ns) {
		Failf("Entry to guestbook wasn't correctly added in %v seconds.", guestbookResponseTimeout.Seconds())
	}
}

// Returns whether received expected response from guestbook on time.
func waitForGuestbookResponse(c *client.Client, cmd, arg, expectedResponse string, timeout time.Duration, ns string) bool {
	for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) {
		res, err := makeRequestToGuestbook(c, cmd, arg, ns)
		if err == nil && res == expectedResponse {
			return true
		}
	}
	return false
}

func makeRequestToGuestbook(c *client.Client, cmd, value string, ns string) (string, error) {
	result, err := c.Get().
		Prefix("proxy").
		Namespace(ns).
		Resource("services").
		Name("frontend").
		Suffix("/index.php").
		Param("cmd", cmd).
		Param("key", "messages").
		Param("value", value).
		Do().
		Raw()
	return string(result), err
}

type updateDemoData struct {
	Image string
}

// getUDData creates a validator function based on the input string (i.e. kitten.jpg).
// For example, if you send "kitten.jpg", this function veridies that the image jpg = kitten.jpg
// in the container's json field.
func getUDData(jpgExpected string, ns string) func(*client.Client, string) error {

	// getUDData validates data.json in the update-demo (returns nil if data is ok).
	return func(c *client.Client, podID string) error {
		Logf("validating pod %s", podID)
		body, err := c.Get().
			Prefix("proxy").
			Namespace(ns).
			Resource("pods").
			Name(podID).
			Suffix("data.json").
			Do().
			Raw()
		if err != nil {
			return err
		}
		Logf("got data: %s", body)
		var data updateDemoData
		if err := json.Unmarshal(body, &data); err != nil {
			return err
		}
		Logf("Unmarshalled json jpg/img => %s , expecting %s .", data, jpgExpected)
		if strings.Contains(data.Image, jpgExpected) {
			return nil
		} else {
			return errors.New(fmt.Sprintf("data served up in container is innaccurate, %s didn't contain %s", data, jpgExpected))
		}
	}
}
<commit_msg>E2E tests for kubectl logs and patch<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"

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

const (
	nautilusImage            = "gcr.io/google_containers/update-demo:nautilus"
	kittenImage              = "gcr.io/google_containers/update-demo:kitten"
	updateDemoSelector       = "name=update-demo"
	updateDemoContainer      = "update-demo"
	frontendSelector         = "name=frontend"
	redisMasterSelector      = "name=redis-master"
	redisSlaveSelector       = "name=redis-slave"
	kubectlProxyPort         = 8011
	guestbookStartupTimeout  = 10 * time.Minute
	guestbookResponseTimeout = 3 * time.Minute
	simplePodSelector        = "name=nginx"
	simplePodName            = "nginx"
	nginxDefaultOutput       = "Welcome to nginx!"
	simplePodPort            = 80
)

var (
	portForwardRegexp = regexp.MustCompile("Forwarding from 127.0.0.1:([0-9]+) -> 80")
)

var _ = Describe("Kubectl client", func() {
	defer GinkgoRecover()
	var c *client.Client
	var ns string
	var testingNs *api.Namespace
	BeforeEach(func() {
		var err error
		c, err = loadClient()
		expectNoError(err)
		testingNs, err = createTestingNS("kubectl", c)
		ns = testingNs.Name
		Expect(err).NotTo(HaveOccurred())
	})

	AfterEach(func() {
		By(fmt.Sprintf("Destroying namespace for this suite %v", ns))
		if err := c.Namespaces().Delete(ns); err != nil {
			Failf("Couldn't delete ns %s", err)
		}
	})

	Describe("Update Demo", func() {
		var updateDemoRoot, nautilusPath, kittenPath string
		BeforeEach(func() {
			updateDemoRoot = filepath.Join(testContext.RepoRoot, "examples/update-demo")
			nautilusPath = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
			kittenPath = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
		})

		It("should create and stop a replication controller", func() {
			defer cleanup(nautilusPath, ns, updateDemoSelector)

			By("creating a replication controller")
			runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
		})

		It("should scale a replication controller", func() {
			defer cleanup(nautilusPath, ns, updateDemoSelector)

			By("creating a replication controller")
			runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
			By("scaling down the replication controller")
			runKubectl("scale", "rc", "update-demo-nautilus", "--replicas=1", fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 1, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
			By("scaling up the replication controller")
			runKubectl("scale", "rc", "update-demo-nautilus", "--replicas=2", fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
		})

		It("should do a rolling update of a replication controller", func() {
			By("creating the initial replication controller")
			runKubectl("create", "-f", nautilusPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
			By("rolling-update to new replication controller")
			runKubectl("rolling-update", "update-demo-nautilus", "--update-period=1s", "-f", kittenPath, fmt.Sprintf("--namespace=%v", ns))
			validateController(c, kittenImage, 2, "update-demo", updateDemoSelector, getUDData("kitten.jpg", ns), ns)
			// Everything will hopefully be cleaned up when the namespace is deleted.
		})
	})

	Describe("Guestbook application", func() {
		var guestbookPath string

		BeforeEach(func() {
			guestbookPath = filepath.Join(testContext.RepoRoot, "examples/guestbook")

			// requires ExternalLoadBalancer support
			SkipUnlessProviderIs("gce", "gke", "aws")
		})

		It("should create and stop a working application", func() {
			defer cleanup(guestbookPath, ns, frontendSelector, redisMasterSelector, redisSlaveSelector)

			By("creating all guestbook components")
			runKubectl("create", "-f", guestbookPath, fmt.Sprintf("--namespace=%v", ns))

			By("validating guestbook app")
			validateGuestbookApp(c, ns)
		})
	})

	Describe("Simple pod", func() {
		var podPath string

		BeforeEach(func() {
			podPath = filepath.Join(testContext.RepoRoot, "examples/pod.yaml")
			By("creating the pod")
			runKubectl("create", "-f", podPath, fmt.Sprintf("--namespace=%v", ns))
			checkPodsRunningReady(c, ns, []string{simplePodName}, podStartTimeout)

		})
		AfterEach(func() {
			cleanup(podPath, ns, simplePodSelector)
		})

		It("should support exec", func() {
			By("executing a command in the container")
			execOutput := runKubectl("exec", fmt.Sprintf("--namespace=%v", ns), simplePodName, "echo", "running", "in", "container")
			expectedExecOutput := "running in container"
			if execOutput != expectedExecOutput {
				Failf("Unexpected kubectl exec output. Wanted '%s', got '%s'", execOutput, expectedExecOutput)
			}
		})
		It("should support port-forward", func() {
			By("forwarding the container port to a local port")
			cmd := kubectlCmd("port-forward", fmt.Sprintf("--namespace=%v", ns), "-p", simplePodName, fmt.Sprintf(":%d", simplePodPort))
			defer func() {
				if err := cmd.Process.Kill(); err != nil {
					Logf("ERROR failed to kill kubectl port-forward command! The process may leak")
				}
			}()
			// This is somewhat ugly but is the only way to retrieve the port that was picked
			// by the port-forward command. We don't want to hard code the port as we have no
			// way of guaranteeing we can pick one that isn't in use, particularly on Jenkins.
			Logf("starting port-forward command and streaming output")
			stdout, stderr, err := startCmdAndStreamOutput(cmd)
			if err != nil {
				Failf("Failed to start port-forward command: %v", err)
			}
			defer stdout.Close()
			defer stderr.Close()

			buf := make([]byte, 128)
			var n int
			Logf("reading from `kubectl port-forward` command's stderr")
			if n, err = stderr.Read(buf); err != nil {
				Failf("Failed to read from kubectl port-forward stderr: %v", err)
			}
			portForwardOutput := string(buf[:n])
			match := portForwardRegexp.FindStringSubmatch(portForwardOutput)
			if len(match) != 2 {
				Failf("Failed to parse kubectl port-forward output: %s", portForwardOutput)
			}
			By("curling local port output")
			localAddr := fmt.Sprintf("http://localhost:%s", match[1])
			body, err := curl(localAddr)
			if err != nil {
				Failf("Failed http.Get of forwarded port (%s): %v", localAddr, err)
			}
			if !strings.Contains(body, nginxDefaultOutput) {
				Failf("Container port output missing expected value. Wanted:'%s', got: %s", nginxDefaultOutput, body)
			}
		})
	})

	Describe("Kubectl label", func() {
		var podPath string
		var nsFlag string
		BeforeEach(func() {
			podPath = filepath.Join(testContext.RepoRoot, "examples/pod.yaml")
			By("creating the pod")
			nsFlag = fmt.Sprintf("--namespace=%v", ns)
			runKubectl("create", "-f", podPath, nsFlag)
			checkPodsRunningReady(c, ns, []string{simplePodName}, podStartTimeout)
		})
		AfterEach(func() {
			cleanup(podPath, ns, simplePodSelector)
		})

		It("should update the label on a resource", func() {
			labelName := "testing-label"
			labelValue := "testing-label-value"

			By("adding the label " + labelName + " with value " + labelValue + " to a pod")
			runKubectl("label", "pods", simplePodName, labelName+"="+labelValue, nsFlag)
			By("verifying the pod has the label " + labelName + " with the value " + labelValue)
			output := runKubectl("get", "pod", simplePodName, "-L", labelName, nsFlag)
			if !strings.Contains(output, labelValue) {
				Failf("Failed updating label " + labelName + " to the pod " + simplePodName)
			}

			By("removing the label " + labelName + " of a pod")
			runKubectl("label", "pods", simplePodName, labelName+"-", nsFlag)
			By("verifying the pod doesn't have the label " + labelName)
			output = runKubectl("get", "pod", simplePodName, "-L", labelName, nsFlag)
			if strings.Contains(output, labelValue) {
				Failf("Failed removing label " + labelName + " of the pod " + simplePodName)
			}
		})
	})

	Describe("Kubectl logs", func() {
		It("should find a string in pod logs", func() {
			mkpath := func(file string) string {
				return filepath.Join(testContext.RepoRoot, "examples/guestbook-go", file)
			}
			controllerJson := mkpath("redis-master-controller.json")
			nsFlag := fmt.Sprintf("--namespace=%v", ns)
			By("creating Redis RC")
			runKubectl("create", "-f", controllerJson, nsFlag)
			By("checking logs")
			forEachPod(c, ns, "app", "redis", func(pod api.Pod) {
				_, err := lookForStringInLog(ns, pod.Name, "redis-master", "The server is now ready to accept connections", podStartTimeout)
				Expect(err).NotTo(HaveOccurred())
			})
		})
	})

	Describe("Kubectl patch", func() {
		It("should add annotations for pods in rc", func() {
			mkpath := func(file string) string {
				return filepath.Join(testContext.RepoRoot, "examples/guestbook-go", file)
			}
			controllerJson := mkpath("redis-master-controller.json")
			nsFlag := fmt.Sprintf("--namespace=%v", ns)
			By("creating Redis RC")
			runKubectl("create", "-f", controllerJson, nsFlag)
			By("patching all pods")
			forEachPod(c, ns, "app", "redis", func(pod api.Pod) {
				runKubectl("patch", "pod", pod.Name, nsFlag, "-p", "{\"metadata\":{\"annotations\":{\"x\":\"y\"}}}")
			})

			By("checking annotations")
			forEachPod(c, ns, "app", "redis", func(pod api.Pod) {
				found := false
				for key, val := range pod.Annotations {
					if key == "x" && val == "y" {
						found = true
					}
				}
				if !found {
					Failf("Added annation not found")
				}
			})
		})
	})
})

func curl(addr string) (string, error) {
	resp, err := http.Get(addr)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body[:]), nil
}

func validateGuestbookApp(c *client.Client, ns string) {
	Logf("Waiting for frontend to serve content.")
	if !waitForGuestbookResponse(c, "get", "", `{"data": ""}`, guestbookStartupTimeout, ns) {
		Failf("Frontend service did not start serving content in %v seconds.", guestbookStartupTimeout.Seconds())
	}

	Logf("Trying to add a new entry to the guestbook.")
	if !waitForGuestbookResponse(c, "set", "TestEntry", `{"message": "Updated"}`, guestbookResponseTimeout, ns) {
		Failf("Cannot added new entry in %v seconds.", guestbookResponseTimeout.Seconds())
	}

	Logf("Verifying that added entry can be retrieved.")
	if !waitForGuestbookResponse(c, "get", "", `{"data": "TestEntry"}`, guestbookResponseTimeout, ns) {
		Failf("Entry to guestbook wasn't correctly added in %v seconds.", guestbookResponseTimeout.Seconds())
	}
}

// Returns whether received expected response from guestbook on time.
func waitForGuestbookResponse(c *client.Client, cmd, arg, expectedResponse string, timeout time.Duration, ns string) bool {
	for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) {
		res, err := makeRequestToGuestbook(c, cmd, arg, ns)
		if err == nil && res == expectedResponse {
			return true
		}
	}
	return false
}

func makeRequestToGuestbook(c *client.Client, cmd, value string, ns string) (string, error) {
	result, err := c.Get().
		Prefix("proxy").
		Namespace(ns).
		Resource("services").
		Name("frontend").
		Suffix("/index.php").
		Param("cmd", cmd).
		Param("key", "messages").
		Param("value", value).
		Do().
		Raw()
	return string(result), err
}

type updateDemoData struct {
	Image string
}

// getUDData creates a validator function based on the input string (i.e. kitten.jpg).
// For example, if you send "kitten.jpg", this function veridies that the image jpg = kitten.jpg
// in the container's json field.
func getUDData(jpgExpected string, ns string) func(*client.Client, string) error {

	// getUDData validates data.json in the update-demo (returns nil if data is ok).
	return func(c *client.Client, podID string) error {
		Logf("validating pod %s", podID)
		body, err := c.Get().
			Prefix("proxy").
			Namespace(ns).
			Resource("pods").
			Name(podID).
			Suffix("data.json").
			Do().
			Raw()
		if err != nil {
			return err
		}
		Logf("got data: %s", body)
		var data updateDemoData
		if err := json.Unmarshal(body, &data); err != nil {
			return err
		}
		Logf("Unmarshalled json jpg/img => %s , expecting %s .", data, jpgExpected)
		if strings.Contains(data.Image, jpgExpected) {
			return nil
		} else {
			return errors.New(fmt.Sprintf("data served up in container is innaccurate, %s didn't contain %s", data, jpgExpected))
		}
	}
}
<|endoftext|>


<commit_before>package cyberark

import (
	"net/url"
	"testing"

	"github.com/stretchr/testify/assert"
)

func DoShouldFailWhenNoClient(t *testing.T) {
	s := &GetPasswordService{}
	_, err := s.Do()
	assert.NotNil(t, err)
	assert.Equal(t, "Client is required", err.Error())
}

func DoShouldFailWhenNoAppID(t *testing.T) {
	c, err := NewClient(SetHost("foo"))
	assert.Nil(t, err)

	_, err = c.GetPassword().Do()
	assert.NotNil(t, err)
	assert.Equal(t, "AppID is required", err.Error())
}

func TestAppIDShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).AppID("app")
	assert.Equal(t, "app", s.appID)
}

func TestAddressShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Address("address")
	assert.Equal(t, "address", s.address)
}

func TestDatabaseShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Database("database")
	assert.Equal(t, "database", s.database)
}

func TestFolderShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Folder("folder")
	assert.Equal(t, "folder", s.folder)
}

func TestObjectShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Object("object")
	assert.Equal(t, "object", s.object)
}

func TestPolicyIDShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).PolicyID("policy")
	assert.Equal(t, "policy", s.policyID)
}

func TestQueryShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Query("query")
	assert.Equal(t, "query", s.query)
}

func TestQueryFormatShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).QueryFormat("query format")
	assert.Equal(t, "query format", s.queryFormat)
}

func TestReasonShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Reason("reason")
	assert.Equal(t, "reason", s.reason)
}

func TestSafeShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Safe("safe")
	assert.Equal(t, "safe", s.safe)
}

func TestTimeoutShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Timeout(1000)
	assert.Equal(t, 1000, s.timeout)
}

func TestUserNameShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).UserName("user")
	assert.Equal(t, "user", s.userName)
}

func TestSetParamShouldSetWhenValuePresent(t *testing.T) {
	params := url.Values{}
	setParam(&params, "foo", "bar")
	assert.Equal(t, 1, len(params))
	assert.Equal(t, "bar", params.Get("foo"))
}

func TestSetParamShouldNotSetWhenNoValue(t *testing.T) {
	params := url.Values{}
	setParam(&params, "foo", "")
	assert.Equal(t, 0, len(params))
}

func TestBuildURLGetsPathAndParams(t *testing.T) {
	s := newGetPasswordService(nil)
	s.appID = "foo"
	s.safe = "bar"
	s.object = "baz"

	path, params := s.buildURL()

	assert.Equal(t, "Accounts", path)
	assert.Equal(t, "appId=foo&object=baz&safe=bar&timeout=30", params.Encode())
}
<commit_msg>Fix test function names<commit_after>package cyberark

import (
	"net/url"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDoShouldFailWhenNoClient(t *testing.T) {
	s := &GetPasswordService{}
	_, err := s.Do()
	assert.NotNil(t, err)
	assert.Equal(t, "Client is required", err.Error())
}

func TestDoShouldFailWhenNoAppID(t *testing.T) {
	c, err := NewClient(SetHost("foo"))
	assert.Nil(t, err)

	_, err = c.GetPassword().Do()
	assert.NotNil(t, err)
	assert.Equal(t, "AppID is required", err.Error())
}

func TestAppIDShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).AppID("app")
	assert.Equal(t, "app", s.appID)
}

func TestAddressShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Address("address")
	assert.Equal(t, "address", s.address)
}

func TestDatabaseShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Database("database")
	assert.Equal(t, "database", s.database)
}

func TestFolderShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Folder("folder")
	assert.Equal(t, "folder", s.folder)
}

func TestObjectShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Object("object")
	assert.Equal(t, "object", s.object)
}

func TestPolicyIDShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).PolicyID("policy")
	assert.Equal(t, "policy", s.policyID)
}

func TestQueryShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Query("query")
	assert.Equal(t, "query", s.query)
}

func TestQueryFormatShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).QueryFormat("query format")
	assert.Equal(t, "query format", s.queryFormat)
}

func TestReasonShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Reason("reason")
	assert.Equal(t, "reason", s.reason)
}

func TestSafeShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Safe("safe")
	assert.Equal(t, "safe", s.safe)
}

func TestTimeoutShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).Timeout(1000)
	assert.Equal(t, 1000, s.timeout)
}

func TestUserNameShouldGetSet(t *testing.T) {
	s := newGetPasswordService(nil).UserName("user")
	assert.Equal(t, "user", s.userName)
}

func TestSetParamShouldSetWhenValuePresent(t *testing.T) {
	params := url.Values{}
	setParam(&params, "foo", "bar")
	assert.Equal(t, 1, len(params))
	assert.Equal(t, "bar", params.Get("foo"))
}

func TestSetParamShouldNotSetWhenNoValue(t *testing.T) {
	params := url.Values{}
	setParam(&params, "foo", "")
	assert.Equal(t, 0, len(params))
}

func TestBuildURLGetsPathAndParams(t *testing.T) {
	s := newGetPasswordService(nil)
	s.appID = "foo"
	s.safe = "bar"
	s.object = "baz"

	path, params := s.buildURL()

	assert.Equal(t, "Accounts", path)
	assert.Equal(t, "appId=foo&object=baz&safe=bar&timeout=30", params.Encode())
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
)

// Functions main purpose is to break a large problem which requires many code
// lines into a number of smaller tasks (functions). Also the same task can be
// invoked several times, so a function promotes code reuse.

// There are 3 types of functions in Go:
// - Normal functions with an identifier
// - Anonymous or lamda functions
// - Methods

// Any of these can have parameters and return values. The definition of all the
// function parameters and return values, together with their types, is called
// the function signature.

// The function main is special, go programs begins execution in the function
// named main located in package main.

func main() {

	// You invoke the function by specifying the name of the package it defined in
	// followed by a . (dot) followed by the name of the function and any parameters.
	// However if the function is defined in the current package then it can
	// invoked by referring to its name and providing the any parameters
	Greet()

	x, y := 1, 2
	// You can capture the returned value either assigning to a variable or
	// passing it as argument to another function
	r := add(x, y)
	fmt.Printf("The sum of %d and %d is %d\n", x, y, r)

	numr, denom := 3, 0
	quot, err := divide(numr, denom)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("Result of %d / %d is %d\n", numr, denom, quot)
	}

	// One or more returned values can be omitted using the blank identifier _ (underscore)
	// For example here the second retured value error is being discarded
	// NOTE: Its considered bad parctice to ignore errors. Please dont do this in normal code.
	// The pupose is to demonstrate that you can discard one or more returned
	// values if you please to do so.
	q, _ := divide(numr, denom)
	fmt.Printf("Result of %d / %d is %d\n", numr, denom, q)

	// call the variadic function sum
	n := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	// n... is the shorthand to send
	s := sum("Sum of input number is:", n...)
	fmt.Printf("%s", s)

	// call recursive function
	fmt.Printf("Fibonacci of 10 is %d\n", fibonacci(10))

	// A function that does have a name is called anonymous function
	// (also known under the names of a lambda function, a function literal, or a closure).
	// Such a function cannot stand on its own, since complier would throw an error.
	// Hence they must be either assigned to variable or must be directly invoked.

	// The variable prod's value is a function that returns product of the passed numbers
	prod := func(x, y int) int {
		return x * y
	}
	fmt.Printf("%d * %d = %d\n", x, y, prod(x, y))

	// To directly invoke an anonymous function, put pair of () within which
	// we can list the optional parameters to the function.
	func(x, y int) {
		fmt.Printf("%d %% %d = %d\n", x, y, x%y)
	}(4, 2) // 4,2 are the parameters to the anonymous function
}

// The keyword func introduces a function
// A function can take zero or more paramaters
// One of the functions parameters can accept arbitary number of values
// A function can return zero or more values, unlike other languages
// A function can take other function as paramters or return functions as return values
// A function which starts with capital/uppercase letter is exported (visible/accessible to other packages)
// The order of function definition is of no consequnce, however its idiomatic
// to define the main function as first function.

// Greet is a function that take no paraters and returns no values. Notice this
// function start with capital letter hence it is said to a exported function.
func Greet() {
	fmt.Printf("Hello how are you?\n")
}

// add is a function that take two parameters of type int and return a single
// value of the type int. Notice this function start with lowercase letter hence
// it is said to be un-exported function.
func add(x, y int) int {
	return x + y
}

var ErrDivideByZero = errors.New("Division by zero is not allowed")

// A function can return one or more values. This forms very foundations of Go error
// handling machinary, since unlike other language go does not support exception handling
func divide(x, y int) (int, error) {
	if y == 0 {
		return 0, ErrDivideByZero
	}
	return x / y, nil
}

// A go function can accept arbitary number of values for a paramater.
// Such functions are called as variadic functions. A variadic parameter
// has ... prefixed to its type.
// There can only be one such parameter. If a function happens to take
// more than one parameter, then the parameter that accepts multiple values
// must be the last one. The following example show one such function.
// The value of the variadic parameter is accessible as a slice within the
// function body, which are be iterated over using the for..range loop
func sum(title string, nums ...int) string {
	fmt.Printf("Data type of nums is %T\n", nums)
	s := 0
	for _, v := range nums {
		s += v
	}
	return fmt.Sprintf("%s %d\n", title, s)
}

// A function that calls itself in the body of the function is called a recursive function.
func fibonacci(num int) int {
	if num == 0 {
		return 0
	} else if num == 1 {
		return 1
	}

	return fibonacci(num-1) + fibonacci(num-2)
}
<commit_msg>add anon function sample<commit_after>package main

import (
	"errors"
	"fmt"
)

// Functions main purpose is to break a large problem which requires many code
// lines into a number of smaller tasks (functions). Also the same task can be
// invoked several times, so a function promotes code reuse.

// There are 3 types of functions in Go:
// - Normal functions with an identifier
// - Anonymous or lamda functions
// - Methods

// Any of these can have parameters and return values. The definition of all the
// function parameters and return values, together with their types, is called
// the function signature.

// The function main is special, go programs begins execution in the function
// named main located in package main.

func main() {

	// You invoke the function by specifying the name of the package it defined in
	// followed by a . (dot) followed by the name of the function and any parameters.
	// However if the function is defined in the current package then it can
	// invoked by referring to its name and providing the any parameters
	Greet()

	x, y := 1, 2
	// You can capture the returned value either assigning to a variable or
	// passing it as argument to another function
	r := add(x, y)
	fmt.Printf("The sum of %d and %d is %d\n", x, y, r)

	numr, denom := 3, 0
	quot, err := divide(numr, denom)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("Result of %d / %d is %d\n", numr, denom, quot)
	}

	// One or more returned values can be omitted using the blank identifier _ (underscore)
	// For example here the second retured value error is being discarded
	// NOTE: Its considered bad parctice to ignore errors. Please dont do this in normal code.
	// The pupose is to demonstrate that you can discard one or more returned
	// values if you please to do so.
	q, _ := divide(numr, denom)
	fmt.Printf("Result of %d / %d is %d\n", numr, denom, q)

	// call the variadic function sum
	n := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	// n... is the shorthand to send
	s := sum("Sum of input number is:", n...)
	fmt.Printf("%s", s)

	// call recursive function
	fmt.Printf("Fibonacci of 10 is %d\n", fibonacci(10))

	// A function that does have a name is called anonymous function
	// (also known under the names of a lambda function, a function literal, or a closure).
	// Such a function cannot stand on its own, since complier would throw an error.
	// Hence they must be either assigned to variable or must be directly invoked.

	// The variable prod's value is a function that returns product of the passed numbers
	prod := func(x, y int) int {
		return x * y
	}
	fmt.Printf("%d * %d = %d\n", x, y, prod(x, y))

	// To directly invoke an anonymous function, put pair of () after the closing
	// '}' brackets within which we can list the optional parameters to the function.
	func(x, y int) {
		fmt.Printf("%d %% %d = %d\n", x, y, x%y)
	}(4, 2) // 4,2 are the parameters to the anonymous function
}

// The keyword func introduces a function
// A function can take zero or more paramaters
// One of the functions parameters can accept arbitary number of values
// A function can return zero or more values, unlike other languages
// A function can take other function as paramters or return functions as return values
// A function which starts with capital/uppercase letter is exported (visible/accessible to other packages)
// The order of function definition is of no consequnce, however its idiomatic
// to define the main function as first function.

// Greet is a function that take no paraters and returns no values. Notice this
// function start with capital letter hence it is said to a exported function.
func Greet() {
	fmt.Printf("Hello how are you?\n")
}

// add is a function that take two parameters of type int and return a single
// value of the type int. Notice this function start with lowercase letter hence
// it is said to be un-exported function.
func add(x, y int) int {
	return x + y
}

var ErrDivideByZero = errors.New("Division by zero is not allowed")

// A function can return one or more values. This forms very foundations of Go error
// handling machinary, since unlike other language go does not support exception handling
func divide(x, y int) (int, error) {
	if y == 0 {
		return 0, ErrDivideByZero
	}
	return x / y, nil
}

// A go function can accept arbitary number of values for a paramater.
// Such functions are called as variadic functions. A variadic parameter
// has ... prefixed to its type.
// There can only be one such parameter. If a function happens to take
// more than one parameter, then the parameter that accepts multiple values
// must be the last one. The following example show one such function.
// The value of the variadic parameter is accessible as a slice within the
// function body, which are be iterated over using the for..range loop
func sum(title string, nums ...int) string {
	fmt.Printf("Data type of nums is %T\n", nums)
	s := 0
	for _, v := range nums {
		s += v
	}
	return fmt.Sprintf("%s %d\n", title, s)
}

// A function that calls itself in the body of the function is called a recursive function.
func fibonacci(num int) int {
	if num == 0 {
		return 0
	} else if num == 1 {
		return 1
	}

	return fibonacci(num-1) + fibonacci(num-2)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
)

// Functions main purpose is to break a large problem which requires many code
// lines into a number of smaller tasks (functions). Also the same task can be
// invoked several times, so a function promotes code reuse.

// There are 3 types of functions in Go:
// - Normal functions with an identifier
// - Anonymous or lamda functions
// - Methods

// Any of these can have parameters and return values. The definition of all the
// function parameters and return values, together with their types, is called
// the function signature.

// The function main is special, go programs begins execution in the function
// named main located in package main.

func main() {

	// You invoke the function by specifying the name of the package it defined in
	// followed by a . (dot) followed by the name of the function and any parameters.
	// However if the function is defined in the current package then it can
	// invoked by referring to its name and providing the any parameters
	Greet()

	x, y := 1, 2
	// You can capture the returned value either assigning to a variable or
	// passing it as argument to another function
	r := add(x, y)
	fmt.Printf("The sum of %d and %d is %d\n", x, y, r)

	numr, denom := 3, 0
	quot, err := divide(numr, denom)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("Result of %d / %d is %d\n", numr, denom, quot)
	}

	// One or more returned values can be discarded using the blank identifier _ (underscore)

	// When would this be useful?
	// Recall that its illegal to declare a variable and not use it. Now suppose
	// you have function that you wrote or calling a function defined in some
	// package, but you do not want to consume one or more returned values.
	// The only way out, is to use the blank indentifier.

	// For example here the second retured value error is being discarded
	// NOTE: Its considered bad parctice to ignore errors. Please dont do this in normal code.
	// The pupose is to demonstrate how to discard one or more returned values.
	q, _ := divide(numr, denom)
	fmt.Printf("Result of %d / %d is %d\n", numr, denom, q)

	// call the variadic function sum
	n := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	// n... is the shorthand to send
	s := sum("Sum of input number is:", n...)
	fmt.Printf("%s", s)

	// call recursive function
	fmt.Printf("Fibonacci of 10 is %d\n", fibonacci(10))

	// A function that does have a name is called anonymous function
	// (also known under the names of a lambda function, a function literal, or a closure).
	// Such a function cannot stand on its own, since complier would throw an error.
	// Hence such functions  must be either assigned to variable or must be
	// directly invoked or returned as output value of a named function

	// The variable prod's value is a function that returns product of the passed numbers
	prod := func(x, y int) int {
		return x * y
	}
	fmt.Printf("%d * %d = %d\n", x, y, prod(x, y))

	// To directly invoke an anonymous function, put pair of () after the closing
	// '}' brackets within which we can list the optional parameters to the function.
	func(x, y int) {
		fmt.Printf("%d %% %d = %d\n", x, y, x%y)
	}(4, 2) // 4,2 are the parameters to the anonymous function
}

// The keyword func introduces a function
// A function can take zero or more paramaters
// One of the functions parameters can accept arbitary number of values
// A function can return zero or more values, unlike other languages
// A function can take other function as paramters or return functions as return values
// A function which starts with capital/uppercase letter is exported (visible/accessible to other packages)
// The order in which functions are defined in go source file is of no
// consequence, however its idiomatic to define the main function as first function.

// Greet is a function that take no paraters and returns no values. Notice this
// function start with capital letter hence it is said to a exported function.
func Greet() {
	fmt.Printf("Hello how are you?\n")
}

// add is a function that take two parameters of type int and return a single
// value of the type int. Notice this function start with lowercase letter hence
// it is said to be un-exported function.
func add(x, y int) int {
	return x + y
}

var ErrDivideByZero = errors.New("Division by zero is not allowed")

// A function can return one or more values. This forms very foundations of Go error
// handling machinary, since unlike other language go does not support exception handling
func divide(x, y int) (int, error) {
	if y == 0 {
		return 0, ErrDivideByZero
	}
	return x / y, nil
}

// A go function can accept arbitary number of values for a paramater.
// Such functions are called as variadic functions. A variadic parameter
// has ... prefixed to its type.
// There can only be one such parameter. If a function happens to take
// more than one parameter, then the parameter that accepts multiple values
// must be the last one. The following example show one such function.
// The value of the variadic parameter is accessible as a slice within the
// function body, which are be iterated over using the for..range loop
func sum(title string, nums ...int) string {
	fmt.Printf("Data type of nums is %T\n", nums)
	s := 0
	for _, v := range nums {
		s += v
	}
	return fmt.Sprintf("%s %d\n", title, s)
}

// A function that calls itself in the body of the function is called a recursive function.
func fibonacci(num int) int {
	if num == 0 {
		return 0
	} else if num == 1 {
		return 1
	}

	return fibonacci(num-1) + fibonacci(num-2)
}
<commit_msg>fix typos<commit_after>package main

import (
	"errors"
	"fmt"
)

// Functions main purpose is to break a large program which requires many code
// lines into a number of smaller tasks (functions). It also helps enforce the D-R-Y
// (dont repeat yourself) principle, the same task can be invoked several times,
// so a function promotes code reuse.

// There are 3 types of functions in Go:
// - Normal functions with an identifier
// - Anonymous or lamda functions
// - Methods

// Any of these can have parameters and return values. The definition of all the
// function parameters and return values, together with their types, is called
// the function signature.

// The function main is special, go programs begins execution in the function
// named main located in package main.

func main() {

	// You invoke the function by specifying the name of the package it is
	// defined in followed by a . (dot) followed by the name of the function
	// and any parameters within a set of parantheses.
	// However if the function is defined in the current package then it can
	// invoked by referring to its name and providing the any parameters
	Greet()

	x, y := 1, 2
	// You can capture the returned value either assigning it to a variable or
	// passing it as argument to another function
	r := add(x, y)
	fmt.Printf("The sum of %d and %d is %d\n", x, y, r)

	numr, denom := 3, 0
	quot, err := divide(numr, denom)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Printf("Result of %d / %d is %d\n", numr, denom, quot)
	}

	// One or more returned values can be discarded using the blank identifier _ (underscore)

	// When would this be useful?
	// Recall that its illegal to declare a variable and not use it. Now suppose
	// you have function that you wrote or calling a function defined in some
	// package, but you do not want to consume one or more returned values.
	// The only way out, is to use the blank indentifier.

	// For example here the second retured value error is being discarded
	// NOTE: Its considered bad parctice to ignore errors. Please dont do this in normal code.
	// The pupose is to demonstrate how to discard one or more returned values.
	q, _ := divide(numr, denom)
	fmt.Printf("Result of %d / %d is %d\n", numr, denom, q)

	// call the variadic function sum
	n := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
	// n... is the shorthand to send
	s := sum("Sum of input number is:", n...)
	fmt.Printf("%s", s)

	// call recursive function
	fmt.Printf("Fibonacci of 10 is %d\n", fibonacci(10))

	// A function that does not have a name is called anonymous function
	// (also known under the names of a lambda function, a function literal, or a closure).
	// Such a function cannot stand on its own, since complier would throw an error.
	// Hence such functions  must be either assigned to variable or must be
	// directly invoked or returned as output value of a named function

	// The variable prod's value is a function that returns product of the passed numbers
	prod := func(x, y int) int {
		return x * y
	}
	fmt.Printf("%d * %d = %d\n", x, y, prod(x, y))

	// To directly invoke an anonymous function, put pair of () after the closing
	// '}' brackets within which we can list the optional parameters to the function.
	func(x, y int) {
		fmt.Printf("%d %% %d = %d\n", x, y, x%y)
	}(4, 2) // 4,2 are the parameters to the anonymous function
}

// The keyword func introduces a function
// A function can take zero or more paramaters
// One of the functions parameters can accept arbitary number of values
// A function can return zero or more values, unlike other languages
// A function can take other function as paramters or return functions as return values
// A function which starts with capital/uppercase letter is exported (visible/accessible to other packages)
// The order in which functions are defined in go source file is of no
// consequence, however it is idiomatic to define the main function as first function.

// Greet is a function that take no paraters and returns no values. Notice this
// function start with capital letter hence it is said to be a exported function.
func Greet() {
	fmt.Printf("Hello how are you?\n")
}

// add is a function that take two parameters of type int and return a single
// value of the type int. Notice this function start with lowercase letter hence
// it is said to be un-exported function.
func add(x, y int) int {
	return x + y
}

var ErrDivideByZero = errors.New("Division by zero is not allowed")

// A function can return one or more values. This forms very foundations of Go error
// handling machinary, since unlike other language go does not support exception handling
func divide(x, y int) (int, error) {
	if y == 0 {
		return 0, ErrDivideByZero
	}
	return x / y, nil
}

// A go function can accept arbitary number of values for a paramater.
// Such functions are called as variadic functions. A variadic parameter
// has ... prefixed to its type.
// There can only be one such parameter. If a function happens to take
// more than one parameter, then the parameter that accepts multiple values
// must be the last one. The following example show one such function.
// The value of the variadic parameter is accessible as a slice within the
// function body, which are be iterated over using the for..range loop
func sum(title string, nums ...int) string {
	fmt.Printf("Data type of nums is %T\n", nums)
	s := 0
	for _, v := range nums {
		s += v
	}
	return fmt.Sprintf("%s %d\n", title, s)
}

// A function that calls itself in the body of the function is called a recursive function.
func fibonacci(num int) int {
	if num == 0 {
		return 0
	} else if num == 1 {
		return 1
	}

	return fibonacci(num-1) + fibonacci(num-2)
}
<|endoftext|>


<commit_before>package app

import (
	// Stdlib
	"flag"

	// Internal
	"github.com/salsita/SalsaFlow/git-trunk/config"
	"github.com/salsita/SalsaFlow/git-trunk/errors"
	flags "github.com/salsita/SalsaFlow/git-trunk/flag"
	"github.com/salsita/SalsaFlow/git-trunk/log"
	"github.com/salsita/SalsaFlow/git-trunk/modules"
)

var (
	LogFlag *flags.StringEnumFlag = flags.NewStringEnumFlag(
		log.LevelStrings(), log.MustLevelToString(log.Info))
)

func RegisterGlobalFlags(flags *flag.FlagSet) {
	flags.Var(LogFlag, "log", "set logging verbosity; {trace|debug|verbose|info|off}")
}

func Init() (err *errors.Error) {
	// Set up logging.
	log.SetV(log.MustStringToLevel(LogFlag.Value()))

	// Load the workflow configuration.
	if err = config.Load(); err != nil {
		return
	}

	// Bootstrap the modules.
	if err = modules.Bootstrap(); err != nil {
		return
	}

	return nil
}

func MustInit() {
	var logger = log.V(log.Info)
	if err := Init(); err != nil {
		err.Fatal(logger)
	}
}
<commit_msg>git-trunk/app: Make the code more idiomatic<commit_after>package app

import (
	// Stdlib
	"flag"

	// Internal
	"github.com/salsita/SalsaFlow/git-trunk/config"
	"github.com/salsita/SalsaFlow/git-trunk/errors"
	flags "github.com/salsita/SalsaFlow/git-trunk/flag"
	"github.com/salsita/SalsaFlow/git-trunk/log"
	"github.com/salsita/SalsaFlow/git-trunk/modules"
)

var (
	LogFlag *flags.StringEnumFlag = flags.NewStringEnumFlag(
		log.LevelStrings(), log.MustLevelToString(log.Info))
)

func RegisterGlobalFlags(flags *flag.FlagSet) {
	flags.Var(LogFlag, "log", "set logging verbosity; {trace|debug|verbose|info|off}")
}

func Init() *errors.Error {
	// Set up logging.
	log.SetV(log.MustStringToLevel(LogFlag.Value()))

	// Load the workflow configuration.
	if err := config.Load(); err != nil {
		return err
	}

	// Bootstrap the modules.
	if err := modules.Bootstrap(); err != nil {
		return err
	}

	return nil
}

func MustInit() {
	var logger = log.V(log.Info)
	if err := Init(); err != nil {
		err.Fatal(logger)
	}
}
<|endoftext|>


<commit_before>package gitmedia

import (
	"errors"
	"fmt"
	"github.com/github/git-media/git"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const Version = "0.3.2"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	LocalLinkDir       string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func LocalLinkPath(sha string) (string, error) {
	if len(sha) == 0 {
		return "", fmt.Errorf("Error trying to create local object directory, invalid sha: '%s'", sha)
	}
	path := filepath.Join(LocalLinkDir, sha[0:2])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local object directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha[2:len(sha)]), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

var shaMatcher = regexp.MustCompile(`^[0-9a-f]{40}`)

func CurrentRef() (string, error) {
	head, err := ioutil.ReadFile(filepath.Join(LocalGitDir, "HEAD"))
	if err != nil {
		return "", err
	}

	if shaMatcher.Match(head) {
		return strings.TrimSpace(string(head)), nil
	}

	headString := string(head)
	parts := strings.Split(headString, " ")
	if len(parts) != 2 {
		return "", errors.New("Unable to parse HEAD")
	}

	refFile := strings.TrimSpace(parts[1])
	sha, err := ioutil.ReadFile(filepath.Join(LocalGitDir, refFile))
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(sha)), nil
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		LocalLinkDir = filepath.Join(LocalMediaDir, "objects")
		TempDir = filepath.Join(LocalMediaDir, "tmp")

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}

		if err := os.MkdirAll(LocalLinkDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create objects directory in '%s': %s", LocalLinkDir, err))
		}
	}

	gitVersion, err := git.Config.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (GitHub; %s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<commit_msg>アアー アアアア アーアア<commit_after>package gitmedia

import (
	"errors"
	"fmt"
	"github.com/github/git-media/git"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const Version = "0.3.3"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	LocalLinkDir       string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func LocalLinkPath(sha string) (string, error) {
	if len(sha) == 0 {
		return "", fmt.Errorf("Error trying to create local object directory, invalid sha: '%s'", sha)
	}
	path := filepath.Join(LocalLinkDir, sha[0:2])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local object directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha[2:len(sha)]), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

var shaMatcher = regexp.MustCompile(`^[0-9a-f]{40}`)

func CurrentRef() (string, error) {
	head, err := ioutil.ReadFile(filepath.Join(LocalGitDir, "HEAD"))
	if err != nil {
		return "", err
	}

	if shaMatcher.Match(head) {
		return strings.TrimSpace(string(head)), nil
	}

	headString := string(head)
	parts := strings.Split(headString, " ")
	if len(parts) != 2 {
		return "", errors.New("Unable to parse HEAD")
	}

	refFile := strings.TrimSpace(parts[1])
	sha, err := ioutil.ReadFile(filepath.Join(LocalGitDir, refFile))
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(sha)), nil
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		LocalLinkDir = filepath.Join(LocalMediaDir, "objects")
		TempDir = filepath.Join(LocalMediaDir, "tmp")

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}

		if err := os.MkdirAll(LocalLinkDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create objects directory in '%s': %s", LocalLinkDir, err))
		}
	}

	gitVersion, err := git.Config.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (GitHub; %s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<|endoftext|>


<commit_before>package gitmedia

import (
	"fmt"
	"github.com/github/git-media/gitconfig"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const Version = "0.2.2"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}

	gitVersion, err := gitconfig.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (%s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<commit_msg>Add vendor info to useragent string<commit_after>package gitmedia

import (
	"fmt"
	"github.com/github/git-media/gitconfig"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const Version = "0.2.2"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}

	gitVersion, err := gitconfig.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (GitHub; %s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	BuildOS   = flag.String("os", "", "OS to target: darwin, freebsd, linux, windows")
	BuildArch = flag.String("arch", "", "Arch to target: 386, amd64")
	BuildAll  = flag.Bool("all", false, "Builds all architectures")
	ShowHelp  = flag.Bool("help", false, "Shows help")
)

func main() {
	cmd, err := exec.Command("script/fmt").Output()
	if err != nil {
		panic(err)
	}

	if len(cmd) > 0 {
		fmt.Println(string(cmd))
	}

	flag.Parse()
	if *ShowHelp {
		fmt.Println("usage: script/bootstrap [-os] [-arch] [-all]")
		flag.PrintDefaults()
		return
	}

	if *BuildAll {
		for _, buildos := range []string{"darwin", "freebsd", "linux", "windows"} {
			for _, buildarch := range []string{"386", "amd64"} {
				build(buildos, buildarch)
			}
		}
	} else {
		build(*BuildOS, *BuildArch)
	}
}

func build(buildos, buildarch string) {
	addenv := len(buildos) > 0 && len(buildarch) > 0
	name := "git-media-" + gitmedia.Version
	dir := "bin"

	if addenv {
		fmt.Printf("Building for %s/%s\n", buildos, buildarch)
		dir = filepath.Join(dir, "releases", buildos+"-"+buildarch, name)
	}

	filepath.Walk("cmd", func(path string, info os.FileInfo, err error) error {
		if !strings.HasSuffix(path, ".go") {
			return nil
		}

		cmd := filepath.Base(path)
		cmd = cmd[0 : len(cmd)-3]
		return buildCommand(path, dir, buildos, buildarch)
	})

	if addenv {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			fmt.Println("Error setting up installer:\n", err.Error())
			return
		}

		err = setupInstaller(buildos, buildarch, dir)
		if err != nil {
			fmt.Println("Error setting up installer:\n", err.Error())
		}
	}
}

func buildCommand(path, dir, buildos, buildarch string) error {
	addenv := len(buildos) > 0 && len(buildarch) > 0
	name := filepath.Base(path)
	name = name[0 : len(name)-3]

	bin := filepath.Join(dir, name)

	if buildos == "windows" {
		bin = bin + ".exe"
	}

	cmd := exec.Command("go", "build", "-o", bin, path)
	if addenv {
		cmd.Env = []string{
			"GOOS=" + buildos,
			"GOARCH=" + buildarch,
			"GOPATH=" + os.Getenv("GOPATH"),
			"GOROOT=" + os.Getenv("GOROOT"),
		}
	}

	output, err := cmd.CombinedOutput()
	if len(output) > 0 {
		fmt.Println(string(output))
	}
	return err
}

func setupInstaller(buildos, buildarch, dir string) error {
	if buildos == "windows" {
		return winInstaller(buildos, buildarch, dir)
	} else {
		return unixInstaller(buildos, buildarch, dir)
	}
}

func unixInstaller(buildos, buildarch, dir string) error {
	fullInstallPath := filepath.Join(dir, "install.sh")
	cmd := exec.Command("cp", "script/install.sh.example", fullInstallPath)
	if err := logAndRun(cmd); err != nil {
		return err
	}

	if err := os.Chmod(fullInstallPath, 0755); err != nil {
		return err
	}

	name := zipName(buildos, buildarch) + ".tar.gz"
	cmd = exec.Command("tar", "czf", "../"+name, filepath.Base(dir))
	cmd.Dir = filepath.Dir(dir)
	return logAndRun(cmd)
}

func winInstaller(buildos, buildarch, dir string) error {
	cmd := exec.Command("cp", "script/install.bat.example", filepath.Join(dir, "install.bat"))
	if err := logAndRun(cmd); err != nil {
		return err
	}

	installerPath := filepath.Dir(filepath.Dir(dir))

	name := zipName(buildos, buildarch) + ".zip"
	full := filepath.Join(installerPath, name)
	matches, err := filepath.Glob(dir + "/*")
	if err != nil {
		return err
	}

	args := make([]string, len(matches)+2)
	args[0] = "-j" // junk the zip paths
	args[1] = full
	copy(args[2:], matches)

	cmd = exec.Command("zip", args...)
	return logAndRun(cmd)
}

func logAndRun(cmd *exec.Cmd) error {
	fmt.Printf(" - %s\n", strings.Join(cmd.Args, " "))
	if len(cmd.Dir) > 0 {
		fmt.Printf("   - in %s\n", cmd.Dir)
	}

	output, err := cmd.CombinedOutput()
	fmt.Println(string(output))
	return err
}

func zipName(os, arch string) string {
	return fmt.Sprintf("git-media-%s-%s-%s", os, arch, gitmedia.Version)
}
<commit_msg>dump a build_matrix.json after cross compiling<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	BuildOS    = flag.String("os", "", "OS to target: darwin, freebsd, linux, windows")
	BuildArch  = flag.String("arch", "", "Arch to target: 386, amd64")
	BuildAll   = flag.Bool("all", false, "Builds all architectures")
	ShowHelp   = flag.Bool("help", false, "Shows help")
	matrixKeys = map[string]string{
		"darwin":  "Mac",
		"freebsd": "FreeBSD",
		"linux":   "Linux",
		"windows": "Windows",
		"amd64":   "AMD64",
	}
)

type Release struct {
	Label    string
	Filename string
}

func main() {
	cmd, err := exec.Command("script/fmt").Output()
	if err != nil {
		panic(err)
	}

	if len(cmd) > 0 {
		fmt.Println(string(cmd))
	}

	flag.Parse()
	if *ShowHelp {
		fmt.Println("usage: script/bootstrap [-os] [-arch] [-all]")
		flag.PrintDefaults()
		return
	}

	buildMatrix := make(map[string]Release)

	errored := false

	if *BuildAll {
		for _, buildos := range []string{"darwin", "freebsd", "linux", "windows"} {
			for _, buildarch := range []string{"386", "amd64"} {
				if err := build(buildos, buildarch, buildMatrix); err != nil {
					errored = true
				}
			}
		}
	} else {
		build(*BuildOS, *BuildArch, buildMatrix)
		errored = true // skip build matrix stuff
	}

	if !errored {
		by, err := json.Marshal(buildMatrix)
		if err != nil {
			fmt.Println("Error encoding build matrix to json:", err)
			return
		}

		file, err := os.Create("bin/releases/build_matrix.json")
		if err != nil {
			fmt.Println("Error creating build_matrix.json:", err)
			return
		}

		written, err := file.Write(by)
		file.Close()

		if err != nil {
			fmt.Println("Error writing build_matrix.json", err)
			return
		}

		if jsonSize := len(by); written != jsonSize {
			fmt.Printf("Expected to write %d bytes, actually wrote %d.\n", jsonSize, written)
		}
	}
}

func build(buildos, buildarch string, buildMatrix map[string]Release) error {
	addenv := len(buildos) > 0 && len(buildarch) > 0
	name := "git-media-" + gitmedia.Version
	dir := "bin"

	if addenv {
		fmt.Printf("Building for %s/%s\n", buildos, buildarch)
		dir = filepath.Join(dir, "releases", buildos+"-"+buildarch, name)
	}

	filepath.Walk("cmd", func(path string, info os.FileInfo, err error) error {
		if !strings.HasSuffix(path, ".go") {
			return nil
		}

		cmd := filepath.Base(path)
		cmd = cmd[0 : len(cmd)-3]
		return buildCommand(path, dir, buildos, buildarch)
	})

	if addenv {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			fmt.Println("Error setting up installer:\n", err.Error())
			return err
		}

		err = setupInstaller(buildos, buildarch, dir, buildMatrix)
		if err != nil {
			fmt.Println("Error setting up installer:\n", err.Error())
			return err
		}
	}

	return nil
}

func buildCommand(path, dir, buildos, buildarch string) error {
	addenv := len(buildos) > 0 && len(buildarch) > 0
	name := filepath.Base(path)
	name = name[0 : len(name)-3]

	bin := filepath.Join(dir, name)

	if buildos == "windows" {
		bin = bin + ".exe"
	}

	cmd := exec.Command("go", "build", "-o", bin, path)
	if addenv {
		cmd.Env = []string{
			"GOOS=" + buildos,
			"GOARCH=" + buildarch,
			"GOPATH=" + os.Getenv("GOPATH"),
			"GOROOT=" + os.Getenv("GOROOT"),
		}
	}

	output, err := cmd.CombinedOutput()
	if len(output) > 0 {
		fmt.Println(string(output))
	}
	return err
}

func setupInstaller(buildos, buildarch, dir string, buildMatrix map[string]Release) error {
	if buildos == "windows" {
		return winInstaller(buildos, buildarch, dir, buildMatrix)
	} else {
		return unixInstaller(buildos, buildarch, dir, buildMatrix)
	}
}

func unixInstaller(buildos, buildarch, dir string, buildMatrix map[string]Release) error {
	fullInstallPath := filepath.Join(dir, "install.sh")
	cmd := exec.Command("cp", "script/install.sh.example", fullInstallPath)
	if err := logAndRun(cmd); err != nil {
		return err
	}

	if err := os.Chmod(fullInstallPath, 0755); err != nil {
		return err
	}

	name := zipName(buildos, buildarch) + ".tar.gz"

	addToMatrix(buildMatrix, buildos, buildarch, name)

	cmd = exec.Command("tar", "czf", "../"+name, filepath.Base(dir))
	cmd.Dir = filepath.Dir(dir)
	return logAndRun(cmd)
}

func addToMatrix(buildMatrix map[string]Release, buildos, buildarch, name string) {
	buildMatrix[fmt.Sprintf("%s-%s", buildos, buildarch)] = Release{
		Label:    releaseLabel(buildos, buildarch),
		Filename: name,
	}
}

func winInstaller(buildos, buildarch, dir string, buildMatrix map[string]Release) error {
	cmd := exec.Command("cp", "script/install.bat.example", filepath.Join(dir, "install.bat"))
	if err := logAndRun(cmd); err != nil {
		return err
	}

	installerPath := filepath.Dir(filepath.Dir(dir))

	name := zipName(buildos, buildarch) + ".zip"
	full := filepath.Join(installerPath, name)
	matches, err := filepath.Glob(dir + "/*")
	if err != nil {
		return err
	}

	addToMatrix(buildMatrix, buildos, buildarch, name)

	args := make([]string, len(matches)+2)
	args[0] = "-j" // junk the zip paths
	args[1] = full
	copy(args[2:], matches)

	cmd = exec.Command("zip", args...)
	return logAndRun(cmd)
}

func logAndRun(cmd *exec.Cmd) error {
	fmt.Printf(" - %s\n", strings.Join(cmd.Args, " "))
	if len(cmd.Dir) > 0 {
		fmt.Printf("   - in %s\n", cmd.Dir)
	}

	output, err := cmd.CombinedOutput()
	fmt.Println(string(output))
	return err
}

func zipName(os, arch string) string {
	return fmt.Sprintf("git-media-%s-%s-%s", os, arch, gitmedia.Version)
}

func releaseLabel(buildos, buildarch string) string {
	return fmt.Sprintf("%s %s", key(buildos), key(buildarch))
}

func key(k string) string {
	if s, ok := matrixKeys[k]; ok {
		return s
	}
	return k
}
<|endoftext|>


<commit_before>// run

// 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.

// This used to crash because the scheduler
// tried to kick off a new scheduling thread for f
// when time.Nanoseconds went into the system call.
// It's not okay to schedule new goroutines
// until main has started.

package main

import "time"

func f() {
}

func init() {
	go f()
	time.Now()
}

func main() {
}
<commit_msg>test/initsyscall.go: delete It's testing an old property of the language and is no longer relevant.<commit_after><|endoftext|>


<commit_before>package version

import "fmt"

const Name = "XD"

const Major = "0"

const Minor = "0"

const Patch = "7"

var Git string

func Version() string {
	return fmt.Sprintf("%s-%s.%s.%s%s", Name, Major, Minor, Patch, Git)
}
<commit_msg>bump to 0.0.8<commit_after>package version

import "fmt"

const Name = "XD"

const Major = "0"

const Minor = "0"

const Patch = "8"

var Git string

func Version() string {
	return fmt.Sprintf("%s-%s.%s.%s%s", Name, Major, Minor, Patch, Git)
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

// +build solaris

package terminal // import "golang.org/x/crypto/ssh/terminal"

import (
	"golang.org/x/sys/unix"
	"io"
	"syscall"
)

// State contains the state of a terminal.
type State struct {
	termios unix.Termios
}

// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
	_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
	return err == nil
}

// ReadPassword reads a line of input from a terminal without local echo.  This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
	// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
	val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
	if err != nil {
		return nil, err
	}
	oldState := *val

	newState := oldState
	newState.Lflag &^= syscall.ECHO
	newState.Lflag |= syscall.ICANON | syscall.ISIG
	newState.Iflag |= syscall.ICRNL
	err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
	if err != nil {
		return nil, err
	}

	defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)

	var buf [16]byte
	var ret []byte
	for {
		n, err := syscall.Read(fd, buf[:])
		if err != nil {
			return nil, err
		}
		if n == 0 {
			if len(ret) == 0 {
				return nil, io.EOF
			}
			break
		}
		if buf[n-1] == '\n' {
			n--
		}
		ret = append(ret, buf[:n]...)
		if n < len(buf) {
			break
		}
	}

	return ret, nil
}

// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
// see http://cr.illumos.org/~webrev/andy_js/1060/
func MakeRaw(fd int) (*State, error) {
	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
	if err != nil {
		return nil, err
	}

	oldState := State{termios: *termios}

	termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
	termios.Oflag &^= unix.OPOST
	termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
	termios.Cflag &^= unix.CSIZE | unix.PARENB
	termios.Cflag |= unix.CS8
	termios.Cc[unix.VMIN] = 1
	termios.Cc[unix.VTIME] = 0

	if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
		return nil, err
	}

	return &oldState, nil
}

// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, oldState *State) error {
	return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
}

// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
	if err != nil {
		return nil, err
	}

	return &State{termios: *termios}, nil
}

// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
	if err != nil {
		return 0, 0, err
	}
	return int(ws.Col), int(ws.Row), nil
}
<commit_msg>Remove import comment. Fixes #337<commit_after>// Copyright 2015 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.

// +build solaris

package terminal

import (
	"io"
	"syscall"

	"golang.org/x/sys/unix"
)

// State contains the state of a terminal.
type State struct {
	termios unix.Termios
}

// IsTerminal returns whether the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
	_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
	return err == nil
}

// ReadPassword reads a line of input from a terminal without local echo.  This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
	// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
	val, err := unix.IoctlGetTermios(fd, unix.TCGETS)
	if err != nil {
		return nil, err
	}
	oldState := *val

	newState := oldState
	newState.Lflag &^= syscall.ECHO
	newState.Lflag |= syscall.ICANON | syscall.ISIG
	newState.Iflag |= syscall.ICRNL
	err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState)
	if err != nil {
		return nil, err
	}

	defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState)

	var buf [16]byte
	var ret []byte
	for {
		n, err := syscall.Read(fd, buf[:])
		if err != nil {
			return nil, err
		}
		if n == 0 {
			if len(ret) == 0 {
				return nil, io.EOF
			}
			break
		}
		if buf[n-1] == '\n' {
			n--
		}
		ret = append(ret, buf[:n]...)
		if n < len(buf) {
			break
		}
	}

	return ret, nil
}

// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
// see http://cr.illumos.org/~webrev/andy_js/1060/
func MakeRaw(fd int) (*State, error) {
	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
	if err != nil {
		return nil, err
	}

	oldState := State{termios: *termios}

	termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
	termios.Oflag &^= unix.OPOST
	termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
	termios.Cflag &^= unix.CSIZE | unix.PARENB
	termios.Cflag |= unix.CS8
	termios.Cc[unix.VMIN] = 1
	termios.Cc[unix.VTIME] = 0

	if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil {
		return nil, err
	}

	return &oldState, nil
}

// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, oldState *State) error {
	return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios)
}

// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
	if err != nil {
		return nil, err
	}

	return &State{termios: *termios}, nil
}

// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
	if err != nil {
		return 0, 0, err
	}
	return int(ws.Col), int(ws.Row), nil
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package machiner

import (
	"fmt"

	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state/api/params"
	"launchpad.net/juju-core/state/api/watcher"
)

// Machine represents a juju machine as seen by a machiner worker.
type Machine struct {
	tag  string
	life params.Life
	st   *State
}

// Tag returns the machine's tag.
func (m *Machine) Tag() string {
	return m.tag
}

// Life returns the machine's lifecycle value.
func (m *Machine) Life() params.Life {
	return m.life
}

// Refresh updates the cached local copy of the machine's data.
func (m *Machine) Refresh() error {
	life, err := m.st.machineLife(m.tag)
	if err != nil {
		return err
	}
	m.life = life
	return nil
}

// SetStatus sets the status of the machine.
func (m *Machine) SetStatus(status params.Status, info string, data params.StatusData) error {
	var result params.ErrorResults
	args := params.SetStatus{
		Entities: []params.SetEntityStatus{
			{Tag: m.tag, Status: status, Info: info, Data: data},
		},
	}
	err := m.st.caller.Call("Machiner", "", "SetStatus", args, &result)
	if err != nil {
		return err
	}
	return result.OneError()
}

// SetMachineAddresses sets the machine determined addresses of the machine.
func (m *Machine) SetMachineAddresses(addresses []instance.Address) error {
	var result params.ErrorResults
	args := params.SetMachinesAddresses{
		MachineAddresses: []params.MachineAddresses{
			{Tag: m.Tag(), Addresses: addresses},
		},
	}
	err := m.st.caller.Call("Machiner", "", "SetMachineAddresses", args, &result)
	if err != nil {
		return err
	}
	return result.OneError()
}

// EnsureDead sets the machine lifecycle to Dead if it is Alive or
// Dying. It does nothing otherwise.
func (m *Machine) EnsureDead() error {
	var result params.ErrorResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: m.tag}},
	}
	err := m.st.caller.Call("Machiner", "", "EnsureDead", args, &result)
	if err != nil {
		return err
	}
	return result.OneError()
}

// Watch returns a watcher for observing changes to the machine.
func (m *Machine) Watch() (watcher.NotifyWatcher, error) {
	var results params.NotifyWatchResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: m.tag}},
	}
	err := m.st.caller.Call("Machiner", "", "Watch", args, &results)
	if err != nil {
		return nil, err
	}
	if len(results.Results) != 1 {
		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		return nil, result.Error
	}
	w := watcher.NewNotifyWatcher(m.st.caller, result)
	return w, nil
}
<commit_msg>state/api/machiner<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package machiner

import (
	"fmt"

	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state/api/params"
	"launchpad.net/juju-core/state/api/watcher"
)

// Machine represents a juju machine as seen by a machiner worker.
type Machine struct {
	tag  string
	life params.Life
	st   *State
}

// Tag returns the machine's tag.
func (m *Machine) Tag() string {
	return m.tag
}

// Life returns the machine's lifecycle value.
func (m *Machine) Life() params.Life {
	return m.life
}

// Refresh updates the cached local copy of the machine's data.
func (m *Machine) Refresh() error {
	life, err := m.st.machineLife(m.tag)
	if err != nil {
		return err
	}
	m.life = life
	return nil
}

// SetStatus sets the status of the machine.
func (m *Machine) SetStatus(status params.Status, info string, data params.StatusData) error {
	var result params.ErrorResults
	args := params.SetStatus{
		Entities: []params.SetEntityStatus{
			{Tag: m.tag, Status: status, Info: info, Data: data},
		},
	}
	err := m.st.call("SetStatus", args, &result)
	if err != nil {
		return err
	}
	return result.OneError()
}

// SetMachineAddresses sets the machine determined addresses of the machine.
func (m *Machine) SetMachineAddresses(addresses []instance.Address) error {
	var result params.ErrorResults
	args := params.SetMachinesAddresses{
		MachineAddresses: []params.MachineAddresses{
			{Tag: m.Tag(), Addresses: addresses},
		},
	}
	err := m.st.call("SetMachineAddresses", args, &result)
	if err != nil {
		return err
	}
	return result.OneError()
}

// EnsureDead sets the machine lifecycle to Dead if it is Alive or
// Dying. It does nothing otherwise.
func (m *Machine) EnsureDead() error {
	var result params.ErrorResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: m.tag}},
	}
	err := m.st.call("EnsureDead", args, &result)
	if err != nil {
		return err
	}
	return result.OneError()
}

// Watch returns a watcher for observing changes to the machine.
func (m *Machine) Watch() (watcher.NotifyWatcher, error) {
	var results params.NotifyWatchResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: m.tag}},
	}
	err := m.st.call("Watch", args, &results)
	if err != nil {
		return nil, err
	}
	if len(results.Results) != 1 {
		return nil, fmt.Errorf("expected one result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		return nil, result.Error
	}
	w := watcher.NewNotifyWatcher(m.st.caller, result)
	return w, nil
}
<|endoftext|>