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