Skip to content

Commit

Permalink
add support for specify exclude root module path (#251)
Browse files Browse the repository at this point in the history
* add settings for excluding paths in root module discovery

* update

* move & unexport ToLowerVolumePath

Co-authored-by: Radek Simko <[email protected]>
  • Loading branch information
njuCZ and radeksimko authored Aug 5, 2020
1 parent 35dd3fb commit 66ab417
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 15 deletions.
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"`

// 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):]
}

0 comments on commit 66ab417

Please sign in to comment.