pulumi/pkg/ast/refs.go
joeduffy c478ffbe40 Preserve blank ""s in RefParts
This changes the logic when parsing RefParts so that we can actually
round-trip them faithfully when required.  To do this, by default we
preserve blank ""s in the RefPart fields that are legally omitted from
the Ref string.  Then, there is a Defaults() method that can populate
the missing fields with the defaults if desired.
2016-11-22 17:24:49 -08:00

94 lines
2.6 KiB
Go

// Copyright 2016 Marapongo, Inc. All rights reserved.
package ast
import (
"errors"
"fmt"
"strings"
)
// RefParts parses the parts of a Ref into a data structure for convenient access.
func (r Ref) Parse() (RefParts, error) {
s := string(r)
parsed := RefParts{}
// Look for the leading protocol, if any.
protoEnd := strings.Index(s, "://")
if protoEnd != -1 {
// Remember it and then strip it off for subsequent parsing.
parsed.Proto = s[:protoEnd+3]
s = s[protoEnd+3:]
}
// Strip off the version first, so looking for dots doesn't get confused.
verIndex := strings.Index(s, "@")
if verIndex != -1 {
parsed.Version = VersionSpec(s[verIndex+1:])
if err := parsed.Version.Check(); err != nil {
return parsed, errors.New("Illegal version spec: " + err.Error())
}
s = s[:verIndex]
}
// Now look to see if there is a dot, indicating a base part.
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {
// A base exists; look for a slash (indicating the name), and capture everything up to it (including it).
// TODO(joe): this might be questionable; e.g., domain-less hosts will require a trailing period.
slashIndex := strings.Index(s, NameDelimiter)
if slashIndex == -1 {
return parsed, errors.New("Expected a name to follow the base URL")
} else {
parsed.Base = s[:slashIndex+1]
s = s[slashIndex+1:]
}
}
// Anything remaining at this point represents the name.
parsed.Name = Name(s)
return parsed, nil
}
// RefParts represents a parsed Ref structure.
type RefParts struct {
Proto string // the protocol (e.g., "https://").
Base string // the base part of the URL (e.g., "mu.hub.com/").
Name Name // the name part of the URL (e.g., "mu/container").
Version VersionSpec // the version part of the URL (e.g., "^1.0.6").
}
var _ fmt.Stringer = RefParts{} // compile-time assertion that RefParts implements Stringer.
// DefaultRefProto is the default ref protocol.
const DefaultRefProto = "https://"
// DefaultRefBase is the base part used if a Ref doesn't specify one explicitly.
const DefaultRefBase = "hub.mu.com/"
// DefaultRefVersion is the default ref version if none is specified.
const DefaultRefVersion = LatestVersion
// Defaults replaces any empty parts of the RefParts with their default values.
func (r RefParts) Defaults() RefParts {
d := r
if d.Proto == "" {
d.Proto = DefaultRefProto
}
if d.Base == "" {
d.Base = DefaultRefBase
}
if string(d.Version) == "" {
d.Version = DefaultRefVersion
}
return d
}
func (r RefParts) String() string {
s := r.Proto + r.Base + string(r.Name)
if string(r.Version) != "" {
s += "@" + string(r.Version)
}
return s
}