mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 18:01:01 -06:00
a0f4a313ef
configs.Parser is the entry-point for this package, providing functions to load and parse HCL-based configuration files. We use the library "afero" to decouple the parser from the physical OS filesystem, which here allows us to easily use an in-memory filesystem for testing and will, in future, allow us to read files from more unusual places, such as configuration embedded in a plan file.
86 lines
2.5 KiB
Go
86 lines
2.5 KiB
Go
package configs
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/hcl2/hcl"
|
|
"github.com/hashicorp/hcl2/hclparse"
|
|
"github.com/spf13/afero"
|
|
)
|
|
|
|
// Parser is the main interface to read configuration files and other related
|
|
// files from disk.
|
|
//
|
|
// It retains a cache of all files that are loaded so that they can be used
|
|
// to create source code snippets in diagnostics, etc.
|
|
type Parser struct {
|
|
fs afero.Afero
|
|
p *hclparse.Parser
|
|
}
|
|
|
|
// NewParser creates and returns a new Parser that reads files from the given
|
|
// filesystem. If a nil filesystem is passed then the system's "real" filesystem
|
|
// will be used, via afero.OsFs.
|
|
func NewParser(fs afero.Fs) *Parser {
|
|
if fs == nil {
|
|
fs = afero.OsFs{}
|
|
}
|
|
|
|
return &Parser{
|
|
fs: afero.Afero{Fs: fs},
|
|
p: hclparse.NewParser(),
|
|
}
|
|
}
|
|
|
|
// LoadHCLFile is a low-level method that reads the file at the given path,
|
|
// parses it, and returns the hcl.Body representing its root. In many cases
|
|
// it is better to use one of the other Load*File methods on this type,
|
|
// which additionally decode the root body in some way and return a higher-level
|
|
// construct.
|
|
//
|
|
// If the file cannot be read at all -- e.g. because it does not exist -- then
|
|
// this method will return a nil body and error diagnostics. In this case
|
|
// callers may wish to ignore the provided error diagnostics and produce
|
|
// a more context-sensitive error instead.
|
|
//
|
|
// The file will be parsed using the HCL native syntax unless the filename
|
|
// ends with ".json", in which case the HCL JSON syntax will be used.
|
|
func (p *Parser) LoadHCLFile(path string) (hcl.Body, hcl.Diagnostics) {
|
|
src, err := p.fs.ReadFile(path)
|
|
|
|
if err != nil {
|
|
return nil, hcl.Diagnostics{
|
|
{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Failed to read file",
|
|
Detail: fmt.Sprintf("The file %q could not be read.", path),
|
|
},
|
|
}
|
|
}
|
|
|
|
var file *hcl.File
|
|
var diags hcl.Diagnostics
|
|
switch {
|
|
case strings.HasSuffix(path, ".json"):
|
|
file, diags = p.p.ParseJSON(src, path)
|
|
default:
|
|
file, diags = p.p.ParseHCL(src, path)
|
|
}
|
|
|
|
// If the returned file or body is nil, then we'll return a non-nil empty
|
|
// body so we'll meet our contract that nil means an error reading the file.
|
|
if file == nil || file.Body == nil {
|
|
return hcl.EmptyBody(), diags
|
|
}
|
|
|
|
return file.Body, diags
|
|
}
|
|
|
|
// Sources returns a map of the cached source buffers for all files that
|
|
// have been loaded through this parser, with source filenames (as requested
|
|
// when each file was opened) as the keys.
|
|
func (p *Parser) Sources() map[string][]byte {
|
|
return p.p.Sources()
|
|
}
|