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

ask for init if current folder is empty root module #257

Merged
merged 3 commits into from
Nov 20, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
11 changes: 11 additions & 0 deletions internal/terraform/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ func (e *Executor) setLogPath(method string) error {
return e.tf.SetLogPath(logPath)
}

func (e *Executor) Init(ctx context.Context) error {
ctx, cancel := e.withTimeout(ctx)
defer cancel()
err := e.setLogPath("Init")
if err != nil {
return err
}

return e.contextfulError(ctx, "Init", e.tf.Init(ctx))
}

func (e *Executor) Format(ctx context.Context, input []byte) ([]byte, error) {
ctx, cancel := e.withTimeout(ctx)
defer cancel()
Expand Down
14 changes: 14 additions & 0 deletions internal/terraform/exec/mock/executor.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/terraform/exec/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type TerraformExecutor interface {
SetExecLogPath(path string) error
SetTimeout(duration time.Duration)
GetExecPath() string
Init(ctx context.Context) error
Format(ctx context.Context, input []byte) ([]byte, error)
Version(ctx context.Context) (*version.Version, error)
ProviderSchemas(ctx context.Context) (*tfjson.ProviderSchemas, error)
Expand Down
10 changes: 10 additions & 0 deletions internal/terraform/rootmodule/root_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,16 @@ func (rm *rootModule) discoverTerraformExecutor(ctx context.Context) error {
return nil
}

func (rm *rootModule) ExecuteTerraformInit(ctx context.Context) error {
if !rm.IsTerraformAvailable() {
if err := rm.discoverTerraformExecutor(ctx); err != nil {
return err
}
}

return rm.tfExec.Init(ctx)
}

func (rm *rootModule) discoverTerraformVersion(ctx context.Context) error {
if rm.tfExec == nil {
return errors.New("no terraform executor - unable to read version")
Expand Down
15 changes: 15 additions & 0 deletions internal/terraform/rootmodule/root_module_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ func (rmm *rootModuleManager) SetLogger(logger *log.Logger) {
rmm.logger = logger
}

func (rmm *rootModuleManager) InitAndUpdateRootModule(ctx context.Context, dir string) (RootModule, error) {
rm, err := rmm.RootModuleByPath(dir)
if err != nil {
return nil, fmt.Errorf("failed to get root module: %+v", err)
}

if err := rm.ExecuteTerraformInit(ctx); err != nil {
return nil, fmt.Errorf("failed to init root module: %+v", err)
}

rootModule := rm.(*rootModule)
rootModule.discoverCaches(ctx, dir)
return rm, rootModule.UpdateProviderSchemaCache(ctx, rootModule.pluginLockFile)
}

func (rmm *rootModuleManager) AddAndStartLoadingRootModule(ctx context.Context, dir string) (RootModule, error) {
dir = filepath.Clean(dir)

Expand Down
2 changes: 2 additions & 0 deletions internal/terraform/rootmodule/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type RootModuleManager interface {
SetTerraformExecLogPath(logPath string)
SetTerraformExecTimeout(timeout time.Duration)

InitAndUpdateRootModule(ctx context.Context, dir string) (RootModule, error)
AddAndStartLoadingRootModule(ctx context.Context, dir string) (RootModule, error)
WorkerPoolSize() int
WorkerQueueSize() int
Expand Down Expand Up @@ -81,6 +82,7 @@ type RootModule interface {
TerraformFormatter() (exec.Formatter, error)
HasTerraformDiscoveryFinished() bool
IsTerraformAvailable() bool
ExecuteTerraformInit(ctx context.Context) error
Modules() []ModuleRecord
}

Expand Down
68 changes: 58 additions & 10 deletions langserver/handlers/did_open.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package handlers
import (
"context"
"fmt"
"log"
"path/filepath"
"strings"

"github.com/creachadair/jrpc2"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
"github.com/hashicorp/terraform-ls/internal/terraform/rootmodule"
"github.com/hashicorp/terraform-ls/internal/watcher"
lsp "github.com/sourcegraph/go-lsp"
)

Expand Down Expand Up @@ -42,6 +44,11 @@ func (lh *logHandler) TextDocumentDidOpen(ctx context.Context, params lsp.DidOpe
return err
}

w, err := lsctx.Watcher(ctx)
if err != nil {
return err
}

rootDir, _ := lsctx.RootDirectory(ctx)
readableDir := humanReadablePath(rootDir, f.Dir())

Expand Down Expand Up @@ -78,16 +85,10 @@ func (lh *logHandler) TextDocumentDidOpen(ctx context.Context, params lsp.DidOpe
lh.logger.Printf("walker has not finished walking yet, data may be inaccurate for %s", f.FullPath())
} else if len(candidates) == 0 {
// TODO: Only notify once per f.Dir() per session
msg := fmt.Sprintf("No root module found for %q."+
" Functionality may be limited."+
// Unfortunately we can't be any more specific wrt where
// because we don't gather "init-able folders" in any way
" You may need to run terraform init"+
" and reload your editor.", readableDir)
return jrpc2.PushNotify(ctx, "window/showMessage", lsp.ShowMessageParams{
Type: lsp.MTWarning,
Message: msg,
})
// TODO: if there is any change for the provider/module, ask for init. The did change handler should also implement this
if len(f.Text()) != 0 {
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
go askInitForEmptyRootModule(ctx, lh.logger, w, rootDir, f.Dir())
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
}
}

if len(candidates) > 1 {
Expand Down Expand Up @@ -134,3 +135,50 @@ func humanReadablePath(rootDir, path string) string {

return relDir
}

func askInitForEmptyRootModule(ctx context.Context, logger *log.Logger, w watcher.Watcher, rootDir, dir string) {
msg := fmt.Sprintf("No root module found for %q."+
" Functionality may be limited."+
// Unfortunately we can't be any more specific wrt where
// because we don't gather "init-able folders" in any way
" You may need to run terraform init.", humanReadablePath(rootDir, dir))
title := "run `terraform init`"
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
resp, err := jrpc2.PushCall(ctx, "window/showMessageRequest", lsp.ShowMessageRequestParams{
Type: lsp.MTWarning,
Message: msg,
Actions: []lsp.MessageActionItem{
{
Title: title,
},
},
})
if err != nil {
logger.Printf("%+v", err)
return
}
var action lsp.MessageActionItem
if err := resp.UnmarshalResult(&action); err != nil {
logger.Printf("unmarshal MessageActionItem: %+v", err)
return
}
if action.Title == title {
rmm, err := lsctx.RootModuleManager(ctx)
if err != nil {
logger.Printf("%+v", err)
return
}

rm, err := rmm.InitAndUpdateRootModule(ctx, dir)
if err != nil {
logger.Printf("failed to init root module %+v", err)
return
}

paths := rm.PathsToWatch()
logger.Printf("Adding %d paths of root module for watching (%s)", len(paths), dir)
err = w.AddPaths(paths)
if err != nil {
logger.Printf("failed to add watch for dir (%s): %+v", dir, err)
}
}
}
1 change: 1 addition & 0 deletions langserver/handlers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ func (svc *service) Assigner() (jrpc2.Assigner, error) {
ctx = lsctx.WithRootDirectory(ctx, &rootDir)
ctx = lsctx.WithRootModuleManager(ctx, svc.modMgr)
ctx = lsctx.WithRootModuleWalker(ctx, svc.walker)
ctx = lsctx.WithWatcher(ctx, ww)
return handle(ctx, req, lh.TextDocumentDidOpen)
},
"textDocument/didClose": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
Expand Down