addrs: Compact addresses for local project workspaces

f-workspaces2-prototype
Martin Atkins 7 years ago
parent b431efea3b
commit 6ecdbfaeac

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/tfdiags"
)
@ -51,6 +52,103 @@ type ProjectWorkspace struct {
Key InstanceKey
}
// MakeProjectWorkspace is a helper to compactly construct a project workspace
// address for a workspace in the current project.
func MakeProjectWorkspace(name string, key InstanceKey) ProjectWorkspace {
return ProjectWorkspace{
Rel: ProjectWorkspaceCurrent,
Name: name,
Key: key,
}
}
// MakeProjectWorkspaceUpstream is a helper to compactly construct a project
// workspace address for an upstream workspace.
func MakeProjectWorkspaceUpstream(name string, key InstanceKey) ProjectWorkspace {
return ProjectWorkspace{
Rel: ProjectWorkspaceUpstream,
Name: name,
Key: key,
}
}
// ParseProjectWorkspaceCompact parses a project workspace address as it
// appears in workspace-specific scenarios such as on the command line and
// in environment variables.
//
// The result is always a workspace in the current project, and never an
// upstream workspace or any other relationship.
//
// This notation is different than the addresses used within the project
// configuration file, exploiting the fact that it's implied that we're
// talking about workspaces in order to achieve a more compact representation.
//
// The returned address is invalid and should not be used if the returned
// diags contains errors.
func ParseProjectWorkspaceCompact(traversal hcl.Traversal) (ProjectWorkspace, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
if len(traversal) > 2 || len(traversal) < 1 {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid workspace address",
Detail: "A workspace address must be a workspace configuration name, optionally followed by a dot and then a workspace configuration instance key.",
Subject: traversal.SourceRange().Ptr(),
})
return ProjectWorkspace{}, diags
}
ret := ProjectWorkspace{
Rel: ProjectWorkspaceCurrent,
Name: traversal.RootName(),
}
if len(traversal) == 2 {
keyStep, ok := traversal[1].(hcl.TraverseAttr)
if !ok {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid workspace address",
Detail: "If a workspace instance key is provided, it must be given as an attribute name introduced with a dot.",
Subject: keyStep.SourceRange().Ptr(),
})
return ProjectWorkspace{}, diags
}
ret.Key = StringKey(keyStep.Name)
}
return ret, diags
}
// ParseProjectWorkspaceCompactStr is a wrapper around
// ParseProjectWorkspaceCompact that first parses the given string as an HCL
// traversal.
//
// This should be used only in specialized situations since it will cause the
// created references to not have any meaningful source location information.
// If a reference string is coming from a source that should be identified in
// error messages then the caller should instead parse it directly using a
// suitable function from the HCL API and pass the traversal itself to
// ParseRef.
//
// Error diagnostics are returned if either the parsing fails or the analysis
// of the traversal fails. There is no way for the caller to distinguish the
// two kinds of diagnostics programmatically. If error diagnostics are returned
// the returned reference may be nil or incomplete.
func ParseProjectWorkspaceCompactStr(str string) (ProjectWorkspace, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(str), "", hcl.Pos{Line: 1, Column: 1})
diags = diags.Append(parseDiags)
if parseDiags.HasErrors() {
return ProjectWorkspace{}, diags
}
addr, targetDiags := ParseProjectWorkspaceCompact(traversal)
diags = diags.Append(targetDiags)
return addr, diags
}
// Config returns the address of the workspace configuration this instance
// belongs to.
func (w ProjectWorkspace) Config() ProjectWorkspaceConfig {
@ -84,6 +182,34 @@ func (w ProjectWorkspace) String() string {
}
}
// StringCompact returns the compact string representation of a workspace in
// the current project. This is the same format that
// ParseProjectWorkspaceCompact consumes.
//
// This should be used only in sitautions where it is clear from context that
// the result is a workspace address. This is not the form used within the
// project configuration language.
//
// StringCompact is valid to use only for workspaces in the current project.
// This method will panic if used with an upstream workspace or any other
// workspace relationship.
func (w ProjectWorkspace) StringCompact() string {
if w.Rel != ProjectWorkspaceCurrent {
panic("StringCompact on workspace address not in the current project")
}
switch key := w.Key.(type) {
case nil:
return w.Name
case StringKey:
return fmt.Sprintf("%s.%s", w.Name, string(key))
default:
// No other key types are valid for project workspaces, but we'll
// tolerate this anyway for robustness.
return fmt.Sprintf("%s%s", w.Name, key.String())
}
}
// ProjectWorkspaceRelationship defines the relationship between the current
// workspace and the referenced workspace.
type ProjectWorkspaceRelationship int

Loading…
Cancel
Save