terraform/internal/command/workdir/normalize_path.go

53 lines
2.0 KiB
Go
Raw Normal View History

workdir: Start of a new package for working directory state management Thus far our various interactions with the bits of state we keep associated with a working directory have all been implemented directly inside the "command" package -- often in the huge command.Meta type -- and not managed collectively via a single component. There's too many little codepaths reading and writing from the working directory and data directory to refactor it all in one step, but this is an attempt at a first step towards a future where everything that reads and writes from the current working directory would do so via an object that encapsulates the implementation details and offers a high-level API to read and write all of these session-persistent settings. The design here continues our gradual path towards using a dependency injection style where "package main" is solely responsible for directly interacting with the OS command line, the OS environment, the OS working directory, the stdio streams, and the CLI configuration, and then communicating the resulting information to the rest of Terraform by wiring together objects. It seems likely that eventually we'll have enough wiring code in package main to justify a more explicit organization of that code, but for this commit the new "workdir.Dir" object is just wired directly in place of its predecessors, without any significant change of code organization at that top layer. This first commit focuses on the main files and directories we use to find provider plugins, because a subsequent commit will lightly reorganize the separation of concerns for plugin launching with a similar goal of collecting all of the relevant logic together into one spot.
2021-09-02 02:01:44 +02:00
package workdir
import (
"path/filepath"
)
// NormalizePath attempts to transform the given path so that it's relative
// to the working directory, which is our preferred way to present and store
// paths to files and directories within a configuration so that they can
// be portable to operations in other working directories.
//
// It isn't always possible to produce a relative path. For example, on Windows
// the given path might be on a different volume (e.g. drive letter or network
// share) than the working directory.
//
// Note that the result will be relative to the main directory of the receiver,
// which should always be the actual process working directory in normal code,
// but might be some other temporary working directory when in test code.
// If you need to access the file or directory that the result refers to with
// functions that aren't aware of our base directory, you can use something
// like the following, which again should be needed only in test code which
// might need to inspect the filesystem in order to make assertions:
//
// filepath.Join(d.RootModuleDir(), normalizePathResult)
//
// The above is suitable only for situations where the given path is known
// to be beneath the working directory, which is the typical situation for
// temporary working directories created for automated tests.
func (d *Dir) NormalizePath(given string) string {
// We need an absolute version of d.mainDir in order for our "Rel"
// result to be reliable.
absMain, err := filepath.Abs(d.mainDir)
if err != nil {
// Weird, but okay...
return filepath.Clean(given)
}
if !filepath.IsAbs(given) {
given = filepath.Join(absMain, given)
}
ret, err := filepath.Rel(absMain, given)
if err != nil {
// It's not always possible to find a relative path. For example,
// the given path might be on an entirely separate volume
// (e.g. drive letter or network share) on a Windows system, which
// always requires an absolute path.
return filepath.Clean(given)
}
return ret
}