Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: client/libs/logdog/streamname.py

Issue 2243483003: Add LogDog stream name normalization function. (Closed) Base URL: https://github.com/luci/luci-py@master
Patch Set: Allow multi-segment normalization. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | client/libs/logdog/tests/streamname_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 import re 5 import re
6 import types 6 import types
7 7
8 _SEGMENT_RE_BASE = r'[a-zA-Z0-9][a-zA-Z0-9:_\-.]*' 8 _SEGMENT_RE_BASE = r'[a-zA-Z0-9][a-zA-Z0-9:_\-.]*'
9 _STREAM_NAME_RE = re.compile('^(' + _SEGMENT_RE_BASE + ')(/' + 9 _STREAM_NAME_RE = re.compile('^(' + _SEGMENT_RE_BASE + ')(/' +
10 _SEGMENT_RE_BASE + ')*$') 10 _SEGMENT_RE_BASE + ')*$')
11 _MAX_STREAM_NAME_LENGTH = 4096 11 _MAX_STREAM_NAME_LENGTH = 4096
12 12
13 _MAX_TAG_KEY_LENGTH = 64 13 _MAX_TAG_KEY_LENGTH = 64
14 _MAX_TAG_VALUE_LENGTH = 4096 14 _MAX_TAG_VALUE_LENGTH = 4096
15 15
16
16 def validate_stream_name(v, maxlen=None): 17 def validate_stream_name(v, maxlen=None):
17 """Verifies that a given stream name is valid. 18 """Verifies that a given stream name is valid.
18 19
19 Args: 20 Args:
20 v (str): The stream name string. 21 v (str): The stream name string.
21 22
22 23
23 Raises: 24 Raises:
24 ValueError if the stream name is invalid. 25 ValueError if the stream name is invalid.
25 """ 26 """
26 maxlen = maxlen or _MAX_STREAM_NAME_LENGTH 27 maxlen = maxlen or _MAX_STREAM_NAME_LENGTH
27 if len(v) > maxlen: 28 if len(v) > maxlen:
28 raise ValueError('Maximum length exceeded (%d > %d)' % (len(v), maxlen)) 29 raise ValueError('Maximum length exceeded (%d > %d)' % (len(v), maxlen))
29 if _STREAM_NAME_RE.match(v) is None: 30 if _STREAM_NAME_RE.match(v) is None:
30 raise ValueError('Invalid stream name') 31 raise ValueError('Invalid stream name')
31 32
32 33
33 def validate_tag(key, value): 34 def validate_tag(key, value):
34 """Verifies that a given tag key/value is valid. 35 """Verifies that a given tag key/value is valid.
35 36
36 Args: 37 Args:
37 k (str): The tag key. 38 k (str): The tag key.
38 v (str): The tag value. 39 v (str): The tag value.
39 40
40 Raises: 41 Raises:
41 ValueError if the tag is not valid. 42 ValueError if the tag is not valid.
42 """ 43 """
43 validate_stream_name(key, maxlen=_MAX_TAG_KEY_LENGTH) 44 validate_stream_name(key, maxlen=_MAX_TAG_KEY_LENGTH)
44 validate_stream_name(value, maxlen=_MAX_TAG_VALUE_LENGTH) 45 validate_stream_name(value, maxlen=_MAX_TAG_VALUE_LENGTH)
46
47
48 def normalize(v, prefix=None):
49 """Given a string, "v", mutate it into a valid stream name.
50
51 This operates by replacing invalid stream naem characters with underscores (_)
52 when encountered.
53
54 A special case is when "v" begins with an invalid character. In this case, we
55 will replace it with the "prefix", if one is supplied.
56
57 See _STREAM_NAME_RE for a description of a valid stream name.
58
59 Raises:
60 ValueError: If normalization could not be successfully performed.
61 """
62 if len(v) == 0:
63 if not prefix:
64 raise ValueError('Cannot normalize empty name with no prefix.')
65 v = prefix
66 else:
67 out = []
68 for i, ch in enumerate(v):
69 if i == 0 and not _is_valid_stream_char(ch, first=True):
70 # The first letter is special, and must be alphanumeric.
71 # If we have a prefix, prepend that to the resulting string.
72 if prefix is None:
73 raise ValueError('Name has invalid beginning, and no prefix was '
74 'provided.')
75 out.append(prefix)
martiniss 2016/08/11 20:24:43 Doing iteration over every character in a string l
dnj 2016/08/11 20:42:29 If you know a better way to do this, LMK.
76
77 if not _is_valid_stream_char(ch):
78 ch = '_'
79 out.append(ch)
80 v = ''.join(out)
81
82 # Validate the resulting string.
83 validate_stream_name(v)
84 return v
85
86
87 def _is_valid_stream_char(ch, first=False):
88 """Returns (bool): True if a character is alphanumeric.
89
90 The first character must be alphanumeric, matching [a-zA-Z0-9].
91 Additional characters must either be alphanumeric or one of: (: _ - .).
92
93 Args:
94 ch (str): the character to evaluate.
95 first (bool): if true, apply special first-character constraints.
96 """
97 # Alphanumeric check.
98 ch_ord = ord(ch)
99 if ((ch_ord >= ord('0') and ch_ord <= ord('9')) or
martiniss 2016/08/11 20:24:43 Why not use https://docs.python.org/2/library/stri
dnj 2016/08/11 20:42:29 This seems faster, but might as well.
100 (ch_ord >= ord('a') and ch_ord <= ord('z')) or
101 (ch_ord >= ord('A') and ch_ord <= ord('Z'))):
102 return True
103 if first:
104 # The first character must be alphanumeric.
105 return False
106
107 # Check additional middle-name characters:
108 return ch in ':_-./'
OLDNEW
« no previous file with comments | « no previous file | client/libs/logdog/tests/streamname_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698