Skip to content

Commit

Permalink
refactoring: Introduce workspace (manager) abstraction
Browse files Browse the repository at this point in the history
The main theme of the refactoring is to decouple a few concepts:
 - watcher
 - schema storage
 - terraform executable discovery
 - terraform executor

and introduce a new concept of workspace manager
which better reflects the reality.
  • Loading branch information
radeksimko committed Jun 18, 2020
1 parent 378dba4 commit dc0aa44
Show file tree
Hide file tree
Showing 59 changed files with 1,898 additions and 662 deletions.
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/workspace"
"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 := workspace.NewWorkspace(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=
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/workspace"
"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"}
ctxWorkspaceMngr = &contextKey{"workspace 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 WithWorkspaceManager(wm workspace.WorkspaceManager, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxWorkspaceMngr, wm)
}

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

return tfv, nil
return wm, nil
}

func WithTerraformVersionSetter(v *string, ctx context.Context) context.Context {
return context.WithValue(ctx, ctxTfVersionSetter, v)
func WithParserFinder(pf workspace.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) (workspace.ParserFinder, error) {
pf, ok := ctx.Value(ctxParserFinder).(workspace.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 workspace.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) (workspace.TerraformExecFinder, error) {
pf, ok := ctx.Value(ctxTfExecFinder).(workspace.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

0 comments on commit dc0aa44

Please sign in to comment.