opentofu/internal/getproviders/memoize_source.go
Kuba Martin ebcf7455eb
Rename root module name. (#4)
* Rename module name from "github.com/hashicorp/terraform" to "github.com/placeholderplaceholderplaceholder/opentf".

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Gofmt.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Regenerate protobuf.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Fix comments.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Undo issue and pull request link changes.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Undo comment changes.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Fix comment.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* Undo some link changes.

Signed-off-by: Jakub Martin <kubam@spacelift.io>

* make generate && make protobuf

Signed-off-by: Jakub Martin <kubam@spacelift.io>

---------

Signed-off-by: Jakub Martin <kubam@spacelift.io>
2023-08-17 14:45:11 +02:00

107 lines
3.2 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package getproviders
import (
"context"
"sync"
"github.com/placeholderplaceholderplaceholder/opentf/internal/addrs"
)
// MemoizeSource is a Source that wraps another Source and remembers its
// results so that they can be returned more quickly on future calls to the
// same object.
//
// Each MemoizeSource maintains a cache of response it has seen as part of its
// body. All responses are retained for the remaining lifetime of the object.
// Errors from the underlying source are also cached, and so subsequent calls
// with the same arguments will always produce the same errors.
//
// A MemoizeSource can be called concurrently, with incoming requests processed
// sequentially.
type MemoizeSource struct {
underlying Source
availableVersions map[addrs.Provider]memoizeAvailableVersionsRet
packageMetas map[memoizePackageMetaCall]memoizePackageMetaRet
mu sync.Mutex
}
type memoizeAvailableVersionsRet struct {
VersionList VersionList
Warnings Warnings
Err error
}
type memoizePackageMetaCall struct {
Provider addrs.Provider
Version Version
Target Platform
}
type memoizePackageMetaRet struct {
PackageMeta PackageMeta
Err error
}
var _ Source = (*MemoizeSource)(nil)
// NewMemoizeSource constructs and returns a new MemoizeSource that wraps
// the given underlying source and memoizes its results.
func NewMemoizeSource(underlying Source) *MemoizeSource {
return &MemoizeSource{
underlying: underlying,
availableVersions: make(map[addrs.Provider]memoizeAvailableVersionsRet),
packageMetas: make(map[memoizePackageMetaCall]memoizePackageMetaRet),
}
}
// AvailableVersions requests the available versions from the underlying source
// and caches them before returning them, or on subsequent calls returns the
// result directly from the cache.
func (s *MemoizeSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) {
s.mu.Lock()
defer s.mu.Unlock()
if existing, exists := s.availableVersions[provider]; exists {
return existing.VersionList, nil, existing.Err
}
ret, warnings, err := s.underlying.AvailableVersions(ctx, provider)
s.availableVersions[provider] = memoizeAvailableVersionsRet{
VersionList: ret,
Err: err,
Warnings: warnings,
}
return ret, warnings, err
}
// PackageMeta requests package metadata from the underlying source and caches
// the result before returning it, or on subsequent calls returns the result
// directly from the cache.
func (s *MemoizeSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
s.mu.Lock()
defer s.mu.Unlock()
key := memoizePackageMetaCall{
Provider: provider,
Version: version,
Target: target,
}
if existing, exists := s.packageMetas[key]; exists {
return existing.PackageMeta, existing.Err
}
ret, err := s.underlying.PackageMeta(ctx, provider, version, target)
s.packageMetas[key] = memoizePackageMetaRet{
PackageMeta: ret,
Err: err,
}
return ret, err
}
func (s *MemoizeSource) ForDisplay(provider addrs.Provider) string {
return s.underlying.ForDisplay(provider)
}