opentofu/internal/getmodules/package.go
Martin Atkins 1a8da65314 Refactoring of module source addresses and module installation
It's been a long while since we gave close attention to the codepaths for
module source address parsing and external module package installation.
Due to their age, these codepaths often diverged from our modern practices
such as representing address types in the addrs package, and encapsulating
package installation details only in a particular location.

In particular, this refactor makes source address parsing a separate step
from module installation, which therefore makes the result of that parsing
available to other Terraform subsystems which work with the configuration
representation objects.

This also presented the opportunity to better encapsulate our use of
go-getter into a new package "getmodules" (echoing "getproviders"), which
is intended to be the only part of Terraform that directly interacts with
go-getter.

This is largely just a refactor of the existing functionality into a new
code organization, but there is one notable change in behavior here: the
source address parsing now happens during configuration loading rather
than module installation, which may cause errors about invalid addresses
to be returned in different situations than before. That counts as
backward compatible because we only promise to remain compatible with
configurations that are _valid_, which means that they can be initialized,
planned, and applied without any errors. This doesn't introduce any new
error cases, and instead just makes a pre-existing error case be detected
earlier.

Our module registry client is still using its own special module address
type from registry/regsrc for now, with a small shim from the new
addrs.ModuleSourceRegistry type. Hopefully in a later commit we'll also
rework the registry client to work with the new address type, but this
commit is already big enough as it is.
2021-06-03 08:50:34 -07:00

70 lines
3.4 KiB
Go

package getmodules
import (
getter "github.com/hashicorp/go-getter"
)
// NormalizePackageAddress uses the go-getter "detector" functionality in
// order to turn a user-supplied source address into a normalized address
// which always includes a prefix naming a protocol to fetch with and may
// also include a transformed/normalized version of the protocol-specific
// source address included afterward.
//
// This is part of the implementation of addrs.ParseModulePackage and of
// addrs.ParseModuleSource, so for most callers it'd be better to call
// one of those other functions instead. The addrs package can potentially
// perform other processing in addition to just the go-getter detection.
//
// Note that this function expects to recieve only a package address, not
// a full source address that might also include a subdirectory portion.
// The caller must trim off any subdirectory portion using
// getmodules.SplitPackageSubdir before calling this function, passing in
// just the packageAddr return value, or the result will be incorrect.
//
// The detectors in go-getter can potentially introduce their own
// package subdirectory portions. If that happens then this function will
// return the subdirectory portion as a non-empty subDir return value,
// which the caller must then use as a prefix for any subDir it already
// extracted from the user's given package address.
//
// Some of go-getter's detectors make outgoing HTTP requests, and so
// the behavior of this function may depend on the network connectivity
// of the system where Terraform is running. However, most of the getters
// we use are local-only, and so HTTP requests are only for some ambiguous
// edge-cases, such as the BitBucket detector which has a mechanism to
// detect whether to use Git or Mercurial, because earlier versions of
// BitBucket used to support both.
func NormalizePackageAddress(given string) (packageAddr, subDir string, err error) {
// Because we're passing go-getter no base directory here, the file
// detector will return an error if the user entered a relative filesystem
// path without a "../" or "./" prefix and thus ended up in here.
//
// go-getter's error message for that case is very poor, and so we'll
// try to heuristically detect that situation and return a better error
// message.
// NOTE: We're passing an empty string to the "current working directory"
// here because that's only relevant for relative filesystem paths,
// but Terraform handles relative filesystem paths itself outside of
// go-getter and so it'd always be an error to pass one into here.
// go-getter's "file" detector returns an error if it encounters a
// relative path when the pwd argument is empty.
//
// (Absolute filesystem paths _are_ valid though, for annoying historical
// reasons, and we treat them as remote packages even though "downloading"
// them just means a recursive copy of the source directory tree.)
result, err := getter.Detect(given, "", goGetterDetectors)
if err != nil {
// NOTE: go-getter's error messages are of very inconsistent quality
// and many are not suitable for an end-user audience, but they are all
// just strings and so we can't really do any sort of post-processing
// to improve them and thus we just accept some bad error messages for
// now.
return "", "", err
}
packageAddr, subDir = SplitPackageSubdir(result)
return packageAddr, subDir, nil
}