github.com/opentofu/opentofu@v1.7.1/internal/command/workdir/plugin_dirs.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package workdir 7 8 import ( 9 "encoding/json" 10 "os" 11 "path/filepath" 12 ) 13 14 const PluginPathFilename = "plugin_path" 15 16 // ProviderLocalCacheDir returns the directory we'll use as the 17 // working-directory-specific local cache of providers. 18 // 19 // The provider installer's job is to make sure that all providers needed for 20 // a particular working directory are available in this cache directory. No 21 // other component may write here, and in particular a Dir object itself 22 // never reads or writes into this directory, instead just delegating all of 23 // that responsibility to other components. 24 // 25 // Typically, the caller will ultimately pass the result of this method either 26 // directly or indirectly into providercache.NewDir, to get an object 27 // responsible for managing the contents. 28 func (d *Dir) ProviderLocalCacheDir() string { 29 return filepath.Join(d.dataDir, "providers") 30 } 31 32 // ForcedPluginDirs returns a list of directories to use to find plugins, 33 // instead of the default locations. 34 // 35 // Returns an zero-length list and no error in the normal case where there 36 // are no overridden search directories. If ForcedPluginDirs returns a 37 // non-empty list with no errors then the result totally replaces the default 38 // search directories. 39 func (d *Dir) ForcedPluginDirs() ([]string, error) { 40 raw, err := os.ReadFile(filepath.Join(d.dataDir, PluginPathFilename)) 41 if os.IsNotExist(err) { 42 return nil, nil 43 } 44 45 if err != nil { 46 return nil, err 47 } 48 49 var pluginPath []string 50 if err := json.Unmarshal(raw, &pluginPath); err != nil { 51 return nil, err 52 } 53 return pluginPath, nil 54 } 55 56 // SetForcedPluginDirs records an overridden list of directories to search 57 // to find plugins, instead of the default locations. See ForcePluginDirs 58 // for more information. 59 // 60 // Pass a zero-length list to deactivate forced plugin directories altogether, 61 // thus allowing the working directory to return to using the default 62 // search directories. 63 func (d *Dir) SetForcedPluginDirs(dirs []string) error { 64 65 filePath := filepath.Join(d.dataDir, PluginPathFilename) 66 switch { 67 case len(dirs) == 0: 68 err := os.Remove(filePath) 69 if !os.IsNotExist(err) { 70 return err 71 } 72 return nil 73 default: 74 // We'll ignore errors from this one, because if we fail to create 75 // the directory then we'll fail to create the file below too, 76 // and that subsequent error will more directly reflect what we 77 // are trying to do here. 78 d.ensureDataDir() 79 80 raw, err := json.MarshalIndent(dirs, "", " ") 81 if err != nil { 82 return err 83 } 84 85 return os.WriteFile(filePath, raw, 0644) 86 } 87 }