github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/providercache/dir_modify.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package providercache 5 6 import ( 7 "context" 8 "fmt" 9 "log" 10 11 "github.com/terramate-io/tf/getproviders" 12 ) 13 14 // InstallPackage takes a metadata object describing a package available for 15 // installation, retrieves that package, and installs it into the receiving 16 // cache directory. 17 // 18 // If the allowedHashes set has non-zero length then at least one of the hashes 19 // in the set must match the package that "entry" refers to. If none of the 20 // hashes match then the returned error message assumes that the hashes came 21 // from a lock file. 22 func (d *Dir) InstallPackage(ctx context.Context, meta getproviders.PackageMeta, allowedHashes []getproviders.Hash) (*getproviders.PackageAuthenticationResult, error) { 23 if meta.TargetPlatform != d.targetPlatform { 24 return nil, fmt.Errorf("can't install %s package into cache directory expecting %s", meta.TargetPlatform, d.targetPlatform) 25 } 26 newPath := getproviders.UnpackedDirectoryPathForPackage( 27 d.baseDir, meta.Provider, meta.Version, d.targetPlatform, 28 ) 29 30 // Invalidate our metaCache so that subsequent read calls will re-scan to 31 // incorporate any changes we make here. 32 d.metaCache = nil 33 34 log.Printf("[TRACE] providercache.Dir.InstallPackage: installing %s v%s from %s", meta.Provider, meta.Version, meta.Location) 35 switch meta.Location.(type) { 36 case getproviders.PackageHTTPURL: 37 return installFromHTTPURL(ctx, meta, newPath, allowedHashes) 38 case getproviders.PackageLocalArchive: 39 return installFromLocalArchive(ctx, meta, newPath, allowedHashes) 40 case getproviders.PackageLocalDir: 41 return installFromLocalDir(ctx, meta, newPath, allowedHashes) 42 default: 43 // Should not get here, because the above should be exhaustive for 44 // all implementations of getproviders.Location. 45 return nil, fmt.Errorf("don't know how to install from a %T location", meta.Location) 46 } 47 } 48 49 // LinkFromOtherCache takes a CachedProvider value produced from another Dir 50 // and links it into the cache represented by the receiver Dir. 51 // 52 // This is used to implement tiered caching, where new providers are first 53 // populated into a system-wide shared cache and then linked from there into 54 // a configuration-specific local cache. 55 // 56 // It's invalid to link a CachedProvider from a particular Dir into that same 57 // Dir, because that would otherwise potentially replace a real package 58 // directory with a circular link back to itself. 59 // 60 // If the allowedHashes set has non-zero length then at least one of the hashes 61 // in the set must match the package that "entry" refers to. If none of the 62 // hashes match then the returned error message assumes that the hashes came 63 // from a lock file. 64 func (d *Dir) LinkFromOtherCache(entry *CachedProvider, allowedHashes []getproviders.Hash) error { 65 if len(allowedHashes) > 0 { 66 if matches, err := entry.MatchesAnyHash(allowedHashes); err != nil { 67 return fmt.Errorf( 68 "failed to calculate checksum for cached copy of %s %s in %s: %s", 69 entry.Provider, entry.Version, d.baseDir, err, 70 ) 71 } else if !matches { 72 return fmt.Errorf( 73 "the provider cache at %s has a copy of %s %s that doesn't match any of the checksums recorded in the dependency lock file", 74 d.baseDir, entry.Provider, entry.Version, 75 ) 76 } 77 } 78 79 newPath := getproviders.UnpackedDirectoryPathForPackage( 80 d.baseDir, entry.Provider, entry.Version, d.targetPlatform, 81 ) 82 currentPath := entry.PackageDir 83 log.Printf("[TRACE] providercache.Dir.LinkFromOtherCache: linking %s v%s from existing cache %s to %s", entry.Provider, entry.Version, currentPath, newPath) 84 85 // Invalidate our metaCache so that subsequent read calls will re-scan to 86 // incorporate any changes we make here. 87 d.metaCache = nil 88 89 // We re-use the process of installing from a local directory here, because 90 // the two operations are fundamentally the same: symlink if possible, 91 // deep-copy otherwise. 92 meta := getproviders.PackageMeta{ 93 Provider: entry.Provider, 94 Version: entry.Version, 95 96 // FIXME: How do we populate this? 97 ProtocolVersions: nil, 98 TargetPlatform: d.targetPlatform, 99 100 // Because this is already unpacked, the filename is synthetic 101 // based on the standard naming scheme. 102 Filename: fmt.Sprintf("terraform-provider-%s_%s_%s.zip", 103 entry.Provider.Type, entry.Version, d.targetPlatform), 104 Location: getproviders.PackageLocalDir(currentPath), 105 } 106 // No further hash check here because we already checked the hash 107 // of the source directory above. 108 _, err := installFromLocalDir(context.TODO(), meta, newPath, nil) 109 return err 110 }