main: auto-discover plugins [GH-190]
/cc @pearkes @armon - exe dir and pwd
This commit is contained in:
parent
f2f119d0eb
commit
4fd3dff829
|
@ -1,5 +1,10 @@
|
||||||
## 0.2.1 (unreleased)
|
## 0.2.1 (unreleased)
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
|
||||||
|
* core: Plugins are automatically discovered in the executable directory
|
||||||
|
or pwd if named properly. [GH-190]
|
||||||
|
|
||||||
BUG FIXES:
|
BUG FIXES:
|
||||||
|
|
||||||
* core: Configuration parses when identifier and '=' have no space. [GH-243]
|
* core: Configuration parses when identifier and '=' have no space. [GH-243]
|
||||||
|
|
89
config.go
89
config.go
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -31,22 +32,6 @@ var BuiltinConfig Config
|
||||||
// ContextOpts are the global ContextOpts we use to initialize the CLI.
|
// ContextOpts are the global ContextOpts we use to initialize the CLI.
|
||||||
var ContextOpts terraform.ContextOpts
|
var ContextOpts terraform.ContextOpts
|
||||||
|
|
||||||
func init() {
|
|
||||||
BuiltinConfig.Providers = map[string]string{
|
|
||||||
"aws": "terraform-provider-aws",
|
|
||||||
"digitalocean": "terraform-provider-digitalocean",
|
|
||||||
"heroku": "terraform-provider-heroku",
|
|
||||||
"dnsimple": "terraform-provider-dnsimple",
|
|
||||||
"consul": "terraform-provider-consul",
|
|
||||||
"cloudflare": "terraform-provider-cloudflare",
|
|
||||||
}
|
|
||||||
BuiltinConfig.Provisioners = map[string]string{
|
|
||||||
"local-exec": "terraform-provisioner-local-exec",
|
|
||||||
"remote-exec": "terraform-provisioner-remote-exec",
|
|
||||||
"file": "terraform-provisioner-file",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigFile returns the default path to the configuration file.
|
// ConfigFile returns the default path to the configuration file.
|
||||||
//
|
//
|
||||||
// On Unix-like systems this is the ".terraformrc" file in the home directory.
|
// On Unix-like systems this is the ".terraformrc" file in the home directory.
|
||||||
|
@ -81,6 +66,30 @@ func LoadConfig(path string) (*Config, error) {
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Discover discovers plugins.
|
||||||
|
//
|
||||||
|
// This looks in the directory of the executable and the CWD, in that
|
||||||
|
// order for priority.
|
||||||
|
func (c *Config) Discover() error {
|
||||||
|
// Look in the cwd.
|
||||||
|
if err := c.discover("."); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, look in the same directory as the executable. Any conflicts
|
||||||
|
// will overwrite those found in our current directory.
|
||||||
|
exePath, err := osext.Executable()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERR] Error loading exe directory: %s", err)
|
||||||
|
} else {
|
||||||
|
if err := c.discover(filepath.Dir(exePath)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Merge merges two configurations and returns a third entirely
|
// Merge merges two configurations and returns a third entirely
|
||||||
// new configuration with the two merged.
|
// new configuration with the two merged.
|
||||||
func (c1 *Config) Merge(c2 *Config) *Config {
|
func (c1 *Config) Merge(c2 *Config) *Config {
|
||||||
|
@ -103,6 +112,54 @@ func (c1 *Config) Merge(c2 *Config) *Config {
|
||||||
return &result
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) discover(path string) error {
|
||||||
|
var err error
|
||||||
|
err = c.discoverSingle(
|
||||||
|
filepath.Join(path, "terraform-provider-*"), &c.Providers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.discoverSingle(
|
||||||
|
filepath.Join(path, "terraform-provisioner-*"), &c.Provisioners)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) discoverSingle(glob string, m *map[string]string) error {
|
||||||
|
matches, err := filepath.Glob(glob)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if *m == nil {
|
||||||
|
*m = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, match := range matches {
|
||||||
|
file := filepath.Base(match)
|
||||||
|
|
||||||
|
// If the filename has a ".", trim up to there
|
||||||
|
if idx := strings.Index(file, "."); idx >= 0 {
|
||||||
|
file = file[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for foo-bar-baz. The plugin name is "baz"
|
||||||
|
parts := strings.SplitN(file, "-", 3)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Discoverd plugin: %s = %s", parts[2], match)
|
||||||
|
(*m)[parts[2]] = match
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ProviderFactories returns the mapping of prefixes to
|
// ProviderFactories returns the mapping of prefixes to
|
||||||
// ResourceProviderFactory that can be used to instantiate a
|
// ResourceProviderFactory that can be used to instantiate a
|
||||||
// binary-based plugin.
|
// binary-based plugin.
|
||||||
|
|
4
main.go
4
main.go
|
@ -79,6 +79,10 @@ func wrappedMain() int {
|
||||||
|
|
||||||
// Load the configuration
|
// Load the configuration
|
||||||
config := BuiltinConfig
|
config := BuiltinConfig
|
||||||
|
if err := config.Discover(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error discovering plugins: %s", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we clean up any managed plugins at the end of this
|
// Make sure we clean up any managed plugins at the end of this
|
||||||
defer plugin.CleanupClients()
|
defer plugin.CleanupClients()
|
||||||
|
|
Loading…
Reference in New Issue