diff --git a/internal/context/context.go b/internal/context/context.go index 1878e57e7..2714f4b31 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -2,10 +2,6 @@ package context import ( "context" - "fmt" - "log" - "os" - "os/signal" "github.com/hashicorp/terraform-ls/internal/filesystem" "github.com/hashicorp/terraform-ls/internal/terraform/exec" @@ -13,31 +9,29 @@ import ( "github.com/sourcegraph/go-lsp" ) -func WithSignalCancel(ctx context.Context, l *log.Logger, sigs ...os.Signal) ( - context.Context, context.CancelFunc) { - ctx, cancelFunc := context.WithCancel(ctx) - - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, sigs...) - - go func() { - select { - case sig := <-sigChan: - l.Printf("Cancellation signal (%s) received", sig) - cancelFunc() - case <-ctx.Done(): - } - }() - - f := func() { - signal.Stop(sigChan) - cancelFunc() - } +type contextKey struct { + Name string +} - return ctx, f +func (k *contextKey) String() string { + return k.Name } -const ctxFs = "ctxFilesystem" +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"} + ctxTfExecLogPath = &contextKey{"terraform executor log path"} +) + +func missingContextErr(ctxKey *contextKey) *MissingContextErr { + return &MissingContextErr{ctxKey} +} func WithFilesystem(fs filesystem.Filesystem, ctx context.Context) context.Context { return context.WithValue(ctx, ctxFs, fs) @@ -46,14 +40,12 @@ func WithFilesystem(fs filesystem.Filesystem, ctx context.Context) context.Conte func Filesystem(ctx context.Context) (filesystem.Filesystem, error) { fs, ok := ctx.Value(ctxFs).(filesystem.Filesystem) if !ok { - return nil, fmt.Errorf("no filesystem") + return nil, missingContextErr(ctxFs) } return fs, nil } -const ctxTerraformExec = "ctxTerraformExec" - func WithTerraformExecutor(tf *exec.Executor, ctx context.Context) context.Context { return context.WithValue(ctx, ctxTerraformExec, tf) } @@ -61,14 +53,12 @@ func WithTerraformExecutor(tf *exec.Executor, ctx context.Context) context.Conte func TerraformExecutor(ctx context.Context) (*exec.Executor, error) { tf, ok := ctx.Value(ctxTerraformExec).(*exec.Executor) if !ok { - return nil, fmt.Errorf("no terraform executor") + return nil, missingContextErr(ctxTerraformExec) } return tf, nil } -const ctxClientCapsSetter = "ctxClientCapabilitiesSetter" - func WithClientCapabilitiesSetter(caps *lsp.ClientCapabilities, ctx context.Context) context.Context { return context.WithValue(ctx, ctxClientCapsSetter, caps) } @@ -76,15 +66,13 @@ func WithClientCapabilitiesSetter(caps *lsp.ClientCapabilities, ctx context.Cont func SetClientCapabilities(ctx context.Context, caps *lsp.ClientCapabilities) error { cc, ok := ctx.Value(ctxClientCapsSetter).(*lsp.ClientCapabilities) if !ok { - return fmt.Errorf("no client capabilities setter") + return missingContextErr(ctxClientCapsSetter) } *cc = *caps return nil } -const ctxClientCaps = "ctxClientCapabilities" - func WithClientCapabilities(caps *lsp.ClientCapabilities, ctx context.Context) context.Context { return context.WithValue(ctx, ctxClientCaps, caps) } @@ -92,14 +80,12 @@ func WithClientCapabilities(caps *lsp.ClientCapabilities, ctx context.Context) c func ClientCapabilities(ctx context.Context) (lsp.ClientCapabilities, error) { caps, ok := ctx.Value(ctxClientCaps).(*lsp.ClientCapabilities) if !ok { - return lsp.ClientCapabilities{}, fmt.Errorf("no client capabilities") + return lsp.ClientCapabilities{}, missingContextErr(ctxClientCaps) } return *caps, nil } -const ctxTfSchemaWriter = "ctxTerraformSchemaWriter" - func WithTerraformSchemaWriter(s schema.Writer, ctx context.Context) context.Context { return context.WithValue(ctx, ctxTfSchemaWriter, s) } @@ -107,14 +93,12 @@ func WithTerraformSchemaWriter(s schema.Writer, ctx context.Context) context.Con func TerraformSchemaWriter(ctx context.Context) (schema.Writer, error) { ss, ok := ctx.Value(ctxTfSchemaWriter).(schema.Writer) if !ok { - return nil, fmt.Errorf("no terraform schema writer") + return nil, missingContextErr(ctxTfSchemaWriter) } return ss, nil } -const ctxTfSchemaReader = "ctxTerraformSchemaWriter" - func WithTerraformSchemaReader(s schema.Reader, ctx context.Context) context.Context { return context.WithValue(ctx, ctxTfSchemaReader, s) } @@ -122,14 +106,12 @@ func WithTerraformSchemaReader(s schema.Reader, ctx context.Context) context.Con func TerraformSchemaReader(ctx context.Context) (schema.Reader, error) { ss, ok := ctx.Value(ctxTfSchemaReader).(schema.Reader) if !ok { - return nil, fmt.Errorf("no terraform schema reader") + return nil, missingContextErr(ctxTfSchemaReader) } return ss, nil } -const ctxTfVersion = "ctxTerraformVersion" - func WithTerraformVersion(v string, ctx context.Context) context.Context { return context.WithValue(ctx, ctxTfVersion, v) } @@ -137,14 +119,12 @@ func WithTerraformVersion(v string, ctx context.Context) context.Context { func TerraformVersion(ctx context.Context) (string, error) { tfv, ok := ctx.Value(ctxTfVersion).(string) if !ok { - return "", fmt.Errorf("no Terraform version") + return "", missingContextErr(ctxTfVersion) } return tfv, nil } -const ctxTfVersionSetter = "ctxTerraformVersionSetter" - func WithTerraformVersionSetter(v *string, ctx context.Context) context.Context { return context.WithValue(ctx, ctxTfVersionSetter, v) } @@ -152,15 +132,13 @@ func WithTerraformVersionSetter(v *string, ctx context.Context) context.Context func SetTerraformVersion(ctx context.Context, v string) error { tfv, ok := ctx.Value(ctxTfVersionSetter).(*string) if !ok { - return fmt.Errorf("no Terraform version setter") + return missingContextErr(ctxTfVersionSetter) } *tfv = v return nil } -const ctxTfExecLogPath = "ctxTerraformExecLogPath" - func WithTerraformExecLogPath(path string, ctx context.Context) context.Context { return context.WithValue(ctx, ctxTfExecLogPath, path) } diff --git a/internal/context/errors.go b/internal/context/errors.go new file mode 100644 index 000000000..58965f657 --- /dev/null +++ b/internal/context/errors.go @@ -0,0 +1,11 @@ +package context + +import "fmt" + +type MissingContextErr struct { + CtxKey *contextKey +} + +func (e *MissingContextErr) Error() string { + return fmt.Sprintf("missing context: %s", e.CtxKey) +} diff --git a/internal/context/signal_cancel.go b/internal/context/signal_cancel.go new file mode 100644 index 000000000..f8b30f1c5 --- /dev/null +++ b/internal/context/signal_cancel.go @@ -0,0 +1,32 @@ +package context + +import ( + "context" + "log" + "os" + "os/signal" +) + +func WithSignalCancel(ctx context.Context, l *log.Logger, sigs ...os.Signal) ( + context.Context, context.CancelFunc) { + ctx, cancelFunc := context.WithCancel(ctx) + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, sigs...) + + go func() { + select { + case sig := <-sigChan: + l.Printf("Cancellation signal (%s) received", sig) + cancelFunc() + case <-ctx.Done(): + } + }() + + f := func() { + signal.Stop(sigChan) + cancelFunc() + } + + return ctx, f +}