Skip to content

Commit

Permalink
Replace internal watcher with LSP's watching mechanism (#953)
Browse files Browse the repository at this point in the history
* Reimplement native watcher as LSP' didChangeWatchedFiles

* remove native watcher
  • Loading branch information
radeksimko authored Jun 17, 2022
1 parent b62491a commit 9fcc1c9
Show file tree
Hide file tree
Showing 22 changed files with 729 additions and 846 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/mitchellh/cli v1.1.4
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.5.0
github.com/otiai10/copy v1.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE
github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
Expand Down
14 changes: 0 additions & 14 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/hashicorp/terraform-ls/internal/langserver/diagnostics"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/settings"
"github.com/hashicorp/terraform-ls/internal/terraform/module"
)

type contextKey struct {
Expand All @@ -22,7 +21,6 @@ var (
ctxTfExecPath = &contextKey{"terraform executable path"}
ctxTfExecLogPath = &contextKey{"terraform executor log path"}
ctxTfExecTimeout = &contextKey{"terraform execution timeout"}
ctxWatcher = &contextKey{"watcher"}
ctxRootDir = &contextKey{"root directory"}
ctxCommandPrefix = &contextKey{"command prefix"}
ctxDiagsNotifier = &contextKey{"diagnostics notifier"}
Expand Down Expand Up @@ -53,18 +51,6 @@ func TerraformExecTimeout(ctx context.Context) (time.Duration, bool) {
return path, ok
}

func WithWatcher(ctx context.Context, w module.Watcher) context.Context {
return context.WithValue(ctx, ctxWatcher, w)
}

func Watcher(ctx context.Context) (module.Watcher, error) {
w, ok := ctx.Value(ctxWatcher).(module.Watcher)
if !ok {
return nil, missingContextErr(ctxWatcher)
}
return w, nil
}

func WithTerraformExecPath(ctx context.Context, path string) context.Context {
return context.WithValue(ctx, ctxTfExecPath, path)
}
Expand Down
89 changes: 89 additions & 0 deletions internal/langserver/handlers/did_change_watched_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/hashicorp/terraform-ls/internal/job"
"github.com/hashicorp/terraform-ls/internal/protocol"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/state"
"github.com/hashicorp/terraform-ls/internal/terraform/ast"
"github.com/hashicorp/terraform-ls/internal/terraform/datadir"
"github.com/hashicorp/terraform-ls/internal/uri"
)

Expand All @@ -21,6 +23,74 @@ func (svc *service) DidChangeWatchedFiles(ctx context.Context, params lsp.DidCha
for _, change := range params.Changes {
rawURI := string(change.URI)

// This is necessary because clients may not send delete notifications
// for individual nested files when the parent directory is deleted.
// VS Code / vscode-languageclient behaves this way.
if modUri, ok := datadir.ModuleUriFromDataDir(rawURI); ok {
modHandle := document.DirHandleFromURI(modUri)
if change.Type == protocol.Deleted {
// This is unlikely to happen unless the user manually removed files
// See https://github.com/hashicorp/terraform/issues/30005
err := svc.modStore.UpdateModManifest(modHandle.Path(), nil, nil)
if err != nil {
svc.logger.Printf("failed to remove module manifest for %q: %s", modHandle, err)
}
}
continue
}

if modUri, ok := datadir.ModuleUriFromPluginLockFile(rawURI); ok {
if change.Type == protocol.Deleted {
// This is unlikely to happen unless the user manually removed files
// See https://github.com/hashicorp/terraform/issues/30005
// Cached provider schema could be removed here but it may be useful
// in other modules, so we trade some memory for better UX here.
continue
}

modHandle := document.DirHandleFromURI(modUri)
err := svc.indexModuleIfNotExists(ctx, modHandle)
if err != nil {
svc.logger.Printf("failed to index module %q: %s", modHandle, err)
continue
}

jobIds, err := svc.indexer.PluginLockChanged(ctx, modHandle)
if err != nil {
svc.logger.Printf("error refreshing plugins for %q: %s", rawURI, err)
continue
}
ids = append(ids, jobIds...)
continue
}

if modUri, ok := datadir.ModuleUriFromModuleLockFile(rawURI); ok {
modHandle := document.DirHandleFromURI(modUri)
if change.Type == protocol.Deleted {
// This is unlikely to happen unless the user manually removed files
// See https://github.com/hashicorp/terraform/issues/30005
err := svc.modStore.UpdateModManifest(modHandle.Path(), nil, nil)
if err != nil {
svc.logger.Printf("failed to remove module manifest for %q: %s", modHandle, err)
}
continue
}

err := svc.indexModuleIfNotExists(ctx, modHandle)
if err != nil {
svc.logger.Printf("failed to index module %q: %s", modHandle, err)
continue
}

jobIds, err := svc.indexer.ModuleManifestChanged(ctx, modHandle)
if err != nil {
svc.logger.Printf("error refreshing plugins for %q: %s", modHandle, err)
continue
}
ids = append(ids, jobIds...)
continue
}

rawPath, err := uri.PathFromURI(rawURI)
if err != nil {
svc.logger.Printf("error parsing %q: %s", rawURI, err)
Expand Down Expand Up @@ -137,6 +207,25 @@ func (svc *service) DidChangeWatchedFiles(ctx context.Context, params lsp.DidCha
return nil
}

func (svc *service) indexModuleIfNotExists(ctx context.Context, modHandle document.DirHandle) error {
_, err := svc.modStore.ModuleByPath(modHandle.Path())
if err != nil {
if state.IsModuleNotFound(err) {
err = svc.stateStore.WalkerPaths.EnqueueDir(modHandle)
if err != nil {
return fmt.Errorf("failed to walk module %q: %w", modHandle, err)
}
err = svc.stateStore.WalkerPaths.WaitForDirs(ctx, []document.DirHandle{modHandle})
if err != nil {
return fmt.Errorf("failed to wait for module walk %q: %w", modHandle, err)
}
} else {
return fmt.Errorf("failed to find module %q: %w", modHandle, err)
}
}
return nil
}

func modHandleFromRawOsPath(ctx context.Context, rawPath string) (*parsedModuleHandle, error) {
fi, err := os.Stat(rawPath)
if err != nil {
Expand Down
Loading

0 comments on commit 9fcc1c9

Please sign in to comment.