main: allow enabling plugin caching via config file or environment

Either the environment variable TF_PLUGIN_CACHE_DIR or a setting in the
CLI config file (~/.terraformrc on Unix) allow opting in to the plugin
caching behavior.

This is opt-in because for new users we don't want to pollute their system
with extra directories they don't know about. By opting in to caching, the
user is assuming the responsibility to occasionally prune the cache over
time as older plugins become stale and unused.
This commit is contained in:
Martin Atkins 2017-09-01 16:20:25 -07:00
parent 5c0670fdf4
commit cb17a9a607
3 changed files with 41 additions and 0 deletions

View File

@ -38,6 +38,7 @@ func initCommands(config *Config) {
Ui: Ui, Ui: Ui,
RunningInAutomation: inAutomation, RunningInAutomation: inAutomation,
PluginCacheDir: config.PluginCacheDir,
} }
// The command list is included in the terraform -help // The command list is included in the terraform -help

View File

@ -11,6 +11,8 @@ import (
"github.com/hashicorp/terraform/command" "github.com/hashicorp/terraform/command"
) )
const pluginCacheDirEnvVar = "TF_PLUGIN_CACHE_DIR"
// Config is the structure of the configuration for the Terraform CLI. // Config is the structure of the configuration for the Terraform CLI.
// //
// This is not the configuration for Terraform itself. That is in the // This is not the configuration for Terraform itself. That is in the
@ -21,6 +23,10 @@ type Config struct {
DisableCheckpoint bool `hcl:"disable_checkpoint"` DisableCheckpoint bool `hcl:"disable_checkpoint"`
DisableCheckpointSignature bool `hcl:"disable_checkpoint_signature"` DisableCheckpointSignature bool `hcl:"disable_checkpoint_signature"`
// If set, enables local caching of plugins in this directory to
// avoid repeatedly re-downloading over the Internet.
PluginCacheDir string `hcl:"plugin_cache_dir"`
} }
// BuiltinConfig is the built-in defaults for the configuration. These // BuiltinConfig is the built-in defaults for the configuration. These
@ -75,9 +81,31 @@ func LoadConfig(path string) (*Config, error) {
result.Provisioners[k] = os.ExpandEnv(v) result.Provisioners[k] = os.ExpandEnv(v)
} }
if result.PluginCacheDir != "" {
result.PluginCacheDir = os.ExpandEnv(result.PluginCacheDir)
}
return &result, nil return &result, nil
} }
// EnvConfig returns a Config populated from environment variables.
//
// Any values specified in this config should override those set in the
// configuration file.
func EnvConfig() *Config {
config := &Config{}
if envPluginCacheDir := os.Getenv(pluginCacheDirEnvVar); envPluginCacheDir != "" {
// No Expandenv here, because expanding environment variables inside
// an environment variable would be strange and seems unnecessary.
// (User can expand variables into the value while setting it using
// standard shell features.)
config.PluginCacheDir = envPluginCacheDir
}
return config
}
// 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 {
@ -105,5 +133,10 @@ func (c1 *Config) Merge(c2 *Config) *Config {
result.DisableCheckpoint = c1.DisableCheckpoint || c2.DisableCheckpoint result.DisableCheckpoint = c1.DisableCheckpoint || c2.DisableCheckpoint
result.DisableCheckpointSignature = c1.DisableCheckpointSignature || c2.DisableCheckpointSignature result.DisableCheckpointSignature = c1.DisableCheckpointSignature || c2.DisableCheckpointSignature
result.PluginCacheDir = c1.PluginCacheDir
if result.PluginCacheDir == "" {
result.PluginCacheDir = c2.PluginCacheDir
}
return &result return &result
} }

View File

@ -138,6 +138,13 @@ func wrappedMain() int {
config = *config.Merge(usrcfg) config = *config.Merge(usrcfg)
} }
if envConfig := EnvConfig(); envConfig != nil {
// envConfig takes precedence
config = *envConfig.Merge(&config)
}
log.Printf("[DEBUG] CLI Config is %#v", config)
// In tests, Commands may already be set to provide mock commands // In tests, Commands may already be set to provide mock commands
if Commands == nil { if Commands == nil {
initCommands(&config) initCommands(&config)