Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Nov 16, 2021
1 parent 07aa066 commit be0d532
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 32 deletions.
2 changes: 1 addition & 1 deletion internal/langserver/handlers/complete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ output "test" {
// asynchronously and we currently have no way of waiting
// for them to complete.
// TODO remove once we support synchronous dependent tasks
time.Sleep(1500 * time.Millisecond)
time.Sleep(2500 * time.Millisecond)

ls.CallAndExpectResponse(t, &langserver.CallRequest{
Method: "textDocument/completion",
Expand Down
10 changes: 5 additions & 5 deletions internal/langserver/handlers/did_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ func (lh *logHandler) TextDocumentDidOpen(ctx context.Context, params lsp.DidOpe
// We reparse because the file being opened may not match
// (originally parsed) content on the disk
// TODO: Do this only if we can verify the file differs?
modMgr.EnqueueModuleOp(mod.Path, op.OpTypeParseModuleConfiguration, nil)
modMgr.EnqueueModuleOp(mod.Path, op.OpTypeParseVariables, nil)
modMgr.EnqueueModuleOp(mod.Path, op.OpTypeLoadModuleMetadata, nil)
modMgr.EnqueueModuleOp(mod.Path, op.OpTypeDecodeReferenceTargets, nil)
modMgr.EnqueueModuleOp(mod.Path, op.OpTypeDecodeReferenceOrigins, nil)
modMgr.EnqueueModuleOpWait(mod.Path, op.OpTypeParseModuleConfiguration)
modMgr.EnqueueModuleOpWait(mod.Path, op.OpTypeParseVariables)
modMgr.EnqueueModuleOpWait(mod.Path, op.OpTypeLoadModuleMetadata)
modMgr.EnqueueModuleOpWait(mod.Path, op.OpTypeDecodeReferenceTargets)
modMgr.EnqueueModuleOpWait(mod.Path, op.OpTypeDecodeReferenceOrigins)

if mod.TerraformVersionState == op.OpStateUnknown {
modMgr.EnqueueModuleOp(mod.Path, op.OpTypeGetTerraformVersion, nil)
Expand Down
8 changes: 8 additions & 0 deletions internal/langserver/handlers/references_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"path/filepath"
"testing"
"time"

"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-ls/internal/langserver"
Expand Down Expand Up @@ -178,6 +179,13 @@ variable "instances" {
"uri": "%s/main.tf"
}
}`, submodUri.URI())})

// module manifest-dependent tasks are scheduled & executed
// asynchronously and we currently have no way of waiting
// for them to complete.
// TODO remove once we support synchronous dependent tasks
time.Sleep(3500 * time.Millisecond)

ls.CallAndExpectResponse(t, &langserver.CallRequest{
Method: "textDocument/references",
ReqParams: fmt.Sprintf(`{
Expand Down
6 changes: 3 additions & 3 deletions internal/terraform/module/module_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (ml *moduleLoader) nonPrioCapacity() int64 {
}

func (ml *moduleLoader) executeModuleOp(ctx context.Context, modOp ModuleOperation) {
ml.logger.Printf("executing %q for %s", modOp.Type, modOp.ModulePath)
ml.logger.Printf("ML: executing %q for %q", modOp.Type, modOp.ModulePath)
// TODO: Report progress in % for each op based on queue length
defer modOp.markAsDone()

Expand Down Expand Up @@ -196,7 +196,7 @@ func (ml *moduleLoader) executeModuleOp(ctx context.Context, modOp ModuleOperati
modOp.ModulePath, modOp.Type)
return
}
ml.logger.Printf("finished %q for %s", modOp.Type, modOp.ModulePath)
ml.logger.Printf("ML: finished %q for %q", modOp.Type, modOp.ModulePath)

if modOp.Defer != nil {
go modOp.Defer(opErr)
Expand All @@ -209,7 +209,7 @@ func (ml *moduleLoader) EnqueueModuleOp(modOp ModuleOperation) error {
return err
}

ml.logger.Printf("ML: enqueing %q module operation: %s", modOp.Type, modOp.ModulePath)
ml.logger.Printf("ML: enqueing %q module operation: %q", modOp.Type, modOp.ModulePath)

switch modOp.Type {
case op.OpTypeGetTerraformVersion:
Expand Down
19 changes: 7 additions & 12 deletions internal/terraform/module/module_loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestModuleLoader_referenceCollection(t *testing.T) {
if err != nil {
t.Fatal(err)
}
<-modOp.doneCh
<-modOp.Done()

manifestOp := NewModuleOperation(modPath, op.OpTypeLoadModuleMetadata)
err = ml.EnqueueModuleOp(manifestOp)
Expand All @@ -66,17 +66,12 @@ func TestModuleLoader_referenceCollection(t *testing.T) {
}

t.Log("waiting for all operations to finish")
for i := 0; i <= 2; i++ {
select {
case <-manifestOp.doneCh:
t.Log("manifest parsed")
case <-originsOp.doneCh:
t.Log("origins collected")
case <-targetsOp.doneCh:
t.Log("targets collected")
case <-ctx.Done():
}
}
<-manifestOp.Done()
t.Log("manifest parsed")
<-originsOp.Done()
t.Log("origins collected")
<-targetsOp.Done()
t.Log("targets collected")

mod, err := ss.Modules.ModuleByPath(modPath)
if err != nil {
Expand Down
60 changes: 60 additions & 0 deletions internal/terraform/module/module_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ func (mm *moduleManager) RemoveModule(modPath string) error {
}

func (mm *moduleManager) EnqueueModuleOpWait(modPath string, opType op.OpType) error {
isQueued, err := mm.isAlreadyQueued(modPath, opType)
if err != nil {
return err
}
if isQueued {
return nil
}

modOp := NewModuleOperation(modPath, opType)
mm.loader.EnqueueModuleOp(modOp)

Expand All @@ -91,6 +99,14 @@ func (mm *moduleManager) EnqueueModuleOpWait(modPath string, opType op.OpType) e
}

func (mm *moduleManager) EnqueueModuleOp(modPath string, opType op.OpType, deferFunc DeferFunc) error {
isQueued, err := mm.isAlreadyQueued(modPath, opType)
if err != nil {
return err
}
if isQueued {
return nil
}

modOp := NewModuleOperation(modPath, opType)
modOp.Defer = deferFunc
mm.loader.EnqueueModuleOp(modOp)
Expand All @@ -100,6 +116,50 @@ func (mm *moduleManager) EnqueueModuleOp(modPath string, opType op.OpType, defer
return nil
}

func (mm *moduleManager) isAlreadyQueued(modPath string, opType op.OpType) (bool, error) {
mod, err := mm.moduleStore.ModuleByPath(modPath)
if err != nil {
return false, err
}

switch opType {
case op.OpTypeGetTerraformVersion:
if mod.TerraformVersionState == op.OpStateQueued {
return true, nil
}
case op.OpTypeObtainSchema:
if mod.ProviderSchemaState == op.OpStateQueued {
return true, nil
}
case op.OpTypeParseModuleConfiguration:
if mod.ModuleParsingState == op.OpStateQueued {
return true, nil
}
case op.OpTypeParseVariables:
if mod.VarsParsingState == op.OpStateQueued {
return true, nil
}
case op.OpTypeParseModuleManifest:
if mod.ModManifestState == op.OpStateQueued {
return true, nil
}
case op.OpTypeLoadModuleMetadata:
if mod.MetaState == op.OpStateQueued {
return true, nil
}
case op.OpTypeDecodeReferenceTargets:
if mod.RefTargetsState == op.OpStateQueued {
return true, nil
}
case op.OpTypeDecodeReferenceOrigins:
if mod.RefOriginsState == op.OpStateQueued {
return true, nil
}
}

return false, nil
}

func (mm *moduleManager) CallersOfModule(modPath string) ([]Module, error) {
modules := make([]Module, 0)
callers, err := mm.moduleStore.CallersOfModule(modPath)
Expand Down
1 change: 1 addition & 0 deletions internal/terraform/module/module_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func NewModuleOperation(modPath string, typ op.OpType) ModuleOperation {

func (mo ModuleOperation) markAsDone() {
mo.doneCh <- struct{}{}
close(mo.doneCh)
}

func (mo ModuleOperation) Done() <-chan struct{} {
Expand Down
27 changes: 18 additions & 9 deletions internal/terraform/module/walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,27 +260,36 @@ func (w *Walker) walk(ctx context.Context, rootPath string) error {
}
}

err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeParseModuleConfiguration, nil)
if err != nil {
return err
}

err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeGetTerraformVersion, nil)
if err != nil {
return err
}

dataDir := datadir.WalkDataDirOfModule(w.fs, dir)
if dataDir.ModuleManifestPath != "" {
// References are collected *after* manifest parsing
// so that we reflect any references to submodules.
err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeParseModuleManifest,
decodeCalledModulesFunc(w.modMgr, w.watcher, dir))
if err != nil {
return err
}
}

err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeDecodeReferenceTargets, nil)
if err != nil {
return err
}
err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeDecodeReferenceOrigins, nil)
if err != nil {
return err
} else {
// If there is no module manifest we still collect references
// as this module may also be called by other modules.
err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeDecodeReferenceTargets, nil)
if err != nil {
return err
}
err = w.modMgr.EnqueueModuleOp(dir, op.OpTypeDecodeReferenceOrigins, nil)
if err != nil {
return err
}
}

if dataDir.PluginLockFilePath != "" {
Expand Down
7 changes: 5 additions & 2 deletions internal/terraform/module/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ func decodeCalledModulesFunc(modMgr ModuleManager, w Watcher, modPath string) De
}
modMgr.AddModule(mc.Path)

modMgr.EnqueueModuleOpWait(mc.Path, op.OpTypeParseModuleConfiguration)
modMgr.EnqueueModuleOpWait(mc.Path, op.OpTypeLoadModuleMetadata)
modMgr.EnqueueModuleOp(mc.Path, op.OpTypeParseModuleConfiguration, nil)
modMgr.EnqueueModuleOp(mc.Path, op.OpTypeLoadModuleMetadata, nil)

modMgr.EnqueueModuleOp(mc.Path, op.OpTypeParseVariables, nil)
modMgr.EnqueueModuleOp(mc.Path, op.OpTypeDecodeReferenceTargets, nil)
Expand All @@ -256,6 +256,9 @@ func decodeCalledModulesFunc(modMgr ModuleManager, w Watcher, modPath string) De
w.AddModule(mc.Path)
}
}

modMgr.EnqueueModuleOp(modPath, op.OpTypeDecodeReferenceTargets, nil)
modMgr.EnqueueModuleOp(modPath, op.OpTypeDecodeReferenceOrigins, nil)
}
}

Expand Down

0 comments on commit be0d532

Please sign in to comment.