Repository: opentofu/opentofu
File: internal/providercache/installer.go (Go)

Code before:
			cb(provider, err)
		}
	}

	return need, nil
}

func (i *Installer) ensureProviderVersionsInstall(
	ctx context.Context,
	locks *depsfile.Locks,
	reqs getproviders.Requirements,
	mode InstallMode,
	need map[addrs.Provider]getproviders.Version,
	targetPlatform getproviders.Platform,
	errs map[addrs.Provider]error,
) (map[addrs.Provider]*getproviders.PackageAuthenticationResult, error) {
	evts := installerEventsForContext(ctx)
	authResults := map[addrs.Provider]*getproviders.PackageAuthenticationResult{} // record auth results for all successfully fetched providers

	for provider, version := range need {
		traceCtx, span := tracing.Tracer().Start(ctx,
			"Install Provider",
			trace.WithAttributes(
				attribute.String(attributes.ProviderAddress, provider.String()),
				attribute.String(attributes.ProviderVersion, version.String()),
				attribute.String(attributes.TargetPlatform, targetPlatform.String()),
			),
		)
		if err := traceCtx.Err(); err != nil {
			span.SetStatus(codes.Error, "context cancelled")
			span.RecordError(err)
			// If our context has been cancelled or reached a timeout then
			// we'll abort early, because subsequent operations against
			// that context will fail immediately anyway.
			return nil, err
		}

		lock := locks.Provider(provider)
		var preferredHashes []getproviders.Hash
		if lock != nil && lock.Version() == version { // hash changes are expected if the version is also changing
			preferredHashes = lock.PreferredHashes()
		}

		// If our target directory already has the provider version that fulfills the lock file, carry on
		if installed := i.targetDir.ProviderVersion(provider, version); installed != nil {
			if len(preferredHashes) > 0 {
				if matches, _ := installed.MatchesAnyHash(preferredHashes); matches {
					if cb := evts.ProviderAlreadyInstalled; cb != nil {
						cb(provider, version)
					}
					span.End()

Review comment (suggestion):
Similar to my reaction to our own `package attributes`, I'd suggest that we standardize on renaming this otel import to `otelAttr` (or similar) when we use it outside of the `internal/tracing` subtree, so that our global namespaces don't get cluttered with generic words that overlap with OpenTofu's own concepts.

I made some similar tradeoffs in the OCI registry work where I imported the ORAS-Go packages renamed with `oras` prefixes and the OCI spec packages with `oci` prefixes, since those also tended to have names that collided with existing OpenTofu concepts. The tracing stuff is _even more_ cross-cutting than the OCI registry work -- likely to be imported in all sorts of different files in the long run -- so I think it's worth choosing a standard import name for each OTel package that is less likely to cause confusion and conflicts while still being consistent throughout our codebase.


Code after:
			log.Printf("[DEBUG] Available releases: %s", available)
		}
		errs[provider] = err
		if cb := evts.QueryPackagesFailure; cb != nil {
			cb(provider, err)
		}
	}

	return need, nil
}

func (i *Installer) ensureProviderVersionsInstall(
	ctx context.Context,
	locks *depsfile.Locks,
	reqs getproviders.Requirements,
	mode InstallMode,
	need map[addrs.Provider]getproviders.Version,
	targetPlatform getproviders.Platform,
	errs map[addrs.Provider]error,
) (map[addrs.Provider]*getproviders.PackageAuthenticationResult, error) {
	authResults := map[addrs.Provider]*getproviders.PackageAuthenticationResult{} // record auth results for all successfully fetched providers

	for provider, version := range need {
		traceCtx, span := tracing.Tracer().Start(ctx,
			"Install Provider",
			trace.WithAttributes(
				otelAttr.String(traceattrs.ProviderAddress, provider.String()),
				otelAttr.String(traceattrs.ProviderVersion, version.String()),
				otelAttr.String(traceattrs.TargetPlatform, targetPlatform.String()),
			),
		)

		if err := traceCtx.Err(); err != nil {
			// If our context has been cancelled or reached a timeout then
			// we'll abort early, because subsequent operations against
			// that context will fail immediately anyway.
			tracing.SetSpanError(span, err)
			span.End()
			return nil, err
		}

		authResult, err := i.ensureProviderVersionInstall(traceCtx, locks, reqs, mode, provider, version, targetPlatform)
		if authResult != nil {
			authResults[provider] = authResult
		}
		if err != nil {
			errs[provider] = err
		}
		span.End()
	}
	return authResults, nil