<commit_before>/*
   Copyright 2020 Docker Compose CLI 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 compose

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"

	"github.com/cnabio/cnab-to-oci/remotes"
	"github.com/compose-spec/compose-go/cli"
	"github.com/distribution/distribution/v3/reference"
	cliconfig "github.com/docker/cli/cli/config"
	"github.com/opencontainers/go-digest"
	"github.com/spf13/cobra"

	"github.com/docker/compose-cli/pkg/api"
	"github.com/docker/compose-cli/pkg/compose"
)

type convertOptions struct {
	*projectOptions
	Format        string
	Output        string
	quiet         bool
	resolve       bool
	noInterpolate bool
	services      bool
	volumes       bool
	profiles      bool
	hash          string
}

var addFlagsFuncs []func(cmd *cobra.Command, opts *convertOptions)

func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := convertOptions{
		projectOptions: p,
	}
	cmd := &cobra.Command{
		Aliases: []string{"config"},
		Use:     "convert SERVICES",
		Short:   "Converts the compose file to platform's canonical format",
		PreRunE: Adapt(func(ctx context.Context, args []string) error {
			if opts.quiet {
				devnull, err := os.Open(os.DevNull)
				if err != nil {
					return err
				}
				os.Stdout = devnull
			}
			return nil
		}),
		RunE: Adapt(func(ctx context.Context, args []string) error {
			if opts.services {
				return runServices(opts)
			}
			if opts.volumes {
				return runVolumes(opts)
			}
			if opts.hash != "" {
				return runHash(opts)
			}
			if opts.profiles {
				return runProfiles(opts, args)
			}

			return runConvert(ctx, backend, opts, args)
		}),
	}
	flags := cmd.Flags()
	flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
	flags.BoolVar(&opts.resolve, "resolve-image-digests", false, "Pin image tags to digests.")
	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only validate the configuration, don't print anything.")
	flags.BoolVar(&opts.noInterpolate, "no-interpolate", false, "Don't interpolate environment variables.")

	flags.BoolVar(&opts.services, "services", false, "Print the service names, one per line.")
	flags.BoolVar(&opts.volumes, "volumes", false, "Print the volume names, one per line.")
	flags.BoolVar(&opts.profiles, "profiles", false, "Print the profile names, one per line.")
	flags.StringVar(&opts.hash, "hash", "", "Print the service config hash, one per line.")

	// add flags for hidden backends
	for _, f := range addFlagsFuncs {
		f(cmd, &opts)
	}
	return cmd
}

func runConvert(ctx context.Context, backend api.Service, opts convertOptions, services []string) error {
	var json []byte
	project, err := opts.toProject(services, cli.WithInterpolation(!opts.noInterpolate))
	if err != nil {
		return err
	}

	if opts.resolve {
		configFile := cliconfig.LoadDefaultConfigFile(os.Stderr)

		resolver := remotes.CreateResolver(configFile)
		err = project.ResolveImages(func(named reference.Named) (digest.Digest, error) {
			_, desc, err := resolver.Resolve(ctx, named.String())
			return desc.Digest, err
		})
		if err != nil {
			return err
		}
	}

	json, err = backend.Convert(ctx, project, api.ConvertOptions{
		Format: opts.Format,
		Output: opts.Output,
	})
	if err != nil {
		return err
	}

	if opts.quiet {
		return nil
	}

	var out io.Writer = os.Stdout
	if opts.Output != "" && len(json) > 0 {
		file, err := os.Create(opts.Output)
		if err != nil {
			return err
		}
		out = bufio.NewWriter(file)
	}
	_, err = fmt.Fprint(out, string(json))
	return err
}

func runServices(opts convertOptions) error {
	project, err := opts.toProject(nil)
	if err != nil {
		return err
	}
	for _, s := range project.Services {
		fmt.Println(s.Name)
	}
	return nil
}

func runVolumes(opts convertOptions) error {
	project, err := opts.toProject(nil)
	if err != nil {
		return err
	}
	for n := range project.Volumes {
		fmt.Println(n)
	}
	return nil
}

func runHash(opts convertOptions) error {
	var services []string
	if opts.hash != "*" {
		services = append(services, strings.Split(opts.hash, ",")...)
	}
	project, err := opts.toProject(services)
	if err != nil {
		return err
	}
	for _, s := range project.Services {
		hash, err := compose.ServiceHash(s)
		if err != nil {
			return err
		}
		fmt.Printf("%s %s\n", s.Name, hash)
	}
	return nil
}

func runProfiles(opts convertOptions, services []string) error {
	set := map[string]struct{}{}
	project, err := opts.toProject(services)
	if err != nil {
		return err
	}
	for _, s := range project.AllServices() {
		for _, p := range s.Profiles {
			set[p] = struct{}{}
		}
	}
	profiles := make([]string, 0, len(set))
	for p := range set {
		profiles = append(profiles, p)
	}
	sort.Strings(profiles)
	for _, p := range profiles {
		fmt.Println(p)
	}
	return nil
}
<commit_msg>Print services in dependency order<commit_after>/*
   Copyright 2020 Docker Compose CLI 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 compose

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"

	"github.com/cnabio/cnab-to-oci/remotes"
	"github.com/compose-spec/compose-go/cli"
	"github.com/compose-spec/compose-go/types"
	"github.com/distribution/distribution/v3/reference"
	cliconfig "github.com/docker/cli/cli/config"
	"github.com/opencontainers/go-digest"
	"github.com/spf13/cobra"

	"github.com/docker/compose-cli/pkg/api"
	"github.com/docker/compose-cli/pkg/compose"
)

type convertOptions struct {
	*projectOptions
	Format        string
	Output        string
	quiet         bool
	resolve       bool
	noInterpolate bool
	services      bool
	volumes       bool
	profiles      bool
	hash          string
}

var addFlagsFuncs []func(cmd *cobra.Command, opts *convertOptions)

func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
	opts := convertOptions{
		projectOptions: p,
	}
	cmd := &cobra.Command{
		Aliases: []string{"config"},
		Use:     "convert SERVICES",
		Short:   "Converts the compose file to platform's canonical format",
		PreRunE: Adapt(func(ctx context.Context, args []string) error {
			if opts.quiet {
				devnull, err := os.Open(os.DevNull)
				if err != nil {
					return err
				}
				os.Stdout = devnull
			}
			return nil
		}),
		RunE: Adapt(func(ctx context.Context, args []string) error {
			if opts.services {
				return runServices(opts)
			}
			if opts.volumes {
				return runVolumes(opts)
			}
			if opts.hash != "" {
				return runHash(opts)
			}
			if opts.profiles {
				return runProfiles(opts, args)
			}

			return runConvert(ctx, backend, opts, args)
		}),
	}
	flags := cmd.Flags()
	flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
	flags.BoolVar(&opts.resolve, "resolve-image-digests", false, "Pin image tags to digests.")
	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only validate the configuration, don't print anything.")
	flags.BoolVar(&opts.noInterpolate, "no-interpolate", false, "Don't interpolate environment variables.")

	flags.BoolVar(&opts.services, "services", false, "Print the service names, one per line.")
	flags.BoolVar(&opts.volumes, "volumes", false, "Print the volume names, one per line.")
	flags.BoolVar(&opts.profiles, "profiles", false, "Print the profile names, one per line.")
	flags.StringVar(&opts.hash, "hash", "", "Print the service config hash, one per line.")

	// add flags for hidden backends
	for _, f := range addFlagsFuncs {
		f(cmd, &opts)
	}
	return cmd
}

func runConvert(ctx context.Context, backend api.Service, opts convertOptions, services []string) error {
	var json []byte
	project, err := opts.toProject(services, cli.WithInterpolation(!opts.noInterpolate))
	if err != nil {
		return err
	}

	if opts.resolve {
		configFile := cliconfig.LoadDefaultConfigFile(os.Stderr)

		resolver := remotes.CreateResolver(configFile)
		err = project.ResolveImages(func(named reference.Named) (digest.Digest, error) {
			_, desc, err := resolver.Resolve(ctx, named.String())
			return desc.Digest, err
		})
		if err != nil {
			return err
		}
	}

	json, err = backend.Convert(ctx, project, api.ConvertOptions{
		Format: opts.Format,
		Output: opts.Output,
	})
	if err != nil {
		return err
	}

	if opts.quiet {
		return nil
	}

	var out io.Writer = os.Stdout
	if opts.Output != "" && len(json) > 0 {
		file, err := os.Create(opts.Output)
		if err != nil {
			return err
		}
		out = bufio.NewWriter(file)
	}
	_, err = fmt.Fprint(out, string(json))
	return err
}

func runServices(opts convertOptions) error {
	project, err := opts.toProject(nil)
	if err != nil {
		return err
	}
	return project.WithServices(project.ServiceNames(), func(s types.ServiceConfig) error {
		fmt.Println(s.Name)
		return nil
	})
}

func runVolumes(opts convertOptions) error {
	project, err := opts.toProject(nil)
	if err != nil {
		return err
	}
	for n := range project.Volumes {
		fmt.Println(n)
	}
	return nil
}

func runHash(opts convertOptions) error {
	var services []string
	if opts.hash != "*" {
		services = append(services, strings.Split(opts.hash, ",")...)
	}
	project, err := opts.toProject(services)
	if err != nil {
		return err
	}
	for _, s := range project.Services {
		hash, err := compose.ServiceHash(s)
		if err != nil {
			return err
		}
		fmt.Printf("%s %s\n", s.Name, hash)
	}
	return nil
}

func runProfiles(opts convertOptions, services []string) error {
	set := map[string]struct{}{}
	project, err := opts.toProject(services)
	if err != nil {
		return err
	}
	for _, s := range project.AllServices() {
		for _, p := range s.Profiles {
			set[p] = struct{}{}
		}
	}
	profiles := make([]string, 0, len(set))
	for p := range set {
		profiles = append(profiles, p)
	}
	sort.Strings(profiles)
	for _, p := range profiles {
		fmt.Println(p)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Tekton 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 (
	"flag"
	"log"
	"net/http"
	"os"

	"github.com/tektoncd/pipeline/pkg/apis/pipeline"
	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
	"github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun"
	"github.com/tektoncd/pipeline/pkg/reconciler/taskrun"
	"github.com/tektoncd/pipeline/pkg/version"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/client-go/rest"
	filteredinformerfactory "knative.dev/pkg/client/injection/kube/informers/factory/filtered"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/injection"
	"knative.dev/pkg/injection/sharedmain"
	"knative.dev/pkg/signals"
)

const (
	// ControllerLogKey is the name of the logger for the controller cmd
	ControllerLogKey = "tekton"
)

var (
	entrypointImage          = flag.String("entrypoint-image", "", "The container image containing our entrypoint binary.")
	nopImage                 = flag.String("nop-image", "", "The container image used to stop sidecars")
	gitImage                 = flag.String("git-image", "", "The container image containing our Git binary.")
	kubeconfigWriterImage    = flag.String("kubeconfig-writer-image", "", "The container image containing our kubeconfig writer binary.")
	shellImage               = flag.String("shell-image", "", "The container image containing a shell")
	gsutilImage              = flag.String("gsutil-image", "", "The container image containing gsutil")
	buildGCSFetcherImage     = flag.String("build-gcs-fetcher-image", "", "The container image containing our GCS fetcher binary.")
	prImage                  = flag.String("pr-image", "", "The container image containing our PR binary.")
	imageDigestExporterImage = flag.String("imagedigest-exporter-image", "", "The container image containing our image digest exporter binary.")
	namespace                = flag.String("namespace", corev1.NamespaceAll, "Namespace to restrict informer to. Optional, defaults to all namespaces.")
	versionGiven             = flag.String("version", "devel", "Version of Tekton running")
	threadsPerController     = flag.Int("threads-per-controller", controller.DefaultThreadsPerController, "Threads (goroutines) to create per controller")
	disableHighAvailability  = flag.Bool("disable-ha", false, "Whether to disable high-availability functionality for this component.  This flag will be deprecated "+
		"and removed when we have promoted this feature to stable, so do not pass it without filing an "+
		"issue upstream!")
)

func main() {
	cfg := sharedmain.ParseAndGetConfigOrDie()
	controller.DefaultThreadsPerController = *threadsPerController
	version.SetVersion(*versionGiven)
	images := pipeline.Images{
		EntrypointImage:          *entrypointImage,
		NopImage:                 *nopImage,
		GitImage:                 *gitImage,
		KubeconfigWriterImage:    *kubeconfigWriterImage,
		ShellImage:               *shellImage,
		GsutilImage:              *gsutilImage,
		BuildGCSFetcherImage:     *buildGCSFetcherImage,
		PRImage:                  *prImage,
		ImageDigestExporterImage: *imageDigestExporterImage,
	}
	if err := images.Validate(); err != nil {
		log.Fatal(err)
	}
	if cfg.QPS == 0 {
		cfg.QPS = 2 * rest.DefaultQPS
	}
	if cfg.Burst == 0 {
		cfg.Burst = rest.DefaultBurst
	}
	// FIXME(vdemeester): this is here to not break current behavior
	// multiply by 2, no of controllers being created
	cfg.QPS = 2 * cfg.QPS
	cfg.Burst = 2 * cfg.Burst

	ctx := injection.WithNamespaceScope(signals.NewContext(), *namespace)
	if *disableHighAvailability {
		ctx = sharedmain.WithHADisabled(ctx)
	}

	// sets up liveness and readiness probes.
	mux := http.NewServeMux()

	mux.HandleFunc("/", handler)
	mux.HandleFunc("/health", handler)
	mux.HandleFunc("/readiness", handler)

	port := os.Getenv("PROBES_PORT")
	if port == "" {
		port = "8080"
	}

	go func() {
		// start the web server on port and accept requests
		log.Printf("Readiness and health check server listening on port %s", port)
		log.Fatal(http.ListenAndServe(":"+port, mux))
	}()

	ctx = filteredinformerfactory.WithSelectors(ctx, v1beta1.ManagedByLabelKey)
	sharedmain.MainWithConfig(ctx, ControllerLogKey, cfg,
		taskrun.NewController(*namespace, images),
		pipelinerun.NewController(*namespace, images),
	)
}

func handler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}
<commit_msg>tekton controller name in the logger<commit_after>/*
Copyright 2019 The Tekton 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 (
	"flag"
	"log"
	"net/http"
	"os"

	"github.com/tektoncd/pipeline/pkg/apis/pipeline"
	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
	"github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun"
	"github.com/tektoncd/pipeline/pkg/reconciler/taskrun"
	"github.com/tektoncd/pipeline/pkg/version"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/client-go/rest"
	filteredinformerfactory "knative.dev/pkg/client/injection/kube/informers/factory/filtered"
	"knative.dev/pkg/controller"
	"knative.dev/pkg/injection"
	"knative.dev/pkg/injection/sharedmain"
	"knative.dev/pkg/signals"
)

const (
	// ControllerLogKey is the name of the logger for the controller cmd
	ControllerLogKey = "tekton-pipelines-controller"
)

var (
	entrypointImage          = flag.String("entrypoint-image", "", "The container image containing our entrypoint binary.")
	nopImage                 = flag.String("nop-image", "", "The container image used to stop sidecars")
	gitImage                 = flag.String("git-image", "", "The container image containing our Git binary.")
	kubeconfigWriterImage    = flag.String("kubeconfig-writer-image", "", "The container image containing our kubeconfig writer binary.")
	shellImage               = flag.String("shell-image", "", "The container image containing a shell")
	gsutilImage              = flag.String("gsutil-image", "", "The container image containing gsutil")
	buildGCSFetcherImage     = flag.String("build-gcs-fetcher-image", "", "The container image containing our GCS fetcher binary.")
	prImage                  = flag.String("pr-image", "", "The container image containing our PR binary.")
	imageDigestExporterImage = flag.String("imagedigest-exporter-image", "", "The container image containing our image digest exporter binary.")
	namespace                = flag.String("namespace", corev1.NamespaceAll, "Namespace to restrict informer to. Optional, defaults to all namespaces.")
	versionGiven             = flag.String("version", "devel", "Version of Tekton running")
	threadsPerController     = flag.Int("threads-per-controller", controller.DefaultThreadsPerController, "Threads (goroutines) to create per controller")
	disableHighAvailability  = flag.Bool("disable-ha", false, "Whether to disable high-availability functionality for this component.  This flag will be deprecated "+
		"and removed when we have promoted this feature to stable, so do not pass it without filing an "+
		"issue upstream!")
)

func main() {
	cfg := sharedmain.ParseAndGetConfigOrDie()
	controller.DefaultThreadsPerController = *threadsPerController
	version.SetVersion(*versionGiven)
	images := pipeline.Images{
		EntrypointImage:          *entrypointImage,
		NopImage:                 *nopImage,
		GitImage:                 *gitImage,
		KubeconfigWriterImage:    *kubeconfigWriterImage,
		ShellImage:               *shellImage,
		GsutilImage:              *gsutilImage,
		BuildGCSFetcherImage:     *buildGCSFetcherImage,
		PRImage:                  *prImage,
		ImageDigestExporterImage: *imageDigestExporterImage,
	}
	if err := images.Validate(); err != nil {
		log.Fatal(err)
	}
	if cfg.QPS == 0 {
		cfg.QPS = 2 * rest.DefaultQPS
	}
	if cfg.Burst == 0 {
		cfg.Burst = rest.DefaultBurst
	}
	// FIXME(vdemeester): this is here to not break current behavior
	// multiply by 2, no of controllers being created
	cfg.QPS = 2 * cfg.QPS
	cfg.Burst = 2 * cfg.Burst

	ctx := injection.WithNamespaceScope(signals.NewContext(), *namespace)
	if *disableHighAvailability {
		ctx = sharedmain.WithHADisabled(ctx)
	}

	// sets up liveness and readiness probes.
	mux := http.NewServeMux()

	mux.HandleFunc("/", handler)
	mux.HandleFunc("/health", handler)
	mux.HandleFunc("/readiness", handler)

	port := os.Getenv("PROBES_PORT")
	if port == "" {
		port = "8080"
	}

	go func() {
		// start the web server on port and accept requests
		log.Printf("Readiness and health check server listening on port %s", port)
		log.Fatal(http.ListenAndServe(":"+port, mux))
	}()

	ctx = filteredinformerfactory.WithSelectors(ctx, v1beta1.ManagedByLabelKey)
	sharedmain.MainWithConfig(ctx, ControllerLogKey, cfg,
		taskrun.NewController(*namespace, images),
		pipelinerun.NewController(*namespace, images),
	)
}

func handler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/Azure/azure-docker-extension/pkg/driver"
	"github.com/Azure/azure-docker-extension/pkg/executil"
	"github.com/Azure/azure-docker-extension/pkg/util"
	"github.com/Azure/azure-docker-extension/pkg/vmextension"

	yaml "github.com/cloudfoundry-incubator/candiedyaml"
)

const (
	composeUrl         = "https://github.com/docker/compose/releases/download/1.6.2/docker-compose-Linux-x86_64"
	composeBin         = "docker-compose"
	composeTimeoutSecs = 600

	composeYml     = "docker-compose.yml"
	composeYmlDir  = "/etc/docker/compose"
	composeProject = "compose" // prefix for compose-created containers

	dockerCfgDir  = "/etc/docker"
	dockerCaCert  = "ca.pem"
	dockerSrvCert = "cert.pem"
	dockerSrvKey  = "key.pem"
)

func enable(he vmextension.HandlerEnvironment, d driver.DistroDriver) error {
	// Install docker daemon
	log.Printf("++ install docker")
	if _, err := exec.LookPath("docker"); err == nil {
		log.Printf("docker already installed. not re-installing")
	} else {
		// TODO(ahmetb) Temporary retry logic around installation for serialization
		// problem in Azure VM Scale Sets. In case of scale-up event, the new VM with
		// multiple extensions (such as Linux Diagnostics and Docker Extension) will install
		// the extensions in parallel and that will result in non-deterministic
		// acquisition of dpkg lock (apt-get install) and thus causing one of the
		// extensions to fail.
		//
		// Adding this temporary retry logic just for Linux Diagnostics extension
		// assuming it will take at most 5 minutes to be done with apt-get lock.
		//
		// This retry logic should be removed once the issue is fixed on the resource
		// provider layer.

		var (
			nRetries      = 6
			retryInterval = time.Minute * 1
		)

		for nRetries > 0 {
			if err := d.InstallDocker(); err != nil {
				nRetries--
				if nRetries == 0 {
					return err
				}
				log.Printf("install failed. remaining attempts=%d. error=%v", nRetries, err)
				log.Printf("sleeping %s", retryInterval)
				time.Sleep(retryInterval)
			} else {
				break
			}
		}
	}
	log.Printf("-- install docker")

	// Install docker-compose
	log.Printf("++ install docker-compose")
	if err := installCompose(composeBinPath(d)); err != nil {
		return fmt.Errorf("error installing docker-compose: %v", err)
	}
	log.Printf("-- install docker-compose")

	// Add user to 'docker' group to user docker as non-root
	u, err := util.GetAzureUser()
	if err != nil {
		return fmt.Errorf("failed to get provisioned user: %v", err)
	}
	log.Printf("++ add user to docker group")
	if out, err := executil.Exec("usermod", "-aG", "docker", u); err != nil {
		log.Printf("%s", string(out))
		return err
	}
	log.Printf("-- add user to docker group")

	settings, err := parseSettings(he.HandlerEnvironment.ConfigFolder)
	if err != nil {
		return err
	}

	// Install docker remote access certs
	log.Printf("++ setup docker certs")
	if err := installDockerCerts(*settings, dockerCfgDir); err != nil {
		return fmt.Errorf("error installing docker certs: %v", err)
	}
	log.Printf("-- setup docker certs")

	// Update dockeropts
	log.Printf("++ update dockeropts")
	restartNeeded, err := updateDockerOpts(d, getArgs(*settings, d))
	if err != nil {
		return fmt.Errorf("failed to update dockeropts: %v", err)
	}
	log.Printf("restart needed: %v", restartNeeded)
	log.Printf("-- update dockeropts")

	// Restart docker
	log.Printf("++ restart docker")
	if !restartNeeded {
		log.Printf("no restart needed. issuing only a start command.")
		_ = d.StartDocker() // ignore error as it already may be running due to multiple calls to enable
	} else {
		log.Printf("restarting docker-engine")
		if err := d.RestartDocker(); err != nil {
			return err
		}
	}
	time.Sleep(3 * time.Second) // wait for instance to come up
	log.Printf("-- restart docker")

	// Login Docker registry server
	log.Printf("++ login docker registry")
	if err := loginRegistry(settings.Login); err != nil {
		return err
	}
	log.Printf("-- login docker registry")

	// Compose Up
	log.Printf("++ compose up")
	if err := composeUp(d, settings.ComposeJson, settings.Environment); err != nil {
		return fmt.Errorf("'compose up' failed: %v", err)
	}
	log.Printf("-- compose up")
	return nil
}

// installCompose download docker-compose and saves to the specified path if it
// is not already installed.
func installCompose(path string) error {
	// Check if already installed at path.
	if ok, err := util.PathExists(path); err != nil {
		return err
	} else if ok {
		log.Printf("docker-compose is already installed at %s", path)
		return nil
	}

	// Create dir if not exists
	dir := filepath.Dir(path)
	ok, err := util.PathExists(dir)
	if err != nil {
		return err
	} else if !ok {
		if err := os.MkdirAll(dir, 755); err != nil {
			return err
		}
	}

	log.Printf("Downloading compose from %s", composeUrl)
	resp, err := http.Get(composeUrl)
	if err != nil {
		return fmt.Errorf("error downloading docker-compose: %v", err)
	}
	if resp.StatusCode/100 != 2 {
		return fmt.Errorf("response status code from %s: %s", composeUrl, resp.Status)
	}
	defer resp.Body.Close()

	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0777)
	if err != nil {
		return fmt.Errorf("error creating %s: %v", path, err)
	}

	defer f.Close()
	if _, err := io.Copy(f, resp.Body); err != nil {
		return fmt.Errorf("failed to save response body to %s: %v", path, err)
	}
	return nil
}

// loginRegistry calls the `docker login` command to authenticate the engine to the
// specified registry with given credentials.
func loginRegistry(s dockerLoginSettings) error {
	if !s.HasLoginInfo() {
		log.Println("registry login not specificied")
		return nil
	}
	opts := []string{
		"login",
		"--email=" + s.Email,
		"--username=" + s.Username,
		"--password=" + s.Password,
	}
	if s.Server != "" {
		opts = append(opts, s.Server)
	}
	_, err := executil.Exec("docker", opts...)
	if err != nil {
		return errors.New("'docker login' failed")
	}
	return nil
}

// composeBinPath returns the path docker-compose binary should be installed at
// on the host operating system.
func composeBinPath(d driver.DistroDriver) string {
	return filepath.Join(d.DockerComposeDir(), composeBin)
}

// composeUp converts given json to yaml, saves to a file on the host and
// uses `docker-compose up -d` to create the containers.
func composeUp(d driver.DistroDriver, json map[string]interface{}, env map[string]string) error {
	if len(json) == 0 {
		log.Println("docker-compose config not specified, noop")
		return nil
	}

	// Convert json to yaml
	yaml, err := yaml.Marshal(json)
	if err != nil {
		return fmt.Errorf("error converting to compose.yml: %v", err)
	}

	if err := os.MkdirAll(composeYmlDir, 0777); err != nil {
		return fmt.Errorf("failed creating %s: %v", composeYmlDir, err)
	}
	log.Printf("Using compose yaml:>>>>>\n%s\n<<<<<", string(yaml))
	ymlPath := filepath.Join(composeYmlDir, composeYml)
	if err := ioutil.WriteFile(ymlPath, yaml, 0666); err != nil {
		return fmt.Errorf("error writing %s: %v", ymlPath, err)
	}

	// set timeout for docker-compose -> docker-engine interactions.
	// When downloading large images, docker-compose intermittently times out
	// (gh#docker/compose/issues/2186).
	os.Setenv("COMPOSE_HTTP_TIMEOUT", fmt.Sprintf("%d", composeTimeoutSecs))  // versions <= 1.4.2
	os.Setenv("DOCKER_CLIENT_TIMEOUT", fmt.Sprintf("%d", composeTimeoutSecs)) // version  >= 1.5.0
	defer os.Unsetenv("COMPOSE_HTTP_TIMEOUT")
	defer os.Unsetenv("DOCKER_CLIENT_TIMEOUT")

	// set protected environment variables to be used in docker-compose
	for k, v := range env {
		log.Printf("Setting protected environment variable '%s'.", k)
		os.Setenv(k, v)
		defer os.Unsetenv(k)
	}

	return executil.ExecPipeToFds(executil.Fds{Out: ioutil.Discard}, composeBinPath(d), "-p", composeProject, "-f", ymlPath, "up", "-d")
}

// installDockerCerts saves the configured certs to the specified dir
// if and only if the certs are not already placed there. If no certs
// are provided  or some certs already exist, nothing is written.
func installDockerCerts(s DockerHandlerSettings, dstDir string) error {
	m := []struct {
		src string
		dst string
	}{
		{s.Certs.CABase64, filepath.Join(dstDir, dockerCaCert)},
		{s.Certs.ServerCertBase64, filepath.Join(dstDir, dockerSrvCert)},
		{s.Certs.ServerKeyBase64, filepath.Join(dstDir, dockerSrvKey)},
	}

	// Check if certs are provided
	for _, v := range m {
		if len(v.src) == 0 {
			log.Printf("Docker certificate %s is not provided in the extension settings, skipping docker certs installation", v.dst)
			return nil
		}
	}

	// Check the target directory, if not create
	if ok, err := util.PathExists(dstDir); err != nil {
		return fmt.Errorf("error checking cert dir: %v", err)
	} else if !ok {
		if err := os.MkdirAll(dstDir, 0755); err != nil {
			return err
		}
	}

	// Write the certs
	for _, v := range m {
		// Decode base64
		in := strings.TrimSpace(v.src)
		f, err := base64.StdEncoding.DecodeString(in)
		if err != nil {
			// Fallback to original file input
			f = []byte(in)
		}

		if err := ioutil.WriteFile(v.dst, f, 0600); err != nil {
			return fmt.Errorf("error writing certificate: %v", err)
		}
	}
	return nil
}

func updateDockerOpts(dd driver.DistroDriver, args string) (bool, error) {
	log.Printf("Updating daemon args to: %s", args)
	restartNeeded, err := dd.UpdateDockerArgs(args)
	if err != nil {
		return false, fmt.Errorf("error updating DOCKER_OPTS: %v", err)
	}
	return restartNeeded, nil
}

// getArgs provides set of arguments that should be used in updating Docker
// daemon options based on the distro.
func getArgs(s DockerHandlerSettings, dd driver.DistroDriver) string {
	args := dd.BaseOpts()

	if s.Certs.HasDockerCerts() {
		tls := []string{"--tlsverify",
			fmt.Sprintf("--tlscacert=%s", filepath.Join(dockerCfgDir, dockerCaCert)),
			fmt.Sprintf("--tlscert=%s", filepath.Join(dockerCfgDir, dockerSrvCert)),
			fmt.Sprintf("--tlskey=%s", filepath.Join(dockerCfgDir, dockerSrvKey)),
		}
		args = append(args, tls...)
	}

	if s.Docker.Port != "" {
		args = append(args, fmt.Sprintf("-H=0.0.0.0:%s", s.Docker.Port))
	}

	if len(s.Docker.Options) > 0 {
		args = append(args, s.Docker.Options...)
	}

	return strings.Join(args, " ")
}
<commit_msg>Better error message for compose failures<commit_after>package main

import (
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/Azure/azure-docker-extension/pkg/driver"
	"github.com/Azure/azure-docker-extension/pkg/executil"
	"github.com/Azure/azure-docker-extension/pkg/util"
	"github.com/Azure/azure-docker-extension/pkg/vmextension"

	yaml "github.com/cloudfoundry-incubator/candiedyaml"
)

const (
	composeUrl         = "https://github.com/docker/compose/releases/download/1.6.2/docker-compose-Linux-x86_64"
	composeBin         = "docker-compose"
	composeTimeoutSecs = 600

	composeYml     = "docker-compose.yml"
	composeYmlDir  = "/etc/docker/compose"
	composeProject = "compose" // prefix for compose-created containers

	dockerCfgDir  = "/etc/docker"
	dockerCaCert  = "ca.pem"
	dockerSrvCert = "cert.pem"
	dockerSrvKey  = "key.pem"
)

func enable(he vmextension.HandlerEnvironment, d driver.DistroDriver) error {
	// Install docker daemon
	log.Printf("++ install docker")
	if _, err := exec.LookPath("docker"); err == nil {
		log.Printf("docker already installed. not re-installing")
	} else {
		// TODO(ahmetb) Temporary retry logic around installation for serialization
		// problem in Azure VM Scale Sets. In case of scale-up event, the new VM with
		// multiple extensions (such as Linux Diagnostics and Docker Extension) will install
		// the extensions in parallel and that will result in non-deterministic
		// acquisition of dpkg lock (apt-get install) and thus causing one of the
		// extensions to fail.
		//
		// Adding this temporary retry logic just for Linux Diagnostics extension
		// assuming it will take at most 5 minutes to be done with apt-get lock.
		//
		// This retry logic should be removed once the issue is fixed on the resource
		// provider layer.

		var (
			nRetries      = 6
			retryInterval = time.Minute * 1
		)

		for nRetries > 0 {
			if err := d.InstallDocker(); err != nil {
				nRetries--
				if nRetries == 0 {
					return err
				}
				log.Printf("install failed. remaining attempts=%d. error=%v", nRetries, err)
				log.Printf("sleeping %s", retryInterval)
				time.Sleep(retryInterval)
			} else {
				break
			}
		}
	}
	log.Printf("-- install docker")

	// Install docker-compose
	log.Printf("++ install docker-compose")
	if err := installCompose(composeBinPath(d)); err != nil {
		return fmt.Errorf("error installing docker-compose: %v", err)
	}
	log.Printf("-- install docker-compose")

	// Add user to 'docker' group to user docker as non-root
	u, err := util.GetAzureUser()
	if err != nil {
		return fmt.Errorf("failed to get provisioned user: %v", err)
	}
	log.Printf("++ add user to docker group")
	if out, err := executil.Exec("usermod", "-aG", "docker", u); err != nil {
		log.Printf("%s", string(out))
		return err
	}
	log.Printf("-- add user to docker group")

	settings, err := parseSettings(he.HandlerEnvironment.ConfigFolder)
	if err != nil {
		return err
	}

	// Install docker remote access certs
	log.Printf("++ setup docker certs")
	if err := installDockerCerts(*settings, dockerCfgDir); err != nil {
		return fmt.Errorf("error installing docker certs: %v", err)
	}
	log.Printf("-- setup docker certs")

	// Update dockeropts
	log.Printf("++ update dockeropts")
	restartNeeded, err := updateDockerOpts(d, getArgs(*settings, d))
	if err != nil {
		return fmt.Errorf("failed to update dockeropts: %v", err)
	}
	log.Printf("restart needed: %v", restartNeeded)
	log.Printf("-- update dockeropts")

	// Restart docker
	log.Printf("++ restart docker")
	if !restartNeeded {
		log.Printf("no restart needed. issuing only a start command.")
		_ = d.StartDocker() // ignore error as it already may be running due to multiple calls to enable
	} else {
		log.Printf("restarting docker-engine")
		if err := d.RestartDocker(); err != nil {
			return err
		}
	}
	time.Sleep(3 * time.Second) // wait for instance to come up
	log.Printf("-- restart docker")

	// Login Docker registry server
	log.Printf("++ login docker registry")
	if err := loginRegistry(settings.Login); err != nil {
		return err
	}
	log.Printf("-- login docker registry")

	// Compose Up
	log.Printf("++ compose up")
	if err := composeUp(d, settings.ComposeJson, settings.ComposeEnv, settings.ComposeProtectedEnv); err != nil {
		return fmt.Errorf("'docker-compose up' failed: %v. Check logs at %s.", err, filepath.Join(he.HandlerEnvironment.LogFolder, LogFilename))
	}
	log.Printf("-- compose up")
	return nil
}

// installCompose download docker-compose and saves to the specified path if it
// is not already installed.
func installCompose(path string) error {
	// Check if already installed at path.
	if ok, err := util.PathExists(path); err != nil {
		return err
	} else if ok {
		log.Printf("docker-compose is already installed at %s", path)
		return nil
	}

	// Create dir if not exists
	dir := filepath.Dir(path)
	ok, err := util.PathExists(dir)
	if err != nil {
		return err
	} else if !ok {
		if err := os.MkdirAll(dir, 755); err != nil {
			return err
		}
	}

	log.Printf("Downloading compose from %s", composeUrl)
	resp, err := http.Get(composeUrl)
	if err != nil {
		return fmt.Errorf("error downloading docker-compose: %v", err)
	}
	if resp.StatusCode/100 != 2 {
		return fmt.Errorf("response status code from %s: %s", composeUrl, resp.Status)
	}
	defer resp.Body.Close()

	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0777)
	if err != nil {
		return fmt.Errorf("error creating %s: %v", path, err)
	}

	defer f.Close()
	if _, err := io.Copy(f, resp.Body); err != nil {
		return fmt.Errorf("failed to save response body to %s: %v", path, err)
	}
	return nil
}

// loginRegistry calls the `docker login` command to authenticate the engine to the
// specified registry with given credentials.
func loginRegistry(s dockerLoginSettings) error {
	if !s.HasLoginInfo() {
		log.Println("registry login not specificied")
		return nil
	}
	opts := []string{
		"login",
		"--email=" + s.Email,
		"--username=" + s.Username,
		"--password=" + s.Password,
	}
	if s.Server != "" {
		opts = append(opts, s.Server)
	}
	_, err := executil.Exec("docker", opts...)
	if err != nil {
		return errors.New("'docker login' failed")
	}
	return nil
}

// composeBinPath returns the path docker-compose binary should be installed at
// on the host operating system.
func composeBinPath(d driver.DistroDriver) string {
	return filepath.Join(d.DockerComposeDir(), composeBin)
}

// composeUp converts given json to yaml, saves to a file on the host and
// uses `docker-compose up -d` to create the containers.
func composeUp(d driver.DistroDriver, json map[string]interface{}, env map[string]string) error {
	if len(json) == 0 {
		log.Println("docker-compose config not specified, noop")
		return nil
	}

	// Convert json to yaml
	yaml, err := yaml.Marshal(json)
	if err != nil {
		return fmt.Errorf("error converting to compose.yml: %v", err)
	}

	if err := os.MkdirAll(composeYmlDir, 0777); err != nil {
		return fmt.Errorf("failed creating %s: %v", composeYmlDir, err)
	}
	log.Printf("Using compose yaml:>>>>>\n%s\n<<<<<", string(yaml))
	ymlPath := filepath.Join(composeYmlDir, composeYml)
	if err := ioutil.WriteFile(ymlPath, yaml, 0666); err != nil {
		return fmt.Errorf("error writing %s: %v", ymlPath, err)
	}

	// set timeout for docker-compose -> docker-engine interactions.
	// When downloading large images, docker-compose intermittently times out
	// (gh#docker/compose/issues/2186).
	os.Setenv("COMPOSE_HTTP_TIMEOUT", fmt.Sprintf("%d", composeTimeoutSecs))  // versions <= 1.4.2
	os.Setenv("DOCKER_CLIENT_TIMEOUT", fmt.Sprintf("%d", composeTimeoutSecs)) // version  >= 1.5.0
	defer os.Unsetenv("COMPOSE_HTTP_TIMEOUT")
	defer os.Unsetenv("DOCKER_CLIENT_TIMEOUT")

	// set protected environment variables to be used in docker-compose
	for k, v := range env {
		log.Printf("Setting protected environment variable '%s'.", k)
		os.Setenv(k, v)
		defer os.Unsetenv(k)
	}

	return executil.ExecPipeToFds(executil.Fds{Out: ioutil.Discard}, composeBinPath(d), "-p", composeProject, "-f", ymlPath, "up", "-d")
}

// installDockerCerts saves the configured certs to the specified dir
// if and only if the certs are not already placed there. If no certs
// are provided  or some certs already exist, nothing is written.
func installDockerCerts(s DockerHandlerSettings, dstDir string) error {
	m := []struct {
		src string
		dst string
	}{
		{s.Certs.CABase64, filepath.Join(dstDir, dockerCaCert)},
		{s.Certs.ServerCertBase64, filepath.Join(dstDir, dockerSrvCert)},
		{s.Certs.ServerKeyBase64, filepath.Join(dstDir, dockerSrvKey)},
	}

	// Check if certs are provided
	for _, v := range m {
		if len(v.src) == 0 {
			log.Printf("Docker certificate %s is not provided in the extension settings, skipping docker certs installation", v.dst)
			return nil
		}
	}

	// Check the target directory, if not create
	if ok, err := util.PathExists(dstDir); err != nil {
		return fmt.Errorf("error checking cert dir: %v", err)
	} else if !ok {
		if err := os.MkdirAll(dstDir, 0755); err != nil {
			return err
		}
	}

	// Write the certs
	for _, v := range m {
		// Decode base64
		in := strings.TrimSpace(v.src)
		f, err := base64.StdEncoding.DecodeString(in)
		if err != nil {
			// Fallback to original file input
			f = []byte(in)
		}

		if err := ioutil.WriteFile(v.dst, f, 0600); err != nil {
			return fmt.Errorf("error writing certificate: %v", err)
		}
	}
	return nil
}

func updateDockerOpts(dd driver.DistroDriver, args string) (bool, error) {
	log.Printf("Updating daemon args to: %s", args)
	restartNeeded, err := dd.UpdateDockerArgs(args)
	if err != nil {
		return false, fmt.Errorf("error updating DOCKER_OPTS: %v", err)
	}
	return restartNeeded, nil
}

// getArgs provides set of arguments that should be used in updating Docker
// daemon options based on the distro.
func getArgs(s DockerHandlerSettings, dd driver.DistroDriver) string {
	args := dd.BaseOpts()

	if s.Certs.HasDockerCerts() {
		tls := []string{"--tlsverify",
			fmt.Sprintf("--tlscacert=%s", filepath.Join(dockerCfgDir, dockerCaCert)),
			fmt.Sprintf("--tlscert=%s", filepath.Join(dockerCfgDir, dockerSrvCert)),
			fmt.Sprintf("--tlskey=%s", filepath.Join(dockerCfgDir, dockerSrvKey)),
		}
		args = append(args, tls...)
	}

	if s.Docker.Port != "" {
		args = append(args, fmt.Sprintf("-H=0.0.0.0:%s", s.Docker.Port))
	}

	if len(s.Docker.Options) > 0 {
		args = append(args, s.Docker.Options...)
	}

	return strings.Join(args, " ")
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative 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 (
	"knative.dev/net-istio/pkg/reconciler/ingress"

	// This defines the shared main for injected controllers.
	"knative.dev/pkg/injection/sharedmain"
)

func main() {
	sharedmain.Main("istiocontroller", ingress.NewController)
}
<commit_msg>Allow unknown fields. (#114)<commit_after>/*
Copyright 2019 The Knative 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 (
	"istio.io/api/networking/v1alpha3"
	"knative.dev/net-istio/pkg/reconciler/ingress"

	// This defines the shared main for injected controllers.
	"knative.dev/pkg/injection/sharedmain"
)

func main() {
	// Allow unknown fields in Istio API client.  This is so that we are more resilience
	// in cases user clusers have malformed resources.
	v1alpha3.VirtualServiceUnmarshaler.AllowUnknownFields = true
	v1alpha3.GatewayUnmarshaler.AllowUnknownFields = true

	sharedmain.Main("istiocontroller", ingress.NewController)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/hex"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"sort"
	"strings"
	"syscall"
	"time"

	"github.com/fragments/fragments/internal/backend"
	"github.com/fragments/fragments/internal/client"
	"github.com/fragments/fragments/internal/filestore"
	"github.com/fragments/fragments/internal/server"
	"github.com/fragments/fragments/internal/state"
	"github.com/golang/sync/errgroup"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

func newApplyCommand() *cobra.Command {
	var cmd = &cobra.Command{
		Use:   "apply [dir]",
		Short: "Apply resource changes",
	}

	flags := cmd.Flags()
	ignore := flags.StringSliceP("ignore", "i", []string{"node_modules", "vendor"}, "File/directory patterns to ignore")
	etcdEndpoints := flags.StringSliceP("etcd", "e", []string{"0.0.0.0:2379"}, "ETCD endpoints to connect to for storing state")

	cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return errors.New("target directory must be set")
		}

		for _, target := range args {
			stat, err := os.Stat(target)
			if err != nil {
				return err
			}
			if !stat.IsDir() {
				return errors.Errorf("target must be a directory: %s", target)
			}
		}

		return nil
	}

	cmd.Run = func(cmd *cobra.Command, args []string) {
		walkOptions := &client.WalkOptions{
			Ignore: *ignore,
		}

		// Loop through all targets to resolve resources
		resourcePaths := []string{}
		for _, target := range args {
			paths, err := client.Walk(target, walkOptions)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: %s\n", target, err)
				os.Exit(1)
			}
			resourcePaths = append(resourcePaths, paths...)
		}

		resources := []client.Resource{}
		for _, path := range resourcePaths {
			res, err := client.Load(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "could not load resource: %s: %s\n", err, path)
				os.Exit(1)
			}
			// A nil resource is returned in case the resource was not found in file
			if res != nil {
				resources = append(resources, res...)
			}
		}

		if err := client.CheckDuplicates(resources); err != nil {
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
				os.Exit(1)
			}
		}

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		// Cancel context on signal
		go func() {
			sig := make(chan os.Signal, 1)
			signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
			<-sig
			cancel()
		}()

		excludeSource := *ignore
		for _, r := range resources {
			if r.Type() == client.ResourceTypeFunction {
				excludeSource = append(excludeSource, filepath.Dir(r.File()))
			}
		}

		etcd, err := backend.NewETCDClient(*etcdEndpoints, 3*time.Second)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}

		home, err := homedir.Dir()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}

		uploads := filepath.Join(home, ".fragments", "uploads")
		source := filepath.Join(home, ".fragments", "source")
		sourceStore, err := filestore.NewLocal(uploads, source)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}

		s := server.New(etcd, sourceStore)
		g, ctx := errgroup.WithContext(ctx)
		for _, r := range resources {
			r := r
			g.Go(func() error {
				if function, ok := r.(client.Function); ok {
					meta := r.Meta()
					file := r.File()
					spec := function.Function()
					return applyFunction(ctx, s, meta, file, spec, excludeSource)
				}
				return nil
			})
		}

		if err := g.Wait(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
	}

	return cmd
}

func applyFunction(ctx context.Context, srv *server.Server, meta *client.Meta, file string, spec *client.FunctionSpec, ignore []string) error {
	// Collect function source files
	dir := filepath.Dir(file)
	source, err := client.CollectSource(dir, ignore)
	if err != nil {
		return errors.Wrap(err, "could not collect function source")
	}

	if len(source) == 0 {
		return errors.New("function contains no source")
	}

	// Ensure consistent order for hashing
	sort.Strings(source)

	// Calculate checksum
	// Exclude:
	// - Function definition (so source hash doesn't change on config change)
	// - Sub functions
	checksumExclude := []string{file}
	for _, pattern := range ignore {
		// Ensure we don't exclude a parent function's directory. If do the pattern
		// will match the sub function and its source won't get included in the
		// checksum (don't exclude /foo if we're calculating checksum for /foo/bar)
		if !strings.Contains(dir, pattern) {
			checksumExclude = append(checksumExclude, pattern)
		}
	}
	shasum, err := client.Checksum(source, checksumExclude)
	if err != nil {
		return errors.Wrap(err, "could not calculate source checksum")
	}

	// Construct request
	function := &state.Function{
		Checksum: hex.EncodeToString(shasum),
		Meta: state.Meta{
			Name:   meta.Name,
			Labels: meta.Labels,
		},
		Runtime: spec.Runtime,
	}
	if spec.AWS != nil {
		function.AWS = &state.FunctionAWS{
			Timeout: spec.AWS.Timeout,
			Memory:  spec.AWS.Memory,
		}
	}

	uploadReq, err := srv.PutFunction(ctx, function)
	if err != nil {
		return errors.Wrap(err, "could not put function")
	}

	if uploadReq != nil {
		if err := upload(source, uploadReq); err != nil {
			return errors.Wrap(err, "upload failed")
		}
	}

	return nil
}

func upload(source []string, uploadReq *server.UploadRequest) error {
	return errors.New("not implemented")
}
<commit_msg>Add source upload to apply<commit_after>package main

import (
	"context"
	"encoding/hex"
	"fmt"
	"os"
	"os/signal"
	"path/filepath"
	"sort"
	"strings"
	"syscall"
	"time"

	"github.com/fragments/fragments/internal/backend"
	"github.com/fragments/fragments/internal/client"
	"github.com/fragments/fragments/internal/filestore"
	"github.com/fragments/fragments/internal/server"
	"github.com/fragments/fragments/internal/state"
	"github.com/golang/sync/errgroup"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

func newApplyCommand() *cobra.Command {
	var cmd = &cobra.Command{
		Use:   "apply [dir]",
		Short: "Apply resource changes",
	}

	flags := cmd.Flags()
	ignore := flags.StringSliceP("ignore", "i", []string{"node_modules", "vendor"}, "File/directory patterns to ignore")
	etcdEndpoints := flags.StringSliceP("etcd", "e", []string{"0.0.0.0:2379"}, "ETCD endpoints to connect to for storing state")

	cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
		if len(args) == 0 {
			return errors.New("target directory must be set")
		}

		for _, target := range args {
			stat, err := os.Stat(target)
			if err != nil {
				return err
			}
			if !stat.IsDir() {
				return errors.Errorf("target must be a directory: %s", target)
			}
		}

		return nil
	}

	cmd.Run = func(cmd *cobra.Command, args []string) {
		walkOptions := &client.WalkOptions{
			Ignore: *ignore,
		}

		// Loop through all targets to resolve resources
		resourcePaths := []string{}
		for _, target := range args {
			paths, err := client.Walk(target, walkOptions)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: %s\n", target, err)
				os.Exit(1)
			}
			resourcePaths = append(resourcePaths, paths...)
		}

		resources := []client.Resource{}
		for _, path := range resourcePaths {
			res, err := client.Load(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "could not load resource: %s: %s\n", err, path)
				os.Exit(1)
			}
			// A nil resource is returned in case the resource was not found in file
			if res != nil {
				resources = append(resources, res...)
			}
		}

		if err := client.CheckDuplicates(resources); err != nil {
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
				os.Exit(1)
			}
		}

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		// Cancel context on signal
		go func() {
			sig := make(chan os.Signal, 1)
			signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
			<-sig
			cancel()
		}()

		excludeSource := *ignore
		for _, r := range resources {
			if r.Type() == client.ResourceTypeFunction {
				excludeSource = append(excludeSource, filepath.Dir(r.File()))
			}
		}

		etcd, err := backend.NewETCDClient(*etcdEndpoints, 3*time.Second)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}

		home, err := homedir.Dir()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}

		uploads := filepath.Join(home, ".fragments", "uploads")
		source := filepath.Join(home, ".fragments", "source")
		sourceStore, err := filestore.NewLocal(uploads, source)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}

		s := server.New(etcd, sourceStore)
		g, ctx := errgroup.WithContext(ctx)
		for _, r := range resources {
			r := r
			g.Go(func() error {
				if function, ok := r.(client.Function); ok {
					meta := r.Meta()
					file := r.File()
					spec := function.Function()
					return applyFunction(ctx, s, meta, file, spec, excludeSource)
				}
				return nil
			})
		}

		if err := g.Wait(); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
	}

	return cmd
}

func applyFunction(ctx context.Context, srv *server.Server, meta *client.Meta, file string, spec *client.FunctionSpec, ignore []string) error {
	// Collect function source files
	dir := filepath.Dir(file)
	source, err := client.CollectSource(dir, ignore)
	if err != nil {
		return errors.Wrap(err, "could not collect function source")
	}

	if len(source) == 0 {
		return errors.New("function contains no source")
	}

	// Ensure consistent order for hashing
	sort.Strings(source)

	// Calculate checksum
	// Exclude:
	// - Function definition (so source hash doesn't change on config change)
	// - Sub functions
	checksumExclude := []string{file}
	for _, pattern := range ignore {
		// Ensure we don't exclude a parent function's directory. If do the pattern
		// will match the sub function and its source won't get included in the
		// checksum (don't exclude /foo if we're calculating checksum for /foo/bar)
		if !strings.Contains(dir, pattern) {
			checksumExclude = append(checksumExclude, pattern)
		}
	}
	shasum, err := client.Checksum(source, checksumExclude)
	if err != nil {
		return errors.Wrap(err, "could not calculate source checksum")
	}

	// Construct request
	function := &state.Function{
		Checksum: hex.EncodeToString(shasum),
		Meta: state.Meta{
			Name:   meta.Name,
			Labels: meta.Labels,
		},
		Runtime: spec.Runtime,
	}
	if spec.AWS != nil {
		function.AWS = &state.FunctionAWS{
			Timeout: spec.AWS.Timeout,
			Memory:  spec.AWS.Memory,
		}
	}

	uploadReq, err := srv.PutFunction(ctx, function)
	if err != nil {
		return errors.Wrap(err, "could not put function")
	}

	if uploadReq != nil {
		if err := upload(source, uploadReq); err != nil {
			return errors.Wrap(err, "upload failed")
		}
	}

	return nil
}

func upload(source []string, uploadReq *server.UploadRequest) error {
	targz, err := client.Compress(source)
	if err != nil {
		return errors.Wrap(err, "could not archive source")
	}

	if err := client.Upload(targz, uploadReq.URL); err != nil {
		return errors.Wrap(err, "upload failed")
	}

	return errors.New("confirm not implemented")
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/cosiner/gohper/ds/sortedmap"
	"github.com/cosiner/gohper/goutil"
	"github.com/cosiner/gohper/strings2"
	"github.com/cosiner/gohper/utils/ast"
	"github.com/cosiner/gohper/utils/pair"
)

type Table struct {
	Name   string
	Fields sortedmap.Map
}

type Visitor struct {
	Models map[string]*Table // [modelname]modeltable
	SQLs   map[string]string // [sqlid]sqlstring
}

func newVisitor() Visitor {
	return Visitor{
		Models: make(map[string]*Table),
		SQLs:   make(map[string]string),
	}
}

// add an model and it's field to parse result
func (v Visitor) add(model, table, field, col string) {
	if table == "" {
		table = strings2.ToSnake(model)
	}

	if col == "" {
		col = strings2.ToSnake(field)
	}

	t, has := v.Models[model]
	if !has {
		t = &Table{Name: table}
		v.Models[model] = t
	}

	t.Fields.Set(field, col)
}

func (v Visitor) parseFiles(files ...string) error {
	for _, file := range files {
		err := v.parseFile(file)
		if err != nil {
			return err
		}
	}

	return nil
}

func (v Visitor) parseDir(dir string) error {
	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		return v.parseFile(path)
	})
}

func (v Visitor) parseFile(file string) error {
	parser := ast.Parser{
		Struct: func(a *ast.Attrs) error {
			if !goutil.IsExported(a.TypeName) {
				return ast.TYPE_END
			}

			var table string
			if table = a.S.Tag.Get("table"); table == "-" {
				return ast.TYPE_END
			}

			if col := a.S.Tag.Get("column"); col != "-" {
				v.add(a.TypeName, table, a.S.Field, col)
			}

			return nil
		},

		ParseDoc: true,
		Func: func(a *ast.Attrs) (err error) {
			v.extractSQLs(a.TypeDoc)

			return nil
		},
	}
	return parser.ParseFile(file)
}

// buildModelFields build model map from parse result
func (v Visitor) buildModelFields() map[*Model][]*Field {
	names := make(map[*Model][]*Field, len(v.Models))

	for model, table := range v.Models {
		m := NewModel(model, table.Name)
		fields := table.Fields

		for _, field := range fields.Values {
			names[m] = append(names[m], NewField(field.Key, field.Value.(string)))
		}
	}

	return names
}

func (v Visitor) extractSQLs(docs []string) {
	const (
		INIT = iota
		PARSING

		GOMODEL = "//gomodel "
	)

	var (
		sqls  []string
		name  string
		state = INIT
	)

	for _, d := range docs {
		if state == PARSING {
			d = d[len("//"):]

			if strings.HasPrefix(d, "]") {
				v.SQLs[name] = strings.Join(sqls, " ")
				state = INIT
			} else {
				sqls = append(sqls, strings.TrimSpace(d))
			}

		} else if strings.HasPrefix(d, GOMODEL) {
			d = d[len(GOMODEL):]
			p := pair.Parse(d, "=").Trim()

			if !strings.HasSuffix(p.Value, "[") {
				v.SQLs[p.Key] = p.Value
			} else {
				name = p.Key
				sqls = sqls[:0]

				state = PARSING
			}
		}
	}
}
<commit_msg>fixed uninitialed map<commit_after>package main

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/cosiner/gohper/ds/sortedmap"
	"github.com/cosiner/gohper/goutil"
	"github.com/cosiner/gohper/strings2"
	"github.com/cosiner/gohper/utils/ast"
	"github.com/cosiner/gohper/utils/pair"
)

type Table struct {
	Name   string
	Fields sortedmap.Map
}

type Visitor struct {
	Models map[string]*Table // [modelname]modeltable
	SQLs   map[string]string // [sqlid]sqlstring
}

func newVisitor() Visitor {
	return Visitor{
		Models: make(map[string]*Table),
		SQLs:   make(map[string]string),
	}
}

// add an model and it's field to parse result
func (v Visitor) add(model, table, field, col string) {
	if table == "" {
		table = strings2.ToSnake(model)
	}

	if col == "" {
		col = strings2.ToSnake(field)
	}

	t, has := v.Models[model]
	if !has {
		t = &Table{Name: table, Fields: sortedmap.New()}
		v.Models[model] = t
	}

	t.Fields.Set(field, col)
}

func (v Visitor) parseFiles(files ...string) error {
	for _, file := range files {
		err := v.parseFile(file)
		if err != nil {
			return err
		}
	}

	return nil
}

func (v Visitor) parseDir(dir string) error {
	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		return v.parseFile(path)
	})
}

func (v Visitor) parseFile(file string) error {
	parser := ast.Parser{
		Struct: func(a *ast.Attrs) error {
			if !goutil.IsExported(a.TypeName) {
				return ast.TYPE_END
			}

			var table string
			if table = a.S.Tag.Get("table"); table == "-" {
				return ast.TYPE_END
			}

			if col := a.S.Tag.Get("column"); col != "-" {
				v.add(a.TypeName, table, a.S.Field, col)
			}

			return nil
		},

		ParseDoc: true,
		Func: func(a *ast.Attrs) (err error) {
			v.extractSQLs(a.TypeDoc)

			return nil
		},
	}
	return parser.ParseFile(file)
}

// buildModelFields build model map from parse result
func (v Visitor) buildModelFields() map[*Model][]*Field {
	names := make(map[*Model][]*Field, len(v.Models))

	for model, table := range v.Models {
		m := NewModel(model, table.Name)
		fields := table.Fields

		for _, field := range fields.Values {
			names[m] = append(names[m], NewField(field.Key, field.Value.(string)))
		}
	}

	return names
}

func (v Visitor) extractSQLs(docs []string) {
	const (
		INIT = iota
		PARSING

		GOMODEL = "//gomodel "
	)

	var (
		sqls  []string
		name  string
		state = INIT
	)

	for _, d := range docs {
		if state == PARSING {
			d = d[len("//"):]

			if strings.HasPrefix(d, "]") {
				v.SQLs[name] = strings.Join(sqls, " ")
				state = INIT
			} else {
				sqls = append(sqls, strings.TrimSpace(d))
			}

		} else if strings.HasPrefix(d, GOMODEL) {
			d = d[len(GOMODEL):]
			p := pair.Parse(d, "=").Trim()

			if !strings.HasSuffix(p.Value, "[") {
				v.SQLs[p.Key] = p.Value
			} else {
				name = p.Key
				sqls = sqls[:0]

				state = PARSING
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"

	"github.com/Shopify/sarama"
	"github.com/wvanbergen/kafka/consumergroup"
)

const (
	DefaultKafkaTopics   = "nginx.multitrack"
	DefaultConsumerGroup = "consumer_example.go"
)

var (
	consumerGroup string
	kafkaTopics   []string
	zookeeper     []string
)

func init() {
	consumerGroup = *flag.String("group", DefaultConsumerGroup, "The name of the consumer group, used for coordination and load balancing")
	kafkaTopicsCSV := flag.String("topics", DefaultKafkaTopics, "The comma-separated list of topics to consume")
	zookeeperCSV := flag.String("zookeeper", "", "A comma-separated Zookeeper connection string (e.g. `zookeeper1.local:2181,zookeeper2.local:2181,zookeeper3.local:2181`)")

	flag.Parse()

	if *zookeeperCSV == "" {
		flag.PrintDefaults()
		os.Exit(1)
	}

	zookeeper = strings.Split(*zookeeperCSV, ",")
	kafkaTopics = strings.Split(*kafkaTopicsCSV, ",")

	sarama.Logger = log.New(os.Stdout, "[Sarama] ", log.LstdFlags)
}

func main() {
	config := sarama.NewConsumerConfig()
	config.OffsetMethod = sarama.OffsetMethodNewest
	consumer, consumerErr := consumergroup.JoinConsumerGroup(consumerGroup, kafkaTopics, zookeeper, nil)
	if consumerErr != nil {
		log.Fatalln(consumerErr)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		if err := consumer.Close(); err != nil {
			sarama.Logger.Println("Error closing the consumer", err)
		}
	}()

	eventCount := 0
	offsets := make(map[string]map[int32]int64)

	stream := consumer.Events()
	for event := range stream {
		if event.Err != nil {
			log.Println(event.Err)
			break
		}

		if offsets[event.Topic] == nil {
			offsets[event.Topic] = make(map[int32]int64)
		}

		eventCount += 1
		if offsets[event.Topic][event.Partition] != 0 && offsets[event.Topic][event.Partition] != event.Offset-1 {
			log.Printf("Unexpected offset on %s:%d. Expected %d, found %d, diff %d.\n", event.Topic, event.Partition, offsets[event.Topic][event.Partition]+1, event.Offset, event.Offset-offsets[event.Topic][event.Partition]+1)
		}

		offsets[event.Topic][event.Partition] = event.Offset
	}

	log.Printf("Processed %d events.", eventCount)
	log.Printf("%+v", offsets)
}
<commit_msg>Fix example consumer.<commit_after>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"

	"github.com/Shopify/sarama"
	"github.com/wvanbergen/kafka/consumergroup"
)

const (
	DefaultKafkaTopics   = "nginx.multitrack"
	DefaultConsumerGroup = "consumer_example.go"
)

var (
	consumerGroup string
	kafkaTopics   []string
	zookeeper     []string
)

func init() {
	consumerGroup = *flag.String("group", DefaultConsumerGroup, "The name of the consumer group, used for coordination and load balancing")
	kafkaTopicsCSV := flag.String("topics", DefaultKafkaTopics, "The comma-separated list of topics to consume")
	zookeeperCSV := flag.String("zookeeper", "", "A comma-separated Zookeeper connection string (e.g. `zookeeper1.local:2181,zookeeper2.local:2181,zookeeper3.local:2181`)")

	flag.Parse()

	if *zookeeperCSV == "" {
		flag.PrintDefaults()
		os.Exit(1)
	}

	zookeeper = strings.Split(*zookeeperCSV, ",")
	kafkaTopics = strings.Split(*kafkaTopicsCSV, ",")

	sarama.Logger = log.New(os.Stdout, "[Sarama] ", log.LstdFlags)
}

func main() {
	config := consumergroup.NewConsumerGroupConfig()
	config.InitialOffsetMethod = sarama.OffsetMethodNewest
	consumer, consumerErr := consumergroup.JoinConsumerGroup(consumerGroup, kafkaTopics, zookeeper, config)
	if consumerErr != nil {
		log.Fatalln(consumerErr)
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		if err := consumer.Close(); err != nil {
			sarama.Logger.Println("Error closing the consumer", err)
		}
	}()

	eventCount := 0
	offsets := make(map[string]map[int32]int64)

	stream := consumer.Events()
	for event := range stream {
		if event.Err != nil {
			log.Println(event.Err)
			break
		}

		if offsets[event.Topic] == nil {
			offsets[event.Topic] = make(map[int32]int64)
		}

		eventCount += 1
		if offsets[event.Topic][event.Partition] != 0 && offsets[event.Topic][event.Partition] != event.Offset-1 {
			log.Printf("Unexpected offset on %s:%d. Expected %d, found %d, diff %d.\n", event.Topic, event.Partition, offsets[event.Topic][event.Partition]+1, event.Offset, event.Offset-offsets[event.Topic][event.Partition]+1)
		}

		offsets[event.Topic][event.Partition] = event.Offset
	}

	log.Printf("Processed %d events.", eventCount)
	log.Printf("%+v", offsets)
}
<|endoftext|>


<commit_before>/*
The goquickfix command quick fixes Go source that is well typed but go refuses
to compile e.g. "foo imported but not used".

Run with -help flag for usage information.
*/
package main

import (
	"flag"
	"fmt"
	"os"

	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"

	"github.com/motemen/go-quickfix"
)

var (
	flagWrite = flag.Bool("w", false, "write result to (source) file instead of stdout")
)

func usage() {
	fmt.Fprintln(os.Stderr, `Usage:
  goquickfix [-w] <path>

Flags:`)
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() == 0 {
		flag.Usage()
	}

	// list of files grouped by package.
	files := map[string][]*ast.File{}

	fset := token.NewFileSet()

	for i := 0; i < flag.NArg(); i++ {
		arg := flag.Arg(i)
		fi, err := os.Stat(arg)
		dieIf(err)

		if fi.IsDir() {
			if i != 0 {
				die("you can only specify exact one directory")
			}

			pkgs, err := parser.ParseDir(fset, arg, nil, parser.ParseComments)
			dieIf(err)

			for _, pkg := range pkgs {
				ff := make([]*ast.File, 0, len(pkg.Files))
				for _, f := range pkg.Files {
					ff = append(ff, f)
				}
				files[pkg.Name] = ff
			}
		} else {
			f, err := parser.ParseFile(fset, arg, nil, parser.ParseComments)
			dieIf(err)

			const adhocPkg = ""

			// *.go files are grouped as ad-hoc package.
			if files[adhocPkg] == nil {
				files[adhocPkg] = []*ast.File{}
			}

			files[adhocPkg] = append(files[adhocPkg], f)
		}

	}

	for _, ff := range files {
		err := quickfix.QuickFix(fset, ff)
		dieIf(err)

		for _, f := range ff {
			// TODO: do not write if no change
			out := os.Stdout
			if *flagWrite {
				out, err = os.Create(fset.File(f.Pos()).Name())
				dieIf(err)
			}

			conf := printer.Config{
				Tabwidth: 8,
				Mode:     printer.UseSpaces | printer.TabIndent,
			}
			err := conf.Fprint(out, fset, f)
			dieIf(err)
		}
	}
}

func dieIf(err error) {
	if err != nil {
		die(err)
	}
}

func die(msg interface{}) {
	fmt.Fprintln(os.Stderr, msg)
	os.Exit(1)
}
<commit_msg>goquickfix -revert<commit_after>/*
The goquickfix command quick fixes Go source that is well typed but go refuses
to compile e.g. "foo imported but not used".

Run with -help flag for usage information.
*/
package main

import (
	"flag"
	"fmt"
	"os"

	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"

	"github.com/motemen/go-quickfix"
)

var (
	flagWrite  = flag.Bool("w", false, "write result to (source) file instead of stdout")
	flagRevert = flag.Bool("revert", false, "try to revert possible quickfixes introduced by goquickfix")
)

func usage() {
	fmt.Fprintln(os.Stderr, `Usage:
  goquickfix [-w] [-revert] <path>...

Flags:`)
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() == 0 {
		flag.Usage()
	}

	// list of files grouped by package.
	files := map[string][]*ast.File{}

	fset := token.NewFileSet()

	for i := 0; i < flag.NArg(); i++ {
		arg := flag.Arg(i)
		fi, err := os.Stat(arg)
		dieIf(err)

		if fi.IsDir() {
			if i != 0 {
				die("you can only specify exact one directory")
			}

			pkgs, err := parser.ParseDir(fset, arg, nil, parser.ParseComments)
			dieIf(err)

			for _, pkg := range pkgs {
				ff := make([]*ast.File, 0, len(pkg.Files))
				for _, f := range pkg.Files {
					ff = append(ff, f)
				}
				files[pkg.Name] = ff
			}
		} else {
			f, err := parser.ParseFile(fset, arg, nil, parser.ParseComments)
			dieIf(err)

			const adhocPkg = ""

			// *.go files are grouped as ad-hoc package.
			if files[adhocPkg] == nil {
				files[adhocPkg] = []*ast.File{}
			}

			files[adhocPkg] = append(files[adhocPkg], f)
		}

	}

	for _, ff := range files {
		var err error
		if *flagRevert {
			err = quickfix.RevertQuickFix(fset, ff)
		} else {
			err = quickfix.QuickFix(fset, ff)
		}
		dieIf(err)

		for _, f := range ff {
			// TODO: do not write if no change
			out := os.Stdout
			if *flagWrite {
				out, err = os.Create(fset.File(f.Pos()).Name())
				dieIf(err)
			}

			conf := printer.Config{
				Tabwidth: 8,
				Mode:     printer.UseSpaces | printer.TabIndent,
			}
			err := conf.Fprint(out, fset, f)
			dieIf(err)
		}
	}
}

func dieIf(err error) {
	if err != nil {
		die(err)
	}
}

func die(msg interface{}) {
	fmt.Fprintln(os.Stderr, msg)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"os"
	"os/exec"

	typeconv "github.com/haya14busa/go-typeconv"

	"golang.org/x/tools/go/loader"
)

type option struct {
	write  bool
	doDiff bool
}

func main() {
	opt := &option{}
	flag.BoolVar(&opt.write, "w", false, "write result to (source) file instead of stdout")
	flag.BoolVar(&opt.doDiff, "d", false, "display diffs instead of rewriting files")
	flag.Parse()
	if err := run(os.Stdout, flag.Args(), opt); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

func run(w io.Writer, args []string, opt *option) error {
	prog, typeErrs, err := typeconv.Load(loader.Config{}, args)
	if err != nil {
		return err
	}
	for _, pkg := range prog.InitialPackages() {
		for _, f := range pkg.Files {
			filename := prog.Fset.File(f.Pos()).Name()
			if err := typeconv.RewriteFile(prog.Fset, f, pkg, typeErrs); err != nil {
				return err
			}
			buf := new(bytes.Buffer)
			if err := format.Node(buf, prog.Fset, f); err != nil {
				return err
			}
			res := buf.Bytes()
			in, err := os.Open(filename)
			if err != nil {
				return err
			}
			src, err := ioutil.ReadAll(in)
			if err != nil {
				return err
			}
			if !bytes.Equal(src, res) {
				if opt.write {
					fh, err := os.Create(filename)
					if err != nil {
						return err
					}
					fh.Write(res)
					fh.Close()
				}
				if opt.doDiff {
					data, err := diff(src, res)
					if err != nil {
						return fmt.Errorf("computing diff: %s", err)
					}
					fmt.Fprintf(w, "diff %s gotypeconv/%s\n", filename, filename)
					w.Write(data)
				}
			}
			if !opt.write && !opt.doDiff {
				w.Write(res)
			}
		}
	}
	return nil
}

// copied and modified from $GOPATH/src/github.com/golang/go/src/cmd/gofmt/gofmt.go
//
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
func diff(b1, b2 []byte) (data []byte, err error) {
	f1, err := ioutil.TempFile("", "gotypeconv")
	if err != nil {
		return
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "gotypeconv")
	if err != nil {
		return
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
	if len(data) > 0 {
		// diff exits with a non-zero status when the files don't match.
		// Ignore that failure as long as we get output.
		err = nil
	}
	return

}
<commit_msg>cmd: add -r flag for adding type conversion rules<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"

	typeconv "github.com/haya14busa/go-typeconv"

	"golang.org/x/tools/go/loader"
)

type option struct {
	write  bool
	doDiff bool
	rules  strslice
}

func main() {
	opt := &option{}
	flag.BoolVar(&opt.write, "w", false, "write result to (source) file instead of stdout")
	flag.BoolVar(&opt.doDiff, "d", false, "display diffs instead of rewriting files")
	flag.Var(&opt.rules, "r", "type conversion rules currently just for type conversion of binary expression (e.g., 'int -> uint32')")
	flag.Parse()
	if err := run(os.Stdout, flag.Args(), opt); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

func run(w io.Writer, args []string, opt *option) error {
	if err := addRules(opt.rules); err != nil {
		return err
	}
	prog, typeErrs, err := typeconv.Load(loader.Config{}, args)
	if err != nil {
		return err
	}
	for _, pkg := range prog.InitialPackages() {
		for _, f := range pkg.Files {
			filename := prog.Fset.File(f.Pos()).Name()
			if err := typeconv.RewriteFile(prog.Fset, f, pkg, typeErrs); err != nil {
				return err
			}
			buf := new(bytes.Buffer)
			if err := format.Node(buf, prog.Fset, f); err != nil {
				return err
			}
			res := buf.Bytes()
			in, err := os.Open(filename)
			if err != nil {
				return err
			}
			src, err := ioutil.ReadAll(in)
			if err != nil {
				return err
			}
			if !bytes.Equal(src, res) {
				if opt.write {
					fh, err := os.Create(filename)
					if err != nil {
						return err
					}
					fh.Write(res)
					fh.Close()
				}
				if opt.doDiff {
					data, err := diff(src, res)
					if err != nil {
						return fmt.Errorf("computing diff: %s", err)
					}
					fmt.Fprintf(w, "diff %s gotypeconv/%s\n", filename, filename)
					w.Write(data)
				}
			}
			if !opt.write && !opt.doDiff {
				w.Write(res)
			}
		}
	}
	return nil
}

func addRules(rules []string) error {
	for _, r := range rules {
		f := strings.Split(r, "->")
		if len(f) != 2 {
			return fmt.Errorf("type conversion rule must be the form 'from -> to': %v", r)
		}
		from, to := strings.TrimSpace(f[0]), strings.TrimSpace(f[1])
		typeconv.DefaultRule.Add(from, to)
	}
	return nil
}

// copied and modified from $GOPATH/src/github.com/golang/go/src/cmd/gofmt/gofmt.go
//
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
func diff(b1, b2 []byte) (data []byte, err error) {
	f1, err := ioutil.TempFile("", "gotypeconv")
	if err != nil {
		return
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "gotypeconv")
	if err != nil {
		return
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
	if len(data) > 0 {
		// diff exits with a non-zero status when the files don't match.
		// Ignore that failure as long as we get output.
		err = nil
	}
	return

}

type strslice []string

func (ss *strslice) String() string {
	return fmt.Sprintf("%v", *ss)
}

func (ss *strslice) Set(value string) error {
	*ss = append(*ss, value)
	return nil
}
<|endoftext|>


<commit_before>/** Response object was a struct but i change it to map because of in drywall often some
	data was in response. I mean every response has mandatory fields but sometimes also
	custom data like "newUsername". I don't like it. I think in response type has to be
	field data map[string]interface{}. But my principe is "don't touch client code". And I
	decided do response object as map. It will be flexible for users from node.js.

	type Response struct {
	Success bool `json:"success" bson:"-"`
	Errors  []string `json:"errors" bson:"-"`
	ErrFor  map[string]string `json:"errfor" bson:"-"`
	c  *gin.Context
	Data map[string]interface{} `json:"data" bson:"-"`
}

	I thought leave struct realization.
	I thought do setters and getters. But it will complicate code. Go is not about
	complexity.
*/

package main

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"net/http"
)

func handleXHR(c *gin.Context, data []byte) {
	c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
	c.Data(http.StatusOK, "application/json; charset=utf-8", data)
}

type Response struct {
	Success bool              `json:"success" bson:"-"`
	Errors  []string          `json:"errors" bson:"-"`
	ErrFor  map[string]string `json:"errfor" bson:"-"`
	c       *gin.Context
	Data    map[string]interface{} `json:"data" bson:"-"`
}

func (r *Response) HasErrors() bool {
	return len(r.ErrFor) != 0 || len(r.Errors) != 0
}

func (r *Response) Fail() {
	r.Success = false
	r.Response()
}

func (r *Response) Init(c *gin.Context) {
	r.c = c
	r.Data = map[string]interface{}{}
	r.ErrFor = map[string]string{}
}

func getResponseObj(c *gin.Context) (r *Response) {
	r = &Response{}
	r.c = c
	r.Data = map[string]interface{}{}
	r.ErrFor = map[string]string{}
	return
}

func (r *Response) Recover() {}

func (r *Response) CleanErrors() {
	r.Errors = []string{}
	r.ErrFor = make(map[string]string)
}

func (r *Response) DecodeRequest() {
	err := json.NewDecoder(r.c.Request.Body).Decode(r)
	if err != nil {
		panic(err)
	}
	// clean errors from client
	r.Errors = []string{}
	r.ErrFor = make(map[string]string)
	return
}

func (r *Response) Finish() {
	r.Success = true
	r.Response()
}

func (r *Response) Response() {
	r.Data["success"] = r.Success
	r.Data["errfor"] = r.ErrFor
	r.Data["errors"] = r.Errors
	r.c.JSON(http.StatusOK, r.Data)
}
<commit_msg>[DEBUG]<commit_after>/** Response object was a struct but i change it to map because of in drywall often some
	data was in response. I mean every response has mandatory fields but sometimes also
	custom data like "newUsername". I don't like it. I think in response type has to be
	field data map[string]interface{}. But my principe is "don't touch client code". And I
	decided do response object as map. It will be flexible for users from node.js.

	type Response struct {
	Success bool `json:"success" bson:"-"`
	Errors  []string `json:"errors" bson:"-"`
	ErrFor  map[string]string `json:"errfor" bson:"-"`
	c  *gin.Context
	Data map[string]interface{} `json:"data" bson:"-"`
}

	I thought leave struct realization.
	I thought do setters and getters. But it will complicate code. Go is not about
	complexity.
*/

package main

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"net/http"
	"fmt"
)

func handleXHR(c *gin.Context, data []byte) {
	c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
	c.Data(http.StatusOK, "application/json; charset=utf-8", data)
}

type Response struct {
	Success bool              `json:"success" bson:"-"`
	Errors  []string          `json:"errors" bson:"-"`
	ErrFor  map[string]string `json:"errfor" bson:"-"`
	c       *gin.Context
	Data    map[string]interface{} `json:"data" bson:"-"`
}

func (r *Response) HasErrors() bool {
	return len(r.ErrFor) != 0 || len(r.Errors) != 0
}

func (r *Response) Fail() {
	r.Success = false
	r.Response()
}

func (r *Response) Init(c *gin.Context) {
	r.c = c
	r.Data = map[string]interface{}{}
	r.ErrFor = map[string]string{}
}

func getResponseObj(c *gin.Context) (r *Response) {
	r = &Response{}
	r.c = c
	r.Data = map[string]interface{}{}
	r.ErrFor = map[string]string{}
	return
}

func (r *Response) Recover() {}

func (r *Response) CleanErrors() {
	r.Errors = []string{}
	r.ErrFor = make(map[string]string)
}

func (r *Response) DecodeRequest() {
	err := json.NewDecoder(r.c.Request.Body).Decode(r)
	if err != nil {
		panic(err)
	}
	// clean errors from client
	r.Errors = []string{}
	r.ErrFor = make(map[string]string)
	return
}

func (r *Response) Finish() {
	r.Success = true
	r.Response()
}

func (r *Response) Response() {
	r.Data["success"] = r.Success
	r.Data["errfor"] = r.ErrFor
	r.Data["errors"] = r.Errors
	r.c.JSON(http.StatusOK, r.Data)
}

func DEBUG(i interface{}) {
	fmt.Printf("%v\n%f\n", i, i)
}<|endoftext|>


<commit_before>/*
Copyright The Helm 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 (
	"bytes"
	"fmt"
	"io"

	"github.com/spf13/cobra"
)

const completionDesc = `
Generate autocompletions script for Helm for the specified shell (bash or zsh).

This command can generate shell autocompletions. e.g.

	$ helm completion bash

Can be sourced as such

	$ source <(helm completion bash)
`

var (
	completionShells = map[string]func(out io.Writer, cmd *cobra.Command) error{
		"bash": runCompletionBash,
		"zsh":  runCompletionZsh,
	}
)

func newCompletionCmd(out io.Writer) *cobra.Command {
	shells := []string{}
	for s := range completionShells {
		shells = append(shells, s)
	}

	cmd := &cobra.Command{
		Use:   "completion SHELL",
		Short: "Generate autocompletions script for the specified shell (bash or zsh)",
		Long:  completionDesc,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runCompletion(out, cmd, args)
		},
		ValidArgs: shells,
	}

	return cmd
}

func runCompletion(out io.Writer, cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("shell not specified")
	}
	if len(args) > 1 {
		return fmt.Errorf("too many arguments, expected only the shell type")
	}
	run, found := completionShells[args[0]]
	if !found {
		return fmt.Errorf("unsupported shell type %q", args[0])
	}

	return run(out, cmd)
}

func runCompletionBash(out io.Writer, cmd *cobra.Command) error {
	return cmd.Root().GenBashCompletion(out)
}

func runCompletionZsh(out io.Writer, cmd *cobra.Command) error {
	zshInitialization := `#compdef helm

__helm_bash_source() {
	alias shopt=':'
	alias _expand=_bash_expand
	alias _complete=_bash_comp
	emulate -L sh
	setopt kshglob noshglob braceexpand
	source "$@"
}
__helm_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift
		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__helm_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}
__helm_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?
	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}
__helm_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}
__helm_declare() {
	if [ "$1" == "-F" ]; then
		whence -w "$@"
	else
		builtin declare "$@"
	fi
}
__helm_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}
__helm_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}
__helm_filedir() {
	local RET OLD_IFS w qw
	__debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi
	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"
	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__helm_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}
__helm_quote() {
	if [[ $1 == \'* || $1 == \"* ]]; then
		# Leave out first character
		printf %q "${1:1}"
	else
		printf %q "$1"
	fi
}
autoload -U +X bashcompinit && bashcompinit
# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi
__helm_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__helm_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__helm_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/__helm_declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__helm_type/g" \
	-e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \
	-e 's/FUNCNAME/funcstack/g' \
	<<'BASH_COMPLETION_EOF'
`
	out.Write([]byte(zshInitialization))

	buf := new(bytes.Buffer)
	cmd.Root().GenBashCompletion(buf)
	out.Write(buf.Bytes())

	zshTail := `
BASH_COMPLETION_EOF
}
__helm_bash_source <(__helm_convert_bash_to_zsh)
`
	out.Write([]byte(zshTail))
	return nil
}
<commit_msg>fix(completion): --flag=val breaks zsh completion<commit_after>/*
Copyright The Helm 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 (
	"bytes"
	"fmt"
	"io"

	"github.com/spf13/cobra"
)

const completionDesc = `
Generate autocompletions script for Helm for the specified shell (bash or zsh).

This command can generate shell autocompletions. e.g.

	$ helm completion bash

Can be sourced as such

	$ source <(helm completion bash)
`

var (
	completionShells = map[string]func(out io.Writer, cmd *cobra.Command) error{
		"bash": runCompletionBash,
		"zsh":  runCompletionZsh,
	}
)

func newCompletionCmd(out io.Writer) *cobra.Command {
	shells := []string{}
	for s := range completionShells {
		shells = append(shells, s)
	}

	cmd := &cobra.Command{
		Use:   "completion SHELL",
		Short: "Generate autocompletions script for the specified shell (bash or zsh)",
		Long:  completionDesc,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runCompletion(out, cmd, args)
		},
		ValidArgs: shells,
	}

	return cmd
}

func runCompletion(out io.Writer, cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("shell not specified")
	}
	if len(args) > 1 {
		return fmt.Errorf("too many arguments, expected only the shell type")
	}
	run, found := completionShells[args[0]]
	if !found {
		return fmt.Errorf("unsupported shell type %q", args[0])
	}

	return run(out, cmd)
}

func runCompletionBash(out io.Writer, cmd *cobra.Command) error {
	return cmd.Root().GenBashCompletion(out)
}

func runCompletionZsh(out io.Writer, cmd *cobra.Command) error {
	zshInitialization := `#compdef helm

__helm_bash_source() {
	alias shopt=':'
	alias _expand=_bash_expand
	alias _complete=_bash_comp
	emulate -L sh
	setopt kshglob noshglob braceexpand
	source "$@"
}
__helm_type() {
	# -t is not supported by zsh
	if [ "$1" == "-t" ]; then
		shift
		# fake Bash 4 to disable "complete -o nospace". Instead
		# "compopt +-o nospace" is used in the code to toggle trailing
		# spaces. We don't support that, but leave trailing spaces on
		# all the time
		if [ "$1" = "__helm_compopt" ]; then
			echo builtin
			return 0
		fi
	fi
	type "$@"
}
__helm_compgen() {
	local completions w
	completions=( $(compgen "$@") ) || return $?
	# filter by given word as prefix
	while [[ "$1" = -* && "$1" != -- ]]; do
		shift
		shift
	done
	if [[ "$1" == -- ]]; then
		shift
	fi
	for w in "${completions[@]}"; do
		if [[ "${w}" = "$1"* ]]; then
			echo "${w}"
		fi
	done
}
__helm_compopt() {
	true # don't do anything. Not supported by bashcompinit in zsh
}
__helm_ltrim_colon_completions()
{
	if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
		# Remove colon-word prefix from COMPREPLY items
		local colon_word=${1%${1##*:}}
		local i=${#COMPREPLY[*]}
		while [[ $((--i)) -ge 0 ]]; do
			COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
		done
	fi
}
__helm_get_comp_words_by_ref() {
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[${COMP_CWORD}-1]}"
	words=("${COMP_WORDS[@]}")
	cword=("${COMP_CWORD[@]}")
}
__helm_filedir() {
	local RET OLD_IFS w qw
	__debug "_filedir $@ cur=$cur"
	if [[ "$1" = \~* ]]; then
		# somehow does not work. Maybe, zsh does not call this at all
		eval echo "$1"
		return 0
	fi
	OLD_IFS="$IFS"
	IFS=$'\n'
	if [ "$1" = "-d" ]; then
		shift
		RET=( $(compgen -d) )
	else
		RET=( $(compgen -f) )
	fi
	IFS="$OLD_IFS"
	IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
	for w in ${RET[@]}; do
		if [[ ! "${w}" = "${cur}"* ]]; then
			continue
		fi
		if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
			qw="$(__helm_quote "${w}")"
			if [ -d "${w}" ]; then
				COMPREPLY+=("${qw}/")
			else
				COMPREPLY+=("${qw}")
			fi
		fi
	done
}
__helm_quote() {
	if [[ $1 == \'* || $1 == \"* ]]; then
		# Leave out first character
		printf %q "${1:1}"
	else
		printf %q "$1"
	fi
}
autoload -U +X bashcompinit && bashcompinit
# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
	LWORD='\<'
	RWORD='\>'
fi
__helm_convert_bash_to_zsh() {
	sed \
	-e 's/declare -F/whence -w/' \
	-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
	-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
	-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
	-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
	-e "s/${LWORD}_filedir${RWORD}/__helm_filedir/g" \
	-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__helm_get_comp_words_by_ref/g" \
	-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \
	-e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \
	-e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \
	-e "s/${LWORD}declare${RWORD}/builtin declare/g" \
	-e "s/\\\$(type${RWORD}/\$(__helm_type/g" \
	-e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \
	-e 's/FUNCNAME/funcstack/g' \
	<<'BASH_COMPLETION_EOF'
`
	out.Write([]byte(zshInitialization))

	buf := new(bytes.Buffer)
	cmd.Root().GenBashCompletion(buf)
	out.Write(buf.Bytes())

	zshTail := `
BASH_COMPLETION_EOF
}
__helm_bash_source <(__helm_convert_bash_to_zsh)
`
	out.Write([]byte(zshTail))
	return nil
}
<|endoftext|>