mirror of
https://github.com/hashicorp/terraform.git
synced 2026-03-22 02:20:07 -04:00
97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
// Copyright IBM Corp. 2014, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package moduleaddrs
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// SplitPackageSubdir detects whether the given address string has a
|
|
// subdirectory portion, and if so returns a non-empty subDir string
|
|
// along with the trimmed package address.
|
|
//
|
|
// If the given string doesn't have a subdirectory portion then it'll
|
|
// just be returned verbatim in packageAddr, with an empty subDir value.
|
|
//
|
|
// Although the rest of this package is focused only on direct remote
|
|
// module packages, this particular function and its companion
|
|
// ExpandSubdirGlobs are both also relevant for registry-based module
|
|
// addresses, because a registry translates such an address into a
|
|
// remote module package address and thus can contribute its own
|
|
// additions to the final subdirectory selection.
|
|
func SplitPackageSubdir(given string) (packageAddr, subDir string) {
|
|
packageAddr, subDir = splitPackageSubdirRaw(given)
|
|
if subDir != "" {
|
|
subDir = path.Clean(subDir)
|
|
}
|
|
return packageAddr, subDir
|
|
}
|
|
|
|
func splitPackageSubdirRaw(src string) (packageAddr, subDir string) {
|
|
// URL might contains another url in query parameters
|
|
stop := len(src)
|
|
if idx := strings.Index(src, "?"); idx > -1 {
|
|
stop = idx
|
|
}
|
|
|
|
// Calculate an offset to avoid accidentally marking the scheme
|
|
// as the dir.
|
|
var offset int
|
|
if idx := strings.Index(src[:stop], "://"); idx > -1 {
|
|
offset = idx + 3
|
|
}
|
|
|
|
// First see if we even have an explicit subdir
|
|
idx := strings.Index(src[offset:stop], "//")
|
|
if idx == -1 {
|
|
return src, ""
|
|
}
|
|
|
|
idx += offset
|
|
subdir := src[idx+2:]
|
|
src = src[:idx]
|
|
|
|
// Next, check if we have query parameters and push them onto the
|
|
// URL.
|
|
if idx = strings.Index(subdir, "?"); idx > -1 {
|
|
query := subdir[idx:]
|
|
subdir = subdir[:idx]
|
|
src += query
|
|
}
|
|
|
|
return src, subdir
|
|
}
|
|
|
|
// ExpandSubdirGlobs handles a subdir string that might contain glob syntax,
|
|
// turning it into a concrete subdirectory path by referring to the actual
|
|
// files on disk in the given directory which we assume contains the content
|
|
// of whichever package this is a subdirectory glob for.
|
|
//
|
|
// Subdir globs are used, for example, when a module registry wants to specify
|
|
// to select the contents of the single directory at the root of a conventional
|
|
// tar archive but it doesn't actually know the exact name of that directory.
|
|
// In that case it might specify a subdir of just "*", which this function
|
|
// will then expand into the single subdirectory found inside instDir, or
|
|
// return an error if the result would be ambiguous.
|
|
func ExpandSubdirGlobs(instDir string, subDir string) (string, error) {
|
|
pattern := filepath.Join(instDir, subDir)
|
|
|
|
matches, err := filepath.Glob(pattern)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if len(matches) == 0 {
|
|
return "", fmt.Errorf("subdir %q not found", subDir)
|
|
}
|
|
|
|
if len(matches) > 1 {
|
|
return "", fmt.Errorf("subdir %q matches multiple paths", subDir)
|
|
}
|
|
|
|
return matches[0], nil
|
|
}
|