<commit_before>/*
 Copyright 2020 The GoPlus Authors (goplus.org)

 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 build implements the ``gop build'' command.
package build

import (
	"fmt"
	"go/token"
	"os"
	"path/filepath"

	"github.com/goplus/gop/cl"
	"github.com/goplus/gop/cmd/internal/base"
	"github.com/goplus/gop/cmd/internal/work"
	"github.com/goplus/gop/exec/bytecode"
	"github.com/qiniu/x/log"
)

// -----------------------------------------------------------------------------

// Cmd - gop build
var Cmd = &base.Command{
	UsageLine: "gop build [-v] [-o output] <gopSrcDir|gopSrcFile>",
	Short:     "Build go+ files and execute go build command",
}

var (
	flagBuildOutput string
	flagVerbose     bool
	flag            = &Cmd.Flag
)

func init() {
	flag.StringVar(&flagBuildOutput, "o", "", "go build output file")
	flag.BoolVar(&flagVerbose, "v", false, "print the names of packages as they are compiled.")
	Cmd.Run = runCmd
}

func runCmd(cmd *base.Command, args []string) {
	flag.Parse(args)

	dir, err := os.Getwd()
	if err != nil {
		log.Fatalf("Fail to build: %v", err)
	}

	paths := flag.Args()
	if len(paths) == 0 {
		paths = append(paths, dir)
	}

	cl.CallBuiltinOp = bytecode.CallBuiltinOp
	log.SetFlags(log.Ldefault &^ log.LstdFlags)

	fset := token.NewFileSet()
	pkgs, errs := work.LoadPackages(fset, paths)
	if len(errs) > 0 {
		log.Fatalf("load packages error: %v\n", errs)
	}
	if len(pkgs) == 0 {
		fmt.Println("no Go+ files in ", paths)
	}
	for _, pkg := range pkgs {
		err := work.GenGoPkg(fset, pkg.Pkg, pkg.Dir)
		if err != nil {
			log.Fatalf("generate go package error: %v\n", err)
		}
		var target string
		if flagBuildOutput != "" {
			target = filepath.Join(dir, flagBuildOutput)
		} else {
			target = filepath.Join(pkg.Dir, pkg.Target)
		}
		err = work.GoBuild(pkg.Dir, target)
		if err != nil {
			log.Fatalf("go build error: %v\n", err)
		}
		if flagVerbose && pkg.Name == "main" {
			fmt.Println(target)
		}
	}
}
<commit_msg>gop build output abs check<commit_after>/*
 Copyright 2020 The GoPlus Authors (goplus.org)

 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 build implements the ``gop build'' command.
package build

import (
	"fmt"
	"go/token"
	"os"
	"path/filepath"

	"github.com/goplus/gop/cl"
	"github.com/goplus/gop/cmd/internal/base"
	"github.com/goplus/gop/cmd/internal/work"
	"github.com/goplus/gop/exec/bytecode"
	"github.com/qiniu/x/log"
)

// -----------------------------------------------------------------------------

// Cmd - gop build
var Cmd = &base.Command{
	UsageLine: "gop build [-v] [-o output] <gopSrcDir|gopSrcFile>",
	Short:     "Build go+ files and execute go build command",
}

var (
	flagBuildOutput string
	flagVerbose     bool
	flag            = &Cmd.Flag
)

func init() {
	flag.StringVar(&flagBuildOutput, "o", "", "go build output file")
	flag.BoolVar(&flagVerbose, "v", false, "print the names of packages as they are compiled.")
	Cmd.Run = runCmd
}

func runCmd(cmd *base.Command, args []string) {
	flag.Parse(args)

	dir, err := os.Getwd()
	if err != nil {
		log.Fatalf("Fail to build: %v", err)
	}

	paths := flag.Args()
	if len(paths) == 0 {
		paths = append(paths, dir)
	}

	cl.CallBuiltinOp = bytecode.CallBuiltinOp
	log.SetFlags(log.Ldefault &^ log.LstdFlags)

	fset := token.NewFileSet()
	pkgs, errs := work.LoadPackages(fset, paths)
	if len(errs) > 0 {
		log.Fatalf("load packages error: %v\n", errs)
	}
	if len(pkgs) == 0 {
		fmt.Println("no Go+ files in ", paths)
	}
	for _, pkg := range pkgs {
		err := work.GenGoPkg(fset, pkg.Pkg, pkg.Dir)
		if err != nil {
			log.Fatalf("generate go package error: %v\n", err)
		}
		target := pkg.Target
		if flagBuildOutput != "" {
			target = flagBuildOutput
		}
		if !filepath.IsAbs(target) {
			target = filepath.Join(dir, target)
		}
		err = work.GoBuild(pkg.Dir, target)
		if err != nil {
			log.Fatalf("go build error: %v\n", err)
		}
		if flagVerbose && pkg.Name == "main" {
			fmt.Println(target)
		}
	}
}
<|endoftext|>


<commit_before>package mccli

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
	"github.com/materials-commons/mcstore/cmd/pkg/mc"
)

var uploadDirCommand = cli.Command{
	Name:    "file",
	Aliases: []string{"f"},
	Usage:   "Upload a file to MaterialsCommons",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "project, proj, p",
			Usage: "The project the file is in",
		},
		cli.BoolFlag{
			Name:  "recursive, r",
			Usage: "Should sub directories also be uploaded",
		},
		cli.IntFlag{
			Name:  "parallel, n",
			Value: 3,
			Usage: "Number of simultaneous uploads to perform, defaults to 3",
		},
	},
	Action: uploadDirCLI,
}

func uploadDirCLI(c *cli.Context) {
	if len(c.Args()) != 1 {
		fmt.Println("You must specify a directory to upload")
		os.Exit(1)
	}

	dirPath := filepath.Clean(c.Args()[0])
	if !validateDirectoryPath(dirPath) {
		os.Exit(1)
	}

	project := c.String("project")
	numThreads := getNumThreads(c)
	recursive := c.Bool("recursive")

	client := mc.NewClientAPI()
	if err := client.UploadDirectory(project, dirPath, recursive, numThreads); err != nil {
		fmt.Println("Directory upload failed:", err)
		os.Exit(1)
	}

	fmt.Println("Directory successfully uploaded.")
}
<commit_msg>Cut and paste error. Upload dir had the same command as upload file.<commit_after>package mccli

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
	"github.com/materials-commons/mcstore/cmd/pkg/mc"
)

var uploadDirCommand = cli.Command{
	Name:    "directory",
	Aliases: []string{"dir", "d"},
	Usage:   "Upload a file to MaterialsCommons",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "project, proj, p",
			Usage: "The project the file is in",
		},
		cli.BoolFlag{
			Name:  "recursive, r",
			Usage: "Should sub directories also be uploaded",
		},
		cli.IntFlag{
			Name:  "parallel, n",
			Value: 3,
			Usage: "Number of simultaneous uploads to perform, defaults to 3",
		},
	},
	Action: uploadDirCLI,
}

func uploadDirCLI(c *cli.Context) {
	if len(c.Args()) != 1 {
		fmt.Println("You must specify a directory to upload")
		os.Exit(1)
	}

	dirPath := filepath.Clean(c.Args()[0])
	if !validateDirectoryPath(dirPath) {
		os.Exit(1)
	}

	project := c.String("project")
	numThreads := getNumThreads(c)
	recursive := c.Bool("recursive")

	client := mc.NewClientAPI()
	if err := client.UploadDirectory(project, dirPath, recursive, numThreads); err != nil {
		fmt.Println("Directory upload failed:", err)
		os.Exit(1)
	}

	fmt.Println("Directory successfully uploaded.")
}
<|endoftext|>


<commit_before>package cleanup

import (
	"fmt"
	"path"

	"k8s.io/client-go/kubernetes"

	"github.com/flant/kubedog/pkg/kube"
	"github.com/flant/werf/cmd/werf/common"
	"github.com/flant/werf/pkg/cleaning"
	"github.com/flant/werf/pkg/docker"
	"github.com/flant/werf/pkg/docker_registry"
	"github.com/flant/werf/pkg/git_repo"
	"github.com/flant/werf/pkg/lock"
	"github.com/flant/werf/pkg/tmp_manager"
	"github.com/flant/werf/pkg/util"
	"github.com/flant/werf/pkg/werf"

	"github.com/spf13/cobra"
)

var CmdData struct {
	WithoutKube bool
}

var CommonCmdData common.CmdData

func NewCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "cleanup",
		DisableFlagsInUseLine: true,
		Short:                 "Safely cleanup unused project images and stages",
		Long: common.GetLongCommandDescription(`Safely cleanup unused project images and stages.

First step is 'werf images cleanup' command, which will delete unused images from images repo. Second step is 'werf stages cleanup' command, which will delete unused stages from stages storage to be in sync with the images repo.

It is safe to run this command periodically (daily is enough) by automated cleanup job in parallel with other werf commands such as build, deploy and host cleanup.`),
		Example: `  $ werf cleanup --stages-storage :local --images-repo registry.mydomain.com/myproject`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := common.ApplyLogOptions(&CommonCmdData); err != nil {
				cmd.Help()
				fmt.Println()
				return err
			}
			common.LogVersion()

			return common.LogRunningTime(func() error {
				return runCleanup()
			})
		},
	}

	common.SetupDir(&CommonCmdData, cmd)
	common.SetupTmpDir(&CommonCmdData, cmd)
	common.SetupHomeDir(&CommonCmdData, cmd)

	common.SetupStagesStorage(&CommonCmdData, cmd)
	common.SetupImagesRepo(&CommonCmdData, cmd)
	common.SetupDockerConfig(&CommonCmdData, cmd, "Command needs granted permissions to read, pull and delete images from the specified stages storage and images repo")
	common.SetupInsecureRepo(&CommonCmdData, cmd)
	common.SetupImagesCleanupPolicies(&CommonCmdData, cmd)

	common.SetupKubeConfig(&CommonCmdData, cmd)
	common.SetupKubeContext(&CommonCmdData, cmd)

	common.SetupDryRun(&CommonCmdData, cmd)

	common.SetupLogOptions(&CommonCmdData, cmd)

	cmd.Flags().BoolVarP(&CmdData.WithoutKube, "without-kube", "", false, "Do not skip deployed kubernetes images")

	return cmd
}

func runCleanup() error {
	if err := werf.Init(*CommonCmdData.TmpDir, *CommonCmdData.HomeDir); err != nil {
		return fmt.Errorf("initialization error: %s", err)
	}

	if err := lock.Init(); err != nil {
		return err
	}

	if err := docker_registry.Init(docker_registry.Options{AllowInsecureRepo: *CommonCmdData.InsecureRepo}); err != nil {
		return err
	}

	if err := docker.Init(*CommonCmdData.DockerConfig); err != nil {
		return err
	}

	if err := kube.Init(kube.InitOptions{KubeContext: *CommonCmdData.KubeContext, KubeConfig: *CommonCmdData.KubeConfig}); err != nil {
		return fmt.Errorf("cannot initialize kube: %s", err)
	}

	projectDir, err := common.GetProjectDir(&CommonCmdData)
	if err != nil {
		return fmt.Errorf("getting project dir failed: %s", err)
	}
	common.LogProjectDir(projectDir)

	projectTmpDir, err := tmp_manager.CreateProjectDir()
	if err != nil {
		return fmt.Errorf("getting project tmp dir failed: %s", err)
	}
	defer tmp_manager.ReleaseProjectDir(projectTmpDir)

	werfConfig, err := common.GetWerfConfig(projectDir)
	if err != nil {
		return fmt.Errorf("bad config: %s", err)
	}

	projectName := werfConfig.Meta.Project

	imagesRepo, err := common.GetImagesRepo(projectName, &CommonCmdData)
	if err != nil {
		return err
	}

	stagesRepo, err := common.GetStagesRepo(&CommonCmdData)
	if err != nil {
		return err
	}

	var imagesNames []string
	for _, image := range werfConfig.Images {
		imagesNames = append(imagesNames, image.Name)
	}

	commonRepoOptions := cleaning.CommonRepoOptions{
		ImagesRepo:    imagesRepo,
		StagesStorage: stagesRepo,
		ImagesNames:   imagesNames,
		DryRun:        *CommonCmdData.DryRun,
	}

	var localGitRepo *git_repo.Local
	gitDir := path.Join(projectDir, ".git")
	if exist, err := util.DirExists(gitDir); err != nil {
		return err
	} else if exist {
		localGitRepo = &git_repo.Local{
			Path:   projectDir,
			GitDir: gitDir,
		}
	}

	policies, err := common.GetImagesCleanupPolicies(&CommonCmdData)
	if err != nil {
		return err
	}

	commonProjectOptions := cleaning.CommonProjectOptions{
		ProjectName:   projectName,
		CommonOptions: cleaning.CommonOptions{DryRun: *CommonCmdData.DryRun},
	}

	imagesCleanupOptions := cleaning.ImagesCleanupOptions{
		CommonRepoOptions: commonRepoOptions,
		LocalGit:          localGitRepo,
		KubernetesClients: []kubernetes.Interface{kube.Kubernetes},
		WithoutKube:       CmdData.WithoutKube,
		Policies:          policies,
	}

	stagesCleanupOptions := cleaning.StagesCleanupOptions{
		CommonRepoOptions:    commonRepoOptions,
		CommonProjectOptions: commonProjectOptions,
	}

	cleanupOptions := cleaning.CleanupOptions{
		StagesCleanupOptions: stagesCleanupOptions,
		ImagesCleanupOptions: imagesCleanupOptions,
	}

	if err := cleaning.Cleanup(cleanupOptions); err != nil {
		return err
	}

	return nil
}
<commit_msg>HOTFIX 'werf cleanup': Use all contexts from kube-config to found used images<commit_after>package cleanup

import (
	"fmt"
	"path"

	"github.com/flant/kubedog/pkg/kube"
	"github.com/flant/werf/cmd/werf/common"
	"github.com/flant/werf/pkg/cleaning"
	"github.com/flant/werf/pkg/docker"
	"github.com/flant/werf/pkg/docker_registry"
	"github.com/flant/werf/pkg/git_repo"
	"github.com/flant/werf/pkg/lock"
	"github.com/flant/werf/pkg/tmp_manager"
	"github.com/flant/werf/pkg/util"
	"github.com/flant/werf/pkg/werf"

	"github.com/spf13/cobra"
)

var CmdData struct {
	WithoutKube bool
}

var CommonCmdData common.CmdData

func NewCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:                   "cleanup",
		DisableFlagsInUseLine: true,
		Short:                 "Safely cleanup unused project images and stages",
		Long: common.GetLongCommandDescription(`Safely cleanup unused project images and stages.

First step is 'werf images cleanup' command, which will delete unused images from images repo. Second step is 'werf stages cleanup' command, which will delete unused stages from stages storage to be in sync with the images repo.

It is safe to run this command periodically (daily is enough) by automated cleanup job in parallel with other werf commands such as build, deploy and host cleanup.`),
		Example: `  $ werf cleanup --stages-storage :local --images-repo registry.mydomain.com/myproject`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := common.ApplyLogOptions(&CommonCmdData); err != nil {
				cmd.Help()
				fmt.Println()
				return err
			}
			common.LogVersion()

			return common.LogRunningTime(func() error {
				return runCleanup()
			})
		},
	}

	common.SetupDir(&CommonCmdData, cmd)
	common.SetupTmpDir(&CommonCmdData, cmd)
	common.SetupHomeDir(&CommonCmdData, cmd)

	common.SetupStagesStorage(&CommonCmdData, cmd)
	common.SetupImagesRepo(&CommonCmdData, cmd)
	common.SetupDockerConfig(&CommonCmdData, cmd, "Command needs granted permissions to read, pull and delete images from the specified stages storage and images repo")
	common.SetupInsecureRepo(&CommonCmdData, cmd)
	common.SetupImagesCleanupPolicies(&CommonCmdData, cmd)

	common.SetupKubeConfig(&CommonCmdData, cmd)
	common.SetupKubeContext(&CommonCmdData, cmd)

	common.SetupDryRun(&CommonCmdData, cmd)

	common.SetupLogOptions(&CommonCmdData, cmd)

	cmd.Flags().BoolVarP(&CmdData.WithoutKube, "without-kube", "", false, "Do not skip deployed kubernetes images")

	return cmd
}

func runCleanup() error {
	if err := werf.Init(*CommonCmdData.TmpDir, *CommonCmdData.HomeDir); err != nil {
		return fmt.Errorf("initialization error: %s", err)
	}

	if err := lock.Init(); err != nil {
		return err
	}

	if err := docker_registry.Init(docker_registry.Options{AllowInsecureRepo: *CommonCmdData.InsecureRepo}); err != nil {
		return err
	}

	if err := docker.Init(*CommonCmdData.DockerConfig); err != nil {
		return err
	}

	if err := kube.Init(kube.InitOptions{KubeContext: *CommonCmdData.KubeContext, KubeConfig: *CommonCmdData.KubeConfig}); err != nil {
		return fmt.Errorf("cannot initialize kube: %s", err)
	}

	projectDir, err := common.GetProjectDir(&CommonCmdData)
	if err != nil {
		return fmt.Errorf("getting project dir failed: %s", err)
	}
	common.LogProjectDir(projectDir)

	projectTmpDir, err := tmp_manager.CreateProjectDir()
	if err != nil {
		return fmt.Errorf("getting project tmp dir failed: %s", err)
	}
	defer tmp_manager.ReleaseProjectDir(projectTmpDir)

	werfConfig, err := common.GetWerfConfig(projectDir)
	if err != nil {
		return fmt.Errorf("bad config: %s", err)
	}

	projectName := werfConfig.Meta.Project

	imagesRepo, err := common.GetImagesRepo(projectName, &CommonCmdData)
	if err != nil {
		return err
	}

	stagesRepo, err := common.GetStagesRepo(&CommonCmdData)
	if err != nil {
		return err
	}

	var imagesNames []string
	for _, image := range werfConfig.Images {
		imagesNames = append(imagesNames, image.Name)
	}

	commonRepoOptions := cleaning.CommonRepoOptions{
		ImagesRepo:    imagesRepo,
		StagesStorage: stagesRepo,
		ImagesNames:   imagesNames,
		DryRun:        *CommonCmdData.DryRun,
	}

	var localGitRepo *git_repo.Local
	gitDir := path.Join(projectDir, ".git")
	if exist, err := util.DirExists(gitDir); err != nil {
		return err
	} else if exist {
		localGitRepo = &git_repo.Local{
			Path:   projectDir,
			GitDir: gitDir,
		}
	}

	policies, err := common.GetImagesCleanupPolicies(&CommonCmdData)
	if err != nil {
		return err
	}

	kubernetesClients, err := kube.GetAllClients(kube.GetClientsOptions{KubeConfig: *CommonCmdData.KubeConfig})
	if err != nil {
		return fmt.Errorf("unable to get kubernetes clusters connections: %s", err)
	}

	commonProjectOptions := cleaning.CommonProjectOptions{
		ProjectName:   projectName,
		CommonOptions: cleaning.CommonOptions{DryRun: *CommonCmdData.DryRun},
	}

	imagesCleanupOptions := cleaning.ImagesCleanupOptions{
		CommonRepoOptions: commonRepoOptions,
		LocalGit:          localGitRepo,
		KubernetesClients: kubernetesClients,
		WithoutKube:       CmdData.WithoutKube,
		Policies:          policies,
	}

	stagesCleanupOptions := cleaning.StagesCleanupOptions{
		CommonRepoOptions:    commonRepoOptions,
		CommonProjectOptions: commonProjectOptions,
	}

	cleanupOptions := cleaning.CleanupOptions{
		StagesCleanupOptions: stagesCleanupOptions,
		ImagesCleanupOptions: imagesCleanupOptions,
	}

	if err := cleaning.Cleanup(cleanupOptions); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package service

import (
	"fmt"
	"path/filepath"
	"strings"

	"goa.design/goa/v3/codegen"
	"goa.design/goa/v3/expr"
)

type (
	// endpointsData contains the data necessary to render the
	// service endpoints struct template.
	endpointsData struct {
		// Name is the service name.
		Name string
		// Description is the service description.
		Description string
		// VarName is the endpoint struct name.
		VarName string
		// ClientVarName is the client struct name.
		ClientVarName string
		// ServiceVarName is the service interface name.
		ServiceVarName string
		// Methods lists the endpoint struct methods.
		Methods []*endpointMethodData
		// ClientInitArgs lists the arguments needed to instantiate the client.
		ClientInitArgs string
		// Schemes contains the security schemes types used by the
		// all the endpoints.
		Schemes SchemesData
	}

	// endpointMethodData describes a single endpoint method.
	endpointMethodData struct {
		*MethodData
		// ArgName is the name of the argument used to initialize the client
		// struct method field.
		ArgName string
		// ClientVarName is the corresponding client struct field name.
		ClientVarName string
		// ServiceName is the name of the owner service.
		ServiceName string
		// ServiceVarName is the name of the owner service Go interface.
		ServiceVarName string
	}
)

const (
	// endpointsStructName is the name of the generated endpoints data
	// structure.
	endpointsStructName = "Endpoints"

	// serviceInterfaceName is the name of the generated service interface.
	serviceInterfaceName = "Service"
)

// EndpointFile returns the endpoint file for the given service.
func EndpointFile(genpkg string, service *expr.ServiceExpr) *codegen.File {
	svc := Services.Get(service.Name)
	svcName := codegen.SnakeCase(svc.VarName)
	path := filepath.Join(codegen.Gendir, svcName, "endpoints.go")
	data := endpointData(service)
	var (
		sections []*codegen.SectionTemplate
	)
	{
		header := codegen.Header(service.Name+" endpoints", svc.PkgName,
			[]*codegen.ImportSpec{
				{Path: "context"},
				{Path: "io"},
				{Path: "fmt"},
				codegen.GoaImport(""),
				codegen.GoaImport("security"),
				{Path: genpkg + "/" + svcName + "/" + "views", Name: svc.ViewsPkg},
			})
		def := &codegen.SectionTemplate{
			Name:   "endpoints-struct",
			Source: serviceEndpointsT,
			Data:   data,
		}
		sections = []*codegen.SectionTemplate{header, def}
		for _, m := range data.Methods {
			if m.ServerStream != nil {
				sections = append(sections, &codegen.SectionTemplate{
					Name:   "endpoint-input-struct",
					Source: serviceEndpointStreamStructT,
					Data:   m,
				})
			}
			if m.SkipRequestBodyEncodeDecode {
				sections = append(sections, &codegen.SectionTemplate{
					Name:   "request-body-struct",
					Source: serviceRequestBodyStructT,
					Data:   m,
				})
			}
			if m.SkipResponseBodyEncodeDecode {
				sections = append(sections, &codegen.SectionTemplate{
					Name:   "response-body-struct",
					Source: serviceResponseBodyStructT,
					Data:   m,
				})
			}
		}
		sections = append(sections, &codegen.SectionTemplate{
			Name:   "endpoints-init",
			Source: serviceEndpointsInitT,
			Data:   data,
		})
		sections = append(sections, &codegen.SectionTemplate{
			Name:   "endpoints-use",
			Source: serviceEndpointsUseT,
			Data:   data,
		})
		for _, m := range data.Methods {
			sections = append(sections, &codegen.SectionTemplate{
				Name:    "endpoint-method",
				Source:  serviceEndpointMethodT,
				Data:    m,
				FuncMap: map[string]interface{}{"payloadVar": payloadVar},
			})
		}
	}

	return &codegen.File{Path: path, SectionTemplates: sections}
}

func endpointData(service *expr.ServiceExpr) *endpointsData {
	svc := Services.Get(service.Name)
	methods := make([]*endpointMethodData, len(svc.Methods))
	names := make([]string, len(svc.Methods))
	for i, m := range svc.Methods {
		methods[i] = &endpointMethodData{
			MethodData:     m,
			ArgName:        codegen.Goify(m.VarName, false),
			ServiceName:    svc.Name,
			ServiceVarName: serviceInterfaceName,
			ClientVarName:  clientStructName,
		}
		names[i] = codegen.Goify(m.VarName, false)
	}
	desc := fmt.Sprintf("%s wraps the %q service endpoints.", endpointsStructName, service.Name)
	return &endpointsData{
		Name:           service.Name,
		Description:    desc,
		VarName:        endpointsStructName,
		ClientVarName:  clientStructName,
		ServiceVarName: serviceInterfaceName,
		ClientInitArgs: strings.Join(names, ", "),
		Methods:        methods,
		Schemes:        svc.Schemes,
	}
}

func payloadVar(e *endpointMethodData) string {
	if e.ServerStream != nil || e.SkipRequestBodyEncodeDecode {
		return "ep.Payload"
	}
	return "p"
}

// input: endpointsData
const serviceEndpointsT = `{{ comment .Description }}
type {{ .VarName }} struct {
{{- range .Methods}}
	{{ .VarName }} goa.Endpoint
{{- end }}
}
`

// input: endpointsData
const serviceEndpointsInitT = `{{ printf "New%s wraps the methods of the %q service with endpoints." .VarName .Name | comment }}
func New{{ .VarName }}(s {{ .ServiceVarName }}) *{{ .VarName }} {
{{- if .Schemes }}
	// Casting service to Auther interface
	a := s.(Auther)
{{- end }}
	return &{{ .VarName }}{
{{- range .Methods }}
		{{ .VarName }}: New{{ .VarName }}Endpoint(s{{ range .Schemes }}, a.{{ .Type }}Auth{{ end }}),
{{- end }}
	}
}
`

// input: endpointMethodData
const serviceEndpointStreamStructT = `{{ printf "%s holds both the payload and the server stream of the %q method." .ServerStream.EndpointStruct .Name | comment }}
type {{ .ServerStream.EndpointStruct }} struct {
{{- if .PayloadRef }}
	{{ comment "Payload is the method payload." }}
	Payload {{ .PayloadRef }}
{{- end }}
	{{ printf "Stream is the server stream used by the %q method to send data." .Name | comment }}
	Stream {{ .ServerStream.Interface }}
}
`

// input: endpointMethodData
const serviceRequestBodyStructT = `{{ printf "%s holds both the payload and the HTTP request body reader of the %q method." .RequestStruct .Name | comment }}
type {{ .RequestStruct }} struct {
{{- if .PayloadRef }}
	{{ comment "Payload is the method payload." }}
	Payload {{ .PayloadRef }}
{{- end }}
	{{ comment "Body streams the HTTP request body." }}
	Body io.ReadCloser
}
`

// input: endpointMethodData
const serviceResponseBodyStructT = `{{ printf "%s holds both the result and the HTTP response body reader of the %q method." .ResponseStruct .Name | comment }}
type {{ .ResponseStruct }} struct {
{{- if .ResultRef }}
	{{ comment "Result is the method result." }}
	Result {{ .ResultRef }}
{{- end }}
	{{ comment "Body streams the HTTP response body." }}
	Body io.ReadCloser
}
`

// input: endpointMethodData
const serviceEndpointMethodT = `{{ printf "New%sEndpoint returns an endpoint function that calls the method %q of service %q." .VarName .Name .ServiceName | comment }}
func New{{ .VarName }}Endpoint(s {{ .ServiceVarName }}{{ range .Schemes }}, auth{{ .Type }}Fn security.Auth{{ .Type }}Func{{ end }}) goa.Endpoint {
	return func(ctx context.Context, req interface{}) (interface{}, error) {
{{- if or .ServerStream }}
		ep := req.(*{{ .ServerStream.EndpointStruct }})
{{- else if .SkipRequestBodyEncodeDecode }}
		ep := req.(*{{ .RequestStruct }})
{{- else if .PayloadRef }}
		p := req.({{ .PayloadRef }})
{{- end }}
{{- $payload := payloadVar . }}
{{- if .Requirements }}
		var err error
	{{- range $ridx, $r := .Requirements }}
		{{- if ne $ridx 0 }}
		if err != nil {
		{{- end }}
		{{- range $sidx, $s := .Schemes }}
			{{- if ne $sidx 0 }}
			if err == nil {
			{{- end }}
			{{- if eq .Type "Basic" }}
				sc := security.BasicScheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
				}
				{{- if .UsernamePointer }}
				var user string
				if {{ $payload }}.{{ .UsernameField }} != nil {
					user = *{{ $payload }}.{{ .UsernameField }}
				}
				{{- end }}
				{{- if .PasswordPointer }}
				var pass string
				if {{ $payload }}.{{ .PasswordField }} != nil {
					pass = *{{ $payload }}.{{ .PasswordField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if .UsernamePointer }}user{{ else }}{{ $payload }}.{{ .UsernameField }}{{ end }},
					{{- if .PasswordPointer }}pass{{ else }}{{ $payload }}.{{ .PasswordField }}{{ end }}, &sc)

			{{- else if eq .Type "APIKey" }}
				sc := security.APIKeyScheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
				}
				{{- if $s.CredPointer }}
				var key string
				if {{ $payload }}.{{ $s.CredField }} != nil {
					key = *{{ $payload }}.{{ $s.CredField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if $s.CredPointer }}key{{ else }}{{ $payload }}.{{ $s.CredField }}{{ end }}, &sc)

			{{- else if eq .Type "JWT" }}
				sc := security.JWTScheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
				}
				{{- if $s.CredPointer }}
				var token string
				if {{ $payload }}.{{ $s.CredField }} != nil {
					token = *{{ $payload }}.{{ $s.CredField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if $s.CredPointer }}token{{ else }}{{ $payload }}.{{ $s.CredField }}{{ end }}, &sc)

			{{- else if eq .Type "OAuth2" }}
				sc := security.OAuth2Scheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
					{{- if .Flows }}
					Flows: []*security.OAuthFlow{
						{{- range .Flows }}
						&security.OAuthFlow{
							Type: "{{ .Type }}",
							{{- if .AuthorizationURL }}
							AuthorizationURL: {{ printf "%q" .AuthorizationURL }},
							{{- end }}
							{{- if .TokenURL }}
							TokenURL: {{ printf "%q" .TokenURL }},
							{{- end }}
							{{- if .RefreshURL }}
							RefreshURL: {{ printf "%q" .RefreshURL }},
							{{- end }}
						},
						{{- end }}
					},
					{{- end }}
				}
				{{- if $s.CredPointer }}
				var token string
				if {{ $payload }}.{{ $s.CredField }} != nil {
					token = *{{ $payload }}.{{ $s.CredField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if $s.CredPointer }}token{{ else }}{{ $payload }}.{{ $s.CredField }}{{ end }}, &sc)

			{{- end }}
			{{- if ne $sidx 0 }}
				}
			{{- end }}
		{{- end }}
		{{- if ne $ridx 0 }}
		}
		{{- end }}
	{{- end }}
		if err != nil {
			return nil, err
		}
{{- end }}
{{- if .ServerStream }}
	return nil, s.{{ .VarName }}(ctx, {{ if .PayloadRef }}{{ $payload }}, {{ end }}ep.Stream)
{{- else if .SkipRequestBodyEncodeDecode }}
	{{- if .SkipResponseBodyEncodeDecode }}
	{{ if .ResultRef }}res, {{ end }}body, err := s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
	if err != nil {
		return nil, err
	}
	return &{{ .ResponseStruct }}{ {{ if .ResultRef }}Result: res, {{ end }}Body: body }, nil
	{{- else }}
	return {{ if not .ResultRef }}nil, {{ end }}s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
	{{- end }}
{{- else if .ViewedResult }}
		res,{{ if not .ViewedResult.ViewName }} view,{{ end }} err := s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
		if err != nil {
			return nil, err
		}
		vres := {{ $.ViewedResult.Init.Name }}(res, {{ if .ViewedResult.ViewName }}{{ printf "%q" .ViewedResult.ViewName }}{{ else }}view{{ end }})
		return vres, nil
{{- else }}
	{{- if .SkipResponseBodyEncodeDecode }}
	{{ if .ResultRef }}res, {{ end }}body, err := s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload}}{{ end }})
	if err != nil {
		return nil, err
	}
	return &{{ .ResponseStruct }}{ {{ if .ResultRef }}Result: res, {{ end }}Body: body }, nil
	{{- else }}
	return {{ if not .ResultRef }}nil, {{ end }}s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
	{{- end }}
{{- end }}
	}
}
`

// input: endpointMethodData
const serviceEndpointsUseT = `{{ printf "Use applies the given middleware to all the %q service endpoints." .Name | comment }}
func (e *{{ .VarName }}) Use(m func(goa.Endpoint) goa.Endpoint) {
{{- range .Methods }}
	e.{{ .VarName }} = m(e.{{ .VarName }})
{{- end }}
}
`
<commit_msg>Properly handle result types with multiple views and SkipRequestBodyDecodeEncode (#2543)<commit_after>package service

import (
	"fmt"
	"path/filepath"
	"strings"

	"goa.design/goa/v3/codegen"
	"goa.design/goa/v3/expr"
)

type (
	// endpointsData contains the data necessary to render the
	// service endpoints struct template.
	endpointsData struct {
		// Name is the service name.
		Name string
		// Description is the service description.
		Description string
		// VarName is the endpoint struct name.
		VarName string
		// ClientVarName is the client struct name.
		ClientVarName string
		// ServiceVarName is the service interface name.
		ServiceVarName string
		// Methods lists the endpoint struct methods.
		Methods []*endpointMethodData
		// ClientInitArgs lists the arguments needed to instantiate the client.
		ClientInitArgs string
		// Schemes contains the security schemes types used by the
		// all the endpoints.
		Schemes SchemesData
	}

	// endpointMethodData describes a single endpoint method.
	endpointMethodData struct {
		*MethodData
		// ArgName is the name of the argument used to initialize the client
		// struct method field.
		ArgName string
		// ClientVarName is the corresponding client struct field name.
		ClientVarName string
		// ServiceName is the name of the owner service.
		ServiceName string
		// ServiceVarName is the name of the owner service Go interface.
		ServiceVarName string
	}
)

const (
	// endpointsStructName is the name of the generated endpoints data
	// structure.
	endpointsStructName = "Endpoints"

	// serviceInterfaceName is the name of the generated service interface.
	serviceInterfaceName = "Service"
)

// EndpointFile returns the endpoint file for the given service.
func EndpointFile(genpkg string, service *expr.ServiceExpr) *codegen.File {
	svc := Services.Get(service.Name)
	svcName := codegen.SnakeCase(svc.VarName)
	path := filepath.Join(codegen.Gendir, svcName, "endpoints.go")
	data := endpointData(service)
	var (
		sections []*codegen.SectionTemplate
	)
	{
		header := codegen.Header(service.Name+" endpoints", svc.PkgName,
			[]*codegen.ImportSpec{
				{Path: "context"},
				{Path: "io"},
				{Path: "fmt"},
				codegen.GoaImport(""),
				codegen.GoaImport("security"),
				{Path: genpkg + "/" + svcName + "/" + "views", Name: svc.ViewsPkg},
			})
		def := &codegen.SectionTemplate{
			Name:   "endpoints-struct",
			Source: serviceEndpointsT,
			Data:   data,
		}
		sections = []*codegen.SectionTemplate{header, def}
		for _, m := range data.Methods {
			if m.ServerStream != nil {
				sections = append(sections, &codegen.SectionTemplate{
					Name:   "endpoint-input-struct",
					Source: serviceEndpointStreamStructT,
					Data:   m,
				})
			}
			if m.SkipRequestBodyEncodeDecode {
				sections = append(sections, &codegen.SectionTemplate{
					Name:   "request-body-struct",
					Source: serviceRequestBodyStructT,
					Data:   m,
				})
			}
			if m.SkipResponseBodyEncodeDecode {
				sections = append(sections, &codegen.SectionTemplate{
					Name:   "response-body-struct",
					Source: serviceResponseBodyStructT,
					Data:   m,
				})
			}
		}
		sections = append(sections, &codegen.SectionTemplate{
			Name:   "endpoints-init",
			Source: serviceEndpointsInitT,
			Data:   data,
		})
		sections = append(sections, &codegen.SectionTemplate{
			Name:   "endpoints-use",
			Source: serviceEndpointsUseT,
			Data:   data,
		})
		for _, m := range data.Methods {
			sections = append(sections, &codegen.SectionTemplate{
				Name:    "endpoint-method",
				Source:  serviceEndpointMethodT,
				Data:    m,
				FuncMap: map[string]interface{}{"payloadVar": payloadVar},
			})
		}
	}

	return &codegen.File{Path: path, SectionTemplates: sections}
}

func endpointData(service *expr.ServiceExpr) *endpointsData {
	svc := Services.Get(service.Name)
	methods := make([]*endpointMethodData, len(svc.Methods))
	names := make([]string, len(svc.Methods))
	for i, m := range svc.Methods {
		methods[i] = &endpointMethodData{
			MethodData:     m,
			ArgName:        codegen.Goify(m.VarName, false),
			ServiceName:    svc.Name,
			ServiceVarName: serviceInterfaceName,
			ClientVarName:  clientStructName,
		}
		names[i] = codegen.Goify(m.VarName, false)
	}
	desc := fmt.Sprintf("%s wraps the %q service endpoints.", endpointsStructName, service.Name)
	return &endpointsData{
		Name:           service.Name,
		Description:    desc,
		VarName:        endpointsStructName,
		ClientVarName:  clientStructName,
		ServiceVarName: serviceInterfaceName,
		ClientInitArgs: strings.Join(names, ", "),
		Methods:        methods,
		Schemes:        svc.Schemes,
	}
}

func payloadVar(e *endpointMethodData) string {
	if e.ServerStream != nil || e.SkipRequestBodyEncodeDecode {
		return "ep.Payload"
	}
	return "p"
}

// input: endpointsData
const serviceEndpointsT = `{{ comment .Description }}
type {{ .VarName }} struct {
{{- range .Methods}}
	{{ .VarName }} goa.Endpoint
{{- end }}
}
`

// input: endpointsData
const serviceEndpointsInitT = `{{ printf "New%s wraps the methods of the %q service with endpoints." .VarName .Name | comment }}
func New{{ .VarName }}(s {{ .ServiceVarName }}) *{{ .VarName }} {
{{- if .Schemes }}
	// Casting service to Auther interface
	a := s.(Auther)
{{- end }}
	return &{{ .VarName }}{
{{- range .Methods }}
		{{ .VarName }}: New{{ .VarName }}Endpoint(s{{ range .Schemes }}, a.{{ .Type }}Auth{{ end }}),
{{- end }}
	}
}
`

// input: endpointMethodData
const serviceEndpointStreamStructT = `{{ printf "%s holds both the payload and the server stream of the %q method." .ServerStream.EndpointStruct .Name | comment }}
type {{ .ServerStream.EndpointStruct }} struct {
{{- if .PayloadRef }}
	{{ comment "Payload is the method payload." }}
	Payload {{ .PayloadRef }}
{{- end }}
	{{ printf "Stream is the server stream used by the %q method to send data." .Name | comment }}
	Stream {{ .ServerStream.Interface }}
}
`

// input: endpointMethodData
const serviceRequestBodyStructT = `{{ printf "%s holds both the payload and the HTTP request body reader of the %q method." .RequestStruct .Name | comment }}
type {{ .RequestStruct }} struct {
{{- if .PayloadRef }}
	{{ comment "Payload is the method payload." }}
	Payload {{ .PayloadRef }}
{{- end }}
	{{ comment "Body streams the HTTP request body." }}
	Body io.ReadCloser
}
`

// input: endpointMethodData
const serviceResponseBodyStructT = `{{ printf "%s holds both the result and the HTTP response body reader of the %q method." .ResponseStruct .Name | comment }}
type {{ .ResponseStruct }} struct {
{{- if .ResultRef }}
	{{ comment "Result is the method result." }}
	Result {{ .ResultRef }}
{{- end }}
	{{ comment "Body streams the HTTP response body." }}
	Body io.ReadCloser
}
`

// input: endpointMethodData
const serviceEndpointMethodT = `{{ printf "New%sEndpoint returns an endpoint function that calls the method %q of service %q." .VarName .Name .ServiceName | comment }}
func New{{ .VarName }}Endpoint(s {{ .ServiceVarName }}{{ range .Schemes }}, auth{{ .Type }}Fn security.Auth{{ .Type }}Func{{ end }}) goa.Endpoint {
	return func(ctx context.Context, req interface{}) (interface{}, error) {
{{- if or .ServerStream }}
		ep := req.(*{{ .ServerStream.EndpointStruct }})
{{- else if .SkipRequestBodyEncodeDecode }}
		ep := req.(*{{ .RequestStruct }})
{{- else if .PayloadRef }}
		p := req.({{ .PayloadRef }})
{{- end }}
{{- $payload := payloadVar . }}
{{- if .Requirements }}
		var err error
	{{- range $ridx, $r := .Requirements }}
		{{- if ne $ridx 0 }}
		if err != nil {
		{{- end }}
		{{- range $sidx, $s := .Schemes }}
			{{- if ne $sidx 0 }}
			if err == nil {
			{{- end }}
			{{- if eq .Type "Basic" }}
				sc := security.BasicScheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
				}
				{{- if .UsernamePointer }}
				var user string
				if {{ $payload }}.{{ .UsernameField }} != nil {
					user = *{{ $payload }}.{{ .UsernameField }}
				}
				{{- end }}
				{{- if .PasswordPointer }}
				var pass string
				if {{ $payload }}.{{ .PasswordField }} != nil {
					pass = *{{ $payload }}.{{ .PasswordField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if .UsernamePointer }}user{{ else }}{{ $payload }}.{{ .UsernameField }}{{ end }},
					{{- if .PasswordPointer }}pass{{ else }}{{ $payload }}.{{ .PasswordField }}{{ end }}, &sc)

			{{- else if eq .Type "APIKey" }}
				sc := security.APIKeyScheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
				}
				{{- if $s.CredPointer }}
				var key string
				if {{ $payload }}.{{ $s.CredField }} != nil {
					key = *{{ $payload }}.{{ $s.CredField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if $s.CredPointer }}key{{ else }}{{ $payload }}.{{ $s.CredField }}{{ end }}, &sc)

			{{- else if eq .Type "JWT" }}
				sc := security.JWTScheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
				}
				{{- if $s.CredPointer }}
				var token string
				if {{ $payload }}.{{ $s.CredField }} != nil {
					token = *{{ $payload }}.{{ $s.CredField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if $s.CredPointer }}token{{ else }}{{ $payload }}.{{ $s.CredField }}{{ end }}, &sc)

			{{- else if eq .Type "OAuth2" }}
				sc := security.OAuth2Scheme{
					Name: {{ printf "%q" .SchemeName }},
					Scopes: []string{ {{- range .Scopes }}{{ printf "%q" . }}, {{ end }} },
					RequiredScopes: []string{ {{- range $r.Scopes }}{{ printf "%q" . }}, {{ end }} },
					{{- if .Flows }}
					Flows: []*security.OAuthFlow{
						{{- range .Flows }}
						&security.OAuthFlow{
							Type: "{{ .Type }}",
							{{- if .AuthorizationURL }}
							AuthorizationURL: {{ printf "%q" .AuthorizationURL }},
							{{- end }}
							{{- if .TokenURL }}
							TokenURL: {{ printf "%q" .TokenURL }},
							{{- end }}
							{{- if .RefreshURL }}
							RefreshURL: {{ printf "%q" .RefreshURL }},
							{{- end }}
						},
						{{- end }}
					},
					{{- end }}
				}
				{{- if $s.CredPointer }}
				var token string
				if {{ $payload }}.{{ $s.CredField }} != nil {
					token = *{{ $payload }}.{{ $s.CredField }}
				}
				{{- end }}
				ctx, err = auth{{ .Type }}Fn(ctx, {{ if $s.CredPointer }}token{{ else }}{{ $payload }}.{{ $s.CredField }}{{ end }}, &sc)

			{{- end }}
			{{- if ne $sidx 0 }}
				}
			{{- end }}
		{{- end }}
		{{- if ne $ridx 0 }}
		}
		{{- end }}
	{{- end }}
		if err != nil {
			return nil, err
		}
{{- end }}
{{- if .ServerStream }}
	return nil, s.{{ .VarName }}(ctx, {{ if .PayloadRef }}{{ $payload }}, {{ end }}ep.Stream)
{{- else if .SkipRequestBodyEncodeDecode }}
	{{- if .SkipResponseBodyEncodeDecode }}
	{{ if .ResultRef }}res, {{ end }}body, err := s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
	if err != nil {
		return nil, err
	}
	return &{{ .ResponseStruct }}{ {{ if .ResultRef }}Result: res, {{ end }}Body: body }, nil
	{{- else if .ViewedResult }}
	res, {{ if not .ViewedResult.ViewName }}view, {{ end }}err := s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
	if err != nil {
		return nil, err
	}
	vres := {{ $.ViewedResult.Init.Name }}(res, {{ if .ViewedResult.ViewName }}{{ printf "%q" .ViewedResult.ViewName }}{{ else }}view{{ end }})
	return vres, nil
	{{- else }}
	return {{ if not .ResultRef }}nil, {{ end }}s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
	{{- end }}
{{- else if .ViewedResult }}
	res, {{ if not .ViewedResult.ViewName }}view, {{ end }}err := s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
	if err != nil {
		return nil, err
	}
	vres := {{ $.ViewedResult.Init.Name }}(res, {{ if .ViewedResult.ViewName }}{{ printf "%q" .ViewedResult.ViewName }}{{ else }}view{{ end }})
	return vres, nil
{{- else if .SkipResponseBodyEncodeDecode }}
	{{ if .ResultRef }}res, {{ end }}body, err := s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload}}{{ end }})
	if err != nil {
		return nil, err
	}
	return &{{ .ResponseStruct }}{ {{ if .ResultRef }}Result: res, {{ end }}Body: body }, nil
{{- else }}
	return {{ if not .ResultRef }}nil, {{ end }}s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
{{- end }}
	}
}
`

// input: endpointMethodData
const serviceEndpointsUseT = `{{ printf "Use applies the given middleware to all the %q service endpoints." .Name | comment }}
func (e *{{ .VarName }}) Use(m func(goa.Endpoint) goa.Endpoint) {
{{- range .Methods }}
	e.{{ .VarName }} = m(e.{{ .VarName }})
{{- end }}
}
`
<|endoftext|>


<commit_before>package main

import (
	"github.com/timeredbull/commandmocker"
	"github.com/timeredbull/tsuru/api/app"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"os"
	"path/filepath"
)

func getOutput() *output {
	return &output{
		Services: map[string]Service{
			"umaappqq": Service{
				Units: map[string]app.Unit{
					"umaappqq/0": app.Unit{
						AgentState: "started",
						Machine:    1,
					},
				},
			},
		},
		Machines: map[int]interface{}{
			0: map[interface{}]interface{}{
				"dns-name":       "192.168.0.10",
				"instance-id":    "i-00000zz6",
				"instance-state": "running",
				"agent-state":    "running",
			},
			1: map[interface{}]interface{}{
				"dns-name":       "192.168.0.11",
				"instance-id":    "i-00000zz7",
				"instance-state": "running",
				"agent-state":    "running",
			},
		},
	}
}

func getApp(c *C) *app.App {
	a := &app.App{Name: "umaappqq", State: "STOPPED"}
	err := a.Create()
	c.Assert(err, IsNil)
	return a
}

func (s *S) TestUpdate(c *C) {
	a := getApp(c)
	out := getOutput()
	update(out)

	err := a.Get()
	c.Assert(err, IsNil)
	c.Assert(a.State, Equals, "started")
	c.Assert(a.Units[0].Ip, Equals, "192.168.0.11")
	c.Assert(a.Units[0].Machine, Equals, 1)
	c.Assert(a.Units[0].InstanceState, Equals, "running")
	c.Assert(a.Units[0].MachineAgentState, Equals, "running")
	c.Assert(a.Units[0].AgentState, Equals, "started")
	c.Assert(a.Units[0].InstanceId, Equals, "i-00000zz7")

	a.Destroy()
}

func (s *S) TestUpdateWithMultipleUnits(c *C) {
	a := getApp(c)
	out := getOutput()
	u := app.Unit{AgentState: "started", Machine: 2}
	out.Services["umaappqq"].Units["umaappqq/1"] = u
	out.Machines[2] = map[interface{}]interface{}{
		"dns-name":       "192.168.0.12",
		"instance-id":    "i-00000zz8",
		"instance-state": "running",
		"agent-state":    "running",
	}
	update(out)
	err := a.Get()
	c.Assert(err, IsNil)
	c.Assert(len(a.Units), Equals, 2)
	for _, u = range a.Units {
		if u.Machine == 2 {
			break
		}
	}
	c.Assert(u.Ip, Equals, "192.168.0.12")
	c.Assert(u.InstanceState, Equals, "running")
	c.Assert(u.AgentState, Equals, "started")
	c.Assert(u.MachineAgentState, Equals, "running")
}

func (s *S) TestUpdateWithDownMachine(c *C) {
	a := app.App{Name: "barduscoapp", State: "STOPPED"}
	err := a.Create()
	c.Assert(err, IsNil)
	file, _ := os.Open(filepath.Join("testdata", "broken-output.yaml"))
	jujuOutput, _ := ioutil.ReadAll(file)
	file.Close()
	out := parse(jujuOutput)
	update(out)
	err = a.Get()
	c.Assert(err, IsNil)
	c.Assert(a.State, Equals, "creating")
}

func (s *S) TestUpdateTwice(c *C) {
	a := getApp(c)
	defer a.Destroy()
	out := getOutput()
	update(out)
	err := a.Get()
	c.Assert(err, IsNil)
	c.Assert(a.State, Equals, "started")
	c.Assert(a.Units[0].Ip, Equals, "192.168.0.11")
	c.Assert(a.Units[0].Machine, Equals, 1)
	c.Assert(a.Units[0].InstanceState, Equals, "running")
	c.Assert(a.Units[0].MachineAgentState, Equals, "running")
	c.Assert(a.Units[0].AgentState, Equals, "started")
	update(out)
	err = a.Get()
	c.Assert(len(a.Units), Equals, 1)
}

func (s *S) TestUpdateWithMultipleApps(c *C) {
	appDicts := []map[string]string{
		map[string]string{
			"name": "andrewzito3",
			"ip":   "10.10.10.163",
		},
		map[string]string{
			"name": "flaviapp",
			"ip":   "10.10.10.208",
		},
		map[string]string{
			"name": "mysqlapi",
			"ip":   "10.10.10.131",
		},
		map[string]string{
			"name": "teste_api_semantica",
			"ip":   "10.10.10.189",
		},
		map[string]string{
			"name": "xikin",
			"ip":   "10.10.10.168",
		},
	}
	apps := make([]app.App, len(appDicts))
	for i, appDict := range appDicts {
		a := app.App{Name: appDict["name"]}
		err := a.Create()
		c.Assert(err, IsNil)
		apps[i] = a
	}
	jujuOutput, err := ioutil.ReadFile(filepath.Join("testdata", "multiple-apps.yaml"))
	c.Assert(err, IsNil)
	data := parse(jujuOutput)
	update(data)
	for _, appDict := range appDicts {
		a := app.App{Name: appDict["name"]}
		err := a.Get()
		c.Assert(err, IsNil)
		c.Assert(a.Units[0].Ip, Equals, appDict["ip"])
	}
}

func (s *S) TestParser(c *C) {
	file, _ := os.Open(filepath.Join("testdata", "output.yaml"))
	jujuOutput, _ := ioutil.ReadAll(file)
	file.Close()
	expected := getOutput()
	c.Assert(parse(jujuOutput), DeepEquals, expected)
}

func (s *S) TestCollect(c *C) {
	a := app.App{JujuEnv: "zeta"}
	tmpdir, err := commandmocker.Add("juju", "$*")
	c.Assert(err, IsNil)
	defer commandmocker.Remove(tmpdir)
	out, err := collect(&a)
	c.Assert(err, IsNil)
	c.Assert(string(out), Equals, "status -e zeta")
}

func (s *S) TestAppStatusMachineAgentPending(c *C) {
	u := app.Unit{MachineAgentState: "pending"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusInstanceStatePending(c *C) {
	u := app.Unit{InstanceState: "pending"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusInstanceStateError(c *C) {
	u := app.Unit{InstanceState: "error"}
	st := appState(&u)
	c.Assert(st, Equals, "error")
}

func (s *S) TestAppStatusAgentStatePending(c *C) {
	u := app.Unit{AgentState: "pending", InstanceState: ""}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusAgentAndInstanceRunning(c *C) {
	u := app.Unit{AgentState: "started", InstanceState: "running", MachineAgentState: "running"}
	st := appState(&u)
	c.Assert(st, Equals, "started")
}

func (s *S) TestAppStatusMachineAgentRunningAndInstanceAndAgentPending(c *C) {
	u := app.Unit{AgentState: "pending", InstanceState: "running", MachineAgentState: "running"}
	st := appState(&u)
	c.Assert(st, Equals, "installing")
}

func (s *S) TestAppStatusInstancePending(c *C) {
	u := app.Unit{AgentState: "not-started", InstanceState: "pending"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusInstancePendingWhenMachineStateIsRunning(c *C) {
	u := app.Unit{AgentState: "not-started", MachineAgentState: "running"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatePending(c *C) {
	u := app.Unit{MachineAgentState: "some-state", AgentState: "some-state", InstanceState: "some-other-state"}
	st := appState(&u)
	c.Assert(st, Equals, "pending")
}
<commit_msg>collector: using ioutil.ReadFile instead of os.Open + ioutil.ReadAll<commit_after>package main

import (
	"github.com/timeredbull/commandmocker"
	"github.com/timeredbull/tsuru/api/app"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"path/filepath"
)

func getOutput() *output {
	return &output{
		Services: map[string]Service{
			"umaappqq": Service{
				Units: map[string]app.Unit{
					"umaappqq/0": app.Unit{
						AgentState: "started",
						Machine:    1,
					},
				},
			},
		},
		Machines: map[int]interface{}{
			0: map[interface{}]interface{}{
				"dns-name":       "192.168.0.10",
				"instance-id":    "i-00000zz6",
				"instance-state": "running",
				"agent-state":    "running",
			},
			1: map[interface{}]interface{}{
				"dns-name":       "192.168.0.11",
				"instance-id":    "i-00000zz7",
				"instance-state": "running",
				"agent-state":    "running",
			},
		},
	}
}

func getApp(c *C) *app.App {
	a := &app.App{Name: "umaappqq", State: "STOPPED"}
	err := a.Create()
	c.Assert(err, IsNil)
	return a
}

func (s *S) TestUpdate(c *C) {
	a := getApp(c)
	out := getOutput()
	update(out)

	err := a.Get()
	c.Assert(err, IsNil)
	c.Assert(a.State, Equals, "started")
	c.Assert(a.Units[0].Ip, Equals, "192.168.0.11")
	c.Assert(a.Units[0].Machine, Equals, 1)
	c.Assert(a.Units[0].InstanceState, Equals, "running")
	c.Assert(a.Units[0].MachineAgentState, Equals, "running")
	c.Assert(a.Units[0].AgentState, Equals, "started")
	c.Assert(a.Units[0].InstanceId, Equals, "i-00000zz7")

	a.Destroy()
}

func (s *S) TestUpdateWithMultipleUnits(c *C) {
	a := getApp(c)
	out := getOutput()
	u := app.Unit{AgentState: "started", Machine: 2}
	out.Services["umaappqq"].Units["umaappqq/1"] = u
	out.Machines[2] = map[interface{}]interface{}{
		"dns-name":       "192.168.0.12",
		"instance-id":    "i-00000zz8",
		"instance-state": "running",
		"agent-state":    "running",
	}
	update(out)
	err := a.Get()
	c.Assert(err, IsNil)
	c.Assert(len(a.Units), Equals, 2)
	for _, u = range a.Units {
		if u.Machine == 2 {
			break
		}
	}
	c.Assert(u.Ip, Equals, "192.168.0.12")
	c.Assert(u.InstanceState, Equals, "running")
	c.Assert(u.AgentState, Equals, "started")
	c.Assert(u.MachineAgentState, Equals, "running")
}

func (s *S) TestUpdateWithDownMachine(c *C) {
	a := app.App{Name: "barduscoapp", State: "STOPPED"}
	err := a.Create()
	c.Assert(err, IsNil)
	jujuOutput, err := ioutil.ReadFile(filepath.Join("testdata", "broken-output.yaml"))
	c.Assert(err, IsNil)
	out := parse(jujuOutput)
	update(out)
	err = a.Get()
	c.Assert(err, IsNil)
	c.Assert(a.State, Equals, "creating")
}

func (s *S) TestUpdateTwice(c *C) {
	a := getApp(c)
	defer a.Destroy()
	out := getOutput()
	update(out)
	err := a.Get()
	c.Assert(err, IsNil)
	c.Assert(a.State, Equals, "started")
	c.Assert(a.Units[0].Ip, Equals, "192.168.0.11")
	c.Assert(a.Units[0].Machine, Equals, 1)
	c.Assert(a.Units[0].InstanceState, Equals, "running")
	c.Assert(a.Units[0].MachineAgentState, Equals, "running")
	c.Assert(a.Units[0].AgentState, Equals, "started")
	update(out)
	err = a.Get()
	c.Assert(len(a.Units), Equals, 1)
}

func (s *S) TestUpdateWithMultipleApps(c *C) {
	appDicts := []map[string]string{
		map[string]string{
			"name": "andrewzito3",
			"ip":   "10.10.10.163",
		},
		map[string]string{
			"name": "flaviapp",
			"ip":   "10.10.10.208",
		},
		map[string]string{
			"name": "mysqlapi",
			"ip":   "10.10.10.131",
		},
		map[string]string{
			"name": "teste_api_semantica",
			"ip":   "10.10.10.189",
		},
		map[string]string{
			"name": "xikin",
			"ip":   "10.10.10.168",
		},
	}
	apps := make([]app.App, len(appDicts))
	for i, appDict := range appDicts {
		a := app.App{Name: appDict["name"]}
		err := a.Create()
		c.Assert(err, IsNil)
		apps[i] = a
	}
	jujuOutput, err := ioutil.ReadFile(filepath.Join("testdata", "multiple-apps.yaml"))
	c.Assert(err, IsNil)
	data := parse(jujuOutput)
	update(data)
	for _, appDict := range appDicts {
		a := app.App{Name: appDict["name"]}
		err := a.Get()
		c.Assert(err, IsNil)
		c.Assert(a.Units[0].Ip, Equals, appDict["ip"])
	}
}

func (s *S) TestParser(c *C) {
	jujuOutput, err := ioutil.ReadFile(filepath.Join("testdata", "output.yaml"))
	c.Assert(err, IsNil)
	expected := getOutput()
	c.Assert(parse(jujuOutput), DeepEquals, expected)
}

func (s *S) TestCollect(c *C) {
	a := app.App{JujuEnv: "zeta"}
	tmpdir, err := commandmocker.Add("juju", "$*")
	c.Assert(err, IsNil)
	defer commandmocker.Remove(tmpdir)
	out, err := collect(&a)
	c.Assert(err, IsNil)
	c.Assert(string(out), Equals, "status -e zeta")
}

func (s *S) TestAppStatusMachineAgentPending(c *C) {
	u := app.Unit{MachineAgentState: "pending"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusInstanceStatePending(c *C) {
	u := app.Unit{InstanceState: "pending"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusInstanceStateError(c *C) {
	u := app.Unit{InstanceState: "error"}
	st := appState(&u)
	c.Assert(st, Equals, "error")
}

func (s *S) TestAppStatusAgentStatePending(c *C) {
	u := app.Unit{AgentState: "pending", InstanceState: ""}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusAgentAndInstanceRunning(c *C) {
	u := app.Unit{AgentState: "started", InstanceState: "running", MachineAgentState: "running"}
	st := appState(&u)
	c.Assert(st, Equals, "started")
}

func (s *S) TestAppStatusMachineAgentRunningAndInstanceAndAgentPending(c *C) {
	u := app.Unit{AgentState: "pending", InstanceState: "running", MachineAgentState: "running"}
	st := appState(&u)
	c.Assert(st, Equals, "installing")
}

func (s *S) TestAppStatusInstancePending(c *C) {
	u := app.Unit{AgentState: "not-started", InstanceState: "pending"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatusInstancePendingWhenMachineStateIsRunning(c *C) {
	u := app.Unit{AgentState: "not-started", MachineAgentState: "running"}
	st := appState(&u)
	c.Assert(st, Equals, "creating")
}

func (s *S) TestAppStatePending(c *C) {
	u := app.Unit{MachineAgentState: "some-state", AgentState: "some-state", InstanceState: "some-other-state"}
	st := appState(&u)
	c.Assert(st, Equals, "pending")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
)

var (
	errLogger = log.New(os.Stderr, "", 0)
)

func main() {
	flag.Parse()
	config := loadConfig()

	command := remoteCommand()

	sessions := openSessions(config)

	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT)

	var wg sync.WaitGroup
	done := make(chan bool)
loop:
	for {
		select {
		case <-signals:
			break loop
		case session, ok := <-sessions:
			if ok {
				defer session.Session.Close()
				host := session.Host
				err := requestPty(session.Session)
				if err != nil {
					errLogger.Print(prependHost(host, err.Error()))
					break
				}
				outScanner := initScanner(session)
				wg.Add(1)
				go runRemote(command, session, &wg)
				go output(host, outScanner)
			} else {
				go func() {
					wg.Wait()
					done <- true
				}()
				sessions = nil
			}
		case <-done:
			break loop
		}
	}
}

func remoteCommand() string {
	return strings.Join(flag.Args()[1:], " ")
}

func initScanner(session Session) *bufio.Scanner {
	reader, _ := session.Session.StdoutPipe()
	scanner := bufio.NewScanner(reader)
	return scanner
}

func runRemote(command string, session Session, wg *sync.WaitGroup) {
	err := session.Session.Run(command)
	if err != nil {
		errLogger.Print(prependHost(session.Host, err.Error()))
	}
	wg.Done()
}

func output(host string, scanner *bufio.Scanner) {
	for scanner.Scan() {
		fmt.Println(prependHost(host, scanner.Text()))
	}
}

func prependHost(host, str string) string {
	return "[" + host + "] " + str
}
<commit_msg>print newline after interrupt is caught<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
)

var (
	errLogger = log.New(os.Stderr, "", 0)
)

func main() {
	flag.Parse()
	config := loadConfig()

	command := remoteCommand()

	sessions := openSessions(config)

	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT)

	var wg sync.WaitGroup
	done := make(chan bool)
loop:
	for {
		select {
		case <-signals:
			fmt.Println() // clean up for the next prompt
			break loop
		case session, ok := <-sessions:
			if ok {
				defer session.Session.Close()
				host := session.Host
				err := requestPty(session.Session)
				if err != nil {
					errLogger.Print(prependHost(host, err.Error()))
					break
				}
				outScanner := initScanner(session)
				wg.Add(1)
				go runRemote(command, session, &wg)
				go output(host, outScanner)
			} else {
				go func() {
					wg.Wait()
					done <- true
				}()
				sessions = nil
			}
		case <-done:
			break loop
		}
	}
}

func remoteCommand() string {
	return strings.Join(flag.Args()[1:], " ")
}

func initScanner(session Session) *bufio.Scanner {
	reader, _ := session.Session.StdoutPipe()
	scanner := bufio.NewScanner(reader)
	return scanner
}

func runRemote(command string, session Session, wg *sync.WaitGroup) {
	err := session.Session.Run(command)
	if err != nil {
		errLogger.Print(prependHost(session.Host, err.Error()))
	}
	wg.Done()
}

func output(host string, scanner *bufio.Scanner) {
	for scanner.Scan() {
		fmt.Println(prependHost(host, scanner.Text()))
	}
}

func prependHost(host, str string) string {
	return "[" + host + "] " + str
}
<|endoftext|>


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

package charm

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strings"

	"github.com/juju/schema"
	"gopkg.in/yaml.v1"

	"gopkg.in/juju/charm.v4/hooks"
)

// RelationScope describes the scope of a relation.
type RelationScope string

// Note that schema doesn't support custom string types,
// so when we use these values in a schema.Checker,
// we must store them as strings, not RelationScopes.

const (
	ScopeGlobal    RelationScope = "global"
	ScopeContainer RelationScope = "container"
)

// RelationRole defines the role of a relation.
type RelationRole string

const (
	RoleProvider RelationRole = "provider"
	RoleRequirer RelationRole = "requirer"
	RolePeer     RelationRole = "peer"
)

// Relation represents a single relation defined in the charm
// metadata.yaml file.
type Relation struct {
	Name      string
	Role      RelationRole
	Interface string
	Optional  bool
	Limit     int
	Scope     RelationScope
}

// ImplementedBy returns whether the relation is implemented by the supplied charm.
func (r Relation) ImplementedBy(ch Charm) bool {
	if r.IsImplicit() {
		return true
	}
	var m map[string]Relation
	switch r.Role {
	case RoleProvider:
		m = ch.Meta().Provides
	case RoleRequirer:
		m = ch.Meta().Requires
	case RolePeer:
		m = ch.Meta().Peers
	default:
		panic(fmt.Errorf("unknown relation role %q", r.Role))
	}
	rel, found := m[r.Name]
	if !found {
		return false
	}
	if rel.Interface == r.Interface {
		switch r.Scope {
		case ScopeGlobal:
			return rel.Scope != ScopeContainer
		case ScopeContainer:
			return true
		default:
			panic(fmt.Errorf("unknown relation scope %q", r.Scope))
		}
	}
	return false
}

// IsImplicit returns whether the relation is supplied by juju itself,
// rather than by a charm.
func (r Relation) IsImplicit() bool {
	return (r.Name == "juju-info" &&
		r.Interface == "juju-info" &&
		r.Role == RoleProvider)
}

// Meta represents all the known content that may be defined
// within a charm's metadata.yaml file.
type Meta struct {
	Name        string
	Summary     string
	Description string
	Subordinate bool
	Provides    map[string]Relation `bson:",omitempty"`
	Requires    map[string]Relation `bson:",omitempty"`
	Peers       map[string]Relation `bson:",omitempty"`
	Format      int                 `bson:",omitempty"`
	OldRevision int                 `bson:",omitempty"` // Obsolete
	Categories  []string            `bson:",omitempty"`
	Tags        []string            `bson:",omitempty"`
	Series      string              `bson:",omitempty"`
}

func generateRelationHooks(relName string, allHooks map[string]bool) {
	for _, hookName := range hooks.RelationHooks() {
		allHooks[fmt.Sprintf("%s-%s", relName, hookName)] = true
	}
}

// Hooks returns a map of all possible valid hooks, taking relations
// into account. It's a map to enable fast lookups, and the value is
// always true.
func (m Meta) Hooks() map[string]bool {
	allHooks := make(map[string]bool)
	// Unit hooks
	for _, hookName := range hooks.UnitHooks() {
		allHooks[string(hookName)] = true
	}
	// Relation hooks
	for hookName := range m.Provides {
		generateRelationHooks(hookName, allHooks)
	}
	for hookName := range m.Requires {
		generateRelationHooks(hookName, allHooks)
	}
	for hookName := range m.Peers {
		generateRelationHooks(hookName, allHooks)
	}
	return allHooks
}

func parseCategories(categories interface{}) []string {
	if categories == nil {
		return nil
	}
	slice := categories.([]interface{})
	result := make([]string, 0, len(slice))
	for _, cat := range slice {
		result = append(result, cat.(string))
	}
	return result
}

func parseTags(tags interface{}) []string {
	if tags == nil {
		return nil
	}
	slice := tags.([]interface{})
	result := make([]string, 0, len(slice))
	for _, cat := range slice {
		// todo : check if tag is whitelisted
		result = append(result, cat.(string))
	}
	return result
}

// Todo : cheks if tags are whitelisted or not.
func checkTags(tags interface{}) error {
	return nil
}

// ReadMeta reads the content of a metadata.yaml file and returns
// its representation.
func ReadMeta(r io.Reader) (meta *Meta, err error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}
	raw := make(map[interface{}]interface{})
	err = yaml.Unmarshal(data, raw)
	if err != nil {
		return
	}
	v, err := charmSchema.Coerce(raw, nil)
	if err != nil {
		return nil, errors.New("metadata: " + err.Error())
	}
	m := v.(map[string]interface{})
	meta = &Meta{}
	meta.Name = m["name"].(string)
	// Schema decodes as int64, but the int range should be good
	// enough for revisions.
	meta.Summary = m["summary"].(string)
	meta.Description = m["description"].(string)
	meta.Provides = parseRelations(m["provides"], RoleProvider)
	meta.Requires = parseRelations(m["requires"], RoleRequirer)
	meta.Peers = parseRelations(m["peers"], RolePeer)
	meta.Format = int(m["format"].(int64))
	meta.Categories = parseCategories(m["categories"])
	meta.Tags = parseTags(m["tags"])
	if subordinate := m["subordinate"]; subordinate != nil {
		meta.Subordinate = subordinate.(bool)
	}
	if rev := m["revision"]; rev != nil {
		// Obsolete
		meta.OldRevision = int(m["revision"].(int64))
	}
	if series, ok := m["series"]; ok && series != nil {
		meta.Series = series.(string)
	}
	if err := meta.Check(); err != nil {
		return nil, err
	}
	return meta, nil
}

// Check checks that the metadata is well-formed.
func (meta Meta) Check() error {
	// Check for duplicate or forbidden relation names or interfaces.
	names := map[string]bool{}
	checkRelations := func(src map[string]Relation, role RelationRole) error {
		for name, rel := range src {
			if rel.Name != name {
				return fmt.Errorf("charm %q has mismatched relation name %q; expected %q", meta.Name, rel.Name, name)
			}
			if rel.Role != role {
				return fmt.Errorf("charm %q has mismatched role %q; expected %q", meta.Name, rel.Role, role)
			}
			// Container-scoped require relations on subordinates are allowed
			// to use the otherwise-reserved juju-* namespace.
			if !meta.Subordinate || role != RoleRequirer || rel.Scope != ScopeContainer {
				if reservedName(name) {
					return fmt.Errorf("charm %q using a reserved relation name: %q", meta.Name, name)
				}
			}
			if role != RoleRequirer {
				if reservedName(rel.Interface) {
					return fmt.Errorf("charm %q relation %q using a reserved interface: %q", meta.Name, name, rel.Interface)
				}
			}
			if names[name] {
				return fmt.Errorf("charm %q using a duplicated relation name: %q", meta.Name, name)
			}
			names[name] = true
		}
		return nil
	}
	if err := checkRelations(meta.Provides, RoleProvider); err != nil {
		return err
	}
	if err := checkRelations(meta.Requires, RoleRequirer); err != nil {
		return err
	}
	if err := checkRelations(meta.Peers, RolePeer); err != nil {
		return err
	}
	if err := checkTags(meta.Tags); err != nil {
		return err
	}

	// Subordinate charms must have at least one relation that
	// has container scope, otherwise they can't relate to the
	// principal.
	if meta.Subordinate {
		valid := false
		if meta.Requires != nil {
			for _, relationData := range meta.Requires {
				if relationData.Scope == ScopeContainer {
					valid = true
					break
				}
			}
		}
		if !valid {
			return fmt.Errorf("subordinate charm %q lacks \"requires\" relation with container scope", meta.Name)
		}
	}

	if meta.Series != "" {
		if !IsValidSeries(meta.Series) {
			return fmt.Errorf("charm %q declares invalid series: %q", meta.Name, meta.Series)
		}
	}

	return nil
}

func reservedName(name string) bool {
	return name == "juju" || strings.HasPrefix(name, "juju-")
}

func parseRelations(relations interface{}, role RelationRole) map[string]Relation {
	if relations == nil {
		return nil
	}
	result := make(map[string]Relation)
	for name, rel := range relations.(map[string]interface{}) {
		relMap := rel.(map[string]interface{})
		relation := Relation{
			Name:      name,
			Role:      role,
			Interface: relMap["interface"].(string),
			Optional:  relMap["optional"].(bool),
		}
		if scope := relMap["scope"]; scope != nil {
			relation.Scope = RelationScope(scope.(string))
		}
		if relMap["limit"] != nil {
			// Schema defaults to int64, but we know
			// the int range should be more than enough.
			relation.Limit = int(relMap["limit"].(int64))
		}
		result[name] = relation
	}
	return result
}

// Schema coercer that expands the interface shorthand notation.
// A consistent format is easier to work with than considering the
// potential difference everywhere.
//
// Supports the following variants::
//
//   provides:
//     server: riak
//     admin: http
//     foobar:
//       interface: blah
//
//   provides:
//     server:
//       interface: mysql
//       limit:
//       optional: false
//
// In all input cases, the output is the fully specified interface
// representation as seen in the mysql interface description above.
func ifaceExpander(limit interface{}) schema.Checker {
	return ifaceExpC{limit}
}

type ifaceExpC struct {
	limit interface{}
}

var (
	stringC = schema.String()
	mapC    = schema.StringMap(schema.Any())
)

func (c ifaceExpC) Coerce(v interface{}, path []string) (newv interface{}, err error) {
	s, err := stringC.Coerce(v, path)
	if err == nil {
		newv = map[string]interface{}{
			"interface": s,
			"limit":     c.limit,
			"optional":  false,
			"scope":     string(ScopeGlobal),
		}
		return
	}

	v, err = mapC.Coerce(v, path)
	if err != nil {
		return
	}
	m := v.(map[string]interface{})
	if _, ok := m["limit"]; !ok {
		m["limit"] = c.limit
	}
	return ifaceSchema.Coerce(m, path)
}

var ifaceSchema = schema.FieldMap(
	schema.Fields{
		"interface": schema.String(),
		"limit":     schema.OneOf(schema.Const(nil), schema.Int()),
		"scope":     schema.OneOf(schema.Const(string(ScopeGlobal)), schema.Const(string(ScopeContainer))),
		"optional":  schema.Bool(),
	},
	schema.Defaults{
		"scope":    string(ScopeGlobal),
		"optional": false,
	},
)

var charmSchema = schema.FieldMap(
	schema.Fields{
		"name":        schema.String(),
		"summary":     schema.String(),
		"description": schema.String(),
		"peers":       schema.StringMap(ifaceExpander(int64(1))),
		"provides":    schema.StringMap(ifaceExpander(nil)),
		"requires":    schema.StringMap(ifaceExpander(int64(1))),
		"revision":    schema.Int(), // Obsolete
		"format":      schema.Int(),
		"subordinate": schema.Bool(),
		"categories":  schema.List(schema.String()),
		"tags":        schema.List(schema.String()),
		"series":      schema.String(),
	},
	schema.Defaults{
		"provides":    schema.Omit,
		"requires":    schema.Omit,
		"peers":       schema.Omit,
		"revision":    schema.Omit,
		"format":      1,
		"subordinate": schema.Omit,
		"categories":  schema.Omit,
		"tags":        schema.Omit,
		"series":      schema.Omit,
	},
)
<commit_msg>* removed whitelist checking * common parsing function for categories and tags<commit_after>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charm

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strings"

	"github.com/juju/schema"
	"gopkg.in/yaml.v1"

	"gopkg.in/juju/charm.v4/hooks"
)

// RelationScope describes the scope of a relation.
type RelationScope string

// Note that schema doesn't support custom string types,
// so when we use these values in a schema.Checker,
// we must store them as strings, not RelationScopes.

const (
	ScopeGlobal    RelationScope = "global"
	ScopeContainer RelationScope = "container"
)

// RelationRole defines the role of a relation.
type RelationRole string

const (
	RoleProvider RelationRole = "provider"
	RoleRequirer RelationRole = "requirer"
	RolePeer     RelationRole = "peer"
)

// Relation represents a single relation defined in the charm
// metadata.yaml file.
type Relation struct {
	Name      string
	Role      RelationRole
	Interface string
	Optional  bool
	Limit     int
	Scope     RelationScope
}

// ImplementedBy returns whether the relation is implemented by the supplied charm.
func (r Relation) ImplementedBy(ch Charm) bool {
	if r.IsImplicit() {
		return true
	}
	var m map[string]Relation
	switch r.Role {
	case RoleProvider:
		m = ch.Meta().Provides
	case RoleRequirer:
		m = ch.Meta().Requires
	case RolePeer:
		m = ch.Meta().Peers
	default:
		panic(fmt.Errorf("unknown relation role %q", r.Role))
	}
	rel, found := m[r.Name]
	if !found {
		return false
	}
	if rel.Interface == r.Interface {
		switch r.Scope {
		case ScopeGlobal:
			return rel.Scope != ScopeContainer
		case ScopeContainer:
			return true
		default:
			panic(fmt.Errorf("unknown relation scope %q", r.Scope))
		}
	}
	return false
}

// IsImplicit returns whether the relation is supplied by juju itself,
// rather than by a charm.
func (r Relation) IsImplicit() bool {
	return (r.Name == "juju-info" &&
		r.Interface == "juju-info" &&
		r.Role == RoleProvider)
}

// Meta represents all the known content that may be defined
// within a charm's metadata.yaml file.
type Meta struct {
	Name        string
	Summary     string
	Description string
	Subordinate bool
	Provides    map[string]Relation `bson:",omitempty"`
	Requires    map[string]Relation `bson:",omitempty"`
	Peers       map[string]Relation `bson:",omitempty"`
	Format      int                 `bson:",omitempty"`
	OldRevision int                 `bson:",omitempty"` // Obsolete
	Categories  []string            `bson:",omitempty"`
	Tags        []string            `bson:",omitempty"`
	Series      string              `bson:",omitempty"`
}

func generateRelationHooks(relName string, allHooks map[string]bool) {
	for _, hookName := range hooks.RelationHooks() {
		allHooks[fmt.Sprintf("%s-%s", relName, hookName)] = true
	}
}

// Hooks returns a map of all possible valid hooks, taking relations
// into account. It's a map to enable fast lookups, and the value is
// always true.
func (m Meta) Hooks() map[string]bool {
	allHooks := make(map[string]bool)
	// Unit hooks
	for _, hookName := range hooks.UnitHooks() {
		allHooks[string(hookName)] = true
	}
	// Relation hooks
	for hookName := range m.Provides {
		generateRelationHooks(hookName, allHooks)
	}
	for hookName := range m.Requires {
		generateRelationHooks(hookName, allHooks)
	}
	for hookName := range m.Peers {
		generateRelationHooks(hookName, allHooks)
	}
	return allHooks
}

func parseStringList(list interface{}) []string {
	if list == nil {
		return nil
	}
	slice := list.([]interface{})
	result := make([]string, 0, len(slice))
	for _, cat := range slice {
		result = append(result, cat.(string))
	}
	return result
}

func parseCategories(categories interface{}) []string {
	return parseStringList(categories)
}

func parseTags(tags interface{}) []string {
	return parseStringList(tags)
}

// ReadMeta reads the content of a metadata.yaml file and returns
// its representation.
func ReadMeta(r io.Reader) (meta *Meta, err error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}
	raw := make(map[interface{}]interface{})
	err = yaml.Unmarshal(data, raw)
	if err != nil {
		return
	}
	v, err := charmSchema.Coerce(raw, nil)
	if err != nil {
		return nil, errors.New("metadata: " + err.Error())
	}
	m := v.(map[string]interface{})
	meta = &Meta{}
	meta.Name = m["name"].(string)
	// Schema decodes as int64, but the int range should be good
	// enough for revisions.
	meta.Summary = m["summary"].(string)
	meta.Description = m["description"].(string)
	meta.Provides = parseRelations(m["provides"], RoleProvider)
	meta.Requires = parseRelations(m["requires"], RoleRequirer)
	meta.Peers = parseRelations(m["peers"], RolePeer)
	meta.Format = int(m["format"].(int64))
	meta.Categories = parseCategories(m["categories"])
	meta.Tags = parseTags(m["tags"])
	if subordinate := m["subordinate"]; subordinate != nil {
		meta.Subordinate = subordinate.(bool)
	}
	if rev := m["revision"]; rev != nil {
		// Obsolete
		meta.OldRevision = int(m["revision"].(int64))
	}
	if series, ok := m["series"]; ok && series != nil {
		meta.Series = series.(string)
	}
	if err := meta.Check(); err != nil {
		return nil, err
	}
	return meta, nil
}

// Check checks that the metadata is well-formed.
func (meta Meta) Check() error {
	// Check for duplicate or forbidden relation names or interfaces.
	names := map[string]bool{}
	checkRelations := func(src map[string]Relation, role RelationRole) error {
		for name, rel := range src {
			if rel.Name != name {
				return fmt.Errorf("charm %q has mismatched relation name %q; expected %q", meta.Name, rel.Name, name)
			}
			if rel.Role != role {
				return fmt.Errorf("charm %q has mismatched role %q; expected %q", meta.Name, rel.Role, role)
			}
			// Container-scoped require relations on subordinates are allowed
			// to use the otherwise-reserved juju-* namespace.
			if !meta.Subordinate || role != RoleRequirer || rel.Scope != ScopeContainer {
				if reservedName(name) {
					return fmt.Errorf("charm %q using a reserved relation name: %q", meta.Name, name)
				}
			}
			if role != RoleRequirer {
				if reservedName(rel.Interface) {
					return fmt.Errorf("charm %q relation %q using a reserved interface: %q", meta.Name, name, rel.Interface)
				}
			}
			if names[name] {
				return fmt.Errorf("charm %q using a duplicated relation name: %q", meta.Name, name)
			}
			names[name] = true
		}
		return nil
	}
	if err := checkRelations(meta.Provides, RoleProvider); err != nil {
		return err
	}
	if err := checkRelations(meta.Requires, RoleRequirer); err != nil {
		return err
	}
	if err := checkRelations(meta.Peers, RolePeer); err != nil {
		return err
	}

	// Subordinate charms must have at least one relation that
	// has container scope, otherwise they can't relate to the
	// principal.
	if meta.Subordinate {
		valid := false
		if meta.Requires != nil {
			for _, relationData := range meta.Requires {
				if relationData.Scope == ScopeContainer {
					valid = true
					break
				}
			}
		}
		if !valid {
			return fmt.Errorf("subordinate charm %q lacks \"requires\" relation with container scope", meta.Name)
		}
	}

	if meta.Series != "" {
		if !IsValidSeries(meta.Series) {
			return fmt.Errorf("charm %q declares invalid series: %q", meta.Name, meta.Series)
		}
	}

	return nil
}

func reservedName(name string) bool {
	return name == "juju" || strings.HasPrefix(name, "juju-")
}

func parseRelations(relations interface{}, role RelationRole) map[string]Relation {
	if relations == nil {
		return nil
	}
	result := make(map[string]Relation)
	for name, rel := range relations.(map[string]interface{}) {
		relMap := rel.(map[string]interface{})
		relation := Relation{
			Name:      name,
			Role:      role,
			Interface: relMap["interface"].(string),
			Optional:  relMap["optional"].(bool),
		}
		if scope := relMap["scope"]; scope != nil {
			relation.Scope = RelationScope(scope.(string))
		}
		if relMap["limit"] != nil {
			// Schema defaults to int64, but we know
			// the int range should be more than enough.
			relation.Limit = int(relMap["limit"].(int64))
		}
		result[name] = relation
	}
	return result
}

// Schema coercer that expands the interface shorthand notation.
// A consistent format is easier to work with than considering the
// potential difference everywhere.
//
// Supports the following variants::
//
//   provides:
//     server: riak
//     admin: http
//     foobar:
//       interface: blah
//
//   provides:
//     server:
//       interface: mysql
//       limit:
//       optional: false
//
// In all input cases, the output is the fully specified interface
// representation as seen in the mysql interface description above.
func ifaceExpander(limit interface{}) schema.Checker {
	return ifaceExpC{limit}
}

type ifaceExpC struct {
	limit interface{}
}

var (
	stringC = schema.String()
	mapC    = schema.StringMap(schema.Any())
)

func (c ifaceExpC) Coerce(v interface{}, path []string) (newv interface{}, err error) {
	s, err := stringC.Coerce(v, path)
	if err == nil {
		newv = map[string]interface{}{
			"interface": s,
			"limit":     c.limit,
			"optional":  false,
			"scope":     string(ScopeGlobal),
		}
		return
	}

	v, err = mapC.Coerce(v, path)
	if err != nil {
		return
	}
	m := v.(map[string]interface{})
	if _, ok := m["limit"]; !ok {
		m["limit"] = c.limit
	}
	return ifaceSchema.Coerce(m, path)
}

var ifaceSchema = schema.FieldMap(
	schema.Fields{
		"interface": schema.String(),
		"limit":     schema.OneOf(schema.Const(nil), schema.Int()),
		"scope":     schema.OneOf(schema.Const(string(ScopeGlobal)), schema.Const(string(ScopeContainer))),
		"optional":  schema.Bool(),
	},
	schema.Defaults{
		"scope":    string(ScopeGlobal),
		"optional": false,
	},
)

var charmSchema = schema.FieldMap(
	schema.Fields{
		"name":        schema.String(),
		"summary":     schema.String(),
		"description": schema.String(),
		"peers":       schema.StringMap(ifaceExpander(int64(1))),
		"provides":    schema.StringMap(ifaceExpander(nil)),
		"requires":    schema.StringMap(ifaceExpander(int64(1))),
		"revision":    schema.Int(), // Obsolete
		"format":      schema.Int(),
		"subordinate": schema.Bool(),
		"categories":  schema.List(schema.String()),
		"tags":        schema.List(schema.String()),
		"series":      schema.String(),
	},
	schema.Defaults{
		"provides":    schema.Omit,
		"requires":    schema.Omit,
		"peers":       schema.Omit,
		"revision":    schema.Omit,
		"format":      1,
		"subordinate": schema.Omit,
		"categories":  schema.Omit,
		"tags":        schema.Omit,
		"series":      schema.Omit,
	},
)
<|endoftext|>


<commit_before>package mgos

import (
	"fmt"
	"reflect"
	"strconv"
)

// Getter like url.Values
type Getter interface {
	Get(string) string
}

// FromGetter make strunct from value
func FromGetter(getter Getter, dest interface{}) error {

	switch dest.(type) {
	default:
		return fmt.Errorf("dest is not struct")
	case interface{}:
		elem := reflect.ValueOf(dest).Elem()

		for i := 0; i < elem.NumField(); i++ {
			field := elem.Field(i)
			typeField := elem.Type().Field(i)
			name := typeField.Tag.Get("mgos")
			if name == "" {
				continue
			}

			uv := getter.Get(name)

			switch field.Kind() {
			case reflect.Int8, reflect.Int, reflect.Int64:
				if i, err := strconv.Atoi(uv); err == nil {
					field.SetInt(int64(i))
				}
			case reflect.Uint8, reflect.Uint, reflect.Uint64:
				if i, err := strconv.Atoi(uv); err == nil {
					field.SetUint(uint64(i))
				}
			case reflect.String:
				field.SetString(uv)
			case reflect.Bool:
				if uv != "" && uv != "0" {
					field.SetBool(true)
				}
			default:
				panic(fmt.Sprintf("kind (%s) not supported", elem.Kind()))
			}

		}

	}

	return nil
}
<commit_msg>Add scanner interface.<commit_after>package mgos

import (
	"fmt"
	"reflect"
	"strconv"
)

// Getter like url.Values
type Getter interface {
	Get(string) string
}

type Scanner interface {
	Scan(interface{}) error
}

// FromGetter make strunct from value
func FromGetter(getter Getter, dest interface{}) error {

	switch dest.(type) {
	default:
		return fmt.Errorf("dest is not struct")
	case interface{}:
		elem := reflect.ValueOf(dest).Elem()

		for i := 0; i < elem.NumField(); i++ {
			field := elem.Field(i)
			typeField := elem.Type().Field(i)
			name := typeField.Tag.Get("mgos")
			if name == "" {
				continue
			}

			uv := getter.Get(name)

			switch field.Kind() {
			case reflect.Int8, reflect.Int, reflect.Int64:
				if i, err := strconv.Atoi(uv); err == nil {
					field.SetInt(int64(i))
				}
			case reflect.Uint8, reflect.Uint, reflect.Uint64:
				if i, err := strconv.Atoi(uv); err == nil {
					field.SetUint(uint64(i))
				}
			case reflect.String:
				field.SetString(uv)
			case reflect.Bool:
				if uv != "" && uv != "0" {
					field.SetBool(true)
				}
			case reflect.Struct:
				// i := field.Interface()
				// scanner, ok := i.(Scanner)
				// if !ok {
				// 	return fmt.Errorf("%s is not Scanner", )
				// }
			default:
				panic(fmt.Sprintf("kind (%s) not supported", elem.Kind()))
			}

		}

	}

	return nil
}
<|endoftext|>