func (s Storage) findRegistryModule(mSource, constraint string) (moduleRecord, error) {
	rec := moduleRecord{
		Source: mSource,
	}
	mod, err := regsrc.ParseModuleSource(mSource)
	switch err {
	case nil:
	case regsrc.ErrInvalidModuleSource:
		return rec, nil
	default:
		return rec, err
	}
	rec.registry = true
	log.Printf("[TRACE] %q is a registry module", mod.Display())
	versions, err := s.moduleVersions(mod.String())
	if err != nil {
		log.Printf("[ERROR] error looking up versions for %q: %s", mod.Display(), err)
		return rec, err
	}
	match, err := newestRecord(versions, constraint)
	if err != nil {
		log.Printf("[INFO] no matching version for %q<%s>, %s", mod.Display(), constraint, err)
	}
	log.Printf("[DEBUG] matched %q version %s for %s", mod, match.Version, constraint)
	rec.Dir = match.Dir
	rec.Version = match.Version
	found := rec.Dir != ""
	if (s.Mode == GetModeGet && !found) || (s.Mode == GetModeUpdate) {
		resp, err := s.registry.ModuleVersions(mod)
		if err != nil {
			return rec, err
		}
		if len(resp.Modules) == 0 {
			return rec, fmt.Errorf("module %q not found in registry", mod.Display())
		}
		match, err := newestVersion(resp.Modules[0].Versions, constraint)
		if err != nil {
			return rec, err
		}
		if match == nil {
			return rec, fmt.Errorf("no versions for %q found matching %q", mod.Display(), constraint)
		}
		rec.Version = match.Version
		rec.url, err = s.registry.ModuleLocation(mod, rec.Version)
		if err != nil {
			return rec, err
		}
		host, _ := mod.SvcHost()
		s.output(fmt.Sprintf("  Found version %s of %s on %s", rec.Version, mod.Module(), host.ForDisplay()))
	}
	return rec, nil
}
find a registry module
package module
import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	getter "github.com/hashicorp/go-getter"
	"github.com/hashicorp/terraform/registry"
	"github.com/hashicorp/terraform/registry/regsrc"
	"github.com/hashicorp/terraform/svchost/disco"
	"github.com/mitchellh/cli"
)
const manifestName = "modules.json"
type moduleManifest struct {
	Modules []moduleRecord
}
type moduleRecord struct {
	Source string
	Key string
	Version string
	Dir string
	Root string
	url string
	registry bool
}
type Storage struct {
	StorageDir string
	Ui cli.Ui
	Mode GetMode
	registry *registry.Client
}
func NewStorage(dir string, services *disco.Disco) *Storage {
	regClient := registry.NewClient(services, nil)
	return &Storage{
		StorageDir: dir,
		registry:   regClient,
	}
}
func (s Storage) loadManifest() (moduleManifest, error) {
	manifest := moduleManifest{}
	manifestPath := filepath.Join(s.StorageDir, manifestName)
	data, err := ioutil.ReadFile(manifestPath)
	if err != nil && !os.IsNotExist(err) {
		return manifest, err
	}
	if len(data) == 0 {
		return manifest, nil
	}
	if err := json.Unmarshal(data, &manifest); err != nil {
		return manifest, err
	}
	return manifest, nil
}
func (s Storage) recordModule(rec moduleRecord) error {
	manifest, err := s.loadManifest()
	if err != nil {
		log.Printf("[WARN] error reading module manifest: %s", err)
	}
	for i, stored := range manifest.Modules {
		if rec == stored {
			return nil
		}
		if rec.Dir == stored.Dir {
			manifest.Modules[i] = manifest.Modules[len(manifest.Modules)-1]
			manifest.Modules = manifest.Modules[:len(manifest.Modules)-1]
			break
		}
	}
	manifest.Modules = append(manifest.Modules, rec)
	js, err := json.Marshal(manifest)
	if err != nil {
		panic(err)
	}
	manifestPath := filepath.Join(s.StorageDir, manifestName)
	return ioutil.WriteFile(manifestPath, js, 0644)
}
func (s Storage) moduleVersions(source string) ([]moduleRecord, error) {
	manifest, err := s.loadManifest()
	if err != nil {
		return manifest.Modules, err
	}
	var matching []moduleRecord
	for _, m := range manifest.Modules {
		if m.Source == source && m.Version != "" {
			log.Printf("[DEBUG] found local version %q for module %s", m.Version, m.Source)
			matching = append(matching, m)
		}
	}
	return matching, nil
}
func (s Storage) moduleDir(key string) (string, error) {
	manifest, err := s.loadManifest()
	if err != nil {
		return "", err
	}
	for _, m := range manifest.Modules {
		if m.Key == key {
			return m.Dir, nil
		}
	}
	return "", nil
}
func (s Storage) getModuleRoot(dir string) (string, error) {
	manifest, err := s.loadManifest()
	if err != nil {
		return "", err
	}
	for _, mod := range manifest.Modules {
		if mod.Dir == dir {
			return mod.Root, nil
		}
	}
	return "", nil
}
func (s Storage) recordModuleRoot(dir, root string) error {
	rec := moduleRecord{
		Dir:  dir,
		Root: root,
	}
	return s.recordModule(rec)
}
func (s Storage) output(msg string) {
	if s.Ui == nil || s.Mode == GetModeNone {
		return
	}
	s.Ui.Output(msg)
}
func (s Storage) getStorage(key string, src string) (string, bool, error) {
	storage := &getter.FolderStorage{
		StorageDir: s.StorageDir,
	}
	log.Printf("[DEBUG] fetching module from %s", src)
	if s.Mode > GetModeNone {
		log.Printf("[DEBUG] fetching %q with key %q", src, key)
		if err := storage.Get(key, src, s.Mode == GetModeUpdate); err != nil {
			return "", false, err
		}
	}
	dir, found, err := storage.Dir(key)
	log.Printf("[DEBUG] found %q in %q: %t", src, dir, found)
	return dir, found, err
}
func (s Storage) findModule(key string) (string, error) {
	if s.Mode == GetModeUpdate {
		return "", nil
	}
	return s.moduleDir(key)
}
func (s Storage) GetModule(dst, src string) error {
	mode := s.Mode
	s.Mode = GetModeUpdate
	defer func() {
		s.Mode = mode
	}()
	rec, err := s.findRegistryModule(src, anyVersion)
	if err != nil {
		return err
	}
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}
	source := rec.url
	if source == "" {
		source, err = getter.Detect(src, pwd, getter.Detectors)
		if err != nil {
			return fmt.Errorf("module %s: %s", src, err)
		}
	}
	if source == "" {
		return fmt.Errorf("module %q not found", src)
	}
	return GetCopy(dst, source)
}