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

refactoring: Introduce root module (manager) abstraction #167

Merged
merged 1 commit into from
Jun 18, 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
58 changes: 21 additions & 37 deletions commands/completion_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ import (
"strconv"
"strings"

lsctx "github.com/hashicorp/terraform-ls/internal/context"
"github.com/hashicorp/terraform-ls/internal/filesystem"
ihcl "github.com/hashicorp/terraform-ls/internal/hcl"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
"github.com/hashicorp/terraform-ls/internal/terraform/discovery"
"github.com/hashicorp/terraform-ls/internal/terraform/exec"
"github.com/hashicorp/terraform-ls/internal/terraform/schema"
"github.com/hashicorp/terraform-ls/langserver/handlers"
"github.com/hashicorp/terraform-ls/internal/terraform/rootmodule"
"github.com/hashicorp/terraform-ls/logging"
"github.com/mitchellh/cli"
lsp "github.com/sourcegraph/go-lsp"
Expand Down Expand Up @@ -56,7 +53,8 @@ func (c *CompletionCommand) Run(args []string) int {
return 1
}

lspUri := ilsp.FileHandlerFromPath(path).DocumentURI()
fh := ilsp.FileHandlerFromPath(path)

parts := strings.Split(c.atPos, ":")
if len(parts) != 2 {
c.Ui.Error(fmt.Sprintf("Error parsing at-pos argument: %q (expected line:col format)", c.atPos))
Expand All @@ -79,62 +77,48 @@ func (c *CompletionCommand) Run(args []string) int {
fs := filesystem.NewFilesystem()
fs.SetLogger(logger)
fs.Open(ilsp.FileFromDocumentItem(lsp.TextDocumentItem{
URI: lspUri,
URI: fh.DocumentURI(),
Text: string(content),
Version: 0,
}))

d := &discovery.Discovery{}
tfPath, err := d.LookPath()
file, err := fs.GetFile(fh)
if err != nil {
c.Ui.Error(err.Error())
return 1
}

ss := schema.NewStorage()
ss.SetLogger(logger)
ss.SetSynchronous()

ctx := context.Background()

dir := ilsp.FileHandler(lspUri).Dir()

tf := exec.NewExecutor(ctx, tfPath)
tf.SetWorkdir(dir)
version, err := tf.Version()
hclFile := ihcl.NewFile(file)
fPos, err := ilsp.FilePositionFromDocumentPosition(lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: fh.DocumentURI(),
},
Position: lspPos,
}, file)
if err != nil {
c.Ui.Error(err.Error())
return 1
}

err = ss.ObtainSchemasForWorkspace(tf, dir)
w, err := rootmodule.NewRootModule(context.Background(), fh.Dir())
if err != nil {
c.Ui.Error(err.Error())
return 1
}
p := w.Parser()

ctx = lsctx.WithFilesystem(fs, ctx)
ctx = lsctx.WithTerraformVersion(version, ctx)
ctx = lsctx.WithTerraformExecutor(tf, ctx)
ctx = lsctx.WithTerraformSchemaReader(ss, ctx)
ctx = lsctx.WithClientCapabilities(&lsp.ClientCapabilities{}, ctx)

h := handlers.LogHandler(logger)
items, err := h.TextDocumentComplete(ctx, lsp.CompletionParams{
TextDocumentPositionParams: lsp.TextDocumentPositionParams{
TextDocument: lsp.TextDocumentIdentifier{
URI: lspUri,
},
Position: lspPos,
},
})
pos := fPos.Position()

candidates, err := p.CompletionCandidatesAtPos(hclFile, pos)
if err != nil {
c.Ui.Error(err.Error())
return 1
}

c.Ui.Output(fmt.Sprintf("%#v", items))
cc := &lsp.ClientCapabilities{}
items := ilsp.CompletionList(candidates, pos, cc.TextDocument)

c.Ui.Output(fmt.Sprintf("%#v", items))
return 0
}

Expand Down
13 changes: 5 additions & 8 deletions commands/serve_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,9 @@ func (c *ServeCommand) Run(args []string) int {
logger.Printf("Terraform execution timeout set to %s", d)
}

srv := langserver.NewLangServer(ctx, handlers.NewSession)
srv.SetLogger(logger)

if c.tfExecPath != "" {
path := c.tfExecPath

logger.Printf("Setting Terraform exec path to %q", path)

// just some sanity checking here, no need to get too specific otherwise will be complex cross-OS
if !filepath.IsAbs(path) {
c.Ui.Error(fmt.Sprintf("Expected absolute path for Terraform binary, got %q", path))
Expand All @@ -115,11 +110,13 @@ func (c *ServeCommand) Run(args []string) int {
return 1
}

srv.SetDiscoveryFunc(func() (string, error) {
return path, nil
})
ctx = lsctx.WithTerraformExecPath(path, ctx)
logger.Printf("Terraform exec path set to %q", path)
}

srv := langserver.NewLangServer(ctx, handlers.NewSession)
srv.SetLogger(logger)

if c.port != 0 {
err := srv.StartTCP(fmt.Sprintf("localhost:%d", c.port))
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/creachadair/jrpc2 v0.8.1
github.com/fsnotify/fsnotify v1.4.9
github.com/google/go-cmp v0.4.0
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/hashicorp/go-version v1.2.0
github.com/hashicorp/hcl/v2 v2.5.2-0.20200528183353-fa7c453538de
github.com/hashicorp/terraform-json v0.5.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
radeksimko marked this conversation as resolved.
Show resolved Hide resolved
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl/v2 v2.5.2-0.20200528183353-fa7c453538de h1:bCeWhTigOmP9am0cJA+5kaTtA2RFDmnWIRtBIxo+Ydg=
Expand Down
109 changes: 50 additions & 59 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"time"

"github.com/hashicorp/terraform-ls/internal/filesystem"
"github.com/hashicorp/terraform-ls/internal/terraform/exec"
"github.com/hashicorp/terraform-ls/internal/terraform/schema"
"github.com/hashicorp/terraform-ls/internal/terraform/rootmodule"
"github.com/hashicorp/terraform-ls/internal/watcher"
"github.com/sourcegraph/go-lsp"
)

Expand All @@ -20,15 +20,15 @@ func (k *contextKey) String() string {

var (
ctxFs = &contextKey{"filesystem"}
ctxTerraformExec = &contextKey{"terraform executor"}
ctxClientCapsSetter = &contextKey{"client capabilities setter"}
ctxClientCaps = &contextKey{"client capabilities"}
ctxTfSchemaWriter = &contextKey{"schema writer"}
ctxTfSchemaReader = &contextKey{"schema reader"}
ctxTfVersion = &contextKey{"terraform version"}
ctxTfVersionSetter = &contextKey{"terraform version setter"}
ctxTfExecPath = &contextKey{"terraform executable path"}
ctxTfExecLogPath = &contextKey{"terraform executor log path"}
ctxTfExecTimeout = &contextKey{"terraform execution timeout"}
ctxWatcher = &contextKey{"watcher"}
ctxRootModuleMngr = &contextKey{"root module manager"}
ctxParserFinder = &contextKey{"parser finder"}
ctxTfExecFinder = &contextKey{"terraform exec finder"}
)

func missingContextErr(ctxKey *contextKey) *MissingContextErr {
Expand All @@ -48,19 +48,6 @@ func Filesystem(ctx context.Context) (filesystem.Filesystem, error) {
return fs, nil
}

func WithTerraformExecutor(tf *exec.Executor, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTerraformExec, tf)
}

func TerraformExecutor(ctx context.Context) (*exec.Executor, error) {
tf, ok := ctx.Value(ctxTerraformExec).(*exec.Executor)
if !ok {
return nil, missingContextErr(ctxTerraformExec)
}

return tf, nil
}

func WithClientCapabilitiesSetter(caps *lsp.ClientCapabilities, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxClientCapsSetter, caps)
}
Expand Down Expand Up @@ -88,73 +75,77 @@ func ClientCapabilities(ctx context.Context) (lsp.ClientCapabilities, error) {
return *caps, nil
}

func WithTerraformSchemaWriter(s schema.Writer, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfSchemaWriter, s)
func WithTerraformExecLogPath(path string, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfExecLogPath, path)
}

func TerraformSchemaWriter(ctx context.Context) (schema.Writer, error) {
ss, ok := ctx.Value(ctxTfSchemaWriter).(schema.Writer)
if !ok {
return nil, missingContextErr(ctxTfSchemaWriter)
}
func TerraformExecLogPath(ctx context.Context) (string, bool) {
path, ok := ctx.Value(ctxTfExecLogPath).(string)
return path, ok
}

return ss, nil
func WithTerraformExecTimeout(timeout time.Duration, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfExecTimeout, timeout)
}

func WithTerraformSchemaReader(s schema.Reader, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfSchemaReader, s)
func TerraformExecTimeout(ctx context.Context) (time.Duration, bool) {
path, ok := ctx.Value(ctxTfExecTimeout).(time.Duration)
return path, ok
}

func WithWatcher(w watcher.Watcher, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxWatcher, w)
}

func TerraformSchemaReader(ctx context.Context) (schema.Reader, error) {
ss, ok := ctx.Value(ctxTfSchemaReader).(schema.Reader)
func Watcher(ctx context.Context) (watcher.Watcher, error) {
w, ok := ctx.Value(ctxWatcher).(watcher.Watcher)
if !ok {
return nil, missingContextErr(ctxTfSchemaReader)
return nil, missingContextErr(ctxWatcher)
}

return ss, nil
return w, nil
}

func WithTerraformVersion(v string, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfVersion, v)
func WithRootModuleManager(wm rootmodule.RootModuleManager, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxRootModuleMngr, wm)
}

func TerraformVersion(ctx context.Context) (string, error) {
tfv, ok := ctx.Value(ctxTfVersion).(string)
func RootModuleManager(ctx context.Context) (rootmodule.RootModuleManager, error) {
wm, ok := ctx.Value(ctxRootModuleMngr).(rootmodule.RootModuleManager)
if !ok {
return "", missingContextErr(ctxTfVersion)
return nil, missingContextErr(ctxRootModuleMngr)
}

return tfv, nil
return wm, nil
}

func WithTerraformVersionSetter(v *string, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfVersionSetter, v)
func WithParserFinder(pf rootmodule.ParserFinder, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxParserFinder, pf)
}

func SetTerraformVersion(ctx context.Context, v string) error {
tfv, ok := ctx.Value(ctxTfVersionSetter).(*string)
func ParserFinder(ctx context.Context) (rootmodule.ParserFinder, error) {
pf, ok := ctx.Value(ctxParserFinder).(rootmodule.ParserFinder)
if !ok {
return missingContextErr(ctxTfVersionSetter)
return nil, missingContextErr(ctxParserFinder)
}
*tfv = v

return nil
return pf, nil
}

func WithTerraformExecLogPath(path string, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfExecLogPath, path)
func WithTerraformExecFinder(tef rootmodule.TerraformExecFinder, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfExecFinder, tef)
}

func TerraformExecLogPath(ctx context.Context) (string, bool) {
path, ok := ctx.Value(ctxTfExecLogPath).(string)
return path, ok
func TerraformExecutorFinder(ctx context.Context) (rootmodule.TerraformExecFinder, error) {
pf, ok := ctx.Value(ctxTfExecFinder).(rootmodule.TerraformExecFinder)
if !ok {
return nil, missingContextErr(ctxTfExecFinder)
}
return pf, nil
}

func WithTerraformExecTimeout(timeout time.Duration, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfExecTimeout, timeout)
func WithTerraformExecPath(path string, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfExecPath, path)
}

func TerraformExecTimeout(ctx context.Context) (time.Duration, bool) {
path, ok := ctx.Value(ctxTfExecTimeout).(time.Duration)
func TerraformExecPath(ctx context.Context) (string, bool) {
path, ok := ctx.Value(ctxTfExecPath).(string)
return path, ok
}
4 changes: 2 additions & 2 deletions internal/lsp/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type File interface {
}

type file struct {
fh FileHandler
fh *fileHandler
ls source.Lines
text []byte
version int
Expand Down Expand Up @@ -57,7 +57,7 @@ func (f *file) Version() int {

func FileFromDocumentItem(doc lsp.TextDocumentItem) *file {
return &file{
fh: FileHandler(doc.URI),
fh: FileHandlerFromDocumentURI(doc.URI),
text: []byte(doc.Text),
version: doc.Version,
}
Expand Down
7 changes: 4 additions & 3 deletions internal/lsp/file_change_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package lsp

import (
"github.com/hashicorp/hcl/v2"
"github.com/sourcegraph/go-lsp"
"reflect"
"testing"

"github.com/hashicorp/hcl/v2"
"github.com/sourcegraph/go-lsp"
)

func TestLspRangeToHCL(t *testing.T) {
Expand Down Expand Up @@ -76,7 +77,7 @@ func TestLspRangeToHCL(t *testing.T) {
t.Logf("[DEBUG] Testing %q", v.Name)

result, err := lspRangeToHCL(v.Range, &file{
fh: "file:///test.tf",
fh: FileHandlerFromDocumentURI(lsp.DocumentURI("file:///test.tf")),
text: []byte(v.Content),
})
if err != nil {
Expand Down
Loading