github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/command/meta_dependencies.go (about) 1 package command 2 3 import ( 4 "log" 5 "os" 6 7 "github.com/eliastor/durgaform/internal/depsfile" 8 "github.com/eliastor/durgaform/internal/tfdiags" 9 ) 10 11 // dependenclyLockFilename is the filename of the dependency lock file. 12 // 13 // This file should live in the same directory as the .tf files for the 14 // root module of the configuration, alongside the .durgaform directory 15 // as long as that directory's path isn't overridden by the TF_DATA_DIR 16 // environment variable. 17 // 18 // We always expect to find this file in the current working directory 19 // because that should also be the root module directory. 20 // 21 // Some commands have legacy command line arguments that make the root module 22 // directory something other than the root module directory; when using those, 23 // the lock file will be written in the "wrong" place (the current working 24 // directory instead of the root module directory) but we do that intentionally 25 // to match where the ".durgaform" directory would also be written in that 26 // case. Eventually we will phase out those legacy arguments in favor of the 27 // global -chdir=... option, which _does_ preserve the intended invariant 28 // that the root module directory is always the current working directory. 29 const dependencyLockFilename = ".durgaform.lock.hcl" 30 31 // lockedDependencies reads the dependency lock information from the lock file 32 // in the current working directory. 33 // 34 // If the lock file doesn't exist at the time of the call, lockedDependencies 35 // indicates success and returns an empty Locks object. If the file does 36 // exist then the result is either a representation of the contents of that 37 // file at the instant of the call or error diagnostics explaining some way 38 // in which the lock file is invalid. 39 // 40 // The result is a snapshot of the locked dependencies at the time of the call 41 // and does not update as a result of calling replaceLockedDependencies 42 // or any other modification method. 43 func (m *Meta) lockedDependencies() (*depsfile.Locks, tfdiags.Diagnostics) { 44 // We check that the file exists first, because the underlying HCL 45 // parser doesn't distinguish that error from other error types 46 // in a machine-readable way but we want to treat that as a success 47 // with no locks. There is in theory a race condition here in that 48 // the file could be created or removed in the meantime, but we're not 49 // promising to support two concurrent dependency installation processes. 50 _, err := os.Stat(dependencyLockFilename) 51 if os.IsNotExist(err) { 52 return m.annotateDependencyLocksWithOverrides(depsfile.NewLocks()), nil 53 } 54 55 ret, diags := depsfile.LoadLocksFromFile(dependencyLockFilename) 56 return m.annotateDependencyLocksWithOverrides(ret), diags 57 } 58 59 // replaceLockedDependencies creates or overwrites the lock file in the 60 // current working directory to contain the information recorded in the given 61 // locks object. 62 func (m *Meta) replaceLockedDependencies(new *depsfile.Locks) tfdiags.Diagnostics { 63 return depsfile.SaveLocksToFile(new, dependencyLockFilename) 64 } 65 66 // annotateDependencyLocksWithOverrides modifies the given Locks object in-place 67 // to track as overridden any provider address that's subject to testing 68 // overrides, development overrides, or "unmanaged provider" status. 69 // 70 // This is just an implementation detail of the lockedDependencies method, 71 // not intended for use anywhere else. 72 func (m *Meta) annotateDependencyLocksWithOverrides(ret *depsfile.Locks) *depsfile.Locks { 73 if ret == nil { 74 return ret 75 } 76 77 for addr := range m.ProviderDevOverrides { 78 log.Printf("[DEBUG] Provider %s is overridden by dev_overrides", addr) 79 ret.SetProviderOverridden(addr) 80 } 81 for addr := range m.UnmanagedProviders { 82 log.Printf("[DEBUG] Provider %s is overridden as an \"unmanaged provider\"", addr) 83 ret.SetProviderOverridden(addr) 84 } 85 if m.testingOverrides != nil { 86 for addr := range m.testingOverrides.Providers { 87 log.Printf("[DEBUG] Provider %s is overridden in Meta.testingOverrides", addr) 88 ret.SetProviderOverridden(addr) 89 } 90 } 91 92 return ret 93 }