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 }