func (i *ProviderInstaller) listProviderVersions(name string) ([]Version, error) {
	versions, err := listPluginVersions(i.providerVersionsURL(name))
	if err != nil {
		return nil, err
	}
	return versions, nil
}
list the version available for the named plugin
package discovery
import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"
	"golang.org/x/net/html"
	cleanhttp "github.com/hashicorp/go-cleanhttp"
	getter "github.com/hashicorp/go-getter"
	multierror "github.com/hashicorp/go-multierror"
	"github.com/mitchellh/cli"
)
const protocolVersionHeader = "x-terraform-protocol-version"
var releaseHost = "https://releases.hashicorp.com"
var httpClient = cleanhttp.DefaultClient()
type Installer interface {
	Get(name string, req Constraints) (PluginMeta, error)
	PurgeUnused(used map[string]PluginMeta) (removed PluginMetaSet, err error)
}
type ProviderInstaller struct {
	Dir string
	PluginProtocolVersion uint
	OS   string
	Arch string
	SkipVerify bool
	Ui cli.Ui  
}
func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, error) {
	versions, err := i.listProviderVersions(provider)
	if err != nil {
		return PluginMeta{}, err
	}
	if len(versions) == 0 {
		return PluginMeta{}, ErrorNoSuitableVersion
	}
	versions = allowedVersions(versions, req)
	if len(versions) == 0 {
		return PluginMeta{}, ErrorNoSuitableVersion
	}
	Versions(versions).Sort()
	for _, v := range versions {
		url := i.providerURL(provider, v.String())
		if !i.SkipVerify {
			sha256, err := i.getProviderChecksum(provider, v.String())
			if err != nil {
				return PluginMeta{}, err
			}
			if sha256 != "" {
				url = url + "?checksum=sha256:" + sha256
			}
		}
		log.Printf("[DEBUG] fetching provider info for %s version %s", provider, v)
		if checkPlugin(url, i.PluginProtocolVersion) {
			i.Ui.Info(fmt.Sprintf("- Downloading plugin for provider %q (%s)...", provider, v.String()))
			log.Printf("[DEBUG] getting provider %q version %q at %s", provider, v, url)
			err := getter.Get(i.Dir, url)
			if err != nil {
				return PluginMeta{}, err
			}
			log.Printf("[DEBUG] looking for the %s %s plugin we just installed", provider, v)
			metas := FindPlugins("provider", []string{i.Dir})
			log.Printf("[DEBUG] all plugins found %#v", metas)
			metas, _ = metas.ValidateVersions()
			metas = metas.WithName(provider).WithVersion(v)
			log.Printf("[DEBUG] filtered plugins %#v", metas)
			if metas.Count() == 0 {
				return PluginMeta{}, fmt.Errorf(
					"failed to find installed plugin version %s; this is a bug in Terraform and should be reported",
					v,
				)
			}
			if metas.Count() > 1 {
				return PluginMeta{}, fmt.Errorf(
					"multiple plugins installed for version %s; this is a bug in Terraform and should be reported",
					v,
				)
			}
			return metas.Newest(), nil
		}
		log.Printf("[INFO] incompatible ProtocolVersion for %s version %s", provider, v)
	}
	return PluginMeta{}, ErrorNoVersionCompatible
}
func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaSet, error) {
	purge := make(PluginMetaSet)
	present := FindPlugins("provider", []string{i.Dir})
	for meta := range present {
		chosen, ok := used[meta.Name]
		if !ok {
			purge.Add(meta)
		}
		if chosen.Path != meta.Path {
			purge.Add(meta)
		}
	}
	removed := make(PluginMetaSet)
	var errs error
	for meta := range purge {
		path := meta.Path
		err := os.Remove(path)
		if err != nil {
			errs = multierror.Append(errs, fmt.Errorf(
				"failed to remove unused provider plugin %s: %s",
				path, err,
			))
		} else {
			removed.Add(meta)
		}
	}
	return removed, errs
}
func (i *ProviderInstaller) providerName(name string) string {
	return "terraform-provider-" + name
}
func (i *ProviderInstaller) providerFileName(name, version string) string {
	os := i.OS
	arch := i.Arch
	if os == "" {
		os = runtime.GOOS
	}
	if arch == "" {
		arch = runtime.GOARCH
	}
	return fmt.Sprintf("%s_%s_%s_%s.zip", i.providerName(name), version, os, arch)
}
func (i *ProviderInstaller) providerVersionsURL(name string) string {
	return releaseHost + "/" + i.providerName(name) + "/"
}
func (i *ProviderInstaller) providerURL(name, version string) string {
	return fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, i.providerFileName(name, version))
}
func (i *ProviderInstaller) providerChecksumURL(name, version string) string {
	fileName := fmt.Sprintf("%s_%s_SHA256SUMS", i.providerName(name), version)
	u := fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, fileName)
	return u
}
func (i *ProviderInstaller) getProviderChecksum(name, version string) (string, error) {
	checksums, err := getPluginSHA256SUMs(i.providerChecksumURL(name, version))
	if err != nil {
		return "", err
	}
	return checksumForFile(checksums, i.providerFileName(name, version)), nil
}
func checkPlugin(url string, pluginProtocolVersion uint) bool {
	resp, err := httpClient.Head(url)
	if err != nil {
		log.Printf("[ERROR] error fetching plugin headers: %s", err)
		return false
	}
	if resp.StatusCode != http.StatusOK {
		log.Println("[ERROR] non-200 status fetching plugin headers:", resp.Status)
		return false
	}
	proto := resp.Header.Get(protocolVersionHeader)
	if proto == "" {
		log.Printf("[WARNING] missing %s from: %s", protocolVersionHeader, url)
		return true
	}
	protoVersion, err := strconv.Atoi(proto)
	if err != nil {
		log.Printf("[ERROR] invalid ProtocolVersion: %s", proto)
		return false
	}
	return protoVersion == int(pluginProtocolVersion)
}