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

add support for specify exclude root module path #251

Merged
merged 3 commits into from
Aug 5, 2020
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
34 changes: 33 additions & 1 deletion docs/SETTINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,20 @@ The language server supports the following configuration options:

This allows overriding automatic root module discovery by passing a static list
of absolute or relative paths to root modules (i.e. folders with `*.tf` files
which have been `terraform init`-ed).
which have been `terraform init`-ed). Conflicts with `ExcludeModulePaths` option.

Relative paths are resolved relative to the directory opened in the editor.

Path separators are converted automatically to the match separators
of the target platform (e.g. `\` on Windows, or `/` on Unix),
symlinks are followed, trailing slashes automatically removed,
and `~` is replaced with your home directory.

## `ExcludeModulePaths` (`[]string`)

This allows exclude root module path when automatic root module discovery by passing a static list
of absolute or relative paths to root modules (i.e. folders with `*.tf` files
which have been `terraform init`-ed). Conflicts with `rootModulePaths` option.

Relative paths are resolved relative to the directory opened in the editor.

Expand Down Expand Up @@ -37,6 +50,18 @@ Use `initializationOptions` key under the `clients.terraform` section, e.g.
}
}
```
or
```json
{
"clients": {
"terraform": {
"initializationOptions": {
"excludeModulePaths": ["/any/path"]
},
}
}
}
```

### VS Code

Expand All @@ -49,3 +74,10 @@ Use `terraform-ls`, e.g.
}
}
```
or
```json
{
"terraform-ls": {
"excludeRootModules": ["/any/path"]
}
}
7 changes: 6 additions & 1 deletion internal/settings/settings.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package settings

import (
"fmt"
"github.com/mitchellh/mapstructure"
)

type Options struct {
// RootModulePaths describes a list of absolute paths to root modules
RootModulePaths []string `mapstructure:"rootModulePaths"`
RootModulePaths []string `mapstructure:"rootModulePaths"`
ExcludeModulePaths []string `mapstructure:"excludeModulePaths"`
njuCZ marked this conversation as resolved.
Show resolved Hide resolved

// TODO: Need to check for conflict with CLI flags
// TerraformExecPath string
Expand All @@ -15,6 +17,9 @@ type Options struct {
}

func (o *Options) Validate() error {
if len(o.RootModulePaths) != 0 && len(o.ExcludeModulePaths) != 0 {
return fmt.Errorf("at most one of `rootModulePaths` and `excludeModulePaths` could be set")
}
return nil
}

Expand Down
29 changes: 22 additions & 7 deletions internal/terraform/rootmodule/walker.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type Walker struct {
walkingMu *sync.RWMutex
cancelFunc context.CancelFunc
doneCh <-chan struct{}

excludeModulePaths map[string]bool
}

func NewWalker() *Walker {
Expand All @@ -45,6 +47,13 @@ func (w *Walker) SetLogger(logger *log.Logger) {
w.logger = logger
}

func (w *Walker) SetExcludeModulePaths(excludeModulePaths []string) {
w.excludeModulePaths = make(map[string]bool)
for _, path := range excludeModulePaths {
w.excludeModulePaths[path] = true
}
}

type WalkFunc func(ctx context.Context, rootModulePath string) error

func (w *Walker) Stop() {
Expand Down Expand Up @@ -105,6 +114,7 @@ func (w *Walker) IsWalking() bool {

func (w *Walker) walk(ctx context.Context, rootPath string, wf WalkFunc) error {
defer w.Stop()

err := filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
select {
case <-w.doneCh:
Expand All @@ -118,14 +128,19 @@ func (w *Walker) walk(ctx context.Context, rootPath string, wf WalkFunc) error {
return nil
}

if info.Name() == ".terraform" {
rootDir, err := filepath.Abs(filepath.Dir(path))
if err != nil {
return err
}
dir, err := filepath.Abs(filepath.Dir(path))
if err != nil {
return err
}

if _, ok := w.excludeModulePaths[dir]; ok {
w.logger.Printf("successfully exclude root_module: %s", dir)
return filepath.SkipDir
}

w.logger.Printf("found root module %s", rootDir)
return wf(ctx, rootDir)
if info.Name() == ".terraform" {
w.logger.Printf("found root module %s", dir)
return wf(ctx, dir)
}

if !info.IsDir() {
Expand Down
28 changes: 22 additions & 6 deletions langserver/handlers/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"path/filepath"
"strings"

"github.com/creachadair/jrpc2"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
Expand Down Expand Up @@ -108,13 +109,23 @@ func (lh *logHandler) Initialize(ctx context.Context, params lsp.InitializeParam
return serverCaps, nil
}

var excludeModulePaths []string
for _, rawPath := range cfgOpts.ExcludeModulePaths {
rmPath, err := resolvePath(rootDir, rawPath)
if err != nil {
lh.logger.Printf("Ignoring exclude root module path %s: %s", rawPath, err)
continue
}
excludeModulePaths = append(excludeModulePaths, rmPath)
}

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

walker.SetLogger(lh.logger)

walker.SetExcludeModulePaths(excludeModulePaths)
// Walker runs asynchronously so we're intentionally *not*
// passing the request context here
bCtx := context.Background()
Expand All @@ -139,15 +150,20 @@ func (lh *logHandler) Initialize(ctx context.Context, params lsp.InitializeParam
}

func resolvePath(rootDir, rawPath string) (string, error) {
rawPath, err := homedir.Expand(rawPath)
path, err := homedir.Expand(rawPath)
if err != nil {
return "", err
}

if filepath.IsAbs(rawPath) {
return filepath.EvalSymlinks(rawPath)
if !filepath.IsAbs(path) {
path = filepath.Join(rootDir, rawPath)
}

path := filepath.Join(rootDir, rawPath)
return filepath.EvalSymlinks(path)
absPath, err := filepath.EvalSymlinks(path)
return toLowerVolumePath(absPath), err
}

func toLowerVolumePath(path string) string {
volume := filepath.VolumeName(path)
return strings.ToLower(volume) + path[len(volume):]
}