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  }