| // Copyright IBM Corp. 2014, 2026 | |
| // SPDX-License-Identifier: BUSL-1.1 | |
| package workdir | |
| import ( | |
| "encoding/json" | |
| "io/ioutil" | |
| "os" | |
| "path/filepath" | |
| ) | |
| const PluginPathFilename = "plugin_path" | |
| // ProviderLocalCacheDir returns the directory we'll use as the | |
| // working-directory-specific local cache of providers. | |
| // | |
| // The provider installer's job is to make sure that all providers needed for | |
| // a particular working directory are available in this cache directory. No | |
| // other component may write here, and in particular a Dir object itself | |
| // never reads or writes into this directory, instead just delegating all of | |
| // that responsibility to other components. | |
| // | |
| // Typically, the caller will ultimately pass the result of this method either | |
| // directly or indirectly into providercache.NewDir, to get an object | |
| // responsible for managing the contents. | |
| func (d *Dir) ProviderLocalCacheDir() string { | |
| return filepath.Join(d.dataDir, "providers") | |
| } | |
| // ForcedPluginDirs returns a list of directories to use to find plugins, | |
| // instead of the default locations. | |
| // | |
| // Returns an zero-length list and no error in the normal case where there | |
| // are no overridden search directories. If ForcedPluginDirs returns a | |
| // non-empty list with no errors then the result totally replaces the default | |
| // search directories. | |
| func (d *Dir) ForcedPluginDirs() ([]string, error) { | |
| raw, err := ioutil.ReadFile(filepath.Join(d.dataDir, PluginPathFilename)) | |
| if os.IsNotExist(err) { | |
| return nil, nil | |
| } | |
| if err != nil { | |
| return nil, err | |
| } | |
| var pluginPath []string | |
| if err := json.Unmarshal(raw, &pluginPath); err != nil { | |
| return nil, err | |
| } | |
| return pluginPath, nil | |
| } | |
| // SetForcedPluginDirs records an overridden list of directories to search | |
| // to find plugins, instead of the default locations. See ForcePluginDirs | |
| // for more information. | |
| // | |
| // Pass a zero-length list to deactivate forced plugin directories altogether, | |
| // thus allowing the working directory to return to using the default | |
| // search directories. | |
| func (d *Dir) SetForcedPluginDirs(dirs []string) error { | |
| filePath := filepath.Join(d.dataDir, PluginPathFilename) | |
| switch { | |
| case len(dirs) == 0: | |
| err := os.Remove(filePath) | |
| if !os.IsNotExist(err) { | |
| return err | |
| } | |
| return nil | |
| default: | |
| // We'll ignore errors from this one, because if we fail to create | |
| // the directory then we'll fail to create the file below too, | |
| // and that subsequent error will more directly reflect what we | |
| // are trying to do here. | |
| d.ensureDataDir() | |
| raw, err := json.MarshalIndent(dirs, "", " ") | |
| if err != nil { | |
| return err | |
| } | |
| return ioutil.WriteFile(filePath, raw, 0644) | |
| } | |
| } |