mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Ignore existing package hashes for providers lock
command (#31389)
* Ignore existing package hashes for command * missing new line * Fix incorrect logic when deciding change message * fix imports
This commit is contained in:
parent
afd273d636
commit
224728879d
@ -13,6 +13,14 @@ import (
|
|||||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type providersLockChangeType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
providersLockChangeTypeNoChange providersLockChangeType = "providersLockChangeTypeNoChange"
|
||||||
|
providersLockChangeTypeNewProvider providersLockChangeType = "providersLockChangeTypeNewProvider"
|
||||||
|
providersLockChangeTypeNewHashes providersLockChangeType = "providersLockChangeTypeNewHashes"
|
||||||
|
)
|
||||||
|
|
||||||
// ProvidersLockCommand is a Command implementation that implements the
|
// ProvidersLockCommand is a Command implementation that implements the
|
||||||
// "terraform providers lock" command, which creates or updates the current
|
// "terraform providers lock" command, which creates or updates the current
|
||||||
// configuration's dependency lock file using information from upstream
|
// configuration's dependency lock file using information from upstream
|
||||||
@ -225,7 +233,7 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||||||
if keyID != "" {
|
if keyID != "" {
|
||||||
keyID = c.Colorize().Color(fmt.Sprintf(", key ID [reset][bold]%s[reset]", keyID))
|
keyID = c.Colorize().Color(fmt.Sprintf(", key ID [reset][bold]%s[reset]", keyID))
|
||||||
}
|
}
|
||||||
c.Ui.Output(fmt.Sprintf("- Obtained %s checksums for %s (%s%s)", provider.ForDisplay(), platform, auth, keyID))
|
c.Ui.Output(fmt.Sprintf("- Retrieved %s %s for %s (%s%s)", provider.ForDisplay(), version, platform, auth, keyID))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ctx := evts.OnContext(ctx)
|
ctx := evts.OnContext(ctx)
|
||||||
@ -233,7 +241,7 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||||||
dir := providercache.NewDirWithPlatform(tempDir, platform)
|
dir := providercache.NewDirWithPlatform(tempDir, platform)
|
||||||
installer := providercache.NewInstaller(dir, source)
|
installer := providercache.NewInstaller(dir, source)
|
||||||
|
|
||||||
newLocks, err := installer.EnsureProviderVersions(ctx, oldLocks, reqs, providercache.InstallNewProvidersOnly)
|
newLocks, err := installer.EnsureProviderVersions(ctx, oldLocks, reqs, providercache.InstallNewProvidersForce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
tfdiags.Error,
|
tfdiags.Error,
|
||||||
@ -252,6 +260,10 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track whether we've made any changes to the lock file as part of this
|
||||||
|
// operation. We can customise the final message based on our actions.
|
||||||
|
madeAnyChange := false
|
||||||
|
|
||||||
// We now have a separate updated locks object for each platform. We need
|
// We now have a separate updated locks object for each platform. We need
|
||||||
// to merge those all together so that the final result has the union of
|
// to merge those all together so that the final result has the union of
|
||||||
// all of the checksums we saw for each of the providers we've worked on.
|
// all of the checksums we saw for each of the providers we've worked on.
|
||||||
@ -270,7 +282,7 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||||||
constraints = oldLock.VersionConstraints()
|
constraints = oldLock.VersionConstraints()
|
||||||
hashes = append(hashes, oldLock.AllHashes()...)
|
hashes = append(hashes, oldLock.AllHashes()...)
|
||||||
}
|
}
|
||||||
for _, platformLocks := range updatedLocks {
|
for platform, platformLocks := range updatedLocks {
|
||||||
platformLock := platformLocks.Provider(provider)
|
platformLock := platformLocks.Provider(provider)
|
||||||
if platformLock == nil {
|
if platformLock == nil {
|
||||||
continue // weird, but we'll tolerate it to avoid crashing
|
continue // weird, but we'll tolerate it to avoid crashing
|
||||||
@ -282,6 +294,32 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||||||
// platforms here, because the SetProvider method we call below
|
// platforms here, because the SetProvider method we call below
|
||||||
// handles that automatically.
|
// handles that automatically.
|
||||||
hashes = append(hashes, platformLock.AllHashes()...)
|
hashes = append(hashes, platformLock.AllHashes()...)
|
||||||
|
|
||||||
|
// At this point, we've merged all the hashes for this (provider, platform)
|
||||||
|
// combo into the combined hashes for this provider. Let's take this
|
||||||
|
// opportunity to print out a summary for this particular combination.
|
||||||
|
switch providersLockCalculateChangeType(oldLock, platformLock) {
|
||||||
|
case providersLockChangeTypeNewProvider:
|
||||||
|
madeAnyChange = true
|
||||||
|
c.Ui.Output(
|
||||||
|
fmt.Sprintf(
|
||||||
|
"- Obtained %s checksums for %s; This was a new provider and the checksums for this platform are now tracked in the lock file",
|
||||||
|
provider.ForDisplay(),
|
||||||
|
platform))
|
||||||
|
case providersLockChangeTypeNewHashes:
|
||||||
|
madeAnyChange = true
|
||||||
|
c.Ui.Output(
|
||||||
|
fmt.Sprintf(
|
||||||
|
"- Obtained %s checksums for %s; Additional checksums for this platform are now tracked in the lock file",
|
||||||
|
provider.ForDisplay(),
|
||||||
|
platform))
|
||||||
|
case providersLockChangeTypeNoChange:
|
||||||
|
c.Ui.Output(
|
||||||
|
fmt.Sprintf(
|
||||||
|
"- Obtained %s checksums for %s; All checksums for this platform were already tracked in the lock file",
|
||||||
|
provider.ForDisplay(),
|
||||||
|
platform))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
newLocks.SetProvider(provider, version, constraints, hashes)
|
newLocks.SetProvider(provider, version, constraints, hashes)
|
||||||
}
|
}
|
||||||
@ -294,8 +332,12 @@ func (c *ProvidersLockCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Ui.Output(c.Colorize().Color("\n[bold][green]Success![reset] [bold]Terraform has updated the lock file.[reset]"))
|
if madeAnyChange {
|
||||||
c.Ui.Output("\nReview the changes in .terraform.lock.hcl and then commit to your\nversion control system to retain the new checksums.\n")
|
c.Ui.Output(c.Colorize().Color("\n[bold][green]Success![reset] [bold]Terraform has updated the lock file.[reset]"))
|
||||||
|
c.Ui.Output("\nReview the changes in .terraform.lock.hcl and then commit to your\nversion control system to retain the new checksums.\n")
|
||||||
|
} else {
|
||||||
|
c.Ui.Output(c.Colorize().Color("\n[bold][green]Success![reset] [bold]Terraform has validated the lock file and found no need for changes.[reset]"))
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,3 +399,28 @@ Options:
|
|||||||
set of target platforms.
|
set of target platforms.
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// providersLockCalculateChangeType works out whether there is any difference
|
||||||
|
// between oldLock and newLock and returns a variable the main function can use
|
||||||
|
// to decide on which message to print.
|
||||||
|
//
|
||||||
|
// One assumption made here that is not obvious without the context from the
|
||||||
|
// main function is that while platformLock contains the lock information for a
|
||||||
|
// single platform after the current run, oldLock contains the combined
|
||||||
|
// information of all platforms from when the versions were last checked. A
|
||||||
|
// simple equality check is not sufficient for deciding on change as we expect
|
||||||
|
// that oldLock will be a superset of platformLock if no new hashes have been
|
||||||
|
// found.
|
||||||
|
//
|
||||||
|
// We've separated this function out so we can write unit tests around the
|
||||||
|
// logic. This function assumes the platformLock is not nil, as the main
|
||||||
|
// function explicitly checks this before calling this function.
|
||||||
|
func providersLockCalculateChangeType(oldLock *depsfile.ProviderLock, platformLock *depsfile.ProviderLock) providersLockChangeType {
|
||||||
|
if oldLock == nil {
|
||||||
|
return providersLockChangeTypeNewProvider
|
||||||
|
}
|
||||||
|
if oldLock.ContainsAll(platformLock) {
|
||||||
|
return providersLockChangeTypeNoChange
|
||||||
|
}
|
||||||
|
return providersLockChangeTypeNewHashes
|
||||||
|
}
|
||||||
|
@ -8,6 +8,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/internal/addrs"
|
||||||
|
"github.com/hashicorp/terraform/internal/depsfile"
|
||||||
|
"github.com/hashicorp/terraform/internal/getproviders"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,40 +36,7 @@ func TestProvidersLock(t *testing.T) {
|
|||||||
|
|
||||||
// This test depends on the -fs-mirror argument, so we always know what results to expect
|
// This test depends on the -fs-mirror argument, so we always know what results to expect
|
||||||
t.Run("basic", func(t *testing.T) {
|
t.Run("basic", func(t *testing.T) {
|
||||||
td := t.TempDir()
|
testDirectory := "providers-lock/basic"
|
||||||
testCopyDir(t, testFixturePath("providers-lock/basic"), td)
|
|
||||||
defer testChdir(t, td)()
|
|
||||||
|
|
||||||
// Our fixture dir has a generic os_arch dir, which we need to customize
|
|
||||||
// to the actual OS/arch where this test is running in order to get the
|
|
||||||
// desired result.
|
|
||||||
fixtMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch")
|
|
||||||
wantMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
|
|
||||||
err := os.Rename(fixtMachineDir, wantMachineDir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := testProvider()
|
|
||||||
ui := new(cli.MockUi)
|
|
||||||
c := &ProvidersLockCommand{
|
|
||||||
Meta: Meta{
|
|
||||||
Ui: ui,
|
|
||||||
testingOverrides: metaOverridesForProvider(p),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"-fs-mirror=fs-mirror"}
|
|
||||||
code := c.Run(args)
|
|
||||||
if code != 0 {
|
|
||||||
t.Fatalf("wrong exit code; expected 0, got %d", code)
|
|
||||||
}
|
|
||||||
|
|
||||||
lockfile, err := os.ReadFile(".terraform.lock.hcl")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("error reading lockfile")
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := `# This file is maintained automatically by "terraform init".
|
expected := `# This file is maintained automatically by "terraform init".
|
||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
@ -77,10 +47,65 @@ provider "registry.terraform.io/hashicorp/test" {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
if string(lockfile) != expected {
|
runProviderLockGenericTest(t, testDirectory, expected)
|
||||||
t.Fatalf("wrong lockfile content")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// This test depends on the -fs-mirror argument, so we always know what results to expect
|
||||||
|
t.Run("append", func(t *testing.T) {
|
||||||
|
testDirectory := "providers-lock/append"
|
||||||
|
expected := `# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/hashicorp/test" {
|
||||||
|
version = "1.0.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:7MjN4eFisdTv4tlhXH5hL4QQd39Jy4baPhFxwAd/EFE=",
|
||||||
|
"h1:invalid",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
runProviderLockGenericTest(t, testDirectory, expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runProviderLockGenericTest(t *testing.T, testDirectory, expected string) {
|
||||||
|
td := t.TempDir()
|
||||||
|
testCopyDir(t, testFixturePath(testDirectory), td)
|
||||||
|
defer testChdir(t, td)()
|
||||||
|
|
||||||
|
// Our fixture dir has a generic os_arch dir, which we need to customize
|
||||||
|
// to the actual OS/arch where this test is running in order to get the
|
||||||
|
// desired result.
|
||||||
|
fixtMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/os_arch")
|
||||||
|
wantMachineDir := filepath.Join(td, "fs-mirror/registry.terraform.io/hashicorp/test/1.0.0/", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
|
||||||
|
err := os.Rename(fixtMachineDir, wantMachineDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := testProvider()
|
||||||
|
ui := new(cli.MockUi)
|
||||||
|
c := &ProvidersLockCommand{
|
||||||
|
Meta: Meta{
|
||||||
|
Ui: ui,
|
||||||
|
testingOverrides: metaOverridesForProvider(p),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"-fs-mirror=fs-mirror"}
|
||||||
|
code := c.Run(args)
|
||||||
|
if code != 0 {
|
||||||
|
t.Fatalf("wrong exit code; expected 0, got %d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
lockfile, err := os.ReadFile(".terraform.lock.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("error reading lockfile")
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(lockfile) != expected {
|
||||||
|
t.Fatalf("wrong lockfile content")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProvidersLock_args(t *testing.T) {
|
func TestProvidersLock_args(t *testing.T) {
|
||||||
@ -151,3 +176,81 @@ func TestProvidersLock_args(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProvidersLockCalculateChangeType(t *testing.T) {
|
||||||
|
provider := addrs.NewDefaultProvider("provider")
|
||||||
|
v2 := getproviders.MustParseVersion("2.0.0")
|
||||||
|
v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
|
||||||
|
|
||||||
|
t.Run("oldLock == nil", func(t *testing.T) {
|
||||||
|
platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
if ct := providersLockCalculateChangeType(nil, platformLock); ct != providersLockChangeTypeNewProvider {
|
||||||
|
t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNewProvider)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("oldLock == platformLock", func(t *testing.T) {
|
||||||
|
platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
oldLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
if ct := providersLockCalculateChangeType(oldLock, platformLock); ct != providersLockChangeTypeNoChange {
|
||||||
|
t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNoChange)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("oldLock > platformLock", func(t *testing.T) {
|
||||||
|
platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
oldLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"1ZAChGWUMWn4zmIk",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"HWjRvIuWZ1LVatnc",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
"KwhJK4p/U2dqbKhI",
|
||||||
|
})
|
||||||
|
|
||||||
|
if ct := providersLockCalculateChangeType(oldLock, platformLock); ct != providersLockChangeTypeNoChange {
|
||||||
|
t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNoChange)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("oldLock < platformLock", func(t *testing.T) {
|
||||||
|
platformLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"1ZAChGWUMWn4zmIk",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"HWjRvIuWZ1LVatnc",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
"KwhJK4p/U2dqbKhI",
|
||||||
|
})
|
||||||
|
|
||||||
|
oldLock := depsfile.NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
if ct := providersLockCalculateChangeType(oldLock, platformLock); ct != providersLockChangeTypeNewHashes {
|
||||||
|
t.Fatalf("output was %s but should be %s", ct, providersLockChangeTypeNoChange)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
9
internal/command/testdata/providers-lock/append/.terraform.lock.hcl
vendored
Normal file
9
internal/command/testdata/providers-lock/append/.terraform.lock.hcl
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/hashicorp/test" {
|
||||||
|
version = "1.0.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:invalid",
|
||||||
|
]
|
||||||
|
}
|
7
internal/command/testdata/providers-lock/append/main.tf
vendored
Normal file
7
internal/command/testdata/providers-lock/append/main.tf
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
test = {
|
||||||
|
source = "hashicorp/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -403,6 +403,30 @@ func (l *ProviderLock) AllHashes() []getproviders.Hash {
|
|||||||
return l.hashes
|
return l.hashes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainsAll returns true if the hashes in this ProviderLock contains
|
||||||
|
// all the hashes in the target.
|
||||||
|
//
|
||||||
|
// This function assumes the hashes are in each ProviderLock are sorted.
|
||||||
|
// If the ProviderLock was created by the NewProviderLock constructor then
|
||||||
|
// the hashes are guaranteed to be sorted.
|
||||||
|
func (l *ProviderLock) ContainsAll(target *ProviderLock) bool {
|
||||||
|
if target == nil || len(target.hashes) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
targetIndex := 0
|
||||||
|
for ix := 0; ix < len(l.hashes); ix++ {
|
||||||
|
if l.hashes[ix] == target.hashes[targetIndex] {
|
||||||
|
targetIndex++
|
||||||
|
|
||||||
|
if targetIndex >= len(target.hashes) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// PreferredHashes returns a filtered version of the AllHashes return value
|
// PreferredHashes returns a filtered version of the AllHashes return value
|
||||||
// which includes only the strongest of the availabile hash schemes, in
|
// which includes only the strongest of the availabile hash schemes, in
|
||||||
// case legacy hash schemes are deprecated over time but still supported for
|
// case legacy hash schemes are deprecated over time but still supported for
|
||||||
|
@ -216,3 +216,94 @@ func TestLocksProviderSetRemove(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProviderLockContainsAll(t *testing.T) {
|
||||||
|
provider := addrs.NewDefaultProvider("provider")
|
||||||
|
v2 := getproviders.MustParseVersion("2.0.0")
|
||||||
|
v2EqConstraints := getproviders.MustParseVersionConstraints("2.0.0")
|
||||||
|
|
||||||
|
t.Run("non-symmetric", func(t *testing.T) {
|
||||||
|
target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"1ZAChGWUMWn4zmIk",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"HWjRvIuWZ1LVatnc",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
"KwhJK4p/U2dqbKhI",
|
||||||
|
})
|
||||||
|
|
||||||
|
if !original.ContainsAll(target) {
|
||||||
|
t.Errorf("orginal should contain all hashes in target")
|
||||||
|
}
|
||||||
|
if target.ContainsAll(original) {
|
||||||
|
t.Errorf("target should not contain all hashes in orginal")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("symmetric", func(t *testing.T) {
|
||||||
|
target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
if !original.ContainsAll(target) {
|
||||||
|
t.Errorf("orginal should contain all hashes in target")
|
||||||
|
}
|
||||||
|
if !target.ContainsAll(original) {
|
||||||
|
t.Errorf("target should not contain all hashes in orginal")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("edge case - null", func(t *testing.T) {
|
||||||
|
original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
if !original.ContainsAll(nil) {
|
||||||
|
t.Fatalf("orginal should report true on nil")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("edge case - empty", func(t *testing.T) {
|
||||||
|
original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{})
|
||||||
|
|
||||||
|
if !original.ContainsAll(target) {
|
||||||
|
t.Fatalf("orginal should report true on empty")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("edge case - original empty", func(t *testing.T) {
|
||||||
|
original := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{})
|
||||||
|
|
||||||
|
target := NewProviderLock(provider, v2, v2EqConstraints, []getproviders.Hash{
|
||||||
|
"9r3i9a9QmASqMnQM",
|
||||||
|
"K43RHM2klOoywtyW",
|
||||||
|
"swJPXfuCNhJsTM5c",
|
||||||
|
})
|
||||||
|
|
||||||
|
if original.ContainsAll(target) {
|
||||||
|
t.Fatalf("orginal should report false when empty")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -464,7 +464,13 @@ NeedProvider:
|
|||||||
installTo = i.targetDir
|
installTo = i.targetDir
|
||||||
linkTo = nil // no linking needed
|
linkTo = nil // no linking needed
|
||||||
}
|
}
|
||||||
authResult, err := installTo.InstallPackage(ctx, meta, preferredHashes)
|
|
||||||
|
allowedHashes := preferredHashes
|
||||||
|
if mode.forceInstallChecksums() {
|
||||||
|
allowedHashes = []getproviders.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
authResult, err := installTo.InstallPackage(ctx, meta, allowedHashes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: Consider retrying for certain kinds of error that seem
|
// TODO: Consider retrying for certain kinds of error that seem
|
||||||
// likely to be transient. For now, we just treat all errors equally.
|
// likely to be transient. For now, we just treat all errors equally.
|
||||||
@ -594,6 +600,11 @@ const (
|
|||||||
// sets.
|
// sets.
|
||||||
InstallNewProvidersOnly InstallMode = 'N'
|
InstallNewProvidersOnly InstallMode = 'N'
|
||||||
|
|
||||||
|
// InstallNewProvidersForce is an InstallMode that follows the same
|
||||||
|
// logic as InstallNewProvidersOnly except it does not verify existing
|
||||||
|
// checksums but force installs new checksums for all given providers.
|
||||||
|
InstallNewProvidersForce InstallMode = 'F'
|
||||||
|
|
||||||
// InstallUpgrades is an InstallMode that causes the installer to check
|
// InstallUpgrades is an InstallMode that causes the installer to check
|
||||||
// all requested providers to see if new versions are available that
|
// all requested providers to see if new versions are available that
|
||||||
// are also in the given version sets, even if a suitable version of
|
// are also in the given version sets, even if a suitable version of
|
||||||
@ -605,6 +616,10 @@ func (m InstallMode) forceQueryAllProviders() bool {
|
|||||||
return m == InstallUpgrades
|
return m == InstallUpgrades
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m InstallMode) forceInstallChecksums() bool {
|
||||||
|
return m == InstallNewProvidersForce
|
||||||
|
}
|
||||||
|
|
||||||
// InstallerError is an error type that may be returned (but is not guaranteed)
|
// InstallerError is an error type that may be returned (but is not guaranteed)
|
||||||
// from Installer.EnsureProviderVersions to indicate potentially several
|
// from Installer.EnsureProviderVersions to indicate potentially several
|
||||||
// separate failed installation outcomes for different providers included in
|
// separate failed installation outcomes for different providers included in
|
||||||
|
@ -1364,6 +1364,120 @@ func TestEnsureProviderVersions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"force mode ignores hashes": {
|
||||||
|
Source: getproviders.NewMockSource(
|
||||||
|
[]getproviders.PackageMeta{
|
||||||
|
{
|
||||||
|
Provider: beepProvider,
|
||||||
|
Version: getproviders.MustParseVersion("1.0.0"),
|
||||||
|
TargetPlatform: fakePlatform,
|
||||||
|
Location: beepProviderDir,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
LockFile: `
|
||||||
|
provider "example.com/foo/beep" {
|
||||||
|
version = "1.0.0"
|
||||||
|
constraints = ">= 1.0.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:does-not-match",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
Mode: InstallNewProvidersForce,
|
||||||
|
Reqs: getproviders.Requirements{
|
||||||
|
beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
|
||||||
|
},
|
||||||
|
Check: func(t *testing.T, dir *Dir, locks *depsfile.Locks) {
|
||||||
|
if allCached := dir.AllAvailablePackages(); len(allCached) != 1 {
|
||||||
|
t.Errorf("wrong number of cache directory entries; want only one\n%s", spew.Sdump(allCached))
|
||||||
|
}
|
||||||
|
if allLocked := locks.AllProviders(); len(allLocked) != 1 {
|
||||||
|
t.Errorf("wrong number of provider lock entries; want only one\n%s", spew.Sdump(allLocked))
|
||||||
|
}
|
||||||
|
|
||||||
|
gotLock := locks.Provider(beepProvider)
|
||||||
|
wantLock := depsfile.NewProviderLock(
|
||||||
|
beepProvider,
|
||||||
|
getproviders.MustParseVersion("1.0.0"),
|
||||||
|
getproviders.MustParseVersionConstraints(">= 1.0.0"),
|
||||||
|
[]getproviders.Hash{beepProviderHash, "h1:does-not-match"},
|
||||||
|
)
|
||||||
|
if diff := cmp.Diff(wantLock, gotLock, depsfile.ProviderLockComparer); diff != "" {
|
||||||
|
t.Errorf("wrong lock entry\n%s", diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
gotEntry := dir.ProviderLatestVersion(beepProvider)
|
||||||
|
wantEntry := &CachedProvider{
|
||||||
|
Provider: beepProvider,
|
||||||
|
Version: getproviders.MustParseVersion("1.0.0"),
|
||||||
|
PackageDir: filepath.Join(dir.BasePath(), "example.com/foo/beep/1.0.0/bleep_bloop"),
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(wantEntry, gotEntry); diff != "" {
|
||||||
|
t.Errorf("wrong cache entry\n%s", diff)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WantEvents: func(inst *Installer, dir *Dir) map[addrs.Provider][]*testInstallerEventLogItem {
|
||||||
|
return map[addrs.Provider][]*testInstallerEventLogItem{
|
||||||
|
noProvider: {
|
||||||
|
{
|
||||||
|
Event: "PendingProviders",
|
||||||
|
Args: map[addrs.Provider]getproviders.VersionConstraints{
|
||||||
|
beepProvider: getproviders.MustParseVersionConstraints(">= 1.0.0"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: "ProvidersFetched",
|
||||||
|
Args: map[addrs.Provider]*getproviders.PackageAuthenticationResult{
|
||||||
|
beepProvider: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beepProvider: {
|
||||||
|
{
|
||||||
|
Event: "QueryPackagesBegin",
|
||||||
|
Provider: beepProvider,
|
||||||
|
Args: struct {
|
||||||
|
Constraints string
|
||||||
|
Locked bool
|
||||||
|
}{">= 1.0.0", true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: "QueryPackagesSuccess",
|
||||||
|
Provider: beepProvider,
|
||||||
|
Args: "1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: "FetchPackageMeta",
|
||||||
|
Provider: beepProvider,
|
||||||
|
Args: "1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: "FetchPackageBegin",
|
||||||
|
Provider: beepProvider,
|
||||||
|
Args: struct {
|
||||||
|
Version string
|
||||||
|
Location getproviders.PackageLocation
|
||||||
|
}{"1.0.0", beepProviderDir},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: "FetchPackageSuccess",
|
||||||
|
Provider: beepProvider,
|
||||||
|
Args: struct {
|
||||||
|
Version string
|
||||||
|
LocalDir string
|
||||||
|
AuthResult string
|
||||||
|
}{
|
||||||
|
"1.0.0",
|
||||||
|
filepath.Join(dir.BasePath(), "example.com/foo/beep/1.0.0/bleep_bloop"),
|
||||||
|
"unauthenticated",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
Loading…
Reference in New Issue
Block a user