OLD | NEW |
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 collections |
5 import re | 6 import re |
6 import string | 7 import string |
7 import types | 8 import types |
| 9 import urllib |
| 10 import urlparse |
8 | 11 |
9 _ALNUM_CHARS = string.ascii_letters + string.digits | 12 _ALNUM_CHARS = string.ascii_letters + string.digits |
10 _SEGMENT_RE_BASE = r'[a-zA-Z0-9][a-zA-Z0-9:_\-.]*' | 13 _SEGMENT_RE_BASE = r'[a-zA-Z0-9][a-zA-Z0-9:_\-.]*' |
11 _STREAM_NAME_RE = re.compile('^(' + _SEGMENT_RE_BASE + ')(/' + | 14 _STREAM_NAME_RE = re.compile('^(' + _SEGMENT_RE_BASE + ')(/' + |
12 _SEGMENT_RE_BASE + ')*$') | 15 _SEGMENT_RE_BASE + ')*$') |
13 _MAX_STREAM_NAME_LENGTH = 4096 | 16 _MAX_STREAM_NAME_LENGTH = 4096 |
14 | 17 |
15 _MAX_TAG_KEY_LENGTH = 64 | 18 _MAX_TAG_KEY_LENGTH = 64 |
16 _MAX_TAG_VALUE_LENGTH = 4096 | 19 _MAX_TAG_VALUE_LENGTH = 4096 |
17 | 20 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 """ | 101 """ |
99 # Alphanumeric check. | 102 # Alphanumeric check. |
100 if ch in _ALNUM_CHARS: | 103 if ch in _ALNUM_CHARS: |
101 return True | 104 return True |
102 if first: | 105 if first: |
103 # The first character must be alphanumeric. | 106 # The first character must be alphanumeric. |
104 return False | 107 return False |
105 | 108 |
106 # Check additional middle-name characters: | 109 # Check additional middle-name characters: |
107 return ch in ':_-./' | 110 return ch in ':_-./' |
| 111 |
| 112 |
| 113 class StreamPath(collections.namedtuple('_StreamPath', ('prefix', 'name'))): |
| 114 """StreamPath is a full stream path. |
| 115 |
| 116 This consists of both a stream prefix and a stream name. |
| 117 |
| 118 When constructed with parse or make, the stream path must be completely valid. |
| 119 However, invalid stream paths may be constructed by manually instantiation. |
| 120 This can be useful for wildcard query values (e.g., "prefix='foo/*/bar/**'"). |
| 121 """ |
| 122 |
| 123 @classmethod |
| 124 def make(cls, prefix, name): |
| 125 """Returns (StreamPath): The validated StreamPath instance. |
| 126 |
| 127 Args: |
| 128 prefix (str): the prefix component |
| 129 name (str): the name component |
| 130 |
| 131 Raises: |
| 132 ValueError: If path is not a full, valid stream path string. |
| 133 """ |
| 134 inst = cls(prefix=prefix, name=name) |
| 135 inst.validate() |
| 136 return inst |
| 137 |
| 138 @classmethod |
| 139 def parse(cls, path): |
| 140 """Returns (StreamPath): The parsed StreamPath instance. |
| 141 |
| 142 Args: |
| 143 path (str): the full stream path to parse. |
| 144 |
| 145 Raises: |
| 146 ValueError: If path is not a full, valid stream path string. |
| 147 """ |
| 148 parts = path.split('/+/', 1) |
| 149 if len(parts) != 2: |
| 150 raise ValueError('Not a full stream path: [%s]' % (path,)) |
| 151 return cls.make(*parts) |
| 152 |
| 153 def validate(self): |
| 154 """Raises: ValueError if this is not a valid stream name.""" |
| 155 try: |
| 156 validate_stream_name(self.prefix) |
| 157 except ValueError as e: |
| 158 raise ValueError('Invalid prefix component [%s]: %s' % ( |
| 159 self.prefix, e.message,)) |
| 160 |
| 161 try: |
| 162 validate_stream_name(self.name) |
| 163 except ValueError as e: |
| 164 raise ValueError('Invalid name component [%s]: %s' % ( |
| 165 self.name, e.message,)) |
| 166 |
| 167 def __str__(self): |
| 168 return '%s/+/%s' % (self.prefix, self.name) |
| 169 |
| 170 |
| 171 def get_logdog_viewer_url(host, project, *stream_paths): |
| 172 """Returns (str): The LogDog viewer URL for the named stream(s). |
| 173 |
| 174 Args: |
| 175 host (str): The name of the Coordiantor host. |
| 176 project (str): The project name. |
| 177 stream_paths: A set of StreamPath instances for the stream paths to |
| 178 generate the URL for. |
| 179 """ |
| 180 return urlparse.urlunparse(( |
| 181 'https', # Scheme |
| 182 host, # netloc |
| 183 'v/', # path |
| 184 '', # params |
| 185 '&'.join(('s=%s' % (urllib.quote('%s/%s' % (project, path), safe='')) |
| 186 for path in stream_paths)), # query |
| 187 '', # fragment |
| 188 )) |
OLD | NEW |