Skip to content

Commit

Permalink
Support multiple folders natively
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Jun 11, 2021
1 parent 72aef8b commit eb7e476
Show file tree
Hide file tree
Showing 15 changed files with 384 additions and 27 deletions.
3 changes: 2 additions & 1 deletion internal/cmd/inspect_module_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ func (c *InspectModuleCommand) inspect(rootPath string) error {
c.logger, syscall.SIGINT, syscall.SIGTERM)
defer cancel()

err = walker.StartWalking(ctx, rootPath)
walker.EnqueuePath(rootPath)
err = walker.StartWalking(ctx)
if err != nil {
return err
}
Expand Down
86 changes: 86 additions & 0 deletions internal/langserver/handlers/did_change_workspace_folders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package handlers

import (
"context"
"fmt"

"github.com/creachadair/jrpc2"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/uri"
)

func (lh *logHandler) DidChangeWorkspaceFolders(ctx context.Context, params lsp.DidChangeWorkspaceFoldersParams) error {
watcher, err := lsctx.Watcher(ctx)
if err != nil {
return err
}

walker, err := lsctx.ModuleWalker(ctx)
if err != nil {
return err
}

mm, err := lsctx.ModuleManager(ctx)
if err != nil {
return err
}

for _, removed := range params.Event.Removed {
modPath, err := pathFromDocumentURI(removed.URI)
if err != nil {
jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{
Type: lsp.Warning,
Message: fmt.Sprintf("Ignoring removed workspace folder %s: %s."+
" This is most likely bug, please report it.", removed.URI, err),
})
continue
}
walker.RemovePathFromQueue(modPath)

err = watcher.RemoveModule(modPath)
if err != nil {
lh.logger.Printf("failed to remove module from watcher: %s", err)
continue
}

callers, err := mm.CallersOfModule(modPath)
if err != nil {
lh.logger.Printf("failed to remove module from watcher: %s", err)
continue
}
if len(callers) == 0 {
mm.RemoveModule(modPath)
}
}

for _, added := range params.Event.Added {
modPath, err := pathFromDocumentURI(added.URI)
if err != nil {
jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{
Type: lsp.Warning,
Message: fmt.Sprintf("Ignoring new workspace folder %s: %s."+
" This is most likely bug, please report it.", added.URI, err),
})
continue
}
err = watcher.AddModule(modPath)
if err != nil {
lh.logger.Printf("failed to add module to watcher: %s", err)
continue
}

walker.EnqueuePath(modPath)
}

return nil
}

func pathFromDocumentURI(docUri string) (string, error) {
rawPath, err := uri.PathFromURI(docUri)
if err != nil {
return "", err
}

return cleanupPath(rawPath)
}
5 changes: 4 additions & 1 deletion internal/langserver/handlers/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ func initializeResponse(t *testing.T, commandPrefix string) string {
"full": false
},
"workspace": {
"workspaceFolders": {}
"workspaceFolders": {
"supported": true,
"changeNotifications": "workspace/didChangeWorkspaceFolders"
}
}
},
"serverInfo": {
Expand Down
51 changes: 43 additions & 8 deletions internal/langserver/handlers/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ func (lh *logHandler) Initialize(ctx context.Context, params lsp.InitializeParam
DocumentFormattingProvider: true,
DocumentSymbolProvider: true,
WorkspaceSymbolProvider: true,
Workspace: lsp.WorkspaceGn{
WorkspaceFolders: lsp.WorkspaceFoldersGn{
Supported: true,
ChangeNotifications: "workspace/didChangeWorkspaceFolders",
},
},
},
}

Expand Down Expand Up @@ -114,6 +120,36 @@ func (lh *logHandler) Initialize(ctx context.Context, params lsp.InitializeParam
}
cfgOpts := out.Options

if !clientCaps.Workspace.WorkspaceFolders && len(params.WorkspaceFolders) > 0 {
jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{
Type: lsp.Warning,
Message: "Client sent workspace folders despite not declaring support. " +
"Please report this as a bug.",
})
}

walker, err := lsctx.ModuleWalker(ctx)
if err != nil {
return serverCaps, err
}
walker.SetLogger(lh.logger)

if len(params.WorkspaceFolders) > 0 {
for _, folderPath := range params.WorkspaceFolders {
modPath, err := pathFromDocumentURI(folderPath.URI)
if err != nil {
jrpc2.ServerFromContext(ctx).Notify(ctx, "window/showMessage", &lsp.ShowMessageParams{
Type: lsp.Warning,
Message: fmt.Sprintf("Ignoring workspace folder %s: %s."+
" This is most likely bug, please report it.", folderPath.URI, err),
})
continue
}

walker.EnqueuePath(modPath)
}
}

// Static user-provided paths take precedence over dynamic discovery
if len(cfgOpts.ModulePaths) > 0 {
lh.logger.Printf("Attempting to add %d static module paths", len(cfgOpts.ModulePaths))
Expand Down Expand Up @@ -146,17 +182,12 @@ func (lh *logHandler) Initialize(ctx context.Context, params lsp.InitializeParam
excludeModulePaths = append(excludeModulePaths, modPath)
}

walker, err := lsctx.ModuleWalker(ctx)
if err != nil {
return serverCaps, err
}

walker.SetLogger(lh.logger)
walker.SetExcludeModulePaths(excludeModulePaths)
walker.EnqueuePath(fh.Dir())

// Walker runs asynchronously so we're intentionally *not*
// passing the request context here
bCtx := context.Background()
err = walker.StartWalking(bCtx, fh.Dir())
err = walker.StartWalking(context.Background())

return serverCaps, err
}
Expand All @@ -171,6 +202,10 @@ func resolvePath(rootDir, rawPath string) (string, error) {
path = filepath.Join(rootDir, rawPath)
}

return cleanupPath(path)
}

func cleanupPath(path string) (string, error) {
absPath, err := filepath.EvalSymlinks(path)
return toLowerVolumePath(absPath), err
}
Expand Down
11 changes: 11 additions & 0 deletions internal/langserver/handlers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,17 @@ func (svc *service) Assigner() (jrpc2.Assigner, error) {

return handle(ctx, req, lh.TextDocumentDidSave)
},
"workspace/didChangeWorkspaceFolders": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := session.CheckInitializationIsConfirmed()
if err != nil {
return nil, err
}

ctx = lsctx.WithModuleWalker(ctx, svc.walker)
ctx = lsctx.WithWatcher(ctx, svc.watcher)

return handle(ctx, req, lh.DidChangeWorkspaceFolders)
},
"workspace/executeCommand": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := session.CheckInitializationIsConfirmed()
if err != nil {
Expand Down
13 changes: 13 additions & 0 deletions internal/state/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,19 @@ func (s *ModuleStore) Add(modPath string) error {
return nil
}

func (s *ModuleStore) Remove(modPath string) error {
txn := s.db.Txn(true)
defer txn.Abort()

_, err := txn.DeleteAll(s.tableName, "id", modPath)
if err != nil {
return err
}

txn.Commit()
return nil
}

func (s *ModuleStore) CallersOfModule(modPath string) ([]*Module, error) {
txn := s.db.Txn(false)
it, err := txn.Get(s.tableName, "id")
Expand Down
4 changes: 4 additions & 0 deletions internal/terraform/module/module_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,7 @@ func (ml *moduleLoader) EnqueueModuleOp(modOp ModuleOperation) error {

return nil
}

func (ml *moduleLoader) DequeueModule(modPath string) {
ml.queue.DequeueAllModuleOps(modPath)
}
5 changes: 5 additions & 0 deletions internal/terraform/module/module_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ func (mm *moduleManager) AddModule(modPath string) (Module, error) {
return mod, err
}

func (mm *moduleManager) RemoveModule(modPath string) error {
mm.loader.DequeueModule(modPath)
return mm.moduleStore.Remove(modPath)
}

func (mm *moduleManager) EnqueueModuleOpWait(modPath string, opType op.OpType) error {
modOp := NewModuleOperation(modPath, opType)
mm.loader.EnqueueModuleOp(modOp)
Expand Down
9 changes: 5 additions & 4 deletions internal/terraform/module/module_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ func TestModuleManager_ModuleCandidatesByPath(t *testing.T) {

w := SyncWalker(fs, mm)
w.SetLogger(testLogger())
err = w.StartWalking(ctx, tc.walkerRoot)
w.EnqueuePath(tc.walkerRoot)
err = w.StartWalking(ctx)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -437,18 +438,18 @@ func TestSchemaForVariables(t *testing.T) {
}

mod.Meta.Variables = map[string]tfmodule.Variable{
"name": tfmodule.Variable{
"name": {
Description: "name of the module",
Type: cty.String,
},
}
expectedSchema := &schema.BodySchema{Attributes: map[string]*schema.AttributeSchema{
"name": &schema.AttributeSchema{
"name": {
Description: lang.MarkupContent{
Value: "name of the module",
Kind: lang.PlainTextKind,
},
Expr: schema.ExprConstraints{schema.LiteralTypeExpr{cty.String}},
Expr: schema.ExprConstraints{schema.LiteralTypeExpr{Type: cty.String}},
},
}}

Expand Down
14 changes: 14 additions & 0 deletions internal/terraform/module/module_ops_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ func (q *moduleOpsQueue) PopOp() (ModuleOperation, bool) {
return modOp, true
}

func (q *moduleOpsQueue) DequeueAllModuleOps(modPath string) {
q.mu.Lock()
defer q.mu.Unlock()
if q.q.Len() == 0 {
return
}

for i, p := range q.q.ops {
if p.ModulePath == modPath {
q.q.ops = append(q.q.ops[:i], q.q.ops[:i+1]...)
}
}
}

func (q *moduleOpsQueue) Len() int {
q.mu.Lock()
defer q.mu.Unlock()
Expand Down
2 changes: 2 additions & 0 deletions internal/terraform/module/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ModuleManager interface {

SetLogger(logger *log.Logger)
AddModule(modPath string) (Module, error)
RemoveModule(modPath string) error
EnqueueModuleOp(modPath string, opType op.OpType) error
EnqueueModuleOpWait(modPath string, opType op.OpType) error
CancelLoading()
Expand All @@ -54,5 +55,6 @@ type Watcher interface {
Stop() error
SetLogger(*log.Logger)
AddModule(string) error
RemoveModule(string) error
IsModuleWatched(string) bool
}
Loading

0 comments on commit eb7e476

Please sign in to comment.