<commit_before>/*
Copyright 2022 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 main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"context"

	"github.com/sirupsen/logrus"
	"sigs.k8s.io/yaml"
)

const (
	defaultArch = "linux/amd64"
	allArch     = "all"

	gatherStaicScriptName = "gather-static.sh"

	// Relative to root of the repo
	defaultProwImageListFile = "prow/.prow-images.yaml"

	defaultWorkersCount = 10
	defaultRetry        = 3

	// noOpKoDocerRepo is used when images are not pushed
	noOpKoDocerRepo = "ko.local"
)

var (
	rootDir     string
	otherArches = []string{
		"linux/arm64",
		"linux/s390x",
		"linux/ppc64le",
	}
	defaultTags = []string{
		"latest",
		"latest-root",
	}
)

func init() {
	out, err := runCmd(nil, "git", "rev-parse", "--show-toplevel")
	if err != nil {
		logrus.WithError(err).Error("Failed getting git root dir")
		os.Exit(1)
	}
	rootDir = out

	if _, err := runCmdInDirFunc(path.Join(rootDir, "hack/tools"), nil, "go", "build", "-o", path.Join(rootDir, "_bin/ko"), "github.com/google/ko"); err != nil {
		logrus.WithError(err).Error("Failed ensure ko")
		os.Exit(1)
	}
}

type options struct {
	dockerRepo        string
	prowImageListFile string
	workers           int
	push              bool
	maxRetry          int
}

// Mock for unit testing purpose
var runCmdInDirFunc = runCmdInDir

func runCmdInDir(dir string, additionalEnv []string, cmd string, args ...string) (string, error) {
	command := exec.Command(cmd, args...)
	if dir != "" {
		command.Dir = dir
	}
	command.Env = append(os.Environ(), additionalEnv...)
	stdOut, err := command.StdoutPipe()
	if err != nil {
		return "", err
	}
	stdErr, err := command.StderrPipe()
	if err != nil {
		return "", err
	}
	if err := command.Start(); err != nil {
		return "", err
	}
	scanner := bufio.NewScanner(stdOut)
	var allOut string
	for scanner.Scan() {
		out := scanner.Text()
		allOut = allOut + out
		logrus.WithField("cmd", command.Args).Info(out)
	}
	allErr, _ := io.ReadAll(stdErr)
	err = command.Wait()
	// Print error only when command failed
	if err != nil && len(allErr) > 0 {
		logrus.WithField("cmd", command.Args).Error(string(allErr))
	}
	return strings.TrimSpace(allOut), err
}

func runCmd(additionalEnv []string, cmd string, args ...string) (string, error) {
	return runCmdInDirFunc(rootDir, additionalEnv, cmd, args...)
}

type imageDef struct {
	Dir            string `json:"dir"`
	Arch           string `json:"arch"`
	remainingRetry int
}

type imageDefs struct {
	Defs []imageDef `json:"images"`
}

func loadImageDefs(p string) ([]imageDef, error) {
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return nil, err
	}
	var res imageDefs
	if err := yaml.Unmarshal(b, &res); err != nil {
		return nil, err
	}
	return res.Defs, nil
}

func allBaseTags() ([]string, error) {
	gitTag, err := gitTag()
	if err != nil {
		return nil, err
	}
	// Add a `ko-<GIT_TAG>` tag so that it's easy to identify images built from
	// ko vs. images built from bazel, in case there is a revert needed.
	// TODO(chaodaiG): remove `ko-` tag once the images produced by ko proved to
	// be working
	return append(defaultTags, gitTag, "ko-"+gitTag), nil
}

func allTags(arch string) ([]string, error) {
	baseTags, err := allBaseTags()
	if err != nil {
		return nil, err
	}

	var allTags = baseTags
	for _, otherArch := range otherArches {
		if arch != allArch && arch != otherArch {
			continue
		}
		for _, base := range baseTags {
			// So far only platform supported is linux, trimming off the linux/
			// prefix so that there is no slash in tag. Also for consistency reasons.
			platform := strings.Replace(otherArch, "linux/", "", 1)
			allTags = append(allTags, fmt.Sprintf("%s-%s", base, platform))
		}
	}
	return allTags, nil
}

// gitTag returns YYYYMMDD-<GIT_TAG>
func gitTag() (string, error) {
	prefix, err := runCmd(nil, "date", "+v%Y%m%d")
	if err != nil {
		return "", err
	}
	postfix, err := runCmd(nil, "git", "describe", "--always", "--dirty")
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s-%s", prefix, postfix), nil
}

func runGatherStaticScript(id *imageDef, args ...string) error {
	script := path.Join(rootDir, id.Dir, gatherStaicScriptName)
	if _, err := os.Lstat(script); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		return nil
	}
	if _, err := runCmd(nil, script, args...); err != nil {
		return err
	}
	return nil
}

func setup(id *imageDef) error {
	return runGatherStaticScript(id)
}

func teardown(id *imageDef) error {
	return runGatherStaticScript(id, "--cleanup")
}

func buildAndPush(id *imageDef, dockerRepos []string, push bool) error {
	logger := logrus.WithField("image", id.Dir)
	logger.Info("Build and push")
	// So far only supports certain arch
	isSupportedArch := (id.Arch == defaultArch || id.Arch == allArch)
	for _, otherArch := range otherArches {
		if id.Arch == otherArch {
			isSupportedArch = true
		}
	}
	if !isSupportedArch {
		return fmt.Errorf("Arch '%s' not supported, only support %v", id.Arch, append([]string{defaultArch, allArch}, otherArches...))
	}
	publishArgs := []string{"publish", fmt.Sprintf("--tarball=_bin/%s.tar", path.Base(id.Dir)), "--push=false"}
	if push {
		publishArgs = []string{"publish", "--push=true"}
	}
	tags, err := allTags(id.Arch)
	if err != nil {
		return fmt.Errorf("collecting tags: %w", err)
	}
	for _, tag := range tags {
		publishArgs = append(publishArgs, fmt.Sprintf("--tags=%s", tag))
	}
	publishArgs = append(publishArgs, "--base-import-paths", "--platform="+id.Arch, "./"+id.Dir)

	defer teardown(id)
	if err := setup(id); err != nil {
		return fmt.Errorf("setup: %w", err)
	}
	// ko only supports a single docker repo at a time, running this repeatedly
	// on different docker repos so that multiple docker repos can be supported.
	// This process utilized the built in cache of ko, so that pushing to
	// subsequent docker repo(s) is relatively cheap.
	for _, dockerRepo := range dockerRepos {
		if _, err = runCmd([]string{"KO_DOCKER_REPO=" + dockerRepo}, "_bin/ko", publishArgs...); err != nil {
			return fmt.Errorf("running ko: %w", err)
		}
	}
	return nil
}

func main() {
	var o options
	flag.StringVar(&o.prowImageListFile, "prow-images-file", path.Join(rootDir, defaultProwImageListFile), "Yaml file contains list of prow images")
	flag.StringVar(&o.dockerRepo, "ko-docker-repo", os.Getenv("KO_DOCKER_REPO"), "Dockers repos, separated by comma")
	flag.IntVar(&o.workers, "workers", defaultWorkersCount, "Number of workers in parallel")
	flag.BoolVar(&o.push, "push", false, "whether push or not")
	flag.IntVar(&o.maxRetry, "retry", defaultRetry, "Number of times retrying for each image")
	flag.Parse()

	if !o.push && o.dockerRepo == "" {
		o.dockerRepo = noOpKoDocerRepo
	}
	// By default ensures timestamp of images, ref:
	// https://github.com/google/ko#why-are-my-images-all-created-in-1970
	if err := os.Setenv("SOURCE_DATE_EPOCH", strconv.Itoa(int(time.Now().Unix()))); err != nil {
		logrus.WithError(err).Error("Failed setting SOURCE_DATE_EPOCH")
		os.Exit(1)
	}

	// Set VERSION for embedding versions with go build
	gitTag, err := gitTag()
	if err != nil {
		logrus.WithError(err).Error("Failed get git tag")
		os.Exit(1)
	}
	if err := os.Setenv("VERSION", gitTag); err != nil {
		logrus.WithError(err).Error("Failed setting VERSION")
		os.Exit(1)
	}

	ids, err := loadImageDefs(o.prowImageListFile)
	if err != nil {
		logrus.WithError(err).WithField("prow-image-file", o.prowImageListFile).Error("Failed loading")
		os.Exit(1)
	}

	var wg sync.WaitGroup
	imageChan := make(chan imageDef, 10)
	errChan := make(chan error, len(ids))
	doneChan := make(chan imageDef, len(ids))
	// Start workers
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	for i := 0; i < o.workers; i++ {
		go func(ctx context.Context, imageChan chan imageDef, errChan chan error, doneChan chan imageDef) {
			for {
				select {
				case id := <-imageChan:
					err := buildAndPush(&id, strings.Split(o.dockerRepo, ","), o.push)
					if err != nil {
						if id.remainingRetry > 0 {
							// Let another routine handle this, better luck maybe?
							id.remainingRetry--
							imageChan <- id
							// Don't call wg.Done() as we are not done yet
							continue
						}
						errChan <- err
					}
					doneChan <- id
				case <-ctx.Done():
					return
				}
			}
		}(ctx, imageChan, errChan, doneChan)
	}

	for _, id := range ids {
		id := id
		id.remainingRetry = o.maxRetry
		if id.Arch == "" {
			id.Arch = defaultArch
		}
		// Feed into channel instead
		wg.Add(1)
		imageChan <- id
	}

	go func(ctx context.Context, wg *sync.WaitGroup, doneChan chan imageDef) {
		var done int
		for {
			select {
			case id := <-doneChan:
				done++
				logrus.WithFields(logrus.Fields{"image": id.Dir, "done": done, "total": len(ids)}).Info("Done with image.")
				wg.Done()
			case <-ctx.Done():
				return
			}
		}
	}(ctx, &wg, doneChan)

	wg.Wait()
	for {
		select {
		case err := <-errChan:
			logrus.WithError(err).Error("Failed.")
			os.Exit(1)
		default:
			return
		}
	}
}
<commit_msg>Prowimagebuilder: log duratoin spent on building each individual image<commit_after>/*
Copyright 2022 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 main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"

	"context"

	"github.com/sirupsen/logrus"
	"sigs.k8s.io/yaml"
)

const (
	defaultArch = "linux/amd64"
	allArch     = "all"

	gatherStaicScriptName = "gather-static.sh"

	// Relative to root of the repo
	defaultProwImageListFile = "prow/.prow-images.yaml"

	defaultWorkersCount = 10
	defaultRetry        = 3

	// noOpKoDocerRepo is used when images are not pushed
	noOpKoDocerRepo = "ko.local"
)

var (
	rootDir     string
	otherArches = []string{
		"linux/arm64",
		"linux/s390x",
		"linux/ppc64le",
	}
	defaultTags = []string{
		"latest",
		"latest-root",
	}
)

func init() {
	out, err := runCmd(nil, "git", "rev-parse", "--show-toplevel")
	if err != nil {
		logrus.WithError(err).Error("Failed getting git root dir")
		os.Exit(1)
	}
	rootDir = out

	if _, err := runCmdInDirFunc(path.Join(rootDir, "hack/tools"), nil, "go", "build", "-o", path.Join(rootDir, "_bin/ko"), "github.com/google/ko"); err != nil {
		logrus.WithError(err).Error("Failed ensure ko")
		os.Exit(1)
	}
}

type options struct {
	dockerRepo        string
	prowImageListFile string
	workers           int
	push              bool
	maxRetry          int
}

// Mock for unit testing purpose
var runCmdInDirFunc = runCmdInDir

func runCmdInDir(dir string, additionalEnv []string, cmd string, args ...string) (string, error) {
	command := exec.Command(cmd, args...)
	if dir != "" {
		command.Dir = dir
	}
	command.Env = append(os.Environ(), additionalEnv...)
	stdOut, err := command.StdoutPipe()
	if err != nil {
		return "", err
	}
	stdErr, err := command.StderrPipe()
	if err != nil {
		return "", err
	}
	if err := command.Start(); err != nil {
		return "", err
	}
	scanner := bufio.NewScanner(stdOut)
	var allOut string
	for scanner.Scan() {
		out := scanner.Text()
		allOut = allOut + out
		logrus.WithField("cmd", command.Args).Info(out)
	}
	allErr, _ := io.ReadAll(stdErr)
	err = command.Wait()
	// Print error only when command failed
	if err != nil && len(allErr) > 0 {
		logrus.WithField("cmd", command.Args).Error(string(allErr))
	}
	return strings.TrimSpace(allOut), err
}

func runCmd(additionalEnv []string, cmd string, args ...string) (string, error) {
	return runCmdInDirFunc(rootDir, additionalEnv, cmd, args...)
}

type imageDef struct {
	Dir            string `json:"dir"`
	Arch           string `json:"arch"`
	remainingRetry int
}

type imageDefs struct {
	Defs []imageDef `json:"images"`
}

func loadImageDefs(p string) ([]imageDef, error) {
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return nil, err
	}
	var res imageDefs
	if err := yaml.Unmarshal(b, &res); err != nil {
		return nil, err
	}
	return res.Defs, nil
}

func allBaseTags() ([]string, error) {
	gitTag, err := gitTag()
	if err != nil {
		return nil, err
	}
	// Add a `ko-<GIT_TAG>` tag so that it's easy to identify images built from
	// ko vs. images built from bazel, in case there is a revert needed.
	// TODO(chaodaiG): remove `ko-` tag once the images produced by ko proved to
	// be working
	return append(defaultTags, gitTag, "ko-"+gitTag), nil
}

func allTags(arch string) ([]string, error) {
	baseTags, err := allBaseTags()
	if err != nil {
		return nil, err
	}

	var allTags = baseTags
	for _, otherArch := range otherArches {
		if arch != allArch && arch != otherArch {
			continue
		}
		for _, base := range baseTags {
			// So far only platform supported is linux, trimming off the linux/
			// prefix so that there is no slash in tag. Also for consistency reasons.
			platform := strings.Replace(otherArch, "linux/", "", 1)
			allTags = append(allTags, fmt.Sprintf("%s-%s", base, platform))
		}
	}
	return allTags, nil
}

// gitTag returns YYYYMMDD-<GIT_TAG>
func gitTag() (string, error) {
	prefix, err := runCmd(nil, "date", "+v%Y%m%d")
	if err != nil {
		return "", err
	}
	postfix, err := runCmd(nil, "git", "describe", "--always", "--dirty")
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s-%s", prefix, postfix), nil
}

func runGatherStaticScript(id *imageDef, args ...string) error {
	script := path.Join(rootDir, id.Dir, gatherStaicScriptName)
	if _, err := os.Lstat(script); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		return nil
	}
	if _, err := runCmd(nil, script, args...); err != nil {
		return err
	}
	return nil
}

func setup(id *imageDef) error {
	return runGatherStaticScript(id)
}

func teardown(id *imageDef) error {
	return runGatherStaticScript(id, "--cleanup")
}

func buildAndPush(id *imageDef, dockerRepos []string, push bool) error {
	logger := logrus.WithField("image", id.Dir)
	logger.Info("Build and push")
	start := time.Now()
	defer func(logger *logrus.Entry, start time.Time) {
		logger.WithField("duration", time.Since(start).String()).Info("Duration of image building.")
	}(logger, start)
	// So far only supports certain arch
	isSupportedArch := (id.Arch == defaultArch || id.Arch == allArch)
	for _, otherArch := range otherArches {
		if id.Arch == otherArch {
			isSupportedArch = true
		}
	}
	if !isSupportedArch {
		return fmt.Errorf("Arch '%s' not supported, only support %v", id.Arch, append([]string{defaultArch, allArch}, otherArches...))
	}
	publishArgs := []string{"publish", fmt.Sprintf("--tarball=_bin/%s.tar", path.Base(id.Dir)), "--push=false"}
	if push {
		publishArgs = []string{"publish", "--push=true"}
	}
	tags, err := allTags(id.Arch)
	if err != nil {
		return fmt.Errorf("collecting tags: %w", err)
	}
	for _, tag := range tags {
		publishArgs = append(publishArgs, fmt.Sprintf("--tags=%s", tag))
	}
	publishArgs = append(publishArgs, "--base-import-paths", "--platform="+id.Arch, "./"+id.Dir)

	defer teardown(id)
	if err := setup(id); err != nil {
		return fmt.Errorf("setup: %w", err)
	}
	// ko only supports a single docker repo at a time, running this repeatedly
	// on different docker repos so that multiple docker repos can be supported.
	// This process utilized the built in cache of ko, so that pushing to
	// subsequent docker repo(s) is relatively cheap.
	for _, dockerRepo := range dockerRepos {
		if _, err = runCmd([]string{"KO_DOCKER_REPO=" + dockerRepo}, "_bin/ko", publishArgs...); err != nil {
			return fmt.Errorf("running ko: %w", err)
		}
	}
	return nil
}

func main() {
	var o options
	flag.StringVar(&o.prowImageListFile, "prow-images-file", path.Join(rootDir, defaultProwImageListFile), "Yaml file contains list of prow images")
	flag.StringVar(&o.dockerRepo, "ko-docker-repo", os.Getenv("KO_DOCKER_REPO"), "Dockers repos, separated by comma")
	flag.IntVar(&o.workers, "workers", defaultWorkersCount, "Number of workers in parallel")
	flag.BoolVar(&o.push, "push", false, "whether push or not")
	flag.IntVar(&o.maxRetry, "retry", defaultRetry, "Number of times retrying for each image")
	flag.Parse()

	if !o.push && o.dockerRepo == "" {
		o.dockerRepo = noOpKoDocerRepo
	}
	// By default ensures timestamp of images, ref:
	// https://github.com/google/ko#why-are-my-images-all-created-in-1970
	if err := os.Setenv("SOURCE_DATE_EPOCH", strconv.Itoa(int(time.Now().Unix()))); err != nil {
		logrus.WithError(err).Error("Failed setting SOURCE_DATE_EPOCH")
		os.Exit(1)
	}

	// Set VERSION for embedding versions with go build
	gitTag, err := gitTag()
	if err != nil {
		logrus.WithError(err).Error("Failed get git tag")
		os.Exit(1)
	}
	if err := os.Setenv("VERSION", gitTag); err != nil {
		logrus.WithError(err).Error("Failed setting VERSION")
		os.Exit(1)
	}

	ids, err := loadImageDefs(o.prowImageListFile)
	if err != nil {
		logrus.WithError(err).WithField("prow-image-file", o.prowImageListFile).Error("Failed loading")
		os.Exit(1)
	}

	var wg sync.WaitGroup
	imageChan := make(chan imageDef, 10)
	errChan := make(chan error, len(ids))
	doneChan := make(chan imageDef, len(ids))
	// Start workers
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	for i := 0; i < o.workers; i++ {
		go func(ctx context.Context, imageChan chan imageDef, errChan chan error, doneChan chan imageDef) {
			for {
				select {
				case id := <-imageChan:
					err := buildAndPush(&id, strings.Split(o.dockerRepo, ","), o.push)
					if err != nil {
						if id.remainingRetry > 0 {
							// Let another routine handle this, better luck maybe?
							id.remainingRetry--
							imageChan <- id
							// Don't call wg.Done() as we are not done yet
							continue
						}
						errChan <- fmt.Errorf("building image for %s failed: %v", id.Dir, err)
					}
					doneChan <- id
				case <-ctx.Done():
					return
				}
			}
		}(ctx, imageChan, errChan, doneChan)
	}

	for _, id := range ids {
		id := id
		id.remainingRetry = o.maxRetry
		if id.Arch == "" {
			id.Arch = defaultArch
		}
		// Feed into channel instead
		wg.Add(1)
		imageChan <- id
	}

	go func(ctx context.Context, wg *sync.WaitGroup, doneChan chan imageDef) {
		var done int
		for {
			select {
			case id := <-doneChan:
				done++
				logrus.WithFields(logrus.Fields{"image": id.Dir, "done": done, "total": len(ids)}).Info("Done with image.")
				wg.Done()
			case <-ctx.Done():
				return
			}
		}
	}(ctx, &wg, doneChan)

	wg.Wait()
	for {
		select {
		case err := <-errChan:
			logrus.WithError(err).Error("Failed.")
			os.Exit(1)
		default:
			return
		}
	}
}
<|endoftext|>


<commit_before>package isolated

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"strings"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("app command", func() {
	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("app", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("app - Display health and status for an app"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf app APP_NAME"))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say("--guid      Retrieve and display the given app's guid.  All other health and status output for the app is suppressed."))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("apps, events, logs, map-route, push, unmap-route"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no org set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
			})

			It("fails with no targeted org error message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
				helpers.TargetOrg(ReadOnlyOrg)
			})

			It("fails with no targeted space error message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var (
			orgName   string
			spaceName string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()

			setupCF(orgName, spaceName)
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		Context("when the app name is not provided", func() {
			It("tells the user that the app name is required, prints help text, and exits 1", func() {
				session := helpers.CF("app")

				Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
				Eventually(session.Out).Should(Say("NAME:"))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the app does not exist", func() {
			Context("when no flags are given", func() {
				It("tells the user that the app is not found and exits 1", func() {
					appName := helpers.PrefixedRandomName("app")
					session := helpers.CF("app", appName)

					Eventually(session.Out).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("App %s not found", appName))
					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the --guid flag is given", func() {
				It("tells the user that the app is not found and exits 1", func() {
					appName := helpers.PrefixedRandomName("app")
					session := helpers.CF("app", "--guid", appName)

					Eventually(session.Out).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("App %s not found", appName))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		Context("when the app does exist", func() {
			Context("when the app is a buildpack app", func() {
				var (
					domainName string
					tcpDomain  helpers.Domain
					appName    string
				)

				BeforeEach(func() {
					Eventually(helpers.CF("create-isolation-segment", RealIsolationSegment)).Should(Exit(0))
					Eventually(helpers.CF("enable-org-isolation", orgName, RealIsolationSegment)).Should(Exit(0))
					Eventually(helpers.CF("set-space-isolation-segment", spaceName, RealIsolationSegment)).Should(Exit(0))

					appName = helpers.PrefixedRandomName("app")
					domainName = defaultSharedDomain()
					tcpDomain = helpers.NewDomain(orgName, helpers.DomainName("tcp"))
					tcpDomain.CreateWithRouterGroup(helpers.DefaultTCPRouterGroup)
					helpers.WithHelloWorldApp(func(appDir string) {
						manifestContents := []byte(fmt.Sprintf(`
---
applications:
- name: %s
  memory: 128M
  instances: 2
  disk_quota: 128M
  routes:
  - route: %s.%s
  - route: %s:0
`, appName, appName, domainName, tcpDomain.Name))
						manifestPath := filepath.Join(appDir, "manifest.yml")
						err := ioutil.WriteFile(manifestPath, manifestContents, 0666)
						Expect(err).ToNot(HaveOccurred())

						// Create manifest
						Eventually(helpers.CF("push", appName, "-p", appDir, "-f", manifestPath, "-b", "staticfile_buildpack", "--random-route")).Should(Exit(0))
					})
				})

				AfterEach(func() {
					Eventually(helpers.CF("delete", appName, "-f", "-r")).Should(Exit(0))
				})

				Context("when the app is started and has 2 instances", func() {
					It("displays the app information with instances table", func() {
						session := helpers.CF("app", appName)
						Eventually(session).Should(Say("name:\\s+%s", appName))
						Eventually(session).Should(Say("requested state:\\s+started"))
						Eventually(session).Should(Say("instances:\\s+2/2"))
						Eventually(session).Should(Say("isolation segment:\\s+%s", RealIsolationSegment))
						Eventually(session).Should(Say("usage:\\s+128M x 2 instances"))
						Eventually(session).Should(Say("routes:\\s+[a-z-]+\\.%s, %s:\\d+", domainName, tcpDomain.Name))
						Eventually(session).Should(Say("last uploaded:\\s+\\w{3} [0-3]\\d \\w{3} [0-2]\\d:[0-5]\\d:[0-5]\\d \\w+ \\d{4}"))
						Eventually(session).Should(Say("stack:\\s+cflinuxfs2"))
						Eventually(session).Should(Say("buildpack:\\s+staticfile_buildpack"))
						Eventually(session).Should(Say(""))
						Eventually(session).Should(Say("state\\s+since\\s+cpu\\s+memory\\s+disk\\s+details"))
						Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-[01]\\d-[0-3]\\dT[0-2][0-9]:[0-5]\\d:[0-5]\\dZ\\s+\\d+\\.\\d+%.*of 128M.*of 128M"))
						Eventually(session).Should(Say("#1\\s+running\\s+\\d{4}-[01]\\d-[0-3]\\dT[0-2][0-9]:[0-5]\\d:[0-5]\\dZ\\s+\\d+\\.\\d+%.*of 128M.*of 128M"))
						Eventually(session).Should(Exit(0))
					})
				})

				Context("when the app is stopped", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("stop", appName)).Should(Exit(0))
					})

					It("displays the app information", func() {
						session := helpers.CF("app", appName)
						Eventually(session).Should(Say("name:\\s+%s", appName))
						Eventually(session).Should(Say("requested state:\\s+stopped"))
						Eventually(session).Should(Say("instances:\\s+0/2"))
						Eventually(session).Should(Say("usage:\\s+128M x 2 instances"))
						Eventually(session).Should(Say("routes:\\s+[a-z-]+.%s, %s:\\d+", domainName, tcpDomain.Name))
						Eventually(session).Should(Say("last uploaded:"))
						Eventually(session).Should(Say("stack:\\s+cflinuxfs2"))
						Eventually(session).Should(Say("buildpack:\\s+staticfile_buildpack"))

						Eventually(session).Should(Say("There are no running instances of this app."))
						Eventually(session).Should(Exit(0))
					})
				})

				Context("when the app has 0 instances", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("scale", appName, "-i", "0")).Should(Exit(0))
					})

					It("displays the app information", func() {
						session := helpers.CF("app", appName)
						Eventually(session).Should(Say("name:\\s+%s", appName))
						Eventually(session).Should(Say("requested state:\\s+started"))
						Eventually(session).Should(Say("instances:\\s+0/0"))
						Eventually(session).Should(Say("usage:\\s+128M x 0 instances"))
						Eventually(session).Should(Say("routes:\\s+[a-z-]+\\.%s, %s:\\d+", domainName, tcpDomain.Name))
						Eventually(session).Should(Say("last uploaded:"))
						Eventually(session).Should(Say("stack:\\s+cflinuxfs2"))
						Eventually(session).Should(Say("buildpack:\\s+staticfile_buildpack"))

						Eventually(session).Should(Say("There are no running instances of this app."))
						Eventually(session).Should(Exit(0))
					})
				})

				Context("when the --guid flag is given", func() {
					var appGUID string

					BeforeEach(func() {
						session := helpers.CF("curl", fmt.Sprintf("/v2/apps?q=name:%s", appName))
						Eventually(session).Should(Exit(0))
						rawJSON := strings.TrimSpace(string(session.Out.Contents()))
						var AppInfo struct {
							Resources []struct {
								Metadata struct {
									GUID string `json:"guid"`
								} `json:"metadata"`
							} `json:"resources"`
						}

						err := json.Unmarshal([]byte(rawJSON), &AppInfo)
						Expect(err).NotTo(HaveOccurred())

						appGUID = AppInfo.Resources[0].Metadata.GUID
					})

					It("displays the app guid", func() {
						session := helpers.CF("app", "--guid", appName)
						Eventually(session).Should(Say(appGUID))
						Eventually(session).Should(Exit(0))
					})
				})
			})

			Context("when the app is a Docker app", func() {
				var (
					domainName string
					tcpDomain  helpers.Domain
					appName    string
				)

				BeforeEach(func() {
					appName = helpers.PrefixedRandomName("app")
					domainName = defaultSharedDomain()
					tcpDomain = helpers.NewDomain(orgName, helpers.DomainName("tcp"))
					tcpDomain.CreateWithRouterGroup(helpers.DefaultTCPRouterGroup)
					Eventually(helpers.CF("push", appName, "-o", DockerImage)).Should(Exit())
				})

				It("displays the docker image and does not display buildpack", func() {
					session := helpers.CF("app", appName)
					Eventually(session).Should(Say("name:\\s+%s", appName))
					Consistently(session).ShouldNot(Say("buildpack:"))
					Eventually(session).Should(Say("docker image:\\s+%s", DockerImage))
					Consistently(session).ShouldNot(Say("buildpack:"))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})
})
<commit_msg>no need to delete the app manually as the org is deleted after each test<commit_after>package isolated

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"strings"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("app command", func() {
	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("app", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("app - Display health and status for an app"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf app APP_NAME"))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say("--guid      Retrieve and display the given app's guid.  All other health and status output for the app is suppressed."))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("apps, events, logs, map-route, push, unmap-route"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no org set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
			})

			It("fails with no targeted org error message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
				helpers.TargetOrg(ReadOnlyOrg)
			})

			It("fails with no targeted space error message", func() {
				session := helpers.CF("app", "wut")
				Eventually(session.Out).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var (
			orgName   string
			spaceName string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()

			setupCF(orgName, spaceName)
		})

		AfterEach(func() {
			helpers.QuickDeleteOrg(orgName)
		})

		Context("when the app name is not provided", func() {
			It("tells the user that the app name is required, prints help text, and exits 1", func() {
				session := helpers.CF("app")

				Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
				Eventually(session.Out).Should(Say("NAME:"))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the app does not exist", func() {
			Context("when no flags are given", func() {
				It("tells the user that the app is not found and exits 1", func() {
					appName := helpers.PrefixedRandomName("app")
					session := helpers.CF("app", appName)

					Eventually(session.Out).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("App %s not found", appName))
					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the --guid flag is given", func() {
				It("tells the user that the app is not found and exits 1", func() {
					appName := helpers.PrefixedRandomName("app")
					session := helpers.CF("app", "--guid", appName)

					Eventually(session.Out).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("App %s not found", appName))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		Context("when the app does exist", func() {
			Context("when the app is a buildpack app", func() {
				var (
					domainName string
					tcpDomain  helpers.Domain
					appName    string
				)

				BeforeEach(func() {
					Eventually(helpers.CF("create-isolation-segment", RealIsolationSegment)).Should(Exit(0))
					Eventually(helpers.CF("enable-org-isolation", orgName, RealIsolationSegment)).Should(Exit(0))
					Eventually(helpers.CF("set-space-isolation-segment", spaceName, RealIsolationSegment)).Should(Exit(0))

					appName = helpers.PrefixedRandomName("app")
					domainName = defaultSharedDomain()
					tcpDomain = helpers.NewDomain(orgName, helpers.DomainName("tcp"))
					tcpDomain.CreateWithRouterGroup(helpers.DefaultTCPRouterGroup)
					helpers.WithHelloWorldApp(func(appDir string) {
						manifestContents := []byte(fmt.Sprintf(`
---
applications:
- name: %s
  memory: 128M
  instances: 2
  disk_quota: 128M
  routes:
  - route: %s.%s
  - route: %s:0
`, appName, appName, domainName, tcpDomain.Name))
						manifestPath := filepath.Join(appDir, "manifest.yml")
						err := ioutil.WriteFile(manifestPath, manifestContents, 0666)
						Expect(err).ToNot(HaveOccurred())

						// Create manifest
						Eventually(helpers.CF("push", appName, "-p", appDir, "-f", manifestPath, "-b", "staticfile_buildpack", "--random-route")).Should(Exit(0))
					})
				})

				Context("when the app is started and has 2 instances", func() {
					It("displays the app information with instances table", func() {
						session := helpers.CF("app", appName)
						Eventually(session).Should(Say("name:\\s+%s", appName))
						Eventually(session).Should(Say("requested state:\\s+started"))
						Eventually(session).Should(Say("instances:\\s+2/2"))
						Eventually(session).Should(Say("isolation segment:\\s+%s", RealIsolationSegment))
						Eventually(session).Should(Say("usage:\\s+128M x 2 instances"))
						Eventually(session).Should(Say("routes:\\s+[a-z-]+\\.%s, %s:\\d+", domainName, tcpDomain.Name))
						Eventually(session).Should(Say("last uploaded:\\s+\\w{3} [0-3]\\d \\w{3} [0-2]\\d:[0-5]\\d:[0-5]\\d \\w+ \\d{4}"))
						Eventually(session).Should(Say("stack:\\s+cflinuxfs2"))
						Eventually(session).Should(Say("buildpack:\\s+staticfile_buildpack"))
						Eventually(session).Should(Say(""))
						Eventually(session).Should(Say("state\\s+since\\s+cpu\\s+memory\\s+disk\\s+details"))
						Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-[01]\\d-[0-3]\\dT[0-2][0-9]:[0-5]\\d:[0-5]\\dZ\\s+\\d+\\.\\d+%.*of 128M.*of 128M"))
						Eventually(session).Should(Say("#1\\s+running\\s+\\d{4}-[01]\\d-[0-3]\\dT[0-2][0-9]:[0-5]\\d:[0-5]\\dZ\\s+\\d+\\.\\d+%.*of 128M.*of 128M"))
						Eventually(session).Should(Exit(0))
					})
				})

				Context("when the app is stopped", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("stop", appName)).Should(Exit(0))
					})

					It("displays the app information", func() {
						session := helpers.CF("app", appName)
						Eventually(session).Should(Say("name:\\s+%s", appName))
						Eventually(session).Should(Say("requested state:\\s+stopped"))
						Eventually(session).Should(Say("instances:\\s+0/2"))
						Eventually(session).Should(Say("usage:\\s+128M x 2 instances"))
						Eventually(session).Should(Say("routes:\\s+[a-z-]+.%s, %s:\\d+", domainName, tcpDomain.Name))
						Eventually(session).Should(Say("last uploaded:"))
						Eventually(session).Should(Say("stack:\\s+cflinuxfs2"))
						Eventually(session).Should(Say("buildpack:\\s+staticfile_buildpack"))

						Eventually(session).Should(Say("There are no running instances of this app."))
						Eventually(session).Should(Exit(0))
					})
				})

				Context("when the app has 0 instances", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("scale", appName, "-i", "0")).Should(Exit(0))
					})

					It("displays the app information", func() {
						session := helpers.CF("app", appName)
						Eventually(session).Should(Say("name:\\s+%s", appName))
						Eventually(session).Should(Say("requested state:\\s+started"))
						Eventually(session).Should(Say("instances:\\s+0/0"))
						Eventually(session).Should(Say("usage:\\s+128M x 0 instances"))
						Eventually(session).Should(Say("routes:\\s+[a-z-]+\\.%s, %s:\\d+", domainName, tcpDomain.Name))
						Eventually(session).Should(Say("last uploaded:"))
						Eventually(session).Should(Say("stack:\\s+cflinuxfs2"))
						Eventually(session).Should(Say("buildpack:\\s+staticfile_buildpack"))

						Eventually(session).Should(Say("There are no running instances of this app."))
						Eventually(session).Should(Exit(0))
					})
				})

				Context("when the --guid flag is given", func() {
					var appGUID string

					BeforeEach(func() {
						session := helpers.CF("curl", fmt.Sprintf("/v2/apps?q=name:%s", appName))
						Eventually(session).Should(Exit(0))
						rawJSON := strings.TrimSpace(string(session.Out.Contents()))
						var AppInfo struct {
							Resources []struct {
								Metadata struct {
									GUID string `json:"guid"`
								} `json:"metadata"`
							} `json:"resources"`
						}

						err := json.Unmarshal([]byte(rawJSON), &AppInfo)
						Expect(err).NotTo(HaveOccurred())

						appGUID = AppInfo.Resources[0].Metadata.GUID
					})

					It("displays the app guid", func() {
						session := helpers.CF("app", "--guid", appName)
						Eventually(session).Should(Say(appGUID))
						Eventually(session).Should(Exit(0))
					})
				})
			})

			Context("when the app is a Docker app", func() {
				var (
					domainName string
					tcpDomain  helpers.Domain
					appName    string
				)

				BeforeEach(func() {
					appName = helpers.PrefixedRandomName("app")
					domainName = defaultSharedDomain()
					tcpDomain = helpers.NewDomain(orgName, helpers.DomainName("tcp"))
					tcpDomain.CreateWithRouterGroup(helpers.DefaultTCPRouterGroup)
					Eventually(helpers.CF("push", appName, "-o", DockerImage)).Should(Exit())
				})

				It("displays the docker image and does not display buildpack", func() {
					session := helpers.CF("app", appName)
					Eventually(session).Should(Say("name:\\s+%s", appName))
					Consistently(session).ShouldNot(Say("buildpack:"))
					Eventually(session).Should(Say("docker image:\\s+%s", DockerImage))
					Consistently(session).ShouldNot(Say("buildpack:"))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package chipmunk

/*

	Physic engine

	TODO manage disabled objects

*/

import (
	"fmt"
	goz "github.com/20tab/gozmo"
	"github.com/vova616/chipmunk"
	"github.com/vova616/chipmunk/vect"
)

var space *chipmunk.Space

var Gravity goz.Vector2 = goz.Vector2{0, -9.8}

func checkSpace() {
	if space == nil {
		space = chipmunk.NewSpace()
		space.Gravity = vect.Vect{vect.Float(Gravity[0]), vect.Float(Gravity[1])}
	}
}

// Rigid Body
type RigidBody struct {
	body        *chipmunk.Body
	weight      float32
	initialized bool
}

func (rbody *RigidBody) Start(gameObject *goz.GameObject) {
	checkSpace()
	rbody.body = chipmunk.NewBody(vect.Float(rbody.weight), vect.Float(1))
	space.AddBody(rbody.body)
}

func (rbody *RigidBody) Update(gameObject *goz.GameObject) {
	if !rbody.initialized {
		pos := gameObject.Position
		rbody.body.SetPosition(vect.Vect{vect.Float(pos[0]), vect.Float(pos[1])})
		rbody.initialized = true
	}
	pos := rbody.body.Position()
	gameObject.SetPosition(float32(pos.X), float32(pos.Y))
}

func (rbody *RigidBody) GetType() string {
	return "RigidBody"
}

func (rbody *RigidBody) SetAttr(attr string, value interface{}) error {
	switch attr {
	case "velocityX":
		x, _ := goz.CastFloat32(value)
		oldV := rbody.body.Velocity()
		rbody.body.SetVelocity(x, float32(oldV.Y))
	}
	return nil
}

func (rbody *RigidBody) GetAttr(attr string) (interface{}, error) {
	switch attr {
	case "velocityX":
		return float32(rbody.body.Velocity().X), nil
	case "velocityY":
		return float32(rbody.body.Velocity().Y), nil
	}
	return nil, fmt.Errorf("%v attribute of %T not found", attr, rbody)
}

func NewRigidBody(weight float32) goz.Component {
	body := RigidBody{weight: weight}
	return &body
}

func initRigidBody(args []interface{}) goz.Component {
	return NewRigidBody(1)
}

// Static Body
type StaticBody struct {
	body        *chipmunk.Body
	initialized bool
}

func (sbody *StaticBody) Start(gameObject *goz.GameObject) {
	checkSpace()
	sbody.body = chipmunk.NewBodyStatic()
	space.AddBody(sbody.body)
}

func (sbody *StaticBody) Update(gameObject *goz.GameObject) {
	if !sbody.initialized {
		pos := gameObject.Position
		sbody.body.SetPosition(vect.Vect{vect.Float(pos[0]), vect.Float(pos[1])})
		sbody.initialized = true
	}
	pos := sbody.body.Position()
	gameObject.SetPosition(float32(pos.X), float32(pos.Y))
}

func (sbody *StaticBody) GetType() string {
	return "StaticBody"
}

func NewStaticBody() goz.Component {
	body := StaticBody{}
	return &body
}

func initStaticBody(args []interface{}) goz.Component {
	return NewStaticBody()
}

// Shape Circle
type ShapeCircle struct {
	shape       *chipmunk.CircleShape
	initialized bool
}

func (circle *ShapeCircle) Start(gameObject *goz.GameObject) {
	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		return
	}

	fmt.Println("ShapeCircle requires a physic body")
}

func (circle *ShapeCircle) Update(gameObject *goz.GameObject) {
	if circle.initialized {
		return
	}

	circle.initialized = true

	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		rbody := component.(*RigidBody)
		moment := circle.shape.Moment(float32(rbody.body.Mass()))
		rbody.body.SetMoment(moment)
		rbody.body.AddShape(circle.shape.Shape)
		space.AddShape(circle.shape.Shape)
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		sbody := component.(*StaticBody)
		sbody.body.AddShape(circle.shape.Shape)
		space.AddShape(circle.shape.Shape)
		return
	}
}

func (circle *ShapeCircle) SetAttr(attr string, value interface{}) error {
	switch attr {
	case "radius":
		radius, _ := goz.CastFloat32(value)
		circle.shape.Radius = vect.Float(radius)
		circle.shape.Shape.Update()
	}
	return nil
}

func (circle *ShapeCircle) GetAttr(attr string) (interface{}, error) {
	switch attr {
	case "radius":
		return float32(circle.shape.Radius), nil
	}
	return nil, fmt.Errorf("%v attribute of %T not found", attr, circle)
}

func NewShapeCircle() goz.Component {
	circle := ShapeCircle{}
	circle.shape = chipmunk.NewCircle(vect.Vector_Zero, 0).ShapeClass.(*chipmunk.CircleShape)
	return &circle
}

// TODO pass the radius as argument
func initShapeCircle(args []interface{}) goz.Component {
	return NewShapeCircle()
}

// Shape Box
type ShapeBox struct {
	shape       *chipmunk.BoxShape
	initialized bool
}

func (box *ShapeBox) Start(gameObject *goz.GameObject) {
	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		return
	}

	fmt.Println("ShapeBox requires a physic body")
}

func (box *ShapeBox) Update(gameObject *goz.GameObject) {
	if box.initialized {
		return
	}

	box.initialized = true

	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		rbody := component.(*RigidBody)
		moment := box.shape.Moment(float32(rbody.body.Mass()))
		rbody.body.SetMoment(moment)
		rbody.body.AddShape(box.shape.Shape)
		space.AddShape(box.shape.Shape)
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		sbody := component.(*StaticBody)
		sbody.body.AddShape(box.shape.Shape)
		space.AddShape(box.shape.Shape)
		return
	}
}

func (box *ShapeBox) SetAttr(attr string, value interface{}) error {
	switch attr {
	case "width":
		w, _ := goz.CastFloat32(value)
		box.shape.Width = vect.Float(w)
		box.shape.UpdatePoly()
	case "height":
		h, _ := goz.CastFloat32(value)
		box.shape.Height = vect.Float(h)
		box.shape.UpdatePoly()
	}
	return nil
}

func (box *ShapeBox) GetAttr(attr string) (interface{}, error) {
	switch attr {
	case "width":
		return float32(box.shape.Width), nil
	case "height":
		return float32(box.shape.Height), nil
	}
	return nil, fmt.Errorf("%v attribute of %T not found", attr, box)
}

func NewShapeBox() goz.Component {
	box := ShapeBox{}
	box.shape = chipmunk.NewBox(vect.Vector_Zero, 0, 0).ShapeClass.(*chipmunk.BoxShape)
	return &box
}

// TODO pass width and height
func initShapeBox(args []interface{}) goz.Component {
	return NewShapeBox()
}

// this will be called at every world update
func updateWorld(scene *goz.Scene, deltaTime float32) {
	if space == nil {
		return
	}
	space.Step(vect.Float(deltaTime))
}

func init() {
	goz.RegisterComponent("RigidBody", initRigidBody)
	goz.RegisterComponent("StaticBody", initStaticBody)
	goz.RegisterComponent("ShapeCircle", initShapeCircle)
	goz.RegisterComponent("ShapeBox", initShapeBox)
	goz.RegisterUpdater(updateWorld)
}
<commit_msg>implmeneted physic rotation<commit_after>package chipmunk

/*

	Physic engine

	TODO manage disabled objects

*/

import (
	"fmt"
	goz "github.com/20tab/gozmo"
	"github.com/vova616/chipmunk"
	"github.com/vova616/chipmunk/vect"
)

var space *chipmunk.Space

var Gravity goz.Vector2 = goz.Vector2{0, -9.8}

func checkSpace() {
	if space == nil {
		space = chipmunk.NewSpace()
		space.Gravity = vect.Vect{vect.Float(Gravity[0]), vect.Float(Gravity[1])}
	}
}

// Rigid Body
type RigidBody struct {
	body        *chipmunk.Body
	weight      float32
	initialized bool
}

func (rbody *RigidBody) Start(gameObject *goz.GameObject) {
	checkSpace()
	rbody.body = chipmunk.NewBody(vect.Float(rbody.weight), vect.Float(1))
	space.AddBody(rbody.body)
}

func (rbody *RigidBody) Update(gameObject *goz.GameObject) {
	if !rbody.initialized {
		pos := gameObject.Position
		rbody.body.SetPosition(vect.Vect{vect.Float(pos[0]), vect.Float(pos[1])})
		rbody.body.SetAngle(vect.Float(gameObject.Rotation))
		rbody.initialized = true
	}
	pos := rbody.body.Position()
	gameObject.SetPosition(float32(pos.X), float32(pos.Y))
	gameObject.Rotation = float32(rbody.body.Angle())
}

func (rbody *RigidBody) GetType() string {
	return "RigidBody"
}

func (rbody *RigidBody) SetAttr(attr string, value interface{}) error {
	switch attr {
	case "velocityX":
		x, _ := goz.CastFloat32(value)
		oldV := rbody.body.Velocity()
		rbody.body.SetVelocity(x, float32(oldV.Y))
	}
	return nil
}

func (rbody *RigidBody) GetAttr(attr string) (interface{}, error) {
	switch attr {
	case "velocityX":
		return float32(rbody.body.Velocity().X), nil
	case "velocityY":
		return float32(rbody.body.Velocity().Y), nil
	}
	return nil, fmt.Errorf("%v attribute of %T not found", attr, rbody)
}

func NewRigidBody(weight float32) goz.Component {
	body := RigidBody{weight: weight}
	return &body
}

func initRigidBody(args []interface{}) goz.Component {
	return NewRigidBody(1)
}

// Static Body
type StaticBody struct {
	body        *chipmunk.Body
	initialized bool
}

func (sbody *StaticBody) Start(gameObject *goz.GameObject) {
	checkSpace()
	sbody.body = chipmunk.NewBodyStatic()
	space.AddBody(sbody.body)
}

func (sbody *StaticBody) Update(gameObject *goz.GameObject) {
	if !sbody.initialized {
		pos := gameObject.Position
		sbody.body.SetPosition(vect.Vect{vect.Float(pos[0]), vect.Float(pos[1])})
		sbody.body.SetAngle(vect.Float(gameObject.Rotation))
		sbody.initialized = true
	}
	pos := sbody.body.Position()
	gameObject.SetPosition(float32(pos.X), float32(pos.Y))
	gameObject.Rotation = float32(sbody.body.Angle())
}

func (sbody *StaticBody) GetType() string {
	return "StaticBody"
}

func NewStaticBody() goz.Component {
	body := StaticBody{}
	return &body
}

func initStaticBody(args []interface{}) goz.Component {
	return NewStaticBody()
}

// Shape Circle
type ShapeCircle struct {
	shape       *chipmunk.CircleShape
	initialized bool
}

func (circle *ShapeCircle) Start(gameObject *goz.GameObject) {
	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		return
	}

	fmt.Println("ShapeCircle requires a physic body")
}

func (circle *ShapeCircle) Update(gameObject *goz.GameObject) {
	if circle.initialized {
		return
	}

	circle.initialized = true

	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		rbody := component.(*RigidBody)
		moment := circle.shape.Moment(float32(rbody.body.Mass()))
		rbody.body.SetMoment(moment)
		rbody.body.AddShape(circle.shape.Shape)
		space.AddShape(circle.shape.Shape)
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		sbody := component.(*StaticBody)
		sbody.body.AddShape(circle.shape.Shape)
		space.AddShape(circle.shape.Shape)
		return
	}
}

func (circle *ShapeCircle) SetAttr(attr string, value interface{}) error {
	switch attr {
	case "radius":
		radius, _ := goz.CastFloat32(value)
		circle.shape.Radius = vect.Float(radius)
		circle.shape.Shape.Update()
	}
	return nil
}

func (circle *ShapeCircle) GetAttr(attr string) (interface{}, error) {
	switch attr {
	case "radius":
		return float32(circle.shape.Radius), nil
	}
	return nil, fmt.Errorf("%v attribute of %T not found", attr, circle)
}

func NewShapeCircle() goz.Component {
	circle := ShapeCircle{}
	circle.shape = chipmunk.NewCircle(vect.Vector_Zero, 0).ShapeClass.(*chipmunk.CircleShape)
	return &circle
}

// TODO pass the radius as argument
func initShapeCircle(args []interface{}) goz.Component {
	return NewShapeCircle()
}

// Shape Box
type ShapeBox struct {
	shape       *chipmunk.BoxShape
	initialized bool
}

func (box *ShapeBox) Start(gameObject *goz.GameObject) {
	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		return
	}

	fmt.Println("ShapeBox requires a physic body")
}

func (box *ShapeBox) Update(gameObject *goz.GameObject) {
	if box.initialized {
		return
	}

	box.initialized = true

	component := gameObject.GetComponentByType("RigidBody")
	if component != nil {
		rbody := component.(*RigidBody)
		moment := box.shape.Moment(float32(rbody.body.Mass()))
		rbody.body.SetMoment(moment)
		rbody.body.AddShape(box.shape.Shape)
		space.AddShape(box.shape.Shape)
		return
	}

	component = gameObject.GetComponentByType("StaticBody")
	if component != nil {
		sbody := component.(*StaticBody)
		sbody.body.AddShape(box.shape.Shape)
		space.AddShape(box.shape.Shape)
		return
	}
}

func (box *ShapeBox) SetAttr(attr string, value interface{}) error {
	switch attr {
	case "width":
		w, _ := goz.CastFloat32(value)
		box.shape.Width = vect.Float(w)
		box.shape.UpdatePoly()
	case "height":
		h, _ := goz.CastFloat32(value)
		box.shape.Height = vect.Float(h)
		box.shape.UpdatePoly()
	}
	return nil
}

func (box *ShapeBox) GetAttr(attr string) (interface{}, error) {
	switch attr {
	case "width":
		return float32(box.shape.Width), nil
	case "height":
		return float32(box.shape.Height), nil
	}
	return nil, fmt.Errorf("%v attribute of %T not found", attr, box)
}

func NewShapeBox() goz.Component {
	box := ShapeBox{}
	box.shape = chipmunk.NewBox(vect.Vector_Zero, 0, 0).ShapeClass.(*chipmunk.BoxShape)
	return &box
}

// TODO pass width and height
func initShapeBox(args []interface{}) goz.Component {
	return NewShapeBox()
}

// this will be called at every world update
func updateWorld(scene *goz.Scene, deltaTime float32) {
	if space == nil {
		return
	}
	space.Step(vect.Float(deltaTime))
}

func init() {
	goz.RegisterComponent("RigidBody", initRigidBody)
	goz.RegisterComponent("StaticBody", initStaticBody)
	goz.RegisterComponent("ShapeCircle", initShapeCircle)
	goz.RegisterComponent("ShapeBox", initShapeBox)
	goz.RegisterUpdater(updateWorld)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Intel Corporation
//
// 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 storage

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"os/exec"
	"strconv"

	"github.com/01org/ciao/ssntp/uuid"
)

// CephDriver maintains context for the ceph driver interface.
type CephDriver struct {
	// SecretPath is the full path to the cephx keyring file.
	SecretPath string

	// ID is the cephx user ID to use
	ID string
}

// CreateBlockDevice will create a rbd image in the ceph cluster.
func (d CephDriver) CreateBlockDevice(imagePath *string, size int) (BlockDevice, error) {
	// generate a UUID to use for this image.
	ID := uuid.Generate().String()

	var cmd *exec.Cmd

	if imagePath != nil {
		cmd = exec.Command("rbd", "--keyring", d.SecretPath, "--id", d.ID, "--image-format", "1", "import", *imagePath, ID)
	} else {
		// create an empty volume
		cmd = exec.Command("rbd", "--keyring", d.SecretPath, "--id", d.ID, "--image-format", "1", "create", "--size", strconv.Itoa(size), ID)
	}

	err := cmd.Run()
	if err != nil {
		return BlockDevice{}, err
	}

	return BlockDevice{ID: ID}, nil
}

// DeleteBlockDevice will remove a rbd image from the ceph cluster.
func (d CephDriver) DeleteBlockDevice(volumeUUID string) error {
	cmd := exec.Command("rbd", "--keyring", d.SecretPath, "--id", d.ID, "rm", volumeUUID)
	return cmd.Run()
}

func (d CephDriver) getCredentials() []string {
	args := make([]string, 0, 8)
	if d.SecretPath != "" {
		args = append(args, "--keyring", d.SecretPath)
	}

	if d.ID != "" {
		args = append(args, "--id", d.ID)
	}
	return args
}

// MapVolumeToNode maps a ceph volume to a rbd device on a node.  The
// path to the new device is returned if the mapping succeeds.
func (d CephDriver) MapVolumeToNode(volumeUUID string) (string, error) {
	args := append(d.getCredentials(), "map", volumeUUID)
	cmd := exec.Command("rbd", args...)
	data, err := cmd.Output()
	if err != nil {
		return "", err
	}
	scanner := bufio.NewScanner(bytes.NewBuffer(data))
	if !scanner.Scan() {
		return "", fmt.Errorf("Unable to determine device name for %s", volumeUUID)
	}
	return scanner.Text(), nil
}

// UnmapVolumeFromNode unmaps a ceph volume from a local device on a node.
func (d CephDriver) UnmapVolumeFromNode(volumeUUID string) error {
	args := append(d.getCredentials(), "unmap", volumeUUID)
	return exec.Command("rbd", args...).Run()
}

// GetVolumeMapping returns a map of volumeUUID to mapped devices.
func (d CephDriver) GetVolumeMapping() (map[string][]string, error) {
	args := append(d.getCredentials(), "showmapped", "--format", "json")
	cmd := exec.Command("rbd", args...)
	data, err := cmd.Output()
	if err != nil {
		return nil, err
	}

	vmap := map[string]struct {
		Name   string `json:"name"`
		Device string `json:"device"`
	}{}
	err = json.Unmarshal([]byte(data), &vmap)
	if err != nil {
		return nil, fmt.Errorf("Unable to parse output from rbd show mapped: %v", err)
	}

	volumeDevMap := make(map[string][]string)

	for _, v := range vmap {
		volumeDevMap[v.Name] = append(volumeDevMap[v.Name], v.Device)
	}

	return volumeDevMap, nil
}
<commit_msg>ciao-storage: Use image-format 2<commit_after>// Copyright (c) 2016 Intel Corporation
//
// 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 storage

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"os/exec"
	"strconv"

	"github.com/01org/ciao/ssntp/uuid"
)

// CephDriver maintains context for the ceph driver interface.
type CephDriver struct {
	// SecretPath is the full path to the cephx keyring file.
	SecretPath string

	// ID is the cephx user ID to use
	ID string
}

// CreateBlockDevice will create a rbd image in the ceph cluster.
func (d CephDriver) CreateBlockDevice(imagePath *string, size int) (BlockDevice, error) {
	// generate a UUID to use for this image.
	ID := uuid.Generate().String()

	var cmd *exec.Cmd

	// imageFeatures holds the image features to use when creating a ceph rbd image format 2
	// Currently the kernel rdb client only supports layering but in the future more feaures
	// should be added as they are enabled in the kernel.
	imageFeatures := "--image-feature layering"

	if imagePath != nil {
		cmd = exec.Command("rbd", "--keyring", d.SecretPath, "--id", d.ID, imageFeatures, "import", *imagePath, ID)
	} else {
		// create an empty volume
		cmd = exec.Command("rbd", "--keyring", d.SecretPath, "--id", d.ID, imageFeatures, "create", "--size", strconv.Itoa(size), ID)
	}

	err := cmd.Run()
	if err != nil {
		return BlockDevice{}, err
	}

	return BlockDevice{ID: ID}, nil
}

// DeleteBlockDevice will remove a rbd image from the ceph cluster.
func (d CephDriver) DeleteBlockDevice(volumeUUID string) error {
	cmd := exec.Command("rbd", "--keyring", d.SecretPath, "--id", d.ID, "rm", volumeUUID)
	return cmd.Run()
}

func (d CephDriver) getCredentials() []string {
	args := make([]string, 0, 8)
	if d.SecretPath != "" {
		args = append(args, "--keyring", d.SecretPath)
	}

	if d.ID != "" {
		args = append(args, "--id", d.ID)
	}
	return args
}

// MapVolumeToNode maps a ceph volume to a rbd device on a node.  The
// path to the new device is returned if the mapping succeeds.
func (d CephDriver) MapVolumeToNode(volumeUUID string) (string, error) {
	args := append(d.getCredentials(), "map", volumeUUID)
	cmd := exec.Command("rbd", args...)
	data, err := cmd.Output()
	if err != nil {
		return "", err
	}
	scanner := bufio.NewScanner(bytes.NewBuffer(data))
	if !scanner.Scan() {
		return "", fmt.Errorf("Unable to determine device name for %s", volumeUUID)
	}
	return scanner.Text(), nil
}

// UnmapVolumeFromNode unmaps a ceph volume from a local device on a node.
func (d CephDriver) UnmapVolumeFromNode(volumeUUID string) error {
	args := append(d.getCredentials(), "unmap", volumeUUID)
	return exec.Command("rbd", args...).Run()
}

// GetVolumeMapping returns a map of volumeUUID to mapped devices.
func (d CephDriver) GetVolumeMapping() (map[string][]string, error) {
	args := append(d.getCredentials(), "showmapped", "--format", "json")
	cmd := exec.Command("rbd", args...)
	data, err := cmd.Output()
	if err != nil {
		return nil, err
	}

	vmap := map[string]struct {
		Name   string `json:"name"`
		Device string `json:"device"`
	}{}
	err = json.Unmarshal([]byte(data), &vmap)
	if err != nil {
		return nil, fmt.Errorf("Unable to parse output from rbd show mapped: %v", err)
	}

	volumeDevMap := make(map[string][]string)

	for _, v := range vmap {
		volumeDevMap[v.Name] = append(volumeDevMap[v.Name], v.Device)
	}

	return volumeDevMap, nil
}
<|endoftext|>


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

package frontend

import (
	"context"
	"fmt"
	"testing"

	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/postgres"
	"golang.org/x/pkgsite/internal/testing/sample"
)

func TestLatestMinorVersion(t *testing.T) {
	defer postgres.ResetTestDB(testDB, t)
	var persistedModules = []testModule{
		{
			path:            "github.com/mymodule/av1module",
			redistributable: true,
			versions:        []string{"v1.0.0", "v1.0.1"},
			packages: []testPackage{
				{
					suffix:         "bar",
					doc:            sample.DocumentationHTML.String(),
					readmeContents: sample.ReadmeContents,
					readmeFilePath: sample.ReadmeFilePath,
				},
			},
		},
	}
	tt := []struct {
		name             string
		fullPath         string
		modulePath       string
		wantMinorVersion string
		wantErr          error
	}{
		{
			name:             "get latest minor version for a persisted module",
			fullPath:         "github.com/mymodule/av1module",
			modulePath:       internal.UnknownModulePath,
			wantMinorVersion: "v1.0.1",
			wantErr:          nil,
		},
		{
			name:             "module does not exist",
			fullPath:         "github.com/mymodule/doesnotexist",
			modulePath:       internal.UnknownModulePath,
			wantMinorVersion: "",
			wantErr:          fmt.Errorf("error while retriving minor version"),
		},
	}
	ctx := context.Background()
	insertTestModules(ctx, t, persistedModules)
	for _, tc := range tt {
		t.Run(tc.name, func(t *testing.T) {
			v, err := latestMinorVersion(ctx, testDB, tc.fullPath, tc.modulePath)
			if err != nil {
				if tc.wantErr == nil {
					t.Fatalf("got %v, want no error", err)
				}
				return
			}
			if v != tc.wantMinorVersion {
				t.Fatalf("got %q, want %q", tc.wantMinorVersion, v)
			}
		})
	}
}
<commit_msg>internal/frontend: fix latest-version test<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package frontend

import (
	"context"
	"fmt"
	"testing"

	"golang.org/x/pkgsite/internal"
	"golang.org/x/pkgsite/internal/postgres"
	"golang.org/x/pkgsite/internal/testing/sample"
)

func TestLatestMinorVersion(t *testing.T) {
	defer postgres.ResetTestDB(testDB, t)
	var persistedModules = []testModule{
		{
			path:            "github.com/mymodule/av1module",
			redistributable: true,
			versions:        []string{"v1.0.0", "v1.0.1"},
			packages: []testPackage{
				{
					suffix:         "bar",
					doc:            sample.DocumentationHTML.String(),
					readmeContents: sample.ReadmeContents,
					readmeFilePath: sample.ReadmeFilePath,
				},
			},
		},
	}
	tt := []struct {
		name             string
		fullPath         string
		modulePath       string
		wantMinorVersion string
		wantErr          error
	}{
		{
			name:             "package",
			fullPath:         "github.com/mymodule/av1module/bar",
			modulePath:       "github.com/mymodule/av1module",
			wantMinorVersion: "v1.0.1",
		},
		{
			name:             "module",
			fullPath:         "github.com/mymodule/av1module",
			modulePath:       "github.com/mymodule/av1module",
			wantMinorVersion: "v1.0.1",
		},
		{
			name:       "module does not exist",
			fullPath:   "github.com/mymodule/doesnotexist",
			modulePath: internal.UnknownModulePath,
			wantErr:    fmt.Errorf("error while retriving minor version"),
		},
	}
	ctx := context.Background()
	insertTestModules(ctx, t, persistedModules)
	svr := &Server{getDataSource: func(context.Context) internal.DataSource { return testDB }}
	for _, tc := range tt {
		t.Run(tc.name, func(t *testing.T) {
			got := svr.GetLatestInfo(ctx, tc.fullPath, tc.modulePath)
			if got.MinorVersion != tc.wantMinorVersion {
				t.Fatalf("got %q, want %q", tc.wantMinorVersion, got.MinorVersion)
			}
		})
	}
}
<|endoftext|>


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

package source

import (
	"bytes"
	"context"
	"fmt"
	"go/ast"
	"go/printer"
	"go/types"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/snippet"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
	errors "golang.org/x/xerrors"
)

// formatCompletion creates a completion item for a given candidate.
func (c *completer) item(cand candidate) (CompletionItem, error) {
	obj := cand.obj

	// Handle builtin types separately.
	if obj.Parent() == types.Universe {
		return c.formatBuiltin(cand), nil
	}

	var (
		label         = cand.name
		detail        = types.TypeString(obj.Type(), c.qf)
		insert        = label
		kind          = protocol.TextCompletion
		snip          *snippet.Builder
		protocolEdits []protocol.TextEdit
	)
	if obj.Type() == nil {
		detail = ""
	}

	// expandFuncCall mutates the completion label, detail, and snippet
	// to that of an invocation of sig.
	expandFuncCall := func(sig *types.Signature) {
		params := formatParams(sig.Params(), sig.Variadic(), c.qf)
		snip = c.functionCallSnippet(label, params)
		results, writeParens := formatResults(sig.Results(), c.qf)
		detail = "func" + formatFunction(params, results, writeParens)

		// Add variadic "..." if we are using a function result to fill in a variadic parameter.
		if sig.Results().Len() == 1 && c.expectedType.matchesVariadic(sig.Results().At(0).Type()) {
			snip.WriteText("...")
		}
	}

	switch obj := obj.(type) {
	case *types.TypeName:
		detail, kind = formatType(obj.Type(), c.qf)
	case *types.Const:
		kind = protocol.ConstantCompletion
	case *types.Var:
		if _, ok := obj.Type().(*types.Struct); ok {
			detail = "struct{...}" // for anonymous structs
		}
		if obj.IsField() {
			kind = protocol.FieldCompletion
			snip = c.structFieldSnippet(label, detail)
		} else {
			kind = protocol.VariableCompletion
		}
		if obj.Type() == nil {
			break
		}

		if sig, ok := obj.Type().Underlying().(*types.Signature); ok && cand.expandFuncCall {
			expandFuncCall(sig)
		}

		// Add variadic "..." if we are using a variable to fill in a variadic parameter.
		if c.expectedType.matchesVariadic(obj.Type()) {
			snip = &snippet.Builder{}
			snip.WriteText(insert + "...")
		}
	case *types.Func:
		sig, ok := obj.Type().Underlying().(*types.Signature)
		if !ok {
			break
		}
		kind = protocol.FunctionCompletion
		if sig != nil && sig.Recv() != nil {
			kind = protocol.MethodCompletion
		}

		if cand.expandFuncCall {
			expandFuncCall(sig)
		}
	case *types.PkgName:
		kind = protocol.ModuleCompletion
		detail = fmt.Sprintf("%q", obj.Imported().Path())
	case *types.Label:
		kind = protocol.ConstantCompletion
		detail = "label"
	}

	// If this candidate needs an additional import statement,
	// add the additional text edits needed.
	if cand.imp != nil {
		addlEdits, err := c.importEdits(cand.imp)
		if err != nil {
			return CompletionItem{}, err
		}

		protocolEdits = append(protocolEdits, addlEdits...)
		if kind != protocol.ModuleCompletion {
			if detail != "" {
				detail += " "
			}
			detail += fmt.Sprintf("(from %q)", cand.imp.importPath)
		}
	}

	detail = strings.TrimPrefix(detail, "untyped ")
	item := CompletionItem{
		Label:               label,
		InsertText:          insert,
		AdditionalTextEdits: protocolEdits,
		Detail:              detail,
		Kind:                kind,
		Score:               cand.score,
		Depth:               len(c.deepState.chain),
		snippet:             snip,
	}
	// If the user doesn't want documentation for completion items.
	if !c.opts.Documentation {
		return item, nil
	}
	pos := c.view.Session().Cache().FileSet().Position(obj.Pos())

	// We ignore errors here, because some types, like "unsafe" or "error",
	// may not have valid positions that we can use to get documentation.
	if !pos.IsValid() {
		return item, nil
	}
	uri := span.FileURI(pos.Filename)

	// Find the source file of the candidate, starting from a package
	// that should have it in its dependencies.
	searchPkg := c.pkg
	if cand.imp != nil && cand.imp.pkg != nil {
		searchPkg = cand.imp.pkg
	}
	ph, pkg, err := c.view.FindFileInPackage(c.ctx, uri, searchPkg)
	if err != nil {
		return CompletionItem{}, err
	}
	file, _, _, err := ph.Cached()
	if err != nil {
		return CompletionItem{}, err
	}
	if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
		return CompletionItem{}, errors.Errorf("no file for completion object %s", obj.Name())
	}
	ident, err := findIdentifier(c.ctx, c.snapshot, pkg, file, obj.Pos())
	if err != nil {
		return CompletionItem{}, err
	}
	hover, err := ident.Hover(c.ctx)
	if err != nil {
		return CompletionItem{}, err
	}
	item.Documentation = hover.Synopsis
	if c.opts.FullDocumentation {
		item.Documentation = hover.FullDocumentation
	}
	return item, nil
}

// importEdits produces the text edits necessary to add the given import to the current file.
func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
	if imp == nil {
		return nil, nil
	}

	edit, err := addNamedImport(c.view.Session().Cache().FileSet(), c.file, imp.name, imp.importPath)
	if err != nil {
		return nil, err
	}

	return ToProtocolEdits(c.mapper, edit)
}

func (c *completer) formatBuiltin(cand candidate) CompletionItem {
	obj := cand.obj
	item := CompletionItem{
		Label:      obj.Name(),
		InsertText: obj.Name(),
		Score:      cand.score,
	}
	switch obj.(type) {
	case *types.Const:
		item.Kind = protocol.ConstantCompletion
	case *types.Builtin:
		item.Kind = protocol.FunctionCompletion
		builtin := c.view.BuiltinPackage().Lookup(obj.Name())
		if obj == nil {
			break
		}
		decl, ok := builtin.Decl.(*ast.FuncDecl)
		if !ok {
			break
		}
		params, _ := formatFieldList(c.ctx, c.view, decl.Type.Params)
		results, writeResultParens := formatFieldList(c.ctx, c.view, decl.Type.Results)
		item.Label = obj.Name()
		item.Detail = "func" + formatFunction(params, results, writeResultParens)
		item.snippet = c.functionCallSnippet(obj.Name(), params)
	case *types.TypeName:
		if types.IsInterface(obj.Type()) {
			item.Kind = protocol.InterfaceCompletion
		} else {
			item.Kind = protocol.ClassCompletion
		}
	case *types.Nil:
		item.Kind = protocol.VariableCompletion
	}
	return item
}

var replacer = strings.NewReplacer(
	`ComplexType`, `complex128`,
	`FloatType`, `float64`,
	`IntegerType`, `int`,
)

func formatFieldList(ctx context.Context, v View, list *ast.FieldList) ([]string, bool) {
	if list == nil {
		return nil, false
	}
	var writeResultParens bool
	var result []string
	for i := 0; i < len(list.List); i++ {
		if i >= 1 {
			writeResultParens = true
		}
		p := list.List[i]
		cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
		b := &bytes.Buffer{}
		if err := cfg.Fprint(b, v.Session().Cache().FileSet(), p.Type); err != nil {
			log.Error(ctx, "unable to print type", nil, tag.Of("Type", p.Type))
			continue
		}
		typ := replacer.Replace(b.String())
		if len(p.Names) == 0 {
			result = append(result, typ)
		}
		for _, name := range p.Names {
			if name.Name != "" {
				if i == 0 {
					writeResultParens = true
				}
				result = append(result, fmt.Sprintf("%s %s", name.Name, typ))
			} else {
				result = append(result, typ)
			}
		}
	}
	return result, writeResultParens
}

// qualifier returns a function that appropriately formats a types.PkgName
// appearing in a *ast.File.
func qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifier {
	// Construct mapping of import paths to their defined or implicit names.
	imports := make(map[*types.Package]string)
	for _, imp := range f.Imports {
		var obj types.Object
		if imp.Name != nil {
			obj = info.Defs[imp.Name]
		} else {

			obj = info.Implicits[imp]
		}
		if pkgname, ok := obj.(*types.PkgName); ok {
			imports[pkgname.Imported()] = pkgname.Name()
		}
	}
	// Define qualifier to replace full package paths with names of the imports.
	return func(p *types.Package) string {
		if p == pkg {
			return ""
		}
		if name, ok := imports[p]; ok {
			return name
		}
		return p.Name()
	}
}
<commit_msg>internal/lsp: return completion item without documentation<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package source

import (
	"bytes"
	"context"
	"fmt"
	"go/ast"
	"go/printer"
	"go/types"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/snippet"
	"golang.org/x/tools/internal/lsp/telemetry"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
	errors "golang.org/x/xerrors"
)

// formatCompletion creates a completion item for a given candidate.
func (c *completer) item(cand candidate) (CompletionItem, error) {
	obj := cand.obj

	// Handle builtin types separately.
	if obj.Parent() == types.Universe {
		return c.formatBuiltin(cand), nil
	}

	var (
		label         = cand.name
		detail        = types.TypeString(obj.Type(), c.qf)
		insert        = label
		kind          = protocol.TextCompletion
		snip          *snippet.Builder
		protocolEdits []protocol.TextEdit
	)
	if obj.Type() == nil {
		detail = ""
	}

	// expandFuncCall mutates the completion label, detail, and snippet
	// to that of an invocation of sig.
	expandFuncCall := func(sig *types.Signature) {
		params := formatParams(sig.Params(), sig.Variadic(), c.qf)
		snip = c.functionCallSnippet(label, params)
		results, writeParens := formatResults(sig.Results(), c.qf)
		detail = "func" + formatFunction(params, results, writeParens)

		// Add variadic "..." if we are using a function result to fill in a variadic parameter.
		if sig.Results().Len() == 1 && c.expectedType.matchesVariadic(sig.Results().At(0).Type()) {
			snip.WriteText("...")
		}
	}

	switch obj := obj.(type) {
	case *types.TypeName:
		detail, kind = formatType(obj.Type(), c.qf)
	case *types.Const:
		kind = protocol.ConstantCompletion
	case *types.Var:
		if _, ok := obj.Type().(*types.Struct); ok {
			detail = "struct{...}" // for anonymous structs
		}
		if obj.IsField() {
			kind = protocol.FieldCompletion
			snip = c.structFieldSnippet(label, detail)
		} else {
			kind = protocol.VariableCompletion
		}
		if obj.Type() == nil {
			break
		}

		if sig, ok := obj.Type().Underlying().(*types.Signature); ok && cand.expandFuncCall {
			expandFuncCall(sig)
		}

		// Add variadic "..." if we are using a variable to fill in a variadic parameter.
		if c.expectedType.matchesVariadic(obj.Type()) {
			snip = &snippet.Builder{}
			snip.WriteText(insert + "...")
		}
	case *types.Func:
		sig, ok := obj.Type().Underlying().(*types.Signature)
		if !ok {
			break
		}
		kind = protocol.FunctionCompletion
		if sig != nil && sig.Recv() != nil {
			kind = protocol.MethodCompletion
		}

		if cand.expandFuncCall {
			expandFuncCall(sig)
		}
	case *types.PkgName:
		kind = protocol.ModuleCompletion
		detail = fmt.Sprintf("%q", obj.Imported().Path())
	case *types.Label:
		kind = protocol.ConstantCompletion
		detail = "label"
	}

	// If this candidate needs an additional import statement,
	// add the additional text edits needed.
	if cand.imp != nil {
		addlEdits, err := c.importEdits(cand.imp)
		if err != nil {
			return CompletionItem{}, err
		}

		protocolEdits = append(protocolEdits, addlEdits...)
		if kind != protocol.ModuleCompletion {
			if detail != "" {
				detail += " "
			}
			detail += fmt.Sprintf("(from %q)", cand.imp.importPath)
		}
	}

	detail = strings.TrimPrefix(detail, "untyped ")
	item := CompletionItem{
		Label:               label,
		InsertText:          insert,
		AdditionalTextEdits: protocolEdits,
		Detail:              detail,
		Kind:                kind,
		Score:               cand.score,
		Depth:               len(c.deepState.chain),
		snippet:             snip,
	}
	// If the user doesn't want documentation for completion items.
	if !c.opts.Documentation {
		return item, nil
	}
	pos := c.view.Session().Cache().FileSet().Position(obj.Pos())

	// We ignore errors here, because some types, like "unsafe" or "error",
	// may not have valid positions that we can use to get documentation.
	if !pos.IsValid() {
		return item, nil
	}
	uri := span.FileURI(pos.Filename)

	// Find the source file of the candidate, starting from a package
	// that should have it in its dependencies.
	searchPkg := c.pkg
	if cand.imp != nil && cand.imp.pkg != nil {
		searchPkg = cand.imp.pkg
	}
	ph, pkg, err := c.view.FindFileInPackage(c.ctx, uri, searchPkg)
	if err != nil {
		log.Error(c.ctx, "error finding file in package", err, telemetry.URI.Of(uri), telemetry.Package.Of(searchPkg.ID()))
		return item, nil
	}
	file, _, _, err := ph.Cached()
	if err != nil {
		log.Error(c.ctx, "no cached file", err, telemetry.URI.Of(uri))
		return item, nil
	}
	if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
		log.Error(c.ctx, "no file for object", errors.Errorf("no file for completion object %s", obj.Name()), telemetry.URI.Of(uri))
		return item, nil
	}
	ident, err := findIdentifier(c.ctx, c.snapshot, pkg, file, obj.Pos())
	if err != nil {
		log.Error(c.ctx, "failed to findIdentifier", err, telemetry.URI.Of(uri))
		return item, nil
	}
	hover, err := ident.Hover(c.ctx)
	if err != nil {
		log.Error(c.ctx, "failed to find Hover", err, telemetry.URI.Of(uri))
		return item, nil
	}
	item.Documentation = hover.Synopsis
	if c.opts.FullDocumentation {
		item.Documentation = hover.FullDocumentation
	}
	return item, nil
}

// importEdits produces the text edits necessary to add the given import to the current file.
func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
	if imp == nil {
		return nil, nil
	}

	edit, err := addNamedImport(c.view.Session().Cache().FileSet(), c.file, imp.name, imp.importPath)
	if err != nil {
		return nil, err
	}

	return ToProtocolEdits(c.mapper, edit)
}

func (c *completer) formatBuiltin(cand candidate) CompletionItem {
	obj := cand.obj
	item := CompletionItem{
		Label:      obj.Name(),
		InsertText: obj.Name(),
		Score:      cand.score,
	}
	switch obj.(type) {
	case *types.Const:
		item.Kind = protocol.ConstantCompletion
	case *types.Builtin:
		item.Kind = protocol.FunctionCompletion
		builtin := c.view.BuiltinPackage().Lookup(obj.Name())
		if obj == nil {
			break
		}
		decl, ok := builtin.Decl.(*ast.FuncDecl)
		if !ok {
			break
		}
		params, _ := formatFieldList(c.ctx, c.view, decl.Type.Params)
		results, writeResultParens := formatFieldList(c.ctx, c.view, decl.Type.Results)
		item.Label = obj.Name()
		item.Detail = "func" + formatFunction(params, results, writeResultParens)
		item.snippet = c.functionCallSnippet(obj.Name(), params)
	case *types.TypeName:
		if types.IsInterface(obj.Type()) {
			item.Kind = protocol.InterfaceCompletion
		} else {
			item.Kind = protocol.ClassCompletion
		}
	case *types.Nil:
		item.Kind = protocol.VariableCompletion
	}
	return item
}

var replacer = strings.NewReplacer(
	`ComplexType`, `complex128`,
	`FloatType`, `float64`,
	`IntegerType`, `int`,
)

func formatFieldList(ctx context.Context, v View, list *ast.FieldList) ([]string, bool) {
	if list == nil {
		return nil, false
	}
	var writeResultParens bool
	var result []string
	for i := 0; i < len(list.List); i++ {
		if i >= 1 {
			writeResultParens = true
		}
		p := list.List[i]
		cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
		b := &bytes.Buffer{}
		if err := cfg.Fprint(b, v.Session().Cache().FileSet(), p.Type); err != nil {
			log.Error(ctx, "unable to print type", nil, tag.Of("Type", p.Type))
			continue
		}
		typ := replacer.Replace(b.String())
		if len(p.Names) == 0 {
			result = append(result, typ)
		}
		for _, name := range p.Names {
			if name.Name != "" {
				if i == 0 {
					writeResultParens = true
				}
				result = append(result, fmt.Sprintf("%s %s", name.Name, typ))
			} else {
				result = append(result, typ)
			}
		}
	}
	return result, writeResultParens
}

// qualifier returns a function that appropriately formats a types.PkgName
// appearing in a *ast.File.
func qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifier {
	// Construct mapping of import paths to their defined or implicit names.
	imports := make(map[*types.Package]string)
	for _, imp := range f.Imports {
		var obj types.Object
		if imp.Name != nil {
			obj = info.Defs[imp.Name]
		} else {

			obj = info.Implicits[imp]
		}
		if pkgname, ok := obj.(*types.PkgName); ok {
			imports[pkgname.Imported()] = pkgname.Name()
		}
	}
	// Define qualifier to replace full package paths with names of the imports.
	return func(p *types.Package) string {
		if p == pkg {
			return ""
		}
		if name, ok := imports[p]; ok {
			return name
		}
		return p.Name()
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 federatedtypes

import (
	"reflect"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	pkgruntime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
	"k8s.io/kubernetes/federation/pkg/federation-controller/util"
	"k8s.io/kubernetes/pkg/api/v1"
	extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
	kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)

const (
	DaemonSetKind           = "daemonset"
	DaemonSetControllerName = "daemonsets"
)

func init() {
	RegisterFederatedType(DaemonSetKind, DaemonSetControllerName, []schema.GroupVersionResource{extensionsv1.SchemeGroupVersion.WithResource(DaemonSetControllerName)}, NewDaemonSetAdapter)
}

type DaemonSetAdapter struct {
	client federationclientset.Interface
}

func NewDaemonSetAdapter(client federationclientset.Interface) FederatedTypeAdapter {
	return &DaemonSetAdapter{client: client}
}

func (a *DaemonSetAdapter) Kind() string {
	return DaemonSetKind
}

func (a *DaemonSetAdapter) ObjectType() pkgruntime.Object {
	return &extensionsv1.DaemonSet{}
}

func (a *DaemonSetAdapter) IsExpectedType(obj interface{}) bool {
	_, ok := obj.(*extensionsv1.DaemonSet)
	return ok
}

func (a *DaemonSetAdapter) Copy(obj pkgruntime.Object) pkgruntime.Object {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return &extensionsv1.DaemonSet{
		ObjectMeta: util.DeepCopyRelevantObjectMeta(daemonset.ObjectMeta),
		Spec:       *(util.DeepCopyApiTypeOrPanic(&daemonset.Spec).(*extensionsv1.DaemonSetSpec)),
	}
}

func (a *DaemonSetAdapter) Equivalent(obj1, obj2 pkgruntime.Object) bool {
	daemonset1 := obj1.(*extensionsv1.DaemonSet)
	daemonset2 := obj2.(*extensionsv1.DaemonSet)

	// Kubernetes daemonset controller writes a daemonset's hash to
	// the object label as an optimization to avoid recomputing it every
	// time. Adding a new label to the object that the federation is
	// unaware of causes problems because federated controllers compare
	// the objects in federation and their equivalents in clusters and
	// try to reconcile them. This leads to a constant fight between the
	// federated daemonset controller and the cluster controllers, and
	// they never reach a stable state.
	//
	// Ideally, cluster components should not update an object's spec or
	// metadata in a way federation cannot replicate. They can update an
	// object's status though. Therefore, this daemonset hash should
	// be a field in daemonset's status, not a label in object meta.
	// @janetkuo says that this label is only a short term solution. In
	// the near future, they are going to replace it with revision numbers
	// in daemonset status. We can then rip this bandaid out.
	//
	// We are deleting the keys here and that should be fine since we are
	// working on object copies. Also, propagating the deleted labels
	// should also be fine because we don't support daemonset rolling
	// update in federation yet.
	delete(daemonset1.ObjectMeta.Labels, extensionsv1.DefaultDaemonSetUniqueLabelKey)
	delete(daemonset2.ObjectMeta.Labels, extensionsv1.DefaultDaemonSetUniqueLabelKey)

	return util.ObjectMetaEquivalent(daemonset1.ObjectMeta, daemonset2.ObjectMeta) && reflect.DeepEqual(daemonset1.Spec, daemonset2.Spec)
}

func (a *DaemonSetAdapter) NamespacedName(obj pkgruntime.Object) types.NamespacedName {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return types.NamespacedName{Namespace: daemonset.Namespace, Name: daemonset.Name}
}

func (a *DaemonSetAdapter) ObjectMeta(obj pkgruntime.Object) *metav1.ObjectMeta {
	return &obj.(*extensionsv1.DaemonSet).ObjectMeta
}

func (a *DaemonSetAdapter) FedCreate(obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return a.client.Extensions().DaemonSets(daemonset.Namespace).Create(daemonset)
}

func (a *DaemonSetAdapter) FedDelete(namespacedName types.NamespacedName, options *metav1.DeleteOptions) error {
	return a.client.Extensions().DaemonSets(namespacedName.Namespace).Delete(namespacedName.Name, options)
}

func (a *DaemonSetAdapter) FedGet(namespacedName types.NamespacedName) (pkgruntime.Object, error) {
	return a.client.Extensions().DaemonSets(namespacedName.Namespace).Get(namespacedName.Name, metav1.GetOptions{})
}

func (a *DaemonSetAdapter) FedList(namespace string, options metav1.ListOptions) (pkgruntime.Object, error) {
	return a.client.Extensions().DaemonSets(namespace).List(options)
}

func (a *DaemonSetAdapter) FedUpdate(obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return a.client.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
}

func (a *DaemonSetAdapter) FedWatch(namespace string, options metav1.ListOptions) (watch.Interface, error) {
	return a.client.Extensions().DaemonSets(namespace).Watch(options)
}

func (a *DaemonSetAdapter) ClusterCreate(client kubeclientset.Interface, obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return client.Extensions().DaemonSets(daemonset.Namespace).Create(daemonset)
}

func (a *DaemonSetAdapter) ClusterDelete(client kubeclientset.Interface, nsName types.NamespacedName, options *metav1.DeleteOptions) error {
	return client.Extensions().DaemonSets(nsName.Namespace).Delete(nsName.Name, options)
}

func (a *DaemonSetAdapter) ClusterGet(client kubeclientset.Interface, namespacedName types.NamespacedName) (pkgruntime.Object, error) {
	return client.Extensions().DaemonSets(namespacedName.Namespace).Get(namespacedName.Name, metav1.GetOptions{})
}

func (a *DaemonSetAdapter) ClusterList(client kubeclientset.Interface, namespace string, options metav1.ListOptions) (pkgruntime.Object, error) {
	return client.Extensions().DaemonSets(namespace).List(options)
}

func (a *DaemonSetAdapter) ClusterUpdate(client kubeclientset.Interface, obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return client.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
}

func (a *DaemonSetAdapter) ClusterWatch(client kubeclientset.Interface, namespace string, options metav1.ListOptions) (watch.Interface, error) {
	return client.Extensions().DaemonSets(namespace).Watch(options)
}

func (a *DaemonSetAdapter) IsSchedulingAdapter() bool {
	return false
}

func (a *DaemonSetAdapter) NewTestObject(namespace string) pkgruntime.Object {
	return &extensionsv1.DaemonSet{
		ObjectMeta: metav1.ObjectMeta{
			GenerateName: "test-daemonset-",
			Namespace:    namespace,
			Labels:       map[string]string{"app": "test-daemonset"},
		},
		Spec: extensionsv1.DaemonSetSpec{
			Template: v1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{"name": "test-pod"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:  "test-daemonset",
							Image: "images/test-daemonset",
							Ports: []v1.ContainerPort{{ContainerPort: 9376}},
						},
					},
				},
			},
		},
	}
}
<commit_msg>Revert "Ignore `daemonset-controller-hash` label key in federation before comparing the federated object with its cluster equivalent."<commit_after>/*
Copyright 2017 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 federatedtypes

import (
	"reflect"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	pkgruntime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
	federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
	"k8s.io/kubernetes/federation/pkg/federation-controller/util"
	"k8s.io/kubernetes/pkg/api/v1"
	extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
	kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)

const (
	DaemonSetKind           = "daemonset"
	DaemonSetControllerName = "daemonsets"
)

func init() {
	RegisterFederatedType(DaemonSetKind, DaemonSetControllerName, []schema.GroupVersionResource{extensionsv1.SchemeGroupVersion.WithResource(DaemonSetControllerName)}, NewDaemonSetAdapter)
}

type DaemonSetAdapter struct {
	client federationclientset.Interface
}

func NewDaemonSetAdapter(client federationclientset.Interface) FederatedTypeAdapter {
	return &DaemonSetAdapter{client: client}
}

func (a *DaemonSetAdapter) Kind() string {
	return DaemonSetKind
}

func (a *DaemonSetAdapter) ObjectType() pkgruntime.Object {
	return &extensionsv1.DaemonSet{}
}

func (a *DaemonSetAdapter) IsExpectedType(obj interface{}) bool {
	_, ok := obj.(*extensionsv1.DaemonSet)
	return ok
}

func (a *DaemonSetAdapter) Copy(obj pkgruntime.Object) pkgruntime.Object {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return &extensionsv1.DaemonSet{
		ObjectMeta: util.DeepCopyRelevantObjectMeta(daemonset.ObjectMeta),
		Spec:       *(util.DeepCopyApiTypeOrPanic(&daemonset.Spec).(*extensionsv1.DaemonSetSpec)),
	}
}

func (a *DaemonSetAdapter) Equivalent(obj1, obj2 pkgruntime.Object) bool {
	daemonset1 := obj1.(*extensionsv1.DaemonSet)
	daemonset2 := obj2.(*extensionsv1.DaemonSet)
	return util.ObjectMetaEquivalent(daemonset1.ObjectMeta, daemonset2.ObjectMeta) && reflect.DeepEqual(daemonset1.Spec, daemonset2.Spec)
}

func (a *DaemonSetAdapter) NamespacedName(obj pkgruntime.Object) types.NamespacedName {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return types.NamespacedName{Namespace: daemonset.Namespace, Name: daemonset.Name}
}

func (a *DaemonSetAdapter) ObjectMeta(obj pkgruntime.Object) *metav1.ObjectMeta {
	return &obj.(*extensionsv1.DaemonSet).ObjectMeta
}

func (a *DaemonSetAdapter) FedCreate(obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return a.client.Extensions().DaemonSets(daemonset.Namespace).Create(daemonset)
}

func (a *DaemonSetAdapter) FedDelete(namespacedName types.NamespacedName, options *metav1.DeleteOptions) error {
	return a.client.Extensions().DaemonSets(namespacedName.Namespace).Delete(namespacedName.Name, options)
}

func (a *DaemonSetAdapter) FedGet(namespacedName types.NamespacedName) (pkgruntime.Object, error) {
	return a.client.Extensions().DaemonSets(namespacedName.Namespace).Get(namespacedName.Name, metav1.GetOptions{})
}

func (a *DaemonSetAdapter) FedList(namespace string, options metav1.ListOptions) (pkgruntime.Object, error) {
	return a.client.Extensions().DaemonSets(namespace).List(options)
}

func (a *DaemonSetAdapter) FedUpdate(obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return a.client.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
}

func (a *DaemonSetAdapter) FedWatch(namespace string, options metav1.ListOptions) (watch.Interface, error) {
	return a.client.Extensions().DaemonSets(namespace).Watch(options)
}

func (a *DaemonSetAdapter) ClusterCreate(client kubeclientset.Interface, obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return client.Extensions().DaemonSets(daemonset.Namespace).Create(daemonset)
}

func (a *DaemonSetAdapter) ClusterDelete(client kubeclientset.Interface, nsName types.NamespacedName, options *metav1.DeleteOptions) error {
	return client.Extensions().DaemonSets(nsName.Namespace).Delete(nsName.Name, options)
}

func (a *DaemonSetAdapter) ClusterGet(client kubeclientset.Interface, namespacedName types.NamespacedName) (pkgruntime.Object, error) {
	return client.Extensions().DaemonSets(namespacedName.Namespace).Get(namespacedName.Name, metav1.GetOptions{})
}

func (a *DaemonSetAdapter) ClusterList(client kubeclientset.Interface, namespace string, options metav1.ListOptions) (pkgruntime.Object, error) {
	return client.Extensions().DaemonSets(namespace).List(options)
}

func (a *DaemonSetAdapter) ClusterUpdate(client kubeclientset.Interface, obj pkgruntime.Object) (pkgruntime.Object, error) {
	daemonset := obj.(*extensionsv1.DaemonSet)
	return client.Extensions().DaemonSets(daemonset.Namespace).Update(daemonset)
}

func (a *DaemonSetAdapter) ClusterWatch(client kubeclientset.Interface, namespace string, options metav1.ListOptions) (watch.Interface, error) {
	return client.Extensions().DaemonSets(namespace).Watch(options)
}

func (a *DaemonSetAdapter) IsSchedulingAdapter() bool {
	return false
}

func (a *DaemonSetAdapter) NewTestObject(namespace string) pkgruntime.Object {
	return &extensionsv1.DaemonSet{
		ObjectMeta: metav1.ObjectMeta{
			GenerateName: "test-daemonset-",
			Namespace:    namespace,
			Labels:       map[string]string{"app": "test-daemonset"},
		},
		Spec: extensionsv1.DaemonSetSpec{
			Template: v1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{"name": "test-pod"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:  "test-daemonset",
							Image: "images/test-daemonset",
							Ports: []v1.ContainerPort{{ContainerPort: 9376}},
						},
					},
				},
			},
		},
	}
}
<|endoftext|>