package command import ( "encoding/json" "fmt" "io/ioutil" "log" ) type pluginSHA256LockFile struct { Filename string } // Read loads the lock information from the file and returns it. If the file // cannot be read, an empty map is returned to indicate that _no_ providers // are acceptable, since the user must run "terraform init" to lock some // providers before a context can be created. func (pf *pluginSHA256LockFile) Read() map[string][]byte { // Returning an empty map is different than nil because it causes // us to reject all plugins as uninitialized, rather than applying no // constraints at all. // // We don't surface any specific errors here because we want it to all // roll up into our more-user-friendly error that appears when plugin // constraint verification fails during context creation. digests := make(map[string][]byte) buf, err := ioutil.ReadFile(pf.Filename) if err != nil { // This is expected if the user runs any context-using command before // running "terraform init". log.Printf("[INFO] Failed to read plugin lock file %s: %s", pf.Filename, err) return digests } var strDigests map[string]string err = json.Unmarshal(buf, &strDigests) if err != nil { // This should never happen unless the user directly edits the file. log.Printf("[WARN] Plugin lock file %s failed to parse as JSON: %s", pf.Filename, err) return digests } for name, strDigest := range strDigests { var digest []byte _, err := fmt.Sscanf(strDigest, "%x", &digest) if err == nil { digests[name] = digest } else { // This should never happen unless the user directly edits the file. log.Printf("[WARN] Plugin lock file %s has invalid digest for %q", pf.Filename, name) } } return digests }