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