1package command 2 3import ( 4 "os" 5 6 "github.com/hashicorp/terraform/internal/depsfile" 7 "github.com/hashicorp/terraform/internal/tfdiags" 8) 9 10// dependenclyLockFilename is the filename of the dependency lock file. 11// 12// This file should live in the same directory as the .tf files for the 13// root module of the configuration, alongside the .terraform directory 14// as long as that directory's path isn't overridden by the TF_DATA_DIR 15// environment variable. 16// 17// We always expect to find this file in the current working directory 18// because that should also be the root module directory. 19// 20// Some commands have legacy command line arguments that make the root module 21// directory something other than the root module directory; when using those, 22// the lock file will be written in the "wrong" place (the current working 23// directory instead of the root module directory) but we do that intentionally 24// to match where the ".terraform" directory would also be written in that 25// case. Eventually we will phase out those legacy arguments in favor of the 26// global -chdir=... option, which _does_ preserve the intended invariant 27// that the root module directory is always the current working directory. 28const dependencyLockFilename = ".terraform.lock.hcl" 29 30// lockedDependencies reads the dependency lock information from the lock file 31// in the current working directory. 32// 33// If the lock file doesn't exist at the time of the call, lockedDependencies 34// indicates success and returns an empty Locks object. If the file does 35// exist then the result is either a representation of the contents of that 36// file at the instant of the call or error diagnostics explaining some way 37// in which the lock file is invalid. 38// 39// The result is a snapshot of the locked dependencies at the time of the call 40// and does not update as a result of calling replaceLockedDependencies 41// or any other modification method. 42func (m *Meta) lockedDependencies() (*depsfile.Locks, tfdiags.Diagnostics) { 43 // We check that the file exists first, because the underlying HCL 44 // parser doesn't distinguish that error from other error types 45 // in a machine-readable way but we want to treat that as a success 46 // with no locks. There is in theory a race condition here in that 47 // the file could be created or removed in the meantime, but we're not 48 // promising to support two concurrent dependency installation processes. 49 _, err := os.Stat(dependencyLockFilename) 50 if os.IsNotExist(err) { 51 return depsfile.NewLocks(), nil 52 } 53 54 return depsfile.LoadLocksFromFile(dependencyLockFilename) 55} 56 57// replaceLockedDependencies creates or overwrites the lock file in the 58// current working directory to contain the information recorded in the given 59// locks object. 60func (m *Meta) replaceLockedDependencies(new *depsfile.Locks) tfdiags.Diagnostics { 61 return depsfile.SaveLocksToFile(new, dependencyLockFilename) 62} 63