func (i *ProviderInstaller) Get(provider addrs.Provider, req Constraints) (PluginMeta, tfdiags.Diagnostics, error) {
	var diags tfdiags.Diagnostics
	if i.OS == "" {
		i.OS = runtime.GOOS
	}
	if i.Arch == "" {
		i.Arch = runtime.GOARCH
	}
	if i.registry == nil {
		i.registry = registry.NewClient(i.Services, nil)
	}
	allVersions, err := i.listProviderVersions(provider)
	if err != nil {
		log.Printf("[DEBUG] %s", err)
		if registry.IsServiceUnreachable(err) {
			registryHost, err := i.hostname()
			if err == nil && registryHost == regsrc.PublicRegistryHost.Raw {
				return PluginMeta{}, diags, ErrorPublicRegistryUnreachable
			}
			return PluginMeta{}, diags, ErrorServiceUnreachable
		}
		if registry.IsServiceNotProvided(err) {
			return PluginMeta{}, diags, err
		}
		return PluginMeta{}, diags, ErrorNoSuchProvider
	}
	for _, warning := range allVersions.Warnings {
		hostname, err := i.hostname()
		if err != nil {
			return PluginMeta{}, diags, err
		}
		diag := tfdiags.SimpleWarning(fmt.Sprintf("%s: %s", hostname, warning))
		diags = diags.Append(diag)
	}
	if len(allVersions.Versions) == 0 {
		return PluginMeta{}, diags, ErrorNoSuitableVersion
	}
	providerSource := allVersions.ID
	versions := allowedVersions(allVersions, req)
	if len(versions) == 0 {
		return PluginMeta{}, diags, ErrorNoSuitableVersion
	}
	response.ProviderVersionCollection(versions).Sort()
	if err := i.checkPlatformCompatibility(versions[0]); err != nil {
		versions = i.platformCompatibleVersions(versions)
		if len(versions) == 0 {
			return PluginMeta{}, diags, ErrorNoVersionCompatibleWithPlatform
		}
	}
	versionMeta := versions[0]
	v := VersionStr(versionMeta.Version).MustParse()
	if err := i.checkPluginProtocol(versionMeta); err != nil {
		closestMatch, err := i.findClosestProtocolCompatibleVersion(allVersions.Versions)
		if err != nil {
			return PluginMeta{}, diags, err
		}
		var errMsg string
		closestVersion := VersionStr(closestMatch.Version).MustParse()
		if v.NewerThan(closestVersion) {
			errMsg = providerProtocolTooNew
		} else {
			errMsg = providerProtocolTooOld
		}
		constraintStr := req.String()
		if constraintStr == "" {
			constraintStr = "(any version)"
		}
		return PluginMeta{}, diags, errwrap.Wrap(ErrorVersionIncompatible, fmt.Errorf(fmt.Sprintf(
			errMsg, provider.LegacyString(), v.String(), tfversion.String(),
			closestVersion.String(), closestVersion.MinorUpgradeConstraintStr(), constraintStr)))
	}
	downloadURLs, err := i.listProviderDownloadURLs(providerSource, versionMeta.Version)
	if err != nil {
		return PluginMeta{}, diags, err
	}
	providerURL := downloadURLs.DownloadURL
	if !i.SkipVerify {
		sha256, err := i.getProviderChecksum(downloadURLs)
		if err != nil {
			return PluginMeta{}, diags, err
		}
		if sha256 != "" {
			providerURL = providerURL + "?checksum=sha256:" + sha256
		}
	}
	printedProviderName := fmt.Sprintf("%q (%s)", provider.LegacyString(), providerSource)
	i.Ui.Info(fmt.Sprintf("- Downloading plugin for provider %s %s...", printedProviderName, versionMeta.Version))
	log.Printf("[DEBUG] getting provider %s version %q", printedProviderName, versionMeta.Version)
	err = i.install(provider, v, providerURL)
	if err != nil {
		return PluginMeta{}, diags, err
	}
	log.Printf("[DEBUG] looking for the %s %s plugin we just installed", provider.LegacyString(), versionMeta.Version)
	metas := FindPlugins("provider", []string{i.Dir})
	log.Printf("[DEBUG] all plugins found %#v", metas)
	metas, _ = metas.ValidateVersions()
	metas = metas.WithName(provider.Type).WithVersion(v)
	log.Printf("[DEBUG] filtered plugins %#v", metas)
	if metas.Count() == 0 {
		return PluginMeta{}, diags, fmt.Errorf(
			"failed to find installed plugin version %s; this is a bug in Terraform and should be reported",
			versionMeta.Version,
		)
	}
	if metas.Count() > 1 {
		return PluginMeta{}, diags, fmt.Errorf(
			"multiple plugins installed for version %s; this is a bug in Terraform and should be reported",
			versionMeta.Version,
		)
	}
	return metas.Newest(), diags, nil
}
Get is part of an implementation of type Installer, and attempts to download
and install a Terraform provider matching the given constraints.

This method may return one of a number of sentinel errors from this
package to indicate issues that are likely to be resolvable via user action:

ErrorNoSuchProvider: no provider with the given name exists in the repository.
ErrorNoSuitableVersion: the provider exists but no available version matches constraints.
ErrorNoVersionCompatible: a plugin was found within the constraints but it is
incompatible with the current Terraform version.

These errors should be recognized and handled as special cases by the caller
to present a suitable user-oriented error message.

All other errors indicate an internal problem that is likely _not_ solvable
through user action, or at least not within Terraform's scope. Error messages
are produced under the assumption that if presented to the user they will
be presented alongside context about what is being installed, and thus the
error messages do not redundantly include such information.
package discovery
import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"github.com/hashicorp/errwrap"
	getter "github.com/hashicorp/go-getter"
	multierror "github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform-svchost/disco"
	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/httpclient"
	"github.com/hashicorp/terraform/registry"
	"github.com/hashicorp/terraform/registry/regsrc"
	"github.com/hashicorp/terraform/registry/response"
	"github.com/hashicorp/terraform/tfdiags"
	tfversion "github.com/hashicorp/terraform/version"
	"github.com/mitchellh/cli"
)
const protocolVersionHeader = "x-terraform-protocol-version"
var httpClient *http.Client
var errVersionNotFound = errors.New("version not found")
func init() {
	httpClient = httpclient.New()
	httpGetter := &getter.HttpGetter{
		Client: httpClient,
		Netrc:  true,
	}
	getter.Getters["http"] = httpGetter
	getter.Getters["https"] = httpGetter
}
type Installer interface {
	Get(provider addrs.Provider, req Constraints) (PluginMeta, tfdiags.Diagnostics, error)
	PurgeUnused(used map[string]PluginMeta) (removed PluginMetaSet, err error)
}
type ProviderInstaller struct {
	Dir string
	Cache PluginCache
	PluginProtocolVersion uint
	OS   string
	Arch string
	SkipVerify bool
	Ui cli.Ui  
	Services *disco.Disco
	registry *registry.Client
}