forked from hashicorp/go-getter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[2 of 6] introduce CtxDetector ("contextual detector")
The existing Detector interface cannot be extended in a backward compatible way to support new features desired for the GitDetector implementation[0]. The new CtxDetector interface is introduced to allow such extension without breaking backward compatibility with existing users. The new interface also avoids adding new methods to the existing Detector interface that would then need to be supported by all Detector implementations, both in-library and in the wild. A CtxDetector is slightly more cumbersome to use than Detector. Callers can (and should) continue to use Detector unless the enhanced capabilities of one or more of the CtxDetector implementation modules is needed. At the time of writing (2020-08), the only CtxDetector with such extra mojo is the forthcoming GitCtxDetector. Existing Detector implementations can easily be wrapped by CtxDetector implementations. The information available to a CtxDetector impl. is a strict superset of the information provided to a Detector. Where there is no need for the additional context info provided by the CtxDetect dispatch function, impls. can simply pass through the common subset to the Detect method of the analogous Detector impl. CAVEAT: In this changeset the list of ContextualDetectors is commented- out. This is intended to make a clear introduction of the interface type prior to introducing any implementations of it. A forthcoming change will provide such wrapping for all in-tree Detector impls, followed by the introduction of specialization for the GitCtxDetector impl. [0] C.f., hashicorp#268
- Loading branch information
Showing
1 changed file
with
168 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package getter | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hashicorp/go-getter/helper/url" | ||
) | ||
|
||
// CtxDetector (read: "Contextual Detector"), the evil twin of Detector. | ||
// | ||
// Like its Detector sibling, CtxDetector defines an interface that an invalid | ||
// URL or a URL with a blank scheme can be passed through in order to | ||
// determine if its shorthand for something else well-known. | ||
// | ||
// CtxDetector expands on the capabilities of Detector in the following ways: | ||
// | ||
// * A CtxDetector allows the caller to provide more information about its | ||
// invocation context to the CtxDetect dispatch function. This allows for | ||
// some types of useful detections and transformations that were not | ||
// previously possible. | ||
// | ||
// * The CtxDetect dispatch function provides the CtxDetector | ||
// implementations with all of the context information it has available | ||
// to it, including the force token flag (e.g., "git::"). This allows the | ||
// implementations to safely take (or avoid taking) actions that would be | ||
// unsafe otherwise. | ||
// | ||
// A CtxDetector is slightly more cumbersome to use than Detector. Callers can | ||
// (and should) continue to use Detector unless the enhanced capabilities of | ||
// one or more of the CtxDetector implementation is needed. At the time of | ||
// writing (2020-08), the only CtxDetector with such extra mojo is | ||
// GitCtxDetector (q.v.). | ||
// | ||
type CtxDetector interface { | ||
|
||
// CtxDetect will detect whether the string matches a known pattern to | ||
// turn it into a proper URL | ||
// | ||
// 'src' (required) is the input string to be interpretted. In the common | ||
// case this value will have been preparsed by the CtxDetect dispatch | ||
// function; its forcing token (if any) will have been removed; same for | ||
// any 'go-getter' subdir portion('//some/subdir'). Some examples: | ||
// | ||
// "s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz?version=1234" | ||
// | ||
// "github.com/hashicorp/foo.git" | ||
// | ||
// "[email protected]:hashicorp/foo.git?foo=bar" | ||
// | ||
// "../../git-submods/tf-mods/some-tf-module?ref=v1.2.3" | ||
// | ||
// 'pwd' (optional, sometimes) is the filepath that should be taken as the | ||
// current working directory (mainly for the purpose of resolving | ||
// filesystem paths; may be overridden for that purpose by | ||
// 'srcResolveFrom'). Some CtxDetector implementation may require this | ||
// path to be an abosolute filepath. | ||
// | ||
// 'forceToken' (optional) is the forcing token, if any, extracted from | ||
// the input string submitted to the CtxDetect dispatch function. It is | ||
// provided as a param to the CtxDetect method so that CtxDetector | ||
// implementations may recognize 'src' strings intended for them. This | ||
// removes ambiguity when a given 'src' value could be legitimately | ||
// processed by more than one CtxDetector implementation. | ||
// | ||
// 'ctxSubDir' (optional) is the 'go-getter' subdir portion (if any) | ||
// pre-extracted from the source string (as noted above). It is provided | ||
// to the CtxDetector implementation only for contextual awareness, which | ||
// conceivably could inform its decision-making process. It should not be | ||
// incorporated into the result returned by the CtxDetector impl. | ||
// | ||
// 'srcResolveFrom' (optional, sometimes) A caller-provided filepath to be | ||
// used as the directory from which any relative filepath in 'src' should | ||
// be resolved, instead of relative to 'pwd'. An individual CtxDetector | ||
// implementation may require that this value be absolute. | ||
// | ||
// Protocol: Where they need to be resolved, relative filepath values in | ||
// 'src' will be resolved relative to 'pwd', unless | ||
// 'srcResolveFrom' is non-empty; then they will be resolved | ||
// relative to 'srcResolveFrom'. | ||
// | ||
// Note that some CtxDetector impls. (FileCtxDetector, | ||
// GitCtxDetector) can only produce meaningful results in some | ||
// circumstances if they have an absolute directory to resolve | ||
// to. For best results, when 'srcResolveFrom' is non-empty, | ||
// provide an absolute filepath. | ||
// | ||
// The CtxDetect interface itself does not require that either | ||
// 'pwd' or 'srcResolveFrom' be absolute filepaths, but that | ||
// might be required by a particular CtxDetector implementation. | ||
// Know that RFC-compliant use of 'file://' URIs (which some | ||
// CtxDetector impls. emit) permit only absolute filepaths, and | ||
// tools (such as Git) expect this. Providing relative filepaths | ||
// for 'pwd' and/or 'srcResolveFrom' may result in the | ||
// generation of non-legit 'file://' URIs with relative paths in | ||
// them, and a CtxDetector implementation is permitted to reject | ||
// them with an error if it requires an absolute path. | ||
// | ||
CtxDetect(src, pwd, forceToken, ctxSubDir, srcResolveFrom string) (string, bool, error) | ||
} | ||
|
||
// ContextualDetectors is the list of detectors that are tried on an invalid URL. | ||
// This is also the order they're tried (index 0 is first). | ||
var ContextualDetectors []CtxDetector | ||
|
||
func init() { | ||
ContextualDetectors = []CtxDetector{ | ||
// new(GitHubCtxDetector), | ||
// new(GitCtxDetector), | ||
// new(BitBucketCtxDetector), | ||
// new(S3CtxDetector), | ||
// new(GCSCtxDetector), | ||
// new(FileCtxDetector), | ||
} | ||
} | ||
|
||
// CtxDetect turns a source string into another source string if it is | ||
// detected to be of a known pattern. | ||
// | ||
// An empty-string value provided for 'pwd' is interpretted as "not | ||
// provided". Likewise for 'srcResolveFrom'. | ||
// | ||
// The (optional) 'srcResolveFrom' parameter allows the caller to provide a | ||
// directory from which any relative filepath in 'src' should be resolved, | ||
// instead of relative to 'pwd'. This supports those use cases (e.g., | ||
// Terraform modules with relative 'source' filepaths) where the caller | ||
// context for path resolution may be different than the pwd. For best result, | ||
// the provided value should be an absolute filepath. If unneeded, use specify | ||
// the empty string. | ||
// | ||
// The 'cds' []CtxDetector parameter should be the list of detectors to use in | ||
// the order to try them. If you don't want to configure this, just use the | ||
// global ContextualDetectors variable. | ||
// | ||
// This is safe to be called with an already valid source string: CtxDetect | ||
// will just return it. | ||
// | ||
func CtxDetect(src, pwd, srcResolveFrom string, cds []CtxDetector) (string, error) { | ||
|
||
getForce, getSrc := getForcedGetter(src) | ||
|
||
// Separate out the subdir if there is one, we don't pass that to detect | ||
getSrc, subDir := SourceDirSubdir(getSrc) | ||
|
||
u, err := url.Parse(getSrc) | ||
if err == nil && u.Scheme != "" { | ||
// Valid URL | ||
return src, nil | ||
} | ||
|
||
for _, d := range cds { | ||
result, ok, err := d.CtxDetect(getSrc, pwd, getForce, subDir, srcResolveFrom) | ||
if err != nil { | ||
return "", err | ||
} | ||
if !ok { | ||
continue | ||
} | ||
|
||
result, err = handleDetected(result, getForce, subDir) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
return "", fmt.Errorf("invalid source string: %s", src) | ||
} |