blob: b61696c2e6f3bb0d37786337c1f9ab78419c278c [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2013 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package names
5
6import (
7 "fmt"
8 "regexp"
9 "strings"
10)
11
12const RelationTagKind = "relation"
13
14const RelationSnippet = "[a-z][a-z0-9]*(?:[_-][a-z0-9]+)*"
15
16// Relation keys have the format "application1:relName1 application2:relName2".
17// Except the peer relations, which have the format "application:relName"
18// Relation tags have the format "relation-application1.rel1#application2.rel2".
19// For peer relations, the format is "relation-application.rel"
20
21var (
22 validRelation = regexp.MustCompile("^" + ApplicationSnippet + ":" + RelationSnippet + " " + ApplicationSnippet + ":" + RelationSnippet + "$")
23 validPeerRelation = regexp.MustCompile("^" + ApplicationSnippet + ":" + RelationSnippet + "$")
24)
25
26// IsValidRelation returns whether key is a valid relation key.
27func IsValidRelation(key string) bool {
28 return validRelation.MatchString(key) || validPeerRelation.MatchString(key)
29}
30
31type RelationTag struct {
32 key string
33}
34
35func (t RelationTag) String() string { return t.Kind() + "-" + t.key }
36func (t RelationTag) Kind() string { return RelationTagKind }
37func (t RelationTag) Id() string { return relationTagSuffixToKey(t.key) }
38
39// NewRelationTag returns the tag for the relation with the given key.
40func NewRelationTag(relationKey string) RelationTag {
41 if !IsValidRelation(relationKey) {
42 panic(fmt.Sprintf("%q is not a valid relation key", relationKey))
43 }
44 // Replace both ":" with "." and the " " with "#".
45 relationKey = strings.Replace(relationKey, ":", ".", 2)
46 relationKey = strings.Replace(relationKey, " ", "#", 1)
47 return RelationTag{key: relationKey}
48}
49
50// ParseRelationTag parses a relation tag string.
51func ParseRelationTag(relationTag string) (RelationTag, error) {
52 tag, err := ParseTag(relationTag)
53 if err != nil {
54 return RelationTag{}, err
55 }
56 rt, ok := tag.(RelationTag)
57 if !ok {
58 return RelationTag{}, invalidTagError(relationTag, RelationTagKind)
59 }
60 return rt, nil
61}
62
63func relationTagSuffixToKey(s string) string {
64 // Replace both "." with ":" and the "#" with " ".
65 s = strings.Replace(s, ".", ":", 2)
66 return strings.Replace(s, "#", " ", 1)
67}