Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support standalone (not autoloaded) *.tfvars files #621

Merged
merged 1 commit into from
Aug 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*.go text eol=lf
*.tf text eol=lf
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to avoid test failures (in CI) on Windows caused by converted line endings in test config files.

38 changes: 14 additions & 24 deletions internal/decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package decoder

import (
"context"
"fmt"

"github.com/hashicorp/hcl-lang/decoder"
"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl/v2"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
"github.com/hashicorp/terraform-ls/internal/terraform/ast"
"github.com/hashicorp/terraform-ls/internal/terraform/module"
)

Expand All @@ -30,36 +29,27 @@ func DecoderForModule(ctx context.Context, mod module.Module) (*decoder.Decoder,
d.SetUtmMedium(clientName)
}

err := loadFiles(d, mod.ParsedModuleFiles)
if err != nil {
return nil, err
for name, f := range mod.ParsedModuleFiles {
err := d.LoadFile(name.String(), f)
if err != nil {
// skip unreadable files
continue
}
}

return d, nil
}

func DecoderForVariables(mod module.Module) (*decoder.Decoder, error) {
func DecoderForVariables(varsFiles ast.VarsFiles) (*decoder.Decoder, error) {
d := decoder.NewDecoder()

err := loadFiles(d, mod.ParsedModuleFiles)
if err != nil {
return nil, err
}

err = loadFiles(d, mod.ParsedVarsFiles)
if err != nil {
return nil, err
}

return d, nil
}

func loadFiles(d *decoder.Decoder, files map[string]*hcl.File) error {
for name, f := range files {
err := d.LoadFile(name, f)
for name, f := range varsFiles {
err := d.LoadFile(name.String(), f)
if err != nil {
return fmt.Errorf("failed to load a file: %w", err)
// skip unreadable files
continue
}
}
return nil

return d, nil
}
21 changes: 11 additions & 10 deletions internal/filesystem/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package filesystem
import (
"bytes"
"fmt"
"io/fs"
"io/ioutil"
"log"
"os"
Expand Down Expand Up @@ -206,37 +207,37 @@ func (fs *fsystem) ReadFile(name string) ([]byte, error) {
return b, err
}

func (fs *fsystem) ReadDir(name string) ([]os.FileInfo, error) {
memList, err := afero.ReadDir(fs.memFs, name)
func (fsys *fsystem) ReadDir(name string) ([]fs.DirEntry, error) {
memList, err := afero.NewIOFS(fsys.memFs).ReadDir(name)
if err != nil && !os.IsNotExist(err) {
return nil, fmt.Errorf("memory FS: %w", err)
}
osList, err := afero.ReadDir(fs.osFs, name)
osList, err := afero.NewIOFS(fsys.osFs).ReadDir(name)
if err != nil && !os.IsNotExist(err) {
return nil, fmt.Errorf("OS FS: %w", err)
}

list := memList
for _, osFi := range osList {
if fileIsInList(list, osFi) {
for _, osEntry := range osList {
if fileIsInList(list, osEntry) {
continue
}
list = append(list, osFi)
list = append(list, osEntry)
}

return list, nil
}

func fileIsInList(list []os.FileInfo, file os.FileInfo) bool {
for _, fi := range list {
if fi.Name() == file.Name() {
func fileIsInList(list []fs.DirEntry, entry fs.DirEntry) bool {
for _, di := range list {
if di.Name() == entry.Name() {
return true
}
}
return false
}

func (fs *fsystem) Open(name string) (File, error) {
func (fs *fsystem) Open(name string) (fs.File, error) {
f, err := fs.memFs.Open(name)
if err != nil && os.IsNotExist(err) {
return fs.osFs.Open(name)
Expand Down
9 changes: 5 additions & 4 deletions internal/filesystem/filesystem_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package filesystem

import (
"io/fs"
"io/ioutil"
"log"
"os"
Expand Down Expand Up @@ -317,10 +318,10 @@ func TestFilesystem_ReadDir_memFsOnly(t *testing.T) {
}
}

func namesFromFileInfos(fis []os.FileInfo) []string {
names := make([]string, len(fis), len(fis))
for i, fi := range fis {
names[i] = fi.Name()
func namesFromFileInfos(entries []fs.DirEntry) []string {
names := make([]string, len(entries), len(entries))
for i, entry := range entries {
names[i] = entry.Name()
}
return names
}
Expand Down
13 changes: 3 additions & 10 deletions internal/filesystem/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package filesystem

import (
"io/fs"
"log"
"os"

Expand Down Expand Up @@ -51,15 +52,7 @@ type Filesystem interface {

// direct FS methods
ReadFile(name string) ([]byte, error)
ReadDir(name string) ([]os.FileInfo, error)
Open(name string) (File, error)
ReadDir(name string) ([]fs.DirEntry, error)
Open(name string) (fs.File, error)
Stat(name string) (os.FileInfo, error)
}

// File represents an open file in FS
// See io/fs.File in http://golang.org/s/draft-iofs-design
type File interface {
Stat() (os.FileInfo, error)
Read([]byte) (int, error)
Close() error
}
4 changes: 2 additions & 2 deletions internal/langserver/handlers/command/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ func TerraformValidateHandler(ctx context.Context, args cmd.CommandArgs) (interf
validateDiags := diagnostics.HCLDiagsFromJSON(jsonDiags)
diags.EmptyRootDiagnostic()
diags.Append("terraform validate", validateDiags)
diags.Append("HCL", mod.ModuleDiagnostics)
diags.Append("HCL", mod.VarsDiagnostics)
diags.Append("HCL", mod.ModuleDiagnostics.AsMap())
diags.Append("HCL", mod.VarsDiagnostics.AutoloadedOnly().AsMap())

notifier.PublishHCLDiags(ctx, mod.Path, diags)

Expand Down
9 changes: 6 additions & 3 deletions internal/langserver/handlers/did_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/hashicorp/terraform-ls/internal/langserver/diagnostics"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/terraform/ast"
op "github.com/hashicorp/terraform-ls/internal/terraform/module/operation"
)

Expand Down Expand Up @@ -95,9 +96,11 @@ func TextDocumentDidChange(ctx context.Context, params lsp.DidChangeTextDocument

diags := diagnostics.NewDiagnostics()
diags.EmptyRootDiagnostic()
diags.Append("HCL", mod.ModuleDiagnostics)
diags.Append("HCL", mod.VarsDiagnostics)

diags.Append("HCL", mod.ModuleDiagnostics.AsMap())
diags.Append("HCL", mod.VarsDiagnostics.AutoloadedOnly().AsMap())
if vf, ok := ast.NewVarsFilename(f.Filename()); ok && !vf.IsAutoloaded() {
diags.Append("HCL", mod.VarsDiagnostics.ForFile(vf).AsMap())
}
notifier.PublishHCLDiags(ctx, mod.Path, diags)

return nil
Expand Down
24 changes: 23 additions & 1 deletion internal/langserver/handlers/did_close.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package handlers
import (
"context"

"github.com/hashicorp/hcl/v2"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
"github.com/hashicorp/terraform-ls/internal/langserver/diagnostics"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/terraform/ast"
)

func TextDocumentDidClose(ctx context.Context, params lsp.DidCloseTextDocumentParams) error {
Expand All @@ -15,5 +18,24 @@ func TextDocumentDidClose(ctx context.Context, params lsp.DidCloseTextDocumentPa
}

fh := ilsp.FileHandlerFromDocumentURI(params.TextDocument.URI)
return fs.CloseAndRemoveDocument(fh)
err = fs.CloseAndRemoveDocument(fh)
if err != nil {
return err
}

if vf, ok := ast.NewVarsFilename(fh.Filename()); ok && !vf.IsAutoloaded() {
notifier, err := lsctx.DiagnosticsNotifier(ctx)
if err != nil {
return err
}

diags := diagnostics.NewDiagnostics()
diags.EmptyRootDiagnostic()
diags.Append("HCL", map[string]hcl.Diagnostics{
fh.Filename(): {},
})
notifier.PublishHCLDiags(ctx, fh.Dir(), diags)
}

return nil
}
8 changes: 6 additions & 2 deletions internal/langserver/handlers/did_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform-ls/internal/langserver/diagnostics"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/terraform/ast"
"github.com/hashicorp/terraform-ls/internal/terraform/module"
op "github.com/hashicorp/terraform-ls/internal/terraform/module/operation"
)
Expand Down Expand Up @@ -76,8 +77,11 @@ func (lh *logHandler) TextDocumentDidOpen(ctx context.Context, params lsp.DidOpe

diags := diagnostics.NewDiagnostics()
diags.EmptyRootDiagnostic()
diags.Append("HCL", mod.ModuleDiagnostics)
diags.Append("HCL", mod.VarsDiagnostics)
diags.Append("HCL", mod.ModuleDiagnostics.AsMap())
diags.Append("HCL", mod.VarsDiagnostics.AutoloadedOnly().AsMap())
if vf, ok := ast.NewVarsFilename(f.Filename()); ok && !vf.IsAutoloaded() {
diags.Append("HCL", mod.VarsDiagnostics.ForFile(vf).AsMap())
}

notifier.PublishHCLDiags(ctx, mod.Path, diags)

Expand Down
3 changes: 2 additions & 1 deletion internal/langserver/handlers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ func (svc *service) Assigner() (jrpc2.Assigner, error) {
if err != nil {
return nil, err
}
ctx = lsctx.WithDiagnosticsNotifier(ctx, notifier)
ctx = lsctx.WithDocumentStorage(ctx, svc.fs)
return handle(ctx, req, TextDocumentDidClose)
},
Expand Down Expand Up @@ -533,7 +534,7 @@ func schemaForDocument(mf module.ModuleFinder, doc filesystem.Document) (*schema

func decoderForDocument(ctx context.Context, mod module.Module, languageID string) (*decoder.Decoder, error) {
if languageID == ilsp.Tfvars.String() {
return idecoder.DecoderForVariables(mod)
return idecoder.DecoderForVariables(mod.ParsedVarsFiles)
}
return idecoder.DecoderForModule(ctx, mod)
}
29 changes: 15 additions & 14 deletions internal/state/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
tfaddr "github.com/hashicorp/terraform-registry-address"
tfmod "github.com/hashicorp/terraform-schema/module"

"github.com/hashicorp/terraform-ls/internal/terraform/ast"
"github.com/hashicorp/terraform-ls/internal/terraform/datadir"
op "github.com/hashicorp/terraform-ls/internal/terraform/module/operation"
)
Expand Down Expand Up @@ -82,8 +83,8 @@ type Module struct {
RefOriginsErr error
RefOriginsState op.OpState

ParsedModuleFiles map[string]*hcl.File
ParsedVarsFiles map[string]*hcl.File
ParsedModuleFiles ast.ModFiles
ParsedVarsFiles ast.VarsFiles
ModuleParsingErr error
VarsParsingErr error
ModuleParsingState op.OpState
Expand All @@ -93,8 +94,8 @@ type Module struct {
MetaErr error
MetaState op.OpState

ModuleDiagnostics map[string]hcl.Diagnostics
VarsDiagnostics map[string]hcl.Diagnostics
ModuleDiagnostics ast.ModDiags
VarsDiagnostics ast.VarsDiags
}

func (m *Module) Copy() *Module {
Expand Down Expand Up @@ -135,23 +136,23 @@ func (m *Module) Copy() *Module {
}

if m.ParsedModuleFiles != nil {
newMod.ParsedModuleFiles = make(map[string]*hcl.File, len(m.ParsedModuleFiles))
newMod.ParsedModuleFiles = make(ast.ModFiles, len(m.ParsedModuleFiles))
for name, f := range m.ParsedModuleFiles {
// hcl.File is practically immutable once it comes out of parser
newMod.ParsedModuleFiles[name] = f
}
}

if m.ParsedVarsFiles != nil {
newMod.ParsedVarsFiles = make(map[string]*hcl.File, len(m.ParsedVarsFiles))
newMod.ParsedVarsFiles = make(ast.VarsFiles, len(m.ParsedVarsFiles))
for name, f := range m.ParsedVarsFiles {
// hcl.File is practically immutable once it comes out of parser
newMod.ParsedVarsFiles[name] = f
}
}

if m.ModuleDiagnostics != nil {
newMod.ModuleDiagnostics = make(map[string]hcl.Diagnostics, len(m.ModuleDiagnostics))
newMod.ModuleDiagnostics = make(ast.ModDiags, len(m.ModuleDiagnostics))
for name, diags := range m.ModuleDiagnostics {
newMod.ModuleDiagnostics[name] = make(hcl.Diagnostics, len(diags))
for i, diag := range diags {
Expand All @@ -162,7 +163,7 @@ func (m *Module) Copy() *Module {
}

if m.VarsDiagnostics != nil {
newMod.VarsDiagnostics = make(map[string]hcl.Diagnostics, len(m.VarsDiagnostics))
newMod.VarsDiagnostics = make(ast.VarsDiags, len(m.VarsDiagnostics))
for name, diags := range m.VarsDiagnostics {
newMod.VarsDiagnostics[name] = make(hcl.Diagnostics, len(diags))
for i, diag := range diags {
Expand Down Expand Up @@ -503,7 +504,7 @@ func (s *ModuleStore) SetVarsParsingState(path string, state op.OpState) error {
return nil
}

func (s *ModuleStore) UpdateParsedModuleFiles(path string, pFiles map[string]*hcl.File, pErr error) error {
func (s *ModuleStore) UpdateParsedModuleFiles(path string, pFiles ast.ModFiles, pErr error) error {
txn := s.db.Txn(true)
txn.Defer(func() {
s.SetModuleParsingState(path, op.OpStateLoaded)
Expand All @@ -528,7 +529,7 @@ func (s *ModuleStore) UpdateParsedModuleFiles(path string, pFiles map[string]*hc
return nil
}

func (s *ModuleStore) UpdateParsedVarsFiles(path string, pFiles map[string]*hcl.File, pErr error) error {
func (s *ModuleStore) UpdateParsedVarsFiles(path string, vFiles ast.VarsFiles, vErr error) error {
txn := s.db.Txn(true)
txn.Defer(func() {
s.SetVarsParsingState(path, op.OpStateLoaded)
Expand All @@ -540,9 +541,9 @@ func (s *ModuleStore) UpdateParsedVarsFiles(path string, pFiles map[string]*hcl.
return err
}

mod.ParsedVarsFiles = pFiles
mod.ParsedVarsFiles = vFiles

mod.VarsParsingErr = pErr
mod.VarsParsingErr = vErr

err = txn.Insert(s.tableName, mod)
if err != nil {
Expand Down Expand Up @@ -602,7 +603,7 @@ func (s *ModuleStore) UpdateMetadata(path string, meta *tfmod.Meta, mErr error)
return nil
}

func (s *ModuleStore) UpdateModuleDiagnostics(path string, diags map[string]hcl.Diagnostics) error {
func (s *ModuleStore) UpdateModuleDiagnostics(path string, diags ast.ModDiags) error {
txn := s.db.Txn(true)
defer txn.Abort()

Expand All @@ -622,7 +623,7 @@ func (s *ModuleStore) UpdateModuleDiagnostics(path string, diags map[string]hcl.
return nil
}

func (s *ModuleStore) UpdateVarsDiagnostics(path string, diags map[string]hcl.Diagnostics) error {
func (s *ModuleStore) UpdateVarsDiagnostics(path string, diags ast.VarsDiags) error {
txn := s.db.Txn(true)
defer txn.Abort()

Expand Down
Loading