<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package e2e_node

import (
	"time"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/kubernetes/pkg/features"
	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
	"k8s.io/kubernetes/test/e2e/common"
	"k8s.io/kubernetes/test/e2e/framework"
	testutils "k8s.io/kubernetes/test/utils"
	imageutils "k8s.io/kubernetes/test/utils/image"

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

const (
	defaultObservationTimeout = time.Minute * 4
)

var _ = framework.KubeDescribe("StartupProbe [Serial] [Disruptive] [NodeAlphaFeature:StartupProbe]", func() {
	f := framework.NewDefaultFramework("startup-probe-test")
	var podClient *framework.PodClient
	ginkgo.BeforeEach(func() {
		podClient = f.PodClient()
	})

	/*
		These tests are located here as they require tempSetCurrentKubeletConfig to enable the feature gate for startupProbe.
		Once the feature gate has been removed, these tests should come back to test/e2e/common/container_probe.go.
	*/
	ginkgo.Context("when a container has a startup probe", func() {
		tempSetCurrentKubeletConfig(f, func(initialConfig *kubeletconfig.KubeletConfiguration) {
			if initialConfig.FeatureGates == nil {
				initialConfig.FeatureGates = make(map[string]bool)
			}
			initialConfig.FeatureGates[string(features.StartupProbe)] = true
		})

		/*
			Release : v1.16
			Testname: Pod liveness probe, using local file, delayed by startup probe
			Description: A Pod is created with liveness probe that uses ‘exec’ command to cat the non-existent /tmp/health file. Liveness probe MUST NOT fail until startup probe expires.
		*/
		framework.ConformanceIt("should *not* be restarted with a exec \"cat /tmp/health\" because startup probe delays it [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "sleep 600"}
			livenessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    1,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    60,
			}
			pod := startupPodSpec(startupProbe, nil, livenessProbe, cmd)
			common.RunLivenessTest(f, pod, 0, defaultObservationTimeout)
		})

		/*
			Release : v1.16
			Testname: Pod liveness probe, using local file, delayed by startup probe
			Description: A Pod is created with liveness probe that uses ‘exec’ command to cat the non-existent /tmp/health file. Liveness probe MUST fail after startup probe expires. The Pod MUST now be killed and restarted incrementing restart count to 1.
		*/
		framework.ConformanceIt("should be restarted with a exec \"cat /tmp/health\" because startup probe does not delay it long enough [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "sleep 600"}
			livenessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    1,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    3,
			}
			pod := startupPodSpec(startupProbe, nil, livenessProbe, cmd)
			common.RunLivenessTest(f, pod, 1, defaultObservationTimeout)
		})

		/*
			Release : v1.16
			Testname: Pod liveness probe, using local file, startup finished restart
			Description: A Pod is created with liveness probe that uses ‘exec’ command to cat /temp/health file. The Container is started by creating /tmp/startup after 10 seconds, triggering liveness probe to fail. The Pod MUST now be killed and restarted incrementing restart count to 1.
		*/
		framework.ConformanceIt("should be restarted with a exec \"cat /tmp/health\" after startup probe succeeds it [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "sleep 10; echo ok >/tmp/startup; sleep 600"}
			livenessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    1,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/startup"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    60,
			}
			pod := startupPodSpec(startupProbe, nil, livenessProbe, cmd)
			common.RunLivenessTest(f, pod, 1, defaultObservationTimeout)
		})

		/*
			Release : v1.16
			Testname: Pod readiness probe, delayed by startup probe
			Description: A Pod is created with startup and readiness probes. The Container is started by creating /tmp/startup after 45 seconds, delaying the ready state by this amount of time. This is similar to the "Pod readiness probe, with initial delay" test.
		*/
		framework.ConformanceIt("should not be ready until startupProbe succeeds [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "echo ok >/tmp/health; sleep 45; echo ok >/tmp/startup; sleep 600"}
			readinessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 0,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/startup"},
					},
				},
				InitialDelaySeconds: 0,
				FailureThreshold:    60,
			}
			p := podClient.Create(startupPodSpec(startupProbe, readinessProbe, nil, cmd))

			p, err := podClient.Get(p.Name, metav1.GetOptions{})
			framework.ExpectNoError(err)

			f.WaitForPodReady(p.Name)
			isReady, err := testutils.PodRunningReady(p)
			framework.ExpectNoError(err)
			gomega.Expect(isReady).To(gomega.BeTrue(), "pod should be ready")

			// We assume the pod became ready when the container became ready. This
			// is true for a single container pod.
			readyTime, err := common.GetTransitionTimeForReadyCondition(p)
			framework.ExpectNoError(err)
			startedTime, err := common.GetContainerStartedTime(p, "busybox")
			framework.ExpectNoError(err)

			framework.Logf("Container started at %v, pod became ready at %v", startedTime, readyTime)
			if readyTime.Sub(startedTime) < 40*time.Second {
				framework.Failf("Pod became ready before startupProbe succeeded")
			}
		})
	})
})

func startupPodSpec(startupProbe, readinessProbe, livenessProbe *v1.Probe, cmd []string) *v1.Pod {
	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:   "startup-" + string(uuid.NewUUID()),
			Labels: map[string]string{"test": "startup"},
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:           "busybox",
					Image:          imageutils.GetE2EImage(imageutils.BusyBox),
					Command:        cmd,
					LivenessProbe:  livenessProbe,
					ReadinessProbe: readinessProbe,
					StartupProbe:   startupProbe,
				},
			},
		},
	}
}
<commit_msg>Clarify startupProbe e2e tests<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package e2e_node

import (
	"time"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/kubernetes/pkg/features"
	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
	"k8s.io/kubernetes/test/e2e/common"
	"k8s.io/kubernetes/test/e2e/framework"
	testutils "k8s.io/kubernetes/test/utils"
	imageutils "k8s.io/kubernetes/test/utils/image"

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

const (
	defaultObservationTimeout = time.Minute * 4
)

var _ = framework.KubeDescribe("StartupProbe [Serial] [Disruptive] [NodeAlphaFeature:StartupProbe]", func() {
	f := framework.NewDefaultFramework("startup-probe-test")
	var podClient *framework.PodClient
	ginkgo.BeforeEach(func() {
		podClient = f.PodClient()
	})

	/*
		These tests are located here as they require tempSetCurrentKubeletConfig to enable the feature gate for startupProbe.
		Once the feature gate has been removed, these tests should come back to test/e2e/common/container_probe.go.
	*/
	ginkgo.Context("when a container has a startup probe", func() {
		tempSetCurrentKubeletConfig(f, func(initialConfig *kubeletconfig.KubeletConfiguration) {
			if initialConfig.FeatureGates == nil {
				initialConfig.FeatureGates = make(map[string]bool)
			}
			initialConfig.FeatureGates[string(features.StartupProbe)] = true
		})

		/*
			Release : v1.16
			Testname: Pod startup probe restart
			Description: A Pod is created with a failing startup probe. The Pod MUST be killed and restarted incrementing restart count to 1, even if liveness would succeed.
		*/
		framework.ConformanceIt("should be restarted startup probe fails [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "sleep 600"}
			livenessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"/bin/true"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    1,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"/bin/false"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    3,
			}
			pod := startupPodSpec(startupProbe, nil, livenessProbe, cmd)
			common.RunLivenessTest(f, pod, 1, defaultObservationTimeout)
		})

		/*
			Release : v1.16
			Testname: Pod liveness probe delayed (long) by startup probe
			Description: A Pod is created with failing liveness and startup probes. Liveness probe MUST NOT fail until startup probe expires.
		*/
		framework.ConformanceIt("should *not* be restarted by liveness probe because startup probe delays it [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "sleep 600"}
			livenessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"/bin/false"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    1,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"/bin/false"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    60,
			}
			pod := startupPodSpec(startupProbe, nil, livenessProbe, cmd)
			common.RunLivenessTest(f, pod, 0, defaultObservationTimeout)
		})

		/*
			Release : v1.16
			Testname: Pod liveness probe fails after startup success
			Description: A Pod is created with failing liveness probe and delayed startup probe that uses ‘exec’ command to cat /temp/health file. The Container is started by creating /tmp/startup after 10 seconds, triggering liveness probe to fail. The Pod MUST now be killed and restarted incrementing restart count to 1.
		*/
		framework.ConformanceIt("should be restarted by liveness probe after startup probe enables it [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "sleep 10; echo ok >/tmp/startup; sleep 600"}
			livenessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"/bin/false"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    1,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/startup"},
					},
				},
				InitialDelaySeconds: 15,
				FailureThreshold:    60,
			}
			pod := startupPodSpec(startupProbe, nil, livenessProbe, cmd)
			common.RunLivenessTest(f, pod, 1, defaultObservationTimeout)
		})

		/*
			Release : v1.16
			Testname: Pod readiness probe, delayed by startup probe
			Description: A Pod is created with startup and readiness probes. The Container is started by creating /tmp/startup after 45 seconds, delaying the ready state by this amount of time. This is similar to the "Pod readiness probe, with initial delay" test.
		*/
		framework.ConformanceIt("should not be ready until startupProbe succeeds [NodeConformance]", func() {
			cmd := []string{"/bin/sh", "-c", "echo ok >/tmp/health; sleep 45; echo ok >/tmp/startup; sleep 600"}
			readinessProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/health"},
					},
				},
				InitialDelaySeconds: 0,
			}
			startupProbe := &v1.Probe{
				Handler: v1.Handler{
					Exec: &v1.ExecAction{
						Command: []string{"cat", "/tmp/startup"},
					},
				},
				InitialDelaySeconds: 0,
				FailureThreshold:    60,
			}
			p := podClient.Create(startupPodSpec(startupProbe, readinessProbe, nil, cmd))

			p, err := podClient.Get(p.Name, metav1.GetOptions{})
			framework.ExpectNoError(err)

			f.WaitForPodReady(p.Name)
			isReady, err := testutils.PodRunningReady(p)
			framework.ExpectNoError(err)
			gomega.Expect(isReady).To(gomega.BeTrue(), "pod should be ready")

			// We assume the pod became ready when the container became ready. This
			// is true for a single container pod.
			readyTime, err := common.GetTransitionTimeForReadyCondition(p)
			framework.ExpectNoError(err)
			startedTime, err := common.GetContainerStartedTime(p, "busybox")
			framework.ExpectNoError(err)

			framework.Logf("Container started at %v, pod became ready at %v", startedTime, readyTime)
			if readyTime.Sub(startedTime) < 40*time.Second {
				framework.Failf("Pod became ready before startupProbe succeeded")
			}
		})
	})
})

func startupPodSpec(startupProbe, readinessProbe, livenessProbe *v1.Probe, cmd []string) *v1.Pod {
	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:   "startup-" + string(uuid.NewUUID()),
			Labels: map[string]string{"test": "startup"},
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:           "busybox",
					Image:          imageutils.GetE2EImage(imageutils.BusyBox),
					Command:        cmd,
					LivenessProbe:  livenessProbe,
					ReadinessProbe: readinessProbe,
					StartupProbe:   startupProbe,
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2016 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 integration

import (
	"context"
	"os/exec"
	"regexp"
	"strings"
	"testing"
)

// stderrWhitelist are regular expressions acceptable to find in normal stderr
var stderrWhitelist = []string{
	// kubectl out of date warning
	`kubectl`,
	// slow docker warning
	`slow|long time|Restarting the docker service may improve`,
}

// stderrWhitelistRe combines rootCauses into a single regex
var stderrWhitelistRe = regexp.MustCompile(strings.Join(stderrWhitelist, "|"))

// TestErrorSpam asserts that there are no errors displayed
func TestErrorSpam(t *testing.T) {
	if NoneDriver() {
		t.Skip("none driver always shows a warning")
	}
	MaybeParallel(t)

	profile := UniqueProfileName("nospam")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(25))
	defer CleanupWithLogs(t, profile, cancel)

	// This should likely use multi-node once it's ready
	args := append([]string{"start", "-p", profile, "-n=1", "--memory=2250", "--wait=false"}, StartArgs()...)

	rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("%q failed: %v", rr.Command(), err)
	}

	for _, line := range strings.Split(rr.Stderr.String(), "\n") {
		if strings.HasPrefix(line, "E") {
			t.Errorf("unexpected error log: %q", line)
			continue
		}

		if stderrWhitelistRe.MatchString(line) {
			t.Logf("acceptable stderr: %q", line)
			continue
		}

		if len(strings.TrimSpace(line)) > 0 {
			t.Errorf("unexpected stderr: %q", line)
		}
	}

	for _, line := range strings.Split(rr.Stdout.String(), "\n") {
		keywords := []string{"error", "fail", "warning", "conflict"}
		for _, keyword := range keywords {
			if strings.Contains(line, keyword) {
				t.Errorf("unexpected %q in stdout: %q", keyword, line)
			}
		}
	}
}
<commit_msg>Silence cache_images state errors<commit_after>// +build integration

/*
Copyright 2016 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 integration

import (
	"context"
	"os/exec"
	"regexp"
	"strings"
	"testing"
)

// stderrWhitelist are regular expressions acceptable to find in normal stderr
var stderrWhitelist = []string{
	// kubectl out of date warning
	`kubectl`,
	// slow docker warning
	`slow|long time|Restarting the docker service may improve`,
	// don't care if we can't push images to other profiles
	`cache_images.go:.*error getting status`,
}

// stderrWhitelistRe combines rootCauses into a single regex
var stderrWhitelistRe = regexp.MustCompile(strings.Join(stderrWhitelist, "|"))

// TestErrorSpam asserts that there are no errors displayed
func TestErrorSpam(t *testing.T) {
	if NoneDriver() {
		t.Skip("none driver always shows a warning")
	}
	MaybeParallel(t)

	profile := UniqueProfileName("nospam")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(25))
	defer CleanupWithLogs(t, profile, cancel)

	// This should likely use multi-node once it's ready
	args := append([]string{"start", "-p", profile, "-n=1", "--memory=2250", "--wait=false"}, StartArgs()...)

	rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("%q failed: %v", rr.Command(), err)
	}

	for _, line := range strings.Split(rr.Stderr.String(), "\n") {
		if strings.HasPrefix(line, "E") {
			t.Errorf("unexpected error log: %q", line)
			continue
		}

		if stderrWhitelistRe.MatchString(line) {
			t.Logf("acceptable stderr: %q", line)
			continue
		}

		if len(strings.TrimSpace(line)) > 0 {
			t.Errorf("unexpected stderr: %q", line)
		}
	}

	for _, line := range strings.Split(rr.Stdout.String(), "\n") {
		keywords := []string{"error", "fail", "warning", "conflict"}
		for _, keyword := range keywords {
			if strings.Contains(line, keyword) {
				t.Errorf("unexpected %q in stdout: %q", keyword, line)
			}
		}
	}
}
<|endoftext|>


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

package inode_test

import (
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/fs/inode"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsfake"
	. "github.com/jacobsa/ogletest"
)

func TestDir(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const inodeID = 17
const inodeName = "foo/bar/"
const typeCacheTTL = time.Second

type DirTest struct {
	ctx    context.Context
	bucket gcs.Bucket
	clock  timeutil.SimulatedClock

	in *inode.DirInode
}

var _ SetUpInterface = &DirTest{}
var _ TearDownInterface = &DirTest{}

func init() { RegisterTestSuite(&DirTest{}) }

func (t *DirTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))
	t.bucket = gcsfake.NewFakeBucket(&t.clock, "some_bucket")

	// Create the inode. No implicit dirs by default.
	t.resetInode(false)
}

func (t *DirTest) TearDown() {
	t.in.Unlock()
}

func (t *DirTest) resetInode(implicitDirs bool) {
	if t.in != nil {
		t.in.Unlock()
	}

	t.in = inode.NewDirInode(
		inodeID,
		inodeName,
		implicitDirs,
		typeCacheTTL,
		t.bucket,
		&t.clock)

	t.in.Lock()
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DirTest) ID() {
	ExpectEq(inodeID, t.in.ID())
}

func (t *DirTest) Name() {
	ExpectEq(inodeName, t.in.Name())
}

func (t *DirTest) LookupCount() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) Attributes() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_NonExistent() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_DirOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDir() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_Empty() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsDisabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsEnabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_LotsOfEntries() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}
<commit_msg>DirTest.LookupCount<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package inode_test

import (
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/googlecloudplatform/gcsfuse/fs/inode"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/gcsfake"
	. "github.com/jacobsa/ogletest"
)

func TestDir(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const inodeID = 17
const inodeName = "foo/bar/"
const typeCacheTTL = time.Second

type DirTest struct {
	ctx    context.Context
	bucket gcs.Bucket
	clock  timeutil.SimulatedClock

	in *inode.DirInode
}

var _ SetUpInterface = &DirTest{}
var _ TearDownInterface = &DirTest{}

func init() { RegisterTestSuite(&DirTest{}) }

func (t *DirTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.clock.SetTime(time.Date(2015, 4, 5, 2, 15, 0, 0, time.Local))
	t.bucket = gcsfake.NewFakeBucket(&t.clock, "some_bucket")

	// Create the inode. No implicit dirs by default.
	t.resetInode(false)
}

func (t *DirTest) TearDown() {
	t.in.Unlock()
}

func (t *DirTest) resetInode(implicitDirs bool) {
	if t.in != nil {
		t.in.Unlock()
	}

	t.in = inode.NewDirInode(
		inodeID,
		inodeName,
		implicitDirs,
		typeCacheTTL,
		t.bucket,
		&t.clock)

	t.in.Lock()
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DirTest) ID() {
	ExpectEq(inodeID, t.in.ID())
}

func (t *DirTest) Name() {
	ExpectEq(inodeName, t.in.Name())
}

func (t *DirTest) LookupCount() {
	// Increment thrice. The count should now be three.
	t.in.IncrementLookupCount()
	t.in.IncrementLookupCount()
	t.in.IncrementLookupCount()

	// Decrementing twice shouldn't cause destruction. But one more should.
	AssertFalse(t.in.DecrementLookupCount(2))
	ExpectTrue(t.in.DecrementLookupCount(1))
}

func (t *DirTest) Attributes() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_NonExistent() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_DirOnly() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_ImplicitDirOnly_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDir() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Disabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_FileAndDirAndImplicitDir_Enabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) LookUpChild_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_Empty() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsDisabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_NonEmpty_ImplicitDirsEnabled() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_LotsOfEntries() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) ReadEntries_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) CreateChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildFile_TypeCaching() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_DoesntExist() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_Exists() {
	AssertTrue(false, "TODO")
}

func (t *DirTest) DeleteChildDir_TypeCaching() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


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

// TODO: Rewrite using package syscall not cgo

package fuse

/*

// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
// which carries this notice:
//
// The files in this directory are subject to the following license.
//
// The author of this software is Russ Cox.
//
//         Copyright (c) 2006 Russ Cox
//
// Permission to use, copy, modify, and distribute this software for any
// purpose without fee is hereby granted, provided that this entire notice
// is included in all copies of any software which is or includes a copy
// or modification of this software and in all copies of the supporting
// documentation for such software.
//
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
// FITNESS FOR ANY PARTICULAR PURPOSE.

#include <stdlib.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>

#define nil ((void*)0)

static int
mountfuse(char *mtpt, char **err)
{
	int i, pid, fd, r;
	char buf[200];
	struct vfsconf vfs;
	char *f;

	if(getvfsbyname("fusefs", &vfs) < 0){
		if(access(f="/Library/Filesystems/osxfusefs.fs"
			"/Support/load_osxfusefs", 0) < 0){
		         *err = strdup("cannot find load_fusefs");
		   	return -1;
		}
		if((r=system(f)) < 0){
			snprintf(buf, sizeof buf, "%s: %s", f, strerror(errno));
			*err = strdup(buf);
			return -1;
		}
		if(r != 0){
			snprintf(buf, sizeof buf, "load_fusefs failed: exit %d", r);
			*err = strdup(buf);
			return -1;
		}
		if(getvfsbyname("osxfusefs", &vfs) < 0){
			snprintf(buf, sizeof buf, "getvfsbyname osxfusefs: %s", strerror(errno));
			*err = strdup(buf);
			return -1;
		}
	}

	// Look for available FUSE device.
	for(i=0;; i++){
		snprintf(buf, sizeof buf, "/dev/osxfuse%d", i);
		if(access(buf, 0) < 0){
			*err = strdup("no available fuse devices");
			return -1;
		}
		if((fd = open(buf, O_RDWR)) >= 0)
			break;
	}

	pid = fork();
	if(pid < 0)
		return -1;
	if(pid == 0){
		snprintf(buf, sizeof buf, "%d", fd);
		setenv("MOUNT_FUSEFS_CALL_BY_LIB", "", 1);
		// Different versions of MacFUSE put the
		// mount_fusefs binary in different places.
		// Try all.
		// Leopard location
		setenv("MOUNT_FUSEFS_DAEMON_PATH",
			   "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", 1);
		execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
			  "mount_osxfusefs",
			  "-o", "iosize=4096", buf, mtpt, nil);
		fprintf(stderr, "exec mount_osxfusefs: %s\n", strerror(errno));
		_exit(1);
	}
	return fd;
}

*/
import "C"
import (
	"fmt"
	"log"
	"os/exec"
	"syscall"
	"unsafe"
)

func mount(dir string, options string) (int, error) {
	errp := (**C.char)(C.malloc(16))
	*errp = nil
	defer C.free(unsafe.Pointer(errp))
	cdir := C.CString(dir)
	defer C.free(unsafe.Pointer(cdir))
	fd := C.mountfuse(cdir, errp)
	if *errp != nil {
		return -1, mountError(C.GoString(*errp))
	}
	return int(fd), nil
}

type mountError string

func (m mountError) Error() string {
	return string(m)
}

func unmount(mountPoint string) error {
	if err := syscall.Unmount(mountPoint, 0); err != nil {
		return fmt.Errorf("umount(%q): %v", mountPoint, err)
	}
	return nil
}

var umountBinary string

func init() {
	var err error
	umountBinary, err = exec.LookPath("umount")
	if err != nil {
		log.Fatalf("Could not find umount binary: %v", err)
	}
}
<commit_msg>fixed fs name<commit_after>// Copyright 2011 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.

// TODO: Rewrite using package syscall not cgo

package fuse

/*

// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
// which carries this notice:
//
// The files in this directory are subject to the following license.
//
// The author of this software is Russ Cox.
//
//         Copyright (c) 2006 Russ Cox
//
// Permission to use, copy, modify, and distribute this software for any
// purpose without fee is hereby granted, provided that this entire notice
// is included in all copies of any software which is or includes a copy
// or modification of this software and in all copies of the supporting
// documentation for such software.
//
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
// FITNESS FOR ANY PARTICULAR PURPOSE.

#include <stdlib.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>

#define nil ((void*)0)

static int
mountfuse(char *mtpt, char **err)
{
	int i, pid, fd, r;
	char buf[200];
	struct vfsconf vfs;
	char *f;

	if(getvfsbyname("osxfusefs", &vfs) < 0){
		if(access(f="/Library/Filesystems/osxfusefs.fs"
			"/Support/load_osxfusefs", 0) < 0){
		         *err = strdup("cannot find load_fusefs");
		   	return -1;
		}
		if((r=system(f)) < 0){
			snprintf(buf, sizeof buf, "%s: %s", f, strerror(errno));
			*err = strdup(buf);
			return -1;
		}
		if(r != 0){
			snprintf(buf, sizeof buf, "load_fusefs failed: exit %d", r);
			*err = strdup(buf);
			return -1;
		}
		if(getvfsbyname("osxfusefs", &vfs) < 0){
			snprintf(buf, sizeof buf, "getvfsbyname osxfusefs: %s", strerror(errno));
			*err = strdup(buf);
			return -1;
		}
	}

	// Look for available FUSE device.
	for(i=0;; i++){
		snprintf(buf, sizeof buf, "/dev/osxfuse%d", i);
		if(access(buf, 0) < 0){
			*err = strdup("no available fuse devices");
			return -1;
		}
		if((fd = open(buf, O_RDWR)) >= 0)
			break;
	}

	pid = fork();
	if(pid < 0)
		return -1;
	if(pid == 0){
		snprintf(buf, sizeof buf, "%d", fd);
		setenv("MOUNT_FUSEFS_CALL_BY_LIB", "", 1);
		// Different versions of MacFUSE put the
		// mount_fusefs binary in different places.
		// Try all.
		// Leopard location
		setenv("MOUNT_FUSEFS_DAEMON_PATH",
			   "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", 1);
		execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
			  "mount_osxfusefs",
			  "-o", "iosize=4096", buf, mtpt, nil);
		fprintf(stderr, "exec mount_osxfusefs: %s\n", strerror(errno));
		_exit(1);
	}
	return fd;
}

*/
import "C"
import (
	"fmt"
	"log"
	"os/exec"
	"syscall"
	"unsafe"
)

func mount(dir string, options string) (int, error) {
	errp := (**C.char)(C.malloc(16))
	*errp = nil
	defer C.free(unsafe.Pointer(errp))
	cdir := C.CString(dir)
	defer C.free(unsafe.Pointer(cdir))
	fd := C.mountfuse(cdir, errp)
	if *errp != nil {
		return -1, mountError(C.GoString(*errp))
	}
	return int(fd), nil
}

type mountError string

func (m mountError) Error() string {
	return string(m)
}

func unmount(mountPoint string) error {
	if err := syscall.Unmount(mountPoint, 0); err != nil {
		return fmt.Errorf("umount(%q): %v", mountPoint, err)
	}
	return nil
}

var umountBinary string

func init() {
	var err error
	umountBinary, err = exec.LookPath("umount")
	if err != nil {
		log.Fatalf("Could not find umount binary: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestStatsNoStream(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	statsCmd := exec.Command(dockerBinary, "stats", "--no-stream", id)
	type output struct {
		out []byte
		err error
	}

	ch := make(chan output)
	go func() {
		out, err := statsCmd.Output()
		ch <- output{out, err}
	}()

	select {
	case outerr := <-ch:
		c.Assert(outerr.err, checker.IsNil, check.Commentf("Error running stats: %v", outerr.err))
		c.Assert(string(outerr.out), checker.Contains, id) //running container wasn't present in output
	case <-time.After(3 * time.Second):
		statsCmd.Process.Kill()
		c.Fatalf("stats did not return immediately when not streaming")
	}
}

func (s *DockerSuite) TestStatsContainerNotFound(c *check.C) {
	testRequires(c, DaemonIsLinux)

	out, _, err := dockerCmdWithError("stats", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats, got %q instead", out))

	out, _, err = dockerCmdWithError("stats", "--no-stream", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats with --no-stream, got %q instead", out))
}

func (s *DockerSuite) TestStatsAllRunningNoStream(c *check.C) {
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id3 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id3), check.IsNil)
	dockerCmd(c, "stop", id3)

	out, _ = dockerCmd(c, "stats", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
	if strings.Contains(out, id3) {
		c.Fatalf("Did not expect %s in stats, got %s", id3, out)
	}
}

func (s *DockerSuite) TestStatsAllNoStream(c *check.C) {
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	dockerCmd(c, "stop", id1)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)

	out, _ = dockerCmd(c, "stats", "--all", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
}

func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
	testRequires(c, DaemonIsLinux)

	id := make(chan string)
	addedChan := make(chan struct{})

	dockerCmd(c, "run", "-d", "busybox", "top")
	statsCmd := exec.Command(dockerBinary, "stats")
	stdout, err := statsCmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	c.Assert(statsCmd.Start(), check.IsNil)
	defer statsCmd.Process.Kill()

	go func() {
		containerID := <-id
		matchID := regexp.MustCompile(containerID)

		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			switch {
			case matchID.MatchString(scanner.Text()):
				close(addedChan)
			}
		}
	}()

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id <- strings.TrimSpace(out)[:12]

	select {
	case <-time.After(5 * time.Second):
		c.Fatal("failed to observe new container created added to stats")
	case <-addedChan:
		// ignore, done
	}
}
<commit_msg>Fix flaky test TestStatsAllNewContainersAdded<commit_after>package main

import (
	"bufio"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestStatsNoStream(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	statsCmd := exec.Command(dockerBinary, "stats", "--no-stream", id)
	type output struct {
		out []byte
		err error
	}

	ch := make(chan output)
	go func() {
		out, err := statsCmd.Output()
		ch <- output{out, err}
	}()

	select {
	case outerr := <-ch:
		c.Assert(outerr.err, checker.IsNil, check.Commentf("Error running stats: %v", outerr.err))
		c.Assert(string(outerr.out), checker.Contains, id) //running container wasn't present in output
	case <-time.After(3 * time.Second):
		statsCmd.Process.Kill()
		c.Fatalf("stats did not return immediately when not streaming")
	}
}

func (s *DockerSuite) TestStatsContainerNotFound(c *check.C) {
	testRequires(c, DaemonIsLinux)

	out, _, err := dockerCmdWithError("stats", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats, got %q instead", out))

	out, _, err = dockerCmdWithError("stats", "--no-stream", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats with --no-stream, got %q instead", out))
}

func (s *DockerSuite) TestStatsAllRunningNoStream(c *check.C) {
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id3 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id3), check.IsNil)
	dockerCmd(c, "stop", id3)

	out, _ = dockerCmd(c, "stats", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
	if strings.Contains(out, id3) {
		c.Fatalf("Did not expect %s in stats, got %s", id3, out)
	}
}

func (s *DockerSuite) TestStatsAllNoStream(c *check.C) {
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	dockerCmd(c, "stop", id1)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)

	out, _ = dockerCmd(c, "stats", "--all", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
}

func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
	testRequires(c, DaemonIsLinux)

	id := make(chan string)
	addedChan := make(chan struct{})

	dockerCmd(c, "run", "-d", "busybox", "top")
	statsCmd := exec.Command(dockerBinary, "stats")
	stdout, err := statsCmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	c.Assert(statsCmd.Start(), check.IsNil)
	defer statsCmd.Process.Kill()

	go func() {
		containerID := <-id
		matchID := regexp.MustCompile(containerID)

		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			switch {
			case matchID.MatchString(scanner.Text()):
				close(addedChan)
			}
		}
	}()

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	c.Assert(waitRun(strings.TrimSpace(out)), check.IsNil)
	id <- strings.TrimSpace(out)[:12]

	select {
	case <-time.After(5 * time.Second):
		c.Fatal("failed to observe new container created added to stats")
	case <-addedChan:
		// ignore, done
	}
}
<|endoftext|>


<commit_before>package handlers_test

import (
	"fmt"
	"github.com/aclindsa/moneygo/internal/handlers"
	"strconv"
	"testing"
)

type LuaTest struct {
	Name     string
	Lua      string
	Expected string
}

func TestLuaSecurities(t *testing.T) {
	RunWith(t, &data[0], func(t *testing.T, d *TestData) {
		defaultSecurity, err := getSecurity(d.clients[0], d.users[0].DefaultCurrency)
		if err != nil {
			t.Fatalf("Error getting default security: %s", err)
		}

		for _, lt := range []LuaTest{
			{"SecurityId", `return get_default_currency().SecurityId`, strconv.FormatInt(defaultSecurity.SecurityId, 10)},
			{"Name", `return get_default_currency().Name`, defaultSecurity.Name},
			{"Description", `return get_default_currency().Description`, defaultSecurity.Description},
			{"Symbol", `return get_default_currency().Symbol`, defaultSecurity.Symbol},
			{"Precision", `return get_default_currency().Precision`, strconv.FormatInt(int64(defaultSecurity.Precision), 10)},
			{"Type", `return get_default_currency().Type`, strconv.FormatInt(int64(defaultSecurity.Type), 10)},
			{"AlternateId", `return get_default_currency().AlternateId`, defaultSecurity.AlternateId},
		} {
			lua := fmt.Sprintf(`function test()
	%s
end

function generate()
    t = tabulation.new(0)
    t:title(tostring(test()))
	return t
end`, lt.Lua)
			r := handlers.Report{
				Name: lt.Name,
				Lua:  lua,
			}
			report, err := createReport(d.clients[0], &r)
			if err != nil {
				t.Fatalf("Error creating report: %s", err)
			}

			tab, err := tabulateReport(d.clients[0], report.ReportId)
			if err != nil {
				t.Fatalf("Error tabulating report: %s", err)
			}

			if tab.Title != lt.Expected {
				t.Errorf("%s: Returned '%s', expected '%s'", lt.Name, tab.Title, lt.Expected)
			}
		}
	})
}
<commit_msg>testing: Test get_securities() Lua call<commit_after>package handlers_test

import (
	"fmt"
	"github.com/aclindsa/moneygo/internal/handlers"
	"sort"
	"strconv"
	"testing"
)

type LuaTest struct {
	Name     string
	Lua      string
	Expected string
}

// Int64Slice attaches the methods of int64 to []int64, sorting in increasing order.
type Int64Slice []int64

func (p Int64Slice) Len() int           { return len(p) }
func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p Int64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// Sort is a convenience method.
func (p Int64Slice) Sort() { sort.Sort(p) }

func TestLuaSecurities(t *testing.T) {
	RunWith(t, &data[0], func(t *testing.T, d *TestData) {
		defaultSecurity, err := getSecurity(d.clients[0], d.users[0].DefaultCurrency)
		if err != nil {
			t.Fatalf("Error getting default security: %s", err)
		}
		securities, err := getSecurities(d.clients[0])
		if err != nil {
			t.Fatalf("Error getting securities: %s", err)
		}
		securityids := make(Int64Slice, len(*securities.Securities))
		for i, s := range *securities.Securities {
			securityids[i] = s.SecurityId
		}
		securityids.Sort()

		for _, lt := range []LuaTest{
			{"SecurityId", `return get_default_currency().SecurityId`, strconv.FormatInt(defaultSecurity.SecurityId, 10)},
			{"Name", `return get_default_currency().Name`, defaultSecurity.Name},
			{"Description", `return get_default_currency().Description`, defaultSecurity.Description},
			{"Symbol", `return get_default_currency().Symbol`, defaultSecurity.Symbol},
			{"Precision", `return get_default_currency().Precision`, strconv.FormatInt(int64(defaultSecurity.Precision), 10)},
			{"Type", `return get_default_currency().Type`, strconv.FormatInt(int64(defaultSecurity.Type), 10)},
			{"AlternateId", `return get_default_currency().AlternateId`, defaultSecurity.AlternateId},
			{"get_securities()", `
sorted = {}
for id in pairs(get_securities()) do
	table.insert(sorted, id)
end
table.sort(sorted)
str = "["
for i,id in ipairs(sorted) do
	str = str .. id .. " "
end
return string.sub(str, 1, -2) .. "]"`, fmt.Sprint(securityids)},
		} {
			lua := fmt.Sprintf(`function test()
	%s
end

function generate()
    t = tabulation.new(0)
    t:title(tostring(test()))
	return t
end`, lt.Lua)
			r := handlers.Report{
				Name: lt.Name,
				Lua:  lua,
			}
			report, err := createReport(d.clients[0], &r)
			if err != nil {
				t.Fatalf("Error creating report: %s", err)
			}

			tab, err := tabulateReport(d.clients[0], report.ReportId)
			if err != nil {
				t.Fatalf("Error tabulating report: %s", err)
			}

			if tab.Title != lt.Expected {
				t.Errorf("%s: Returned '%s', expected '%s'", lt.Name, tab.Title, lt.Expected)
			}
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"strings"

	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
)

func handleConnection(conn net.Conn, sshServerConfig *ssh.ServerConfig) {
	defer conn.Close()
	defer logrus.WithField("remote_address", conn.RemoteAddr().String()).Infoln("Connection closed")
	serverConn, newChannels, requests, err := ssh.NewServerConn(conn, sshServerConfig)
	if err != nil {
		log.Println("Failed to establish SSH connection:", err)
		return
	}

	getLogEntry(serverConn).Infoln("SSH connection established")
	defer getLogEntry(serverConn).Infoln("SSH connection closed")

	if strings.HasPrefix(string(serverConn.ClientVersion()), "SSH-2.0-OpenSSH") && strings.HasPrefix(string(serverConn.ServerVersion()), "SSH-2.0-OpenSSH") {
		serverConn.SendRequest("hostkeys-00@openssh.com", false, ssh.Marshal(struct{ hostKeys []string }{}))
	}

	go handleGlobalRequests(requests, serverConn)

	channelID := 0
	for newChannel := range newChannels {
		go handleNewChannel(newChannel, channelMetadata{conn: serverConn, channelID: channelID})
		channelID++
	}
}
<commit_msg>fixup! Send a hostkeys-00@openssh.com request if the client is an OpenSSH version and we're pretenting to be one too<commit_after>package main

import (
	"log"
	"net"
	"strings"

	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
)

func handleConnection(conn net.Conn, sshServerConfig *ssh.ServerConfig) {
	defer conn.Close()
	defer logrus.WithField("remote_address", conn.RemoteAddr().String()).Infoln("Connection closed")
	serverConn, newChannels, requests, err := ssh.NewServerConn(conn, sshServerConfig)
	if err != nil {
		log.Println("Failed to establish SSH connection:", err)
		return
	}

	getLogEntry(serverConn).Infoln("SSH connection established")
	defer getLogEntry(serverConn).Infoln("SSH connection closed")

	if strings.HasPrefix(string(serverConn.ClientVersion()), "SSH-2.0-OpenSSH") && strings.HasPrefix(string(serverConn.ServerVersion()), "SSH-2.0-OpenSSH") {
		if _, _, err := serverConn.SendRequest("hostkeys-00@openssh.com", false, ssh.Marshal(struct{ hostKeys []string }{})); err != nil {
			log.Println("Failed to send hostkeys-00@openssh.com request:", err)
			return
		}
	}

	go handleGlobalRequests(requests, serverConn)

	channelID := 0
	for newChannel := range newChannels {
		go handleNewChannel(newChannel, channelMetadata{conn: serverConn, channelID: channelID})
		channelID++
	}
}
<|endoftext|>


<commit_before>package nats

import (
	"bufio"
	"io"
	"sync"
	"net/textproto"
)

type Connection struct {
	rw io.ReadWriteCloser

	r     *bufio.Reader
	w     *bufio.Writer
	re    error
	we    error
	rec   chan error
	wec   chan error
	rLock sync.Mutex
	wLock sync.Mutex

	sc chan bool

	// Sequencer for PINGs/receiving corresponding PONGs
	ps textproto.Pipeline

	// Channel for receiving PONGs
	pc chan bool

	// Channel for receiving messages
	oc chan readObject
}

func NewConnection(rw io.ReadWriteCloser) *Connection {
	var c = new(Connection)

	c.rw = rw

	c.r = bufio.NewReader(rw)
	c.w = bufio.NewWriter(rw)
	c.rec = make(chan error, 1)
	c.wec = make(chan error, 1)

	c.sc = make(chan bool, 1)

	c.pc = make(chan bool)
	c.oc = make(chan readObject)

	return c
}

func (c *Connection) setReadError(e error) {
	if c.re == nil {
		c.re = e
		c.rec <- e
	}
}

func (c *Connection) setWriteError(e error) {
	if c.we == nil {
		c.we = e
		c.wec <- e
	}
}

func (c *Connection) acquireReader() *bufio.Reader {
	c.rLock.Lock()
	return c.r
}

func (c *Connection) releaseReader(r *bufio.Reader) {
	c.r = r
	c.rLock.Unlock()
}

func (c *Connection) acquireWriter() *bufio.Writer {
	c.wLock.Lock()
	return c.w
}

func (c *Connection) releaseWriter(w *bufio.Writer) {
	c.w = w
	c.wLock.Unlock()
}

func (c *Connection) read(r *bufio.Reader) (readObject, error) {
	var o readObject
	var e error

	o, e = read(r)
	if e != nil {
		c.setReadError(e)
		return nil, e
	}

	return o, nil
}

func (c *Connection) write(w *bufio.Writer, o writeObject) error {
	var e error

	e = write(w, o)
	if e != nil {
		c.setWriteError(e)
		return e
	}

	e = w.Flush()
	if e != nil {
		c.setWriteError(e)
		return e
	}

	return e
}

func (c *Connection) pingAndWaitForPong(w *bufio.Writer) bool {
	var e error

	// Write PING and grab sequence number
	e = c.write(w, &writePing{})
	if e != nil {
		c.releaseWriter(w)
		return false
	}

	seq := c.ps.Next()
	c.releaseWriter(w)

	// Wait for PONG
	c.ps.StartResponse(seq)
	_, ok := <-c.pc
	c.ps.EndResponse(seq)

	return ok
}

func (c *Connection) Ping() bool {
	var w *bufio.Writer

	w = c.acquireWriter()
	return c.pingAndWaitForPong(w)
}

func (c *Connection) Write(o writeObject) bool {
	var w *bufio.Writer
	var e error

	w = c.acquireWriter()
	e = c.write(w, o)
	if e != nil {
		c.releaseWriter(w)
		return false
	}

	c.releaseWriter(w)
	return true
}

func (c *Connection) WriteAndPing(o writeObject) bool {
	var w *bufio.Writer
	var e error

	w = c.acquireWriter()
	e = c.write(w, o)
	if e != nil {
		c.releaseWriter(w)
		return false
	}

	return c.pingAndWaitForPong(w)
}

func (c *Connection) Stop() {
	c.sc <- true
}

func (c *Connection) Run() error {
	var r *bufio.Reader
	var rc chan readObject

	r = c.acquireReader()
	rc = make(chan readObject)

	defer c.releaseReader(r)

	go func() {
		var o readObject
		var e error

		defer close(rc)

		for {
			o, e = c.read(r)
			if e != nil {
				break
			}

			rc <- o
		}
	}()

	var stop bool
	var e error
	var ok bool

	for !stop {
		var o readObject

		select {
		case <-c.sc:
			stop = true
		case e = <-c.rec:
			stop = true
		case e = <-c.wec:
			stop = true
		case o, ok = <-rc:
			if ok {
				switch o.(type) {
				case *readPing:
					go func() {
						c.Write(&writePong{})
					}()
				case *readPong:
					c.pc <- true
				default:
					c.oc <- o
				}
			}
		}
	}

	// Close connection
	c.rw.Close()

	// Drain readObject channel to make read goroutine quit
	for _ = range rc {
	}

	// Can't receive more PONGs
	close(c.pc)

	// Can't receive more messages
	close(c.oc)

	return e
}
<commit_msg>Write method for channel of objects<commit_after>package nats

import (
	"bufio"
	"io"
	"sync"
	"net/textproto"
)

type Connection struct {
	rw io.ReadWriteCloser

	r     *bufio.Reader
	w     *bufio.Writer
	re    error
	we    error
	rec   chan error
	wec   chan error
	rLock sync.Mutex
	wLock sync.Mutex

	sc chan bool

	// Sequencer for PINGs/receiving corresponding PONGs
	ps textproto.Pipeline

	// Channel for receiving PONGs
	pc chan bool

	// Channel for receiving messages
	oc chan readObject
}

func NewConnection(rw io.ReadWriteCloser) *Connection {
	var c = new(Connection)

	c.rw = rw

	c.r = bufio.NewReader(rw)
	c.w = bufio.NewWriter(rw)
	c.rec = make(chan error, 1)
	c.wec = make(chan error, 1)

	c.sc = make(chan bool, 1)

	c.pc = make(chan bool)
	c.oc = make(chan readObject)

	return c
}

func (c *Connection) setReadError(e error) {
	if c.re == nil {
		c.re = e
		c.rec <- e
	}
}

func (c *Connection) setWriteError(e error) {
	if c.we == nil {
		c.we = e
		c.wec <- e
	}
}

func (c *Connection) acquireReader() *bufio.Reader {
	c.rLock.Lock()
	return c.r
}

func (c *Connection) releaseReader(r *bufio.Reader) {
	c.r = r
	c.rLock.Unlock()
}

func (c *Connection) acquireWriter() *bufio.Writer {
	c.wLock.Lock()
	return c.w
}

func (c *Connection) releaseWriter(w *bufio.Writer) {
	c.w = w
	c.wLock.Unlock()
}

func (c *Connection) read(r *bufio.Reader) (readObject, error) {
	var o readObject
	var e error

	o, e = read(r)
	if e != nil {
		c.setReadError(e)
		return nil, e
	}

	return o, nil
}

func (c *Connection) write(w *bufio.Writer, o writeObject) error {
	var e error

	e = write(w, o)
	if e != nil {
		c.setWriteError(e)
		return e
	}

	e = w.Flush()
	if e != nil {
		c.setWriteError(e)
		return e
	}

	return e
}

func (c *Connection) pingAndWaitForPong(w *bufio.Writer) bool {
	var e error

	// Write PING and grab sequence number
	e = c.write(w, &writePing{})
	if e != nil {
		c.releaseWriter(w)
		return false
	}

	seq := c.ps.Next()
	c.releaseWriter(w)

	// Wait for PONG
	c.ps.StartResponse(seq)
	_, ok := <-c.pc
	c.ps.EndResponse(seq)

	return ok
}

func (c *Connection) Ping() bool {
	var w *bufio.Writer

	w = c.acquireWriter()
	return c.pingAndWaitForPong(w)
}

func (c *Connection) WriteChannel(oc chan writeObject) bool {
	var w *bufio.Writer
	var e error

	w = c.acquireWriter()
	defer c.releaseWriter(w)

	// Write until EOF
	for o := range oc {
		if e == nil {
			e = c.write(w, o)
		}
	}

	return e == nil
}

func (c *Connection) Write(o writeObject) bool {
	var w *bufio.Writer
	var e error

	w = c.acquireWriter()
	e = c.write(w, o)
	if e != nil {
		c.releaseWriter(w)
		return false
	}

	c.releaseWriter(w)
	return true
}

func (c *Connection) WriteAndPing(o writeObject) bool {
	var w *bufio.Writer
	var e error

	w = c.acquireWriter()
	e = c.write(w, o)
	if e != nil {
		c.releaseWriter(w)
		return false
	}

	return c.pingAndWaitForPong(w)
}

func (c *Connection) Stop() {
	c.sc <- true
}

func (c *Connection) Run() error {
	var r *bufio.Reader
	var rc chan readObject

	r = c.acquireReader()
	rc = make(chan readObject)

	defer c.releaseReader(r)

	go func() {
		var o readObject
		var e error

		defer close(rc)

		for {
			o, e = c.read(r)
			if e != nil {
				break
			}

			rc <- o
		}
	}()

	var stop bool
	var e error
	var ok bool

	for !stop {
		var o readObject

		select {
		case <-c.sc:
			stop = true
		case e = <-c.rec:
			stop = true
		case e = <-c.wec:
			stop = true
		case o, ok = <-rc:
			if ok {
				switch o.(type) {
				case *readPing:
					go func() {
						c.Write(&writePong{})
					}()
				case *readPong:
					c.pc <- true
				default:
					c.oc <- o
				}
			}
		}
	}

	// Close connection
	c.rw.Close()

	// Drain readObject channel to make read goroutine quit
	for _ = range rc {
	}

	// Can't receive more PONGs
	close(c.pc)

	// Can't receive more messages
	close(c.oc)

	return e
}
<|endoftext|>


<commit_before>package specs

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 1
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 2

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>specs-go: bump master back to -dev<commit_after>package specs

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 1
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 2

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package codegen

import (
	"bytes"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	tmpl "text/template"

	"github.com/pkg/errors"
)

// EndpointFiles are group of files generated for an endpoint.
type EndpointFiles struct {
	HandlerFiles []string
	StructFile   string
}

// ClientFiles are group of files generated for a client.
type ClientFiles struct {
	ClientFile string
	StructFile string
}

// EndpointMeta saves meta data used to render an endpoint.
type EndpointMeta struct {
	GatewayPackageName string
	PackageName        string
	IncludedPackages   []string
	Method             *MethodSpec
}

// EndpointTestMeta saves meta data used to render an endpoint test.
type EndpointTestMeta struct {
	PackageName string
	Method      *MethodSpec
}

var camelingRegex = regexp.MustCompile("[0-9A-Za-z]+")
var funcMap = tmpl.FuncMap{
	"title":        strings.Title,
	"Title":        strings.Title,
	"fullTypeName": fullTypeName,
	"statusCodes":  statusCodes,
	"camel":        camelCase,
	"split":        strings.Split,
	"dec":          decrement,
	"basePath":     filepath.Base,
	"pascal":       pascalCase,
}

func fullTypeName(typeName, packageName string) string {
	if typeName == "" || strings.Contains(typeName, ".") {
		return typeName
	}
	return packageName + "." + typeName
}

func statusCodes(codes []StatusCode) string {
	if len(codes) == 0 {
		return "[]int{}"
	}
	buf := bytes.NewBufferString("[]int{")
	for i := 0; i < len(codes)-1; i++ {
		if _, err := buf.WriteString(strconv.Itoa(codes[i].Code) + ","); err != nil {
			return err.Error()
		}
	}
	if _, err := buf.WriteString(strconv.Itoa(codes[len(codes)-1].Code) + "}"); err != nil {
		return err.Error()
	}
	return string(buf.Bytes())
}

func camelCase(src string) string {
	byteSrc := []byte(src)
	chunks := camelingRegex.FindAll(byteSrc, -1)
	for idx, val := range chunks {
		if idx > 0 {
			chunks[idx] = bytes.Title(val)
		} else {
			chunks[idx][0] = bytes.ToLower(val[0:1])[0]
		}
	}
	return string(bytes.Join(chunks, nil))
}

func decrement(num int) int {
	return num - 1
}

func pascalCase(src string) string {
	byteSrc := []byte(src)
	chunks := camelingRegex.FindAll(byteSrc, -1)
	for idx, val := range chunks {
		if idx > 0 {
			chunks[idx] = bytes.Title(val)
		} else {
			chunks[idx][0] = bytes.ToUpper(val[0:1])[0]
		}
	}
	return string(bytes.Join(chunks, nil))
}

// Template generates code for edge gateway clients and edgegateway endpoints.
type Template struct {
	template *tmpl.Template
}

// NewTemplate creates a bundle of templates.
func NewTemplate(templatePattern string) (*Template, error) {
	t, err := tmpl.New("main").Funcs(funcMap).ParseGlob(templatePattern)
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse template files")
	}
	return &Template{
		template: t,
	}, nil
}

// GenerateClientFile generates Go http code for services defined in thrift file.
// It returns the path of generated client file and struct file or an error.
func (t *Template) GenerateClientFile(
	m *ModuleSpec, h *PackageHelper,
) (*ClientFiles, error) {
	if len(m.Services) == 0 {
		return nil, nil
	}

	m.PackageName = m.PackageName + "Client"
	err := t.execTemplateAndFmt("http_client.tmpl", m.GoClientFilePath, m)
	if err != nil {
		return nil, err
	}

	err = t.execTemplateAndFmt("structs.tmpl", m.GoStructsFilePath, m)
	if err != nil {
		return nil, err
	}

	return &ClientFiles{
		ClientFile: m.GoClientFilePath,
		StructFile: m.GoStructsFilePath,
	}, nil
}

// GenerateEndpointFile generates Go code for an zanzibar endpoint defined in
// thrift file. It returns the path of generated method files, struct file or
// an error.
func (t *Template) GenerateEndpointFile(
	m *ModuleSpec, h *PackageHelper,
) (*EndpointFiles, error) {
	if len(m.Services) == 0 {
		return nil, nil
	}

	err := t.execTemplateAndFmt(
		"structs.tmpl", m.GoStructsFilePath, m,
	)
	if err != nil {
		return nil, err
	}

	endpointFiles := &EndpointFiles{
		HandlerFiles: make([]string, 0, len(m.Services[0].Methods)),
		StructFile:   m.GoStructsFilePath,
	}

	for _, service := range m.Services {
		for _, method := range service.Methods {
			dest, err := h.TargetEndpointPath(m.ThriftFile, service.Name, method.Name)
			if err != nil {
				return nil, errors.Wrapf(err,
					"Could not generate endpoint path, service %s, method %s",
					service, method)
			}
			meta := &EndpointMeta{
				GatewayPackageName: h.GoGatewayPackageName(),
				PackageName:        m.PackageName,
				IncludedPackages:   m.IncludedPackages,
				Method:             method,
			}
			err = t.execTemplateAndFmt("endpoint.tmpl", dest, meta)
			if err != nil {
				return nil, err
			}
			endpointFiles.HandlerFiles = append(endpointFiles.HandlerFiles, dest)
		}
	}

	return endpointFiles, nil
}

// GenerateEndpointTestFile generates Go code for testing an zanzibar endpoint
// defined in a thrift file. It returns the path of generated test files,
// or an error.
func (t *Template) GenerateEndpointTestFile(
	m *ModuleSpec, h *PackageHelper,
) ([]string, error) {
	if len(m.Services) == 0 {
		return nil, nil
	}

	testFiles := make([]string, 0, len(m.Services[0].Methods))
	for _, service := range m.Services {
		for _, method := range service.Methods {
			dest, err := h.TargetEndpointTestPath(m.ThriftFile, service.Name, method.Name)
			if err != nil {
				return nil, errors.Wrapf(err,
					"Could not generate endpoint test path, service %s, method %s",
					service, method)
			}
			meta := &EndpointTestMeta{
				PackageName: m.PackageName,
				Method:      method,
			}
			err = t.execTemplateAndFmt("endpoint_test.tmpl", dest, meta)
			if err != nil {
				return nil, err
			}
			testFiles = append(testFiles, dest)
		}
	}

	return testFiles, nil
}

// ClientInfoMeta ...
type ClientInfoMeta struct {
	FieldName   string
	PackageName string
	TypeName    string
}

// ClientsInitFilesMeta ...
type ClientsInitFilesMeta struct {
	IncludedPackages []string
	ClientInfo       []ClientInfoMeta
}

type sortByClientName []*ModuleSpec

func (c sortByClientName) Len() int {
	return len(c)
}
func (c sortByClientName) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c sortByClientName) Less(i, j int) bool {
	return c[i].GoPackage < c[j].GoPackage
}

// GenerateClientsInitFile generates go code to allocate and initialize
// all of the generated clients
func (t *Template) GenerateClientsInitFile(
	clientsMap map[string]*ModuleSpec, h *PackageHelper,
) (string, error) {
	clients := []*ModuleSpec{}
	for _, v := range clientsMap {
		clients = append(clients, v)
	}
	sort.Sort(sortByClientName(clients))

	includedPkgs := []string{}
	for i := 0; i < len(clients); i++ {
		if len(clients[i].Services) == 0 {
			continue
		}

		includedPkgs = append(includedPkgs, clients[i].GoPackage)
	}

	clientInfo := []ClientInfoMeta{}
	for i := 0; i < len(clients); i++ {
		module := clients[i]
		if len(module.Services) == 0 {
			continue
		}

		if len(module.Services) != 1 {
			return "", errors.Errorf(
				"Cannot import client with multiple services: %s",
				module.PackageName,
			)
		}

		service := module.Services[0]
		clientInfo = append(clientInfo, ClientInfoMeta{
			FieldName:   strings.Title(service.Name),
			PackageName: module.PackageName,
			TypeName:    strings.Title(service.Name) + "Client",
		})
	}

	meta := &ClientsInitFilesMeta{
		IncludedPackages: includedPkgs,
		ClientInfo:       clientInfo,
	}

	targetFile := h.TargetClientsInitPath()
	err := t.execTemplateAndFmt("init_clients.tmpl", targetFile, meta)
	if err != nil {
		return "", err
	}

	return targetFile, nil
}

// MainMeta ...
type MainMeta struct {
	IncludedPackages           []string
	GatewayName                string
	RelativeSegmentsToZanzibar []string
}

// GenerateMainFile will use main.tmpl to write out the main.go file
// for a gateway.
func (t *Template) GenerateMainFile(
	g *GatewaySpec, h *PackageHelper,
) (string, error) {
	pkgPath := h.GoGatewayPackageName()
	zanzibarPath := "github.com/uber/zanzibar"
	zIndex := strings.Index(pkgPath, zanzibarPath)

	relativeSegmentsToZanzibar := []string{}

	if zIndex == 0 {
		gatewayPath := pkgPath[len(zanzibarPath)+1:]

		segmentsToRoot := len(strings.Split(gatewayPath, "/"))
		for i := 0; i < segmentsToRoot; i++ {
			relativeSegmentsToZanzibar = append(
				relativeSegmentsToZanzibar, "..",
			)
		}
	} else {
		panic("cannot generate main.go outside zanzibar yet.")
	}

	meta := &MainMeta{
		IncludedPackages: []string{
			h.GoGatewayPackageName() + "/clients",
			h.GoGatewayPackageName() + "/endpoints",
		},
		GatewayName:                g.gatewayName,
		RelativeSegmentsToZanzibar: relativeSegmentsToZanzibar,
	}

	targetFile := h.TargetMainPath()
	err := t.execTemplateAndFmt("main.tmpl", targetFile, meta)
	if err != nil {
		return "", err
	}

	return targetFile, nil
}

func (t *Template) execTemplateAndFmt(templName string, filePath string, data interface{}) error {
	file, err := openFileOrCreate(filePath)
	if err != nil {
		return errors.Wrapf(err, "failed to open file: ", err)
	}
	if err := t.template.ExecuteTemplate(file, templName, data); err != nil {
		return errors.Wrapf(err, "failed to execute template files for file %s", file)
	}

	gofmtCmd := exec.Command("gofmt", "-s", "-w", "-e", filePath)
	gofmtCmd.Stdout = os.Stdout
	gofmtCmd.Stderr = os.Stderr

	if err := gofmtCmd.Run(); err != nil {
		return errors.Wrapf(err, "failed to gofmt file: %s", filePath)
	}

	goimportsCmd := exec.Command("goimports", "-w", "-e", filePath)
	goimportsCmd.Stdout = os.Stdout
	goimportsCmd.Stderr = os.Stderr

	if err := goimportsCmd.Run(); err != nil {
		return errors.Wrapf(err, "failed to goimports file: %s", filePath)
	}

	if err := file.Close(); err != nil {
		return errors.Wrap(err, "failed to close file")
	}

	return nil
}

func openFileOrCreate(file string) (*os.File, error) {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil {
			return nil, err
		}
	}
	return os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
}
<commit_msg>codegen: cleanup pascalCase() func<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package codegen

import (
	"bytes"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	tmpl "text/template"

	"github.com/pkg/errors"
)

// EndpointFiles are group of files generated for an endpoint.
type EndpointFiles struct {
	HandlerFiles []string
	StructFile   string
}

// ClientFiles are group of files generated for a client.
type ClientFiles struct {
	ClientFile string
	StructFile string
}

// EndpointMeta saves meta data used to render an endpoint.
type EndpointMeta struct {
	GatewayPackageName string
	PackageName        string
	IncludedPackages   []string
	Method             *MethodSpec
}

// EndpointTestMeta saves meta data used to render an endpoint test.
type EndpointTestMeta struct {
	PackageName string
	Method      *MethodSpec
}

var camelingRegex = regexp.MustCompile("[0-9A-Za-z]+")
var funcMap = tmpl.FuncMap{
	"title":        strings.Title,
	"Title":        strings.Title,
	"fullTypeName": fullTypeName,
	"statusCodes":  statusCodes,
	"camel":        camelCase,
	"split":        strings.Split,
	"dec":          decrement,
	"basePath":     filepath.Base,
	"pascal":       pascalCase,
}

func fullTypeName(typeName, packageName string) string {
	if typeName == "" || strings.Contains(typeName, ".") {
		return typeName
	}
	return packageName + "." + typeName
}

func statusCodes(codes []StatusCode) string {
	if len(codes) == 0 {
		return "[]int{}"
	}
	buf := bytes.NewBufferString("[]int{")
	for i := 0; i < len(codes)-1; i++ {
		if _, err := buf.WriteString(strconv.Itoa(codes[i].Code) + ","); err != nil {
			return err.Error()
		}
	}
	if _, err := buf.WriteString(strconv.Itoa(codes[len(codes)-1].Code) + "}"); err != nil {
		return err.Error()
	}
	return string(buf.Bytes())
}

func camelCase(src string) string {
	byteSrc := []byte(src)
	chunks := camelingRegex.FindAll(byteSrc, -1)
	for idx, val := range chunks {
		if idx > 0 {
			chunks[idx] = bytes.Title(val)
		} else {
			chunks[idx][0] = bytes.ToLower(val[0:1])[0]
		}
	}
	return string(bytes.Join(chunks, nil))
}

func decrement(num int) int {
	return num - 1
}

func pascalCase(src string) string {
	byteSrc := []byte(src)
	chunks := camelingRegex.FindAll(byteSrc, -1)
	for idx, val := range chunks {
		chunks[idx] = bytes.Title(val)
	}
	return string(bytes.Join(chunks, nil))
}

// Template generates code for edge gateway clients and edgegateway endpoints.
type Template struct {
	template *tmpl.Template
}

// NewTemplate creates a bundle of templates.
func NewTemplate(templatePattern string) (*Template, error) {
	t, err := tmpl.New("main").Funcs(funcMap).ParseGlob(templatePattern)
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse template files")
	}
	return &Template{
		template: t,
	}, nil
}

// GenerateClientFile generates Go http code for services defined in thrift file.
// It returns the path of generated client file and struct file or an error.
func (t *Template) GenerateClientFile(
	m *ModuleSpec, h *PackageHelper,
) (*ClientFiles, error) {
	if len(m.Services) == 0 {
		return nil, nil
	}

	m.PackageName = m.PackageName + "Client"
	err := t.execTemplateAndFmt("http_client.tmpl", m.GoClientFilePath, m)
	if err != nil {
		return nil, err
	}

	err = t.execTemplateAndFmt("structs.tmpl", m.GoStructsFilePath, m)
	if err != nil {
		return nil, err
	}

	return &ClientFiles{
		ClientFile: m.GoClientFilePath,
		StructFile: m.GoStructsFilePath,
	}, nil
}

// GenerateEndpointFile generates Go code for an zanzibar endpoint defined in
// thrift file. It returns the path of generated method files, struct file or
// an error.
func (t *Template) GenerateEndpointFile(
	m *ModuleSpec, h *PackageHelper,
) (*EndpointFiles, error) {
	if len(m.Services) == 0 {
		return nil, nil
	}

	err := t.execTemplateAndFmt(
		"structs.tmpl", m.GoStructsFilePath, m,
	)
	if err != nil {
		return nil, err
	}

	endpointFiles := &EndpointFiles{
		HandlerFiles: make([]string, 0, len(m.Services[0].Methods)),
		StructFile:   m.GoStructsFilePath,
	}

	for _, service := range m.Services {
		for _, method := range service.Methods {
			dest, err := h.TargetEndpointPath(m.ThriftFile, service.Name, method.Name)
			if err != nil {
				return nil, errors.Wrapf(err,
					"Could not generate endpoint path, service %s, method %s",
					service, method)
			}
			meta := &EndpointMeta{
				GatewayPackageName: h.GoGatewayPackageName(),
				PackageName:        m.PackageName,
				IncludedPackages:   m.IncludedPackages,
				Method:             method,
			}
			err = t.execTemplateAndFmt("endpoint.tmpl", dest, meta)
			if err != nil {
				return nil, err
			}
			endpointFiles.HandlerFiles = append(endpointFiles.HandlerFiles, dest)
		}
	}

	return endpointFiles, nil
}

// GenerateEndpointTestFile generates Go code for testing an zanzibar endpoint
// defined in a thrift file. It returns the path of generated test files,
// or an error.
func (t *Template) GenerateEndpointTestFile(
	m *ModuleSpec, h *PackageHelper,
) ([]string, error) {
	if len(m.Services) == 0 {
		return nil, nil
	}

	testFiles := make([]string, 0, len(m.Services[0].Methods))
	for _, service := range m.Services {
		for _, method := range service.Methods {
			dest, err := h.TargetEndpointTestPath(m.ThriftFile, service.Name, method.Name)
			if err != nil {
				return nil, errors.Wrapf(err,
					"Could not generate endpoint test path, service %s, method %s",
					service, method)
			}
			meta := &EndpointTestMeta{
				PackageName: m.PackageName,
				Method:      method,
			}
			err = t.execTemplateAndFmt("endpoint_test.tmpl", dest, meta)
			if err != nil {
				return nil, err
			}
			testFiles = append(testFiles, dest)
		}
	}

	return testFiles, nil
}

// ClientInfoMeta ...
type ClientInfoMeta struct {
	FieldName   string
	PackageName string
	TypeName    string
}

// ClientsInitFilesMeta ...
type ClientsInitFilesMeta struct {
	IncludedPackages []string
	ClientInfo       []ClientInfoMeta
}

type sortByClientName []*ModuleSpec

func (c sortByClientName) Len() int {
	return len(c)
}
func (c sortByClientName) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c sortByClientName) Less(i, j int) bool {
	return c[i].GoPackage < c[j].GoPackage
}

// GenerateClientsInitFile generates go code to allocate and initialize
// all of the generated clients
func (t *Template) GenerateClientsInitFile(
	clientsMap map[string]*ModuleSpec, h *PackageHelper,
) (string, error) {
	clients := []*ModuleSpec{}
	for _, v := range clientsMap {
		clients = append(clients, v)
	}
	sort.Sort(sortByClientName(clients))

	includedPkgs := []string{}
	for i := 0; i < len(clients); i++ {
		if len(clients[i].Services) == 0 {
			continue
		}

		includedPkgs = append(includedPkgs, clients[i].GoPackage)
	}

	clientInfo := []ClientInfoMeta{}
	for i := 0; i < len(clients); i++ {
		module := clients[i]
		if len(module.Services) == 0 {
			continue
		}

		if len(module.Services) != 1 {
			return "", errors.Errorf(
				"Cannot import client with multiple services: %s",
				module.PackageName,
			)
		}

		service := module.Services[0]
		clientInfo = append(clientInfo, ClientInfoMeta{
			FieldName:   strings.Title(service.Name),
			PackageName: module.PackageName,
			TypeName:    strings.Title(service.Name) + "Client",
		})
	}

	meta := &ClientsInitFilesMeta{
		IncludedPackages: includedPkgs,
		ClientInfo:       clientInfo,
	}

	targetFile := h.TargetClientsInitPath()
	err := t.execTemplateAndFmt("init_clients.tmpl", targetFile, meta)
	if err != nil {
		return "", err
	}

	return targetFile, nil
}

// MainMeta ...
type MainMeta struct {
	IncludedPackages           []string
	GatewayName                string
	RelativeSegmentsToZanzibar []string
}

// GenerateMainFile will use main.tmpl to write out the main.go file
// for a gateway.
func (t *Template) GenerateMainFile(
	g *GatewaySpec, h *PackageHelper,
) (string, error) {
	pkgPath := h.GoGatewayPackageName()
	zanzibarPath := "github.com/uber/zanzibar"
	zIndex := strings.Index(pkgPath, zanzibarPath)

	relativeSegmentsToZanzibar := []string{}

	if zIndex == 0 {
		gatewayPath := pkgPath[len(zanzibarPath)+1:]

		segmentsToRoot := len(strings.Split(gatewayPath, "/"))
		for i := 0; i < segmentsToRoot; i++ {
			relativeSegmentsToZanzibar = append(
				relativeSegmentsToZanzibar, "..",
			)
		}
	} else {
		panic("cannot generate main.go outside zanzibar yet.")
	}

	meta := &MainMeta{
		IncludedPackages: []string{
			h.GoGatewayPackageName() + "/clients",
			h.GoGatewayPackageName() + "/endpoints",
		},
		GatewayName:                g.gatewayName,
		RelativeSegmentsToZanzibar: relativeSegmentsToZanzibar,
	}

	targetFile := h.TargetMainPath()
	err := t.execTemplateAndFmt("main.tmpl", targetFile, meta)
	if err != nil {
		return "", err
	}

	return targetFile, nil
}

func (t *Template) execTemplateAndFmt(templName string, filePath string, data interface{}) error {
	file, err := openFileOrCreate(filePath)
	if err != nil {
		return errors.Wrapf(err, "failed to open file: ", err)
	}
	if err := t.template.ExecuteTemplate(file, templName, data); err != nil {
		return errors.Wrapf(err, "failed to execute template files for file %s", file)
	}

	gofmtCmd := exec.Command("gofmt", "-s", "-w", "-e", filePath)
	gofmtCmd.Stdout = os.Stdout
	gofmtCmd.Stderr = os.Stderr

	if err := gofmtCmd.Run(); err != nil {
		return errors.Wrapf(err, "failed to gofmt file: %s", filePath)
	}

	goimportsCmd := exec.Command("goimports", "-w", "-e", filePath)
	goimportsCmd.Stdout = os.Stdout
	goimportsCmd.Stderr = os.Stderr

	if err := goimportsCmd.Run(); err != nil {
		return errors.Wrapf(err, "failed to goimports file: %s", filePath)
	}

	if err := file.Close(); err != nil {
		return errors.Wrap(err, "failed to close file")
	}

	return nil
}

func openFileOrCreate(file string) (*os.File, error) {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil {
			return nil, err
		}
	}
	return os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 cli

import (
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"

	"github.com/spf13/cobra"
	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/util"
)

var NewTypeStr = "pkg"

func pkgNewCmd(cmd *cobra.Command, args []string) {
	NewTypeStr = strings.ToUpper(NewTypeStr)

	pw := project.NewPackageWriter()
	if err := pw.ConfigurePackage(NewTypeStr, args[0]); err != nil {
		NewtUsage(cmd, err)
	}
	if err := pw.WritePackage(); err != nil {
		NewtUsage(cmd, err)
	}
}

type dirOperation func(string, string) error

func pkgCloneCmd(cmd *cobra.Command, args []string) {
	pkgCloneOrMoveCmd(cmd, args, util.CopyDir, "Cloning");
}

func pkgMoveCmd(cmd *cobra.Command, args []string) {
	pkgCloneOrMoveCmd(cmd, args, util.MoveDir, "Moving");
}

func pkgCloneOrMoveCmd(cmd *cobra.Command, args []string, dirOpFn dirOperation, opStr string) {
	if len(args) != 2 {
		NewtUsage(cmd, util.NewNewtError("Exactly two arguments required to pkg move"))
	}

	srcLoc := args[0]
	dstLoc := args[1]

	proj := TryGetProject()
	interfaces.SetProject(proj)

	wd, err := os.Getwd()
	if err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	if err := os.Chdir(proj.Path() + "/"); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	defer os.Chdir(wd)

	/* Find source package, defaulting search to the local project if no
	 * repository descriptor is found.
	 */
	srcRepoName, srcName, err := newtutil.ParsePackageString(srcLoc)
	if err != nil {
		NewtUsage(cmd, err)
	}

	srcRepo := proj.LocalRepo()
	if srcRepoName != "" {
		srcRepo = proj.FindRepo(srcRepoName)
	}

	srcPkg, err := proj.ResolvePackage(srcRepo, srcName)
	if err != nil {
		NewtUsage(cmd, err)
	}

	/* Resolve the destination package to a physical location, and then
	 * move the source package to that location.
	 * dstLoc is assumed to be in the format "@repo/pkg/loc"
	 */
	repoName, pkgName, err := newtutil.ParsePackageString(dstLoc)
	if err != nil {
		NewtUsage(cmd, err)
	}

	dstPath := proj.Path() + "/"
	repo := proj.LocalRepo()
	if repoName != "" {
		dstPath += "repos/" + repoName + "/"
		repo = proj.FindRepo(repoName)
		if repo == nil {
			NewtUsage(cmd, util.NewNewtError("Destination repo "+
				repoName+" does not exist"))
		}
	}
	dstPath += pkgName + "/"

	if util.NodeExist(dstPath) {
		NewtUsage(cmd, util.NewNewtError("Cannot overwrite existing package, "+
			"use pkg delete first"))
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "%s package %s to %s\n",
		opStr, srcLoc, dstLoc)

	if err := dirOpFn(srcPkg.BasePath(), dstPath); err != nil {
		NewtUsage(cmd, err)
	}

	/* Replace the package name in the pkg.yml file */
	pkgData, err := ioutil.ReadFile(dstPath + "/pkg.yml")
	if err != nil {
		NewtUsage(cmd, err)
	}

	re := regexp.MustCompile(regexp.QuoteMeta(srcName))
	res := re.ReplaceAllString(string(pkgData), pkgName)

	if err := ioutil.WriteFile(dstPath+"/pkg.yml", []byte(res), 0666); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	/* If the last element of the package path changes, rename the include
	 * directory.
	 */
	if path.Base(pkgName) != path.Base(srcPkg.Name()) {
		dirOpFn(dstPath+"/include/"+path.Base(srcPkg.Name()),
			dstPath+"/include/"+path.Base(pkgName))
	}
}

func pkgRemoveCmd(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		NewtUsage(cmd, util.NewNewtError("Must specify a package name to delete"))
	}

	proj := TryGetProject()
	interfaces.SetProject(proj)

	wd, err := os.Getwd()
	if err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	if err := os.Chdir(proj.Path() + "/"); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	defer os.Chdir(wd)

	/* Resolve package, and get path from package to ensure we're being asked
	 * to remove a valid path.
	 */
	repoName, pkgName, err := newtutil.ParsePackageString(args[0])
	if err != nil {
		NewtUsage(cmd, err)
	}

	repo := proj.LocalRepo()
	if repoName != "" {
		repo = proj.FindRepo(repoName)
		if repo == nil {
			NewtUsage(cmd, util.NewNewtError("Destination repo "+
				repoName+" does not exist"))
		}
	}

	pkg, err := pkg.LoadLocalPackage(repo, pkgName)
	if err != nil {
		NewtUsage(cmd, err)
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Removing package %s\n",
		args[0])

	if err := os.RemoveAll(pkg.BasePath()); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}
}

func AddPackageCommands(cmd *cobra.Command) {
	/* Add the base package command, on top of which other commands are
	 * keyed
	 */
	pkgHelpText := "Commands for creating and manipulating packages"
	pkgHelpEx := "  newt pkg new --type=pkg libs/mylib"

	pkgCmd := &cobra.Command{
		Use:     "pkg",
		Short:   "Create and manage packages in the current workspace",
		Long:    pkgHelpText,
		Example: pkgHelpEx,
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Help()
		},
	}

	cmd.AddCommand(pkgCmd)

	/* Package new command, create a new package */
	newCmdHelpText := ""
	newCmdHelpEx := ""

	newCmd := &cobra.Command{
		Use:     "new",
		Short:   "Create a new package, from a template",
		Long:    newCmdHelpText,
		Example: newCmdHelpEx,
		Run:     pkgNewCmd,
	}

	newCmd.PersistentFlags().StringVarP(&NewTypeStr, "type", "t",
		"pkg", "Type of package to create: pkg, bsp, sdk.  Default pkg.")

	pkgCmd.AddCommand(newCmd)

	cloneCmdHelpText := ""
	cloneCmdHelpEx := ""

	cloneCmd := &cobra.Command{
		Use:     "clone <srcpkg> <dstpkg>",
		Short:   "Clone an existing package into another",
		Long:    cloneCmdHelpText,
		Example: cloneCmdHelpEx,
		Run:     pkgCloneCmd,
	}

	pkgCmd.AddCommand(cloneCmd)

	moveCmdHelpText := ""
	moveCmdHelpEx := ""

	moveCmd := &cobra.Command{
		Use:     "move <oldpkg> <newpkg>",
		Short:   "Move a package from one location to another",
		Long:    moveCmdHelpText,
		Example: moveCmdHelpEx,
		Run:     pkgMoveCmd,
	}

	pkgCmd.AddCommand(moveCmd)

	removeCmdHelpText := ""
	removeCmdHelpEx := ""

	removeCmd := &cobra.Command{
		Use:     "remove",
		Short:   "Remove a package",
		Long:    removeCmdHelpText,
		Example: removeCmdHelpEx,
		Run:     pkgRemoveCmd,
	}

	pkgCmd.AddCommand(removeCmd)
}
<commit_msg>This closes #40<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 cli

import (
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"

	"github.com/spf13/cobra"
	"mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/util"
)

var NewTypeStr = "pkg"

func pkgNewCmd(cmd *cobra.Command, args []string) {

	if len(args) == 0 {
		NewtUsage(cmd, util.NewNewtError("Must specify a package name"))
	}

	if len(args) != 1 {
		NewtUsage(cmd, util.NewNewtError("Exactly one argument required"))
	}

	NewTypeStr = strings.ToUpper(NewTypeStr)

	pw := project.NewPackageWriter()
	if err := pw.ConfigurePackage(NewTypeStr, args[0]); err != nil {
		NewtUsage(cmd, err)
	}
	if err := pw.WritePackage(); err != nil {
		NewtUsage(cmd, err)
	}
}

type dirOperation func(string, string) error

func pkgCloneCmd(cmd *cobra.Command, args []string) {
	pkgCloneOrMoveCmd(cmd, args, util.CopyDir, "Cloning")
}

func pkgMoveCmd(cmd *cobra.Command, args []string) {
	pkgCloneOrMoveCmd(cmd, args, util.MoveDir, "Moving")
}

func pkgCloneOrMoveCmd(cmd *cobra.Command, args []string, dirOpFn dirOperation, opStr string) {
	if len(args) != 2 {
		NewtUsage(cmd, util.NewNewtError("Exactly two arguments required to pkg move"))
	}

	srcLoc := args[0]
	dstLoc := args[1]

	proj := TryGetProject()
	interfaces.SetProject(proj)

	wd, err := os.Getwd()
	if err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	if err := os.Chdir(proj.Path() + "/"); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	defer os.Chdir(wd)

	/* Find source package, defaulting search to the local project if no
	 * repository descriptor is found.
	 */
	srcRepoName, srcName, err := newtutil.ParsePackageString(srcLoc)
	if err != nil {
		NewtUsage(cmd, err)
	}

	srcRepo := proj.LocalRepo()
	if srcRepoName != "" {
		srcRepo = proj.FindRepo(srcRepoName)
	}

	srcPkg, err := proj.ResolvePackage(srcRepo, srcName)
	if err != nil {
		NewtUsage(cmd, err)
	}

	/* Resolve the destination package to a physical location, and then
	 * move the source package to that location.
	 * dstLoc is assumed to be in the format "@repo/pkg/loc"
	 */
	repoName, pkgName, err := newtutil.ParsePackageString(dstLoc)
	if err != nil {
		NewtUsage(cmd, err)
	}

	dstPath := proj.Path() + "/"
	repo := proj.LocalRepo()
	if repoName != "" {
		dstPath += "repos/" + repoName + "/"
		repo = proj.FindRepo(repoName)
		if repo == nil {
			NewtUsage(cmd, util.NewNewtError("Destination repo "+
				repoName+" does not exist"))
		}
	}
	dstPath += pkgName + "/"

	if util.NodeExist(dstPath) {
		NewtUsage(cmd, util.NewNewtError("Cannot overwrite existing package, "+
			"use pkg delete first"))
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "%s package %s to %s\n",
		opStr, srcLoc, dstLoc)

	if err := dirOpFn(srcPkg.BasePath(), dstPath); err != nil {
		NewtUsage(cmd, err)
	}

	/* Replace the package name in the pkg.yml file */
	pkgData, err := ioutil.ReadFile(dstPath + "/pkg.yml")
	if err != nil {
		NewtUsage(cmd, err)
	}

	re := regexp.MustCompile(regexp.QuoteMeta(srcName))
	res := re.ReplaceAllString(string(pkgData), pkgName)

	if err := ioutil.WriteFile(dstPath+"/pkg.yml", []byte(res), 0666); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	/* If the last element of the package path changes, rename the include
	 * directory.
	 */
	if path.Base(pkgName) != path.Base(srcPkg.Name()) {
		dirOpFn(dstPath+"/include/"+path.Base(srcPkg.Name()),
			dstPath+"/include/"+path.Base(pkgName))
	}
}

func pkgRemoveCmd(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		NewtUsage(cmd, util.NewNewtError("Must specify a package name to delete"))
	}

	proj := TryGetProject()
	interfaces.SetProject(proj)

	wd, err := os.Getwd()
	if err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	if err := os.Chdir(proj.Path() + "/"); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}

	defer os.Chdir(wd)

	/* Resolve package, and get path from package to ensure we're being asked
	 * to remove a valid path.
	 */
	repoName, pkgName, err := newtutil.ParsePackageString(args[0])
	if err != nil {
		NewtUsage(cmd, err)
	}

	repo := proj.LocalRepo()
	if repoName != "" {
		repo = proj.FindRepo(repoName)
		if repo == nil {
			NewtUsage(cmd, util.NewNewtError("Destination repo "+
				repoName+" does not exist"))
		}
	}

	pkg, err := pkg.LoadLocalPackage(repo, pkgName)
	if err != nil {
		NewtUsage(cmd, err)
	}

	util.StatusMessage(util.VERBOSITY_DEFAULT, "Removing package %s\n",
		args[0])

	if err := os.RemoveAll(pkg.BasePath()); err != nil {
		NewtUsage(cmd, util.ChildNewtError(err))
	}
}

func AddPackageCommands(cmd *cobra.Command) {
	/* Add the base package command, on top of which other commands are
	 * keyed
	 */
	pkgHelpText := "Commands for creating and manipulating packages"
	pkgHelpEx := "  newt pkg new --type=pkg sys/mylib"

	pkgCmd := &cobra.Command{
		Use:     "pkg",
		Short:   "Create and manage packages in the current workspace",
		Long:    pkgHelpText,
		Example: pkgHelpEx,
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Help()
		},
	}

	cmd.AddCommand(pkgCmd)

	/* Package new command, create a new package */
	newCmdHelpText := ""
	newCmdHelpEx := ""

	newCmd := &cobra.Command{
		Use:     "new <package-name>",
		Short:   "Create a new package in the current directory, from a template",
		Long:    newCmdHelpText,
		Example: newCmdHelpEx,
		Run:     pkgNewCmd,
	}

	newCmd.PersistentFlags().StringVarP(&NewTypeStr, "type", "t",
		"pkg", "Type of package to create: pkg, bsp, sdk.  Default pkg.")

	pkgCmd.AddCommand(newCmd)

	cloneCmdHelpText := ""
	cloneCmdHelpEx := ""

	cloneCmd := &cobra.Command{
		Use:     "clone <srcpkg> <dstpkg>",
		Short:   "Clone an existing package into another",
		Long:    cloneCmdHelpText,
		Example: cloneCmdHelpEx,
		Run:     pkgCloneCmd,
	}

	pkgCmd.AddCommand(cloneCmd)

	moveCmdHelpText := ""
	moveCmdHelpEx := ""

	moveCmd := &cobra.Command{
		Use:     "move <oldpkg> <newpkg>",
		Short:   "Move a package from one location to another",
		Long:    moveCmdHelpText,
		Example: moveCmdHelpEx,
		Run:     pkgMoveCmd,
	}

	pkgCmd.AddCommand(moveCmd)

	removeCmdHelpText := ""
	removeCmdHelpEx := ""

	removeCmd := &cobra.Command{
		Use:     "remove <package-name>",
		Short:   "Remove a package",
		Long:    removeCmdHelpText,
		Example: removeCmdHelpEx,
		Run:     pkgRemoveCmd,
	}

	pkgCmd.AddCommand(removeCmd)
}
<|endoftext|>