github.com/werf/3p-helm@v2.8.1+incompatible/cmd/helm/load_plugins.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package main
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"os/exec"
    23  	"path/filepath"
    24  	"strings"
    25  
    26  	"github.com/spf13/cobra"
    27  
    28  	"k8s.io/helm/pkg/plugin"
    29  )
    30  
    31  // loadPlugins loads plugins into the command list.
    32  //
    33  // This follows a different pattern than the other commands because it has
    34  // to inspect its environment and then add commands to the base command
    35  // as it finds them.
    36  func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
    37  
    38  	// If HELM_NO_PLUGINS is set to 1, do not load plugins.
    39  	if os.Getenv("HELM_NO_PLUGINS") == "1" {
    40  		return
    41  	}
    42  
    43  	// debug("HELM_PLUGIN_DIRS=%s", settings.PluginDirs())
    44  	found, err := findPlugins(settings.PluginDirs())
    45  	if err != nil {
    46  		fmt.Fprintf(os.Stderr, "failed to load plugins: %s", err)
    47  		return
    48  	}
    49  
    50  	processParent := func(cmd *cobra.Command, args []string) ([]string, error) {
    51  		k, u := manuallyProcessArgs(args)
    52  		if err := cmd.Parent().ParseFlags(k); err != nil {
    53  			return nil, err
    54  		}
    55  		return u, nil
    56  	}
    57  
    58  	// Now we create commands for all of these.
    59  	for _, plug := range found {
    60  		plug := plug
    61  		md := plug.Metadata
    62  		if md.Usage == "" {
    63  			md.Usage = fmt.Sprintf("the %q plugin", md.Name)
    64  		}
    65  
    66  		c := &cobra.Command{
    67  			Use:   md.Name,
    68  			Short: md.Usage,
    69  			Long:  md.Description,
    70  			RunE: func(cmd *cobra.Command, args []string) error {
    71  				u, err := processParent(cmd, args)
    72  				if err != nil {
    73  					return err
    74  				}
    75  
    76  				// Call setupEnv before PrepareCommand because
    77  				// PrepareCommand uses os.ExpandEnv and expects the
    78  				// setupEnv vars.
    79  				plugin.SetupPluginEnv(settings, md.Name, plug.Dir)
    80  				main, argv := plug.PrepareCommand(u)
    81  
    82  				prog := exec.Command(main, argv...)
    83  				prog.Env = os.Environ()
    84  				prog.Stdin = os.Stdin
    85  				prog.Stdout = out
    86  				prog.Stderr = os.Stderr
    87  				if err := prog.Run(); err != nil {
    88  					if eerr, ok := err.(*exec.ExitError); ok {
    89  						os.Stderr.Write(eerr.Stderr)
    90  						return fmt.Errorf("plugin %q exited with error", md.Name)
    91  					}
    92  					return err
    93  				}
    94  				return nil
    95  			},
    96  			// This passes all the flags to the subcommand.
    97  			DisableFlagParsing: true,
    98  		}
    99  
   100  		if md.UseTunnel {
   101  			c.PreRunE = func(cmd *cobra.Command, args []string) error {
   102  				// Parse the parent flag, but not the local flags.
   103  				if _, err := processParent(cmd, args); err != nil {
   104  					return err
   105  				}
   106  				return setupConnection(cmd, args)
   107  			}
   108  		}
   109  
   110  		// TODO: Make sure a command with this name does not already exist.
   111  		baseCmd.AddCommand(c)
   112  	}
   113  }
   114  
   115  // manuallyProcessArgs processes an arg array, removing special args.
   116  //
   117  // Returns two sets of args: known and unknown (in that order)
   118  func manuallyProcessArgs(args []string) ([]string, []string) {
   119  	known := []string{}
   120  	unknown := []string{}
   121  	kvargs := []string{"--host", "--kube-context", "--home", "--tiller-namespace"}
   122  	knownArg := func(a string) bool {
   123  		for _, pre := range kvargs {
   124  			if strings.HasPrefix(a, pre+"=") {
   125  				return true
   126  			}
   127  		}
   128  		return false
   129  	}
   130  	for i := 0; i < len(args); i++ {
   131  		switch a := args[i]; a {
   132  		case "--debug":
   133  			known = append(known, a)
   134  		case "--host", "--kube-context", "--home":
   135  			known = append(known, a, args[i+1])
   136  			i++
   137  		default:
   138  			if knownArg(a) {
   139  				known = append(known, a)
   140  				continue
   141  			}
   142  			unknown = append(unknown, a)
   143  		}
   144  	}
   145  	return known, unknown
   146  }
   147  
   148  // findPlugins returns a list of YAML files that describe plugins.
   149  func findPlugins(plugdirs string) ([]*plugin.Plugin, error) {
   150  	found := []*plugin.Plugin{}
   151  	// Let's get all UNIXy and allow path separators
   152  	for _, p := range filepath.SplitList(plugdirs) {
   153  		matches, err := plugin.LoadAll(p)
   154  		if err != nil {
   155  			return matches, err
   156  		}
   157  		found = append(found, matches...)
   158  	}
   159  	return found, nil
   160  }