| Index: recipe_engine/third_party/client-py/libs/logdog/streamname.py
|
| diff --git a/recipe_engine/third_party/client-py/libs/logdog/streamname.py b/recipe_engine/third_party/client-py/libs/logdog/streamname.py
|
| index 3b92fa72980a69d9ec3180c1e257c1ffe895d20b..8aaffb830b84db23fd0fdc31f93bec56ee7087cf 100644
|
| --- a/recipe_engine/third_party/client-py/libs/logdog/streamname.py
|
| +++ b/recipe_engine/third_party/client-py/libs/logdog/streamname.py
|
| @@ -3,8 +3,10 @@
|
| # that can be found in the LICENSE file.
|
|
|
| import re
|
| +import string
|
| import types
|
|
|
| +_ALNUM_CHARS = string.ascii_letters + string.digits
|
| _SEGMENT_RE_BASE = r'[a-zA-Z0-9][a-zA-Z0-9:_\-.]*'
|
| _STREAM_NAME_RE = re.compile('^(' + _SEGMENT_RE_BASE + ')(/' +
|
| _SEGMENT_RE_BASE + ')*$')
|
| @@ -13,6 +15,7 @@ _MAX_STREAM_NAME_LENGTH = 4096
|
| _MAX_TAG_KEY_LENGTH = 64
|
| _MAX_TAG_VALUE_LENGTH = 4096
|
|
|
| +
|
| def validate_stream_name(v, maxlen=None):
|
| """Verifies that a given stream name is valid.
|
|
|
| @@ -42,3 +45,63 @@ def validate_tag(key, value):
|
| """
|
| validate_stream_name(key, maxlen=_MAX_TAG_KEY_LENGTH)
|
| validate_stream_name(value, maxlen=_MAX_TAG_VALUE_LENGTH)
|
| +
|
| +
|
| +def normalize(v, prefix=None):
|
| + """Given a string, "v", mutate it into a valid stream name.
|
| +
|
| + This operates by replacing invalid stream naem characters with underscores (_)
|
| + when encountered.
|
| +
|
| + A special case is when "v" begins with an invalid character. In this case, we
|
| + will replace it with the "prefix", if one is supplied.
|
| +
|
| + See _STREAM_NAME_RE for a description of a valid stream name.
|
| +
|
| + Raises:
|
| + ValueError: If normalization could not be successfully performed.
|
| + """
|
| + if len(v) == 0:
|
| + if not prefix:
|
| + raise ValueError('Cannot normalize empty name with no prefix.')
|
| + v = prefix
|
| + else:
|
| + out = []
|
| + for i, ch in enumerate(v):
|
| + if i == 0 and not _is_valid_stream_char(ch, first=True):
|
| + # The first letter is special, and must be alphanumeric.
|
| + # If we have a prefix, prepend that to the resulting string.
|
| + if prefix is None:
|
| + raise ValueError('Name has invalid beginning, and no prefix was '
|
| + 'provided.')
|
| + out.append(prefix)
|
| +
|
| + if not _is_valid_stream_char(ch):
|
| + ch = '_'
|
| + out.append(ch)
|
| + v = ''.join(out)
|
| +
|
| + # Validate the resulting string.
|
| + validate_stream_name(v)
|
| + return v
|
| +
|
| +
|
| +def _is_valid_stream_char(ch, first=False):
|
| + """Returns (bool): True if a character is alphanumeric.
|
| +
|
| + The first character must be alphanumeric, matching [a-zA-Z0-9].
|
| + Additional characters must either be alphanumeric or one of: (: _ - .).
|
| +
|
| + Args:
|
| + ch (str): the character to evaluate.
|
| + first (bool): if true, apply special first-character constraints.
|
| + """
|
| + # Alphanumeric check.
|
| + if ch in _ALNUM_CHARS:
|
| + return True
|
| + if first:
|
| + # The first character must be alphanumeric.
|
| + return False
|
| +
|
| + # Check additional middle-name characters:
|
| + return ch in ':_-./'
|
|
|