github.com/ablease/cli@v6.37.1-0.20180613014814-3adbb7d7fb19+incompatible/util/configv3/plugins_config.go (about)

     1  package configv3
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"sort"
    10  	"strings"
    11  
    12  	"code.cloudfoundry.org/cli/util"
    13  )
    14  
    15  // PluginsConfig represents the plugin configuration
    16  type PluginsConfig struct {
    17  	Plugins map[string]Plugin `json:"Plugins"`
    18  }
    19  
    20  // Plugin represents the plugin as a whole, not be confused with PluginCommand
    21  type Plugin struct {
    22  	Name     string
    23  	Location string          `json:"Location"`
    24  	Version  PluginVersion   `json:"Version"`
    25  	Commands []PluginCommand `json:"Commands"`
    26  }
    27  
    28  // CalculateSHA1 returns the sha1 value of the plugin executable. If an error
    29  // is encountered calculating sha1, N/A is returned
    30  func (p Plugin) CalculateSHA1() string {
    31  	fileSHA, err := util.NewSha1Checksum(p.Location).ComputeFileSha1()
    32  
    33  	if err != nil {
    34  		return "N/A"
    35  	}
    36  
    37  	return fmt.Sprintf("%x", fileSHA)
    38  }
    39  
    40  // PluginCommands returns the plugin's commands sorted by command name.
    41  func (p Plugin) PluginCommands() []PluginCommand {
    42  	sort.Slice(p.Commands, func(i, j int) bool {
    43  		return strings.ToLower(p.Commands[i].Name) < strings.ToLower(p.Commands[j].Name)
    44  	})
    45  	return p.Commands
    46  }
    47  
    48  // PluginVersion is the plugin version information
    49  type PluginVersion struct {
    50  	Major int `json:"Major"`
    51  	Minor int `json:"Minor"`
    52  	Build int `json:"Build"`
    53  }
    54  
    55  // String returns the plugin's version in the format x.y.z.
    56  func (v PluginVersion) String() string {
    57  	if v.Major == 0 && v.Minor == 0 && v.Build == 0 {
    58  		return "N/A"
    59  	}
    60  	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Build)
    61  }
    62  
    63  // PluginCommand represents an individual command inside a plugin
    64  type PluginCommand struct {
    65  	Name         string             `json:"Name"`
    66  	Alias        string             `json:"Alias"`
    67  	HelpText     string             `json:"HelpText"`
    68  	UsageDetails PluginUsageDetails `json:"UsageDetails"`
    69  }
    70  
    71  // CommandName returns the name of the plugin. The name is concatenated with
    72  // alias if alias is specified.
    73  func (c PluginCommand) CommandName() string {
    74  	if c.Name != "" && c.Alias != "" {
    75  		return fmt.Sprintf("%s, %s", c.Name, c.Alias)
    76  	}
    77  	return c.Name
    78  }
    79  
    80  // PluginUsageDetails contains the usage metadata provided by the plugin
    81  type PluginUsageDetails struct {
    82  	Usage   string            `json:"Usage"`
    83  	Options map[string]string `json:"Options"`
    84  }
    85  
    86  // AddPlugin adds the specified plugin to PluginsConfig
    87  func (config *Config) AddPlugin(plugin Plugin) {
    88  	config.pluginsConfig.Plugins[plugin.Name] = plugin
    89  }
    90  
    91  func (config *Config) CreatePluginHome() error {
    92  	return os.MkdirAll(config.PluginHome(), 0700)
    93  }
    94  
    95  // GetPlugin returns the requested plugin and true if it exists.
    96  func (config *Config) GetPlugin(pluginName string) (Plugin, bool) {
    97  	plugin, exists := config.pluginsConfig.Plugins[pluginName]
    98  	return plugin, exists
    99  }
   100  
   101  // GetPluginCaseInsensitive finds the first matching plugin name case
   102  // insensitive and returns true if it exists.
   103  func (config *Config) GetPluginCaseInsensitive(pluginName string) (Plugin, bool) {
   104  	for name, plugin := range config.pluginsConfig.Plugins {
   105  		if strings.ToLower(name) == strings.ToLower(pluginName) {
   106  			return plugin, true
   107  		}
   108  	}
   109  
   110  	return Plugin{}, false
   111  }
   112  
   113  // PluginHome returns the plugin configuration directory to:
   114  //   1. The $CF_PLUGIN_HOME/.cf/plugins environment variable if set
   115  //   2. Defaults to the home directory (outlined in LoadConfig)/.cf/plugins
   116  func (config *Config) PluginHome() string {
   117  	if config.ENV.CFPluginHome != "" {
   118  		return filepath.Join(config.ENV.CFPluginHome, ".cf", "plugins")
   119  	}
   120  
   121  	return filepath.Join(homeDirectory(), ".cf", "plugins")
   122  }
   123  
   124  // Plugins returns installed plugins from the config sorted by name (case-insensitive).
   125  func (config *Config) Plugins() []Plugin {
   126  	plugins := []Plugin{}
   127  	for _, plugin := range config.pluginsConfig.Plugins {
   128  		plugins = append(plugins, plugin)
   129  	}
   130  	sort.Slice(plugins, func(i, j int) bool {
   131  		return strings.ToLower(plugins[i].Name) < strings.ToLower(plugins[j].Name)
   132  	})
   133  	return plugins
   134  }
   135  
   136  // RemovePlugin removes the specified plugin from PluginsConfig idempotently
   137  func (config *Config) RemovePlugin(pluginName string) {
   138  	delete(config.pluginsConfig.Plugins, pluginName)
   139  }
   140  
   141  // WritePluginConfig writes the plugin config to config.json in the plugin home
   142  // directory.
   143  func (config *Config) WritePluginConfig() error {
   144  	// Marshal JSON
   145  	rawConfig, err := json.MarshalIndent(config.pluginsConfig, "", "  ")
   146  	if err != nil {
   147  		return err
   148  	}
   149  
   150  	pluginFileDir := filepath.Join(config.PluginHome())
   151  	err = os.MkdirAll(pluginFileDir, 0700)
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	// Write to file
   157  	return ioutil.WriteFile(filepath.Join(pluginFileDir, "config.json"), rawConfig, 0600)
   158  }