Prevously OpenTofu's provider installer would try to install a package even
if there was already a directory there which doesn't match the package
contents. That's effective in making us more likely to end up with a
working provider cache directory, but risks clobbering a package directory
that the operator intentionally modified for some reason.
We'll now require that if an existing directory (or symlink to one) is
present at the place where we'd need to put our cache entry then its
contents must already match what we're trying to install, thereby making
this a no-op. If the existing contents don't match then we'll fail with an
error to let the operator decide whether they need to keep something from
their modified directory before deleting it.
In earlier versions of OpenTofu, silently replacing an existing directory
was actually sometimes done intentionally to ensure that the cache would
definitely match the dependency lock file, but we no longer need to do that
because as of OpenTofu v1.12 the provider installer now exits early
(without downloading anything at all) if a matching package is already
present, so we never end up trying to replace a package that was already
present on disk unless it's the case we're now trying to catch as an error
here.
The handling of this is in PackageLocalArchive because the two
network-based location types (HTTP archive and OCI blob archive) work by
first fetching the archive to a temporary local location and then asking
the local archive location to finish the installation.
This is covered by e2etests rather than a unit test because successfully
hitting this error requires both the "providercache" and "getproviders"
packages to cooperate to let execution reach this late step without any
earlier code doing an early exit due to the directory already being
present. The e2etest runs through that entire codepath to make sure we
reach the error message we're expecting to reach.
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
The "terraform_version" property of the JSON state format (intentionally
misnamed for backward-compatibility with our predecessor) changes each time
we make a new release, so we'll compare it with the currently-expected
version number instead of with a hard-coded value.
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
On Windows, the two sequential plan runs in TestJsonIntoStream have different latencies — the -json-into run is consistently slower and crosses the timer threshold that emits state_lock_acquire, while the -json run does not. This causes a spurious one-line diff between the two outputs.
Strip state_lock_acquire/release lines from both outputs before comparison since these messages are timing-dependent and not relevant to the test's core assertion.
Previously we interpreted a "required_version" argument in a "terraform"
block as if it were specifying an OpenTofu version constraint, when in
reality most modules use this to represent a version constraint for
OpenTofu's predecessor instead.
The primary effect of this commit is to introduce a new top-level block
type called "language" which describes language and implementation
compatibility metadata in a way that intentionally differs from what's used
by OpenTofu's predecessor.
This also causes OpenTofu to ignore the required_version argument unless
it appears in an OpenTofu-specific file with a ".tofu" suffix, and makes
OpenTofu completely ignore the language edition and experimental feature
opt-in options from OpenTofu's predecessor on the assumption that those
could continue to evolve independently of changes in OpenTofu.
We retain support for using required_versions in .tofu files as a bridge
solution for modules that need to remain compatible with OpenTofu versions
prior to v1.12. Module authors should keep following the strategy of
having both a versions.tf and a versions.tofu file for now, and wait until
the OpenTofu v1.11 series is end-of-life before adopting the new "language"
block type.
I also took this opportunity to simplify how we handle these parts of the
configuration, since the OpenTofu project has no immediate plans to use
either multiple language editions or language experiments and so for now
we can reduce our handling of those language features to just enough that
we'd return reasonable error messages if today's OpenTofu is exposed to
a module that was written for a newer version of OpenTofu that extends
these language features. The cross-cutting plumbing for representing the
active experiments for a module is still present so that we can reactivate
it later if we need to, but for now that set will always be empty.
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
We don't typically just broadly run automatic rewriting tools like "go fix"
across our codebase because that tends to cause annoying and unnecessary
merge conflicts when we're backporting to earlier release branches.
But all of the files in this commit were changed in some non-trivial way
already during the OpenTofu v1.11 development period anyway, and so the
likelyhood we'd be able to successfully backport from them is reduced and
therefore this seems like a good opportunity to do some focused
modernization using "go fix".
My rules for what to include or not are admittedly quite "vibes-based", but
the general idea was:
- Focusing on files under the "command" directory only, because that's
already been an area of intentional refactoring during this development
period.
- If the existing diff in a file is already significantly larger than
the changes the fixer proposed to make, or if the fixer is proposing
to change a line that was already changed in this development period.
- More willing to include "_test.go" files than non-test files, even if
they hadn't changed as much already, just because backports from test
files for bug fixes tend to be entirely new test cases more than they
are modifications to existing test cases, and so the risk of conflicts
is lower there.
Signed-off-by: Martin Atkins <mart@degeneration.co.uk>