github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/command/plugins_lock.go (about) 1 package command 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "path/filepath" 10 ) 11 12 func (m *Meta) providerPluginsLock() *pluginSHA256LockFile { 13 return &pluginSHA256LockFile{ 14 Filename: filepath.Join(m.pluginDir(), "lock.json"), 15 } 16 } 17 18 type pluginSHA256LockFile struct { 19 Filename string 20 } 21 22 // Read loads the lock information from the file and returns it. If the file 23 // cannot be read, an empty map is returned to indicate that _no_ providers 24 // are acceptable, since the user must run "terraform init" to lock some 25 // providers before a context can be created. 26 func (pf *pluginSHA256LockFile) Read() map[string][]byte { 27 // Returning an empty map is different than nil because it causes 28 // us to reject all plugins as uninitialized, rather than applying no 29 // constraints at all. 30 // 31 // We don't surface any specific errors here because we want it to all 32 // roll up into our more-user-friendly error that appears when plugin 33 // constraint verification fails during context creation. 34 digests := make(map[string][]byte) 35 36 buf, err := ioutil.ReadFile(pf.Filename) 37 if err != nil { 38 // This is expected if the user runs any context-using command before 39 // running "terraform init". 40 log.Printf("[INFO] Failed to read plugin lock file %s: %s", pf.Filename, err) 41 return digests 42 } 43 44 var strDigests map[string]string 45 err = json.Unmarshal(buf, &strDigests) 46 if err != nil { 47 // This should never happen unless the user directly edits the file. 48 log.Printf("[WARN] Plugin lock file %s failed to parse as JSON: %s", pf.Filename, err) 49 return digests 50 } 51 52 for name, strDigest := range strDigests { 53 var digest []byte 54 _, err := fmt.Sscanf(strDigest, "%x", &digest) 55 if err == nil { 56 digests[name] = digest 57 } else { 58 // This should never happen unless the user directly edits the file. 59 log.Printf("[WARN] Plugin lock file %s has invalid digest for %q", pf.Filename, name) 60 } 61 } 62 63 return digests 64 } 65 66 // Write persists lock information to disk, where it will be retrieved by 67 // future calls to Read. This entirely replaces any previous lock information, 68 // so the given map must be comprehensive. 69 func (pf *pluginSHA256LockFile) Write(digests map[string][]byte) error { 70 strDigests := map[string]string{} 71 for name, digest := range digests { 72 strDigests[name] = fmt.Sprintf("%x", digest) 73 } 74 75 buf, err := json.MarshalIndent(strDigests, "", " ") 76 if err != nil { 77 // should never happen 78 return fmt.Errorf("failed to serialize plugin lock as JSON: %s", err) 79 } 80 81 os.MkdirAll( 82 filepath.Dir(pf.Filename), os.ModePerm, 83 ) // ignore error since WriteFile below will generate a better one anyway 84 85 return ioutil.WriteFile(pf.Filename, buf, os.ModePerm) 86 }