| # Copyright 2018 The LUCI Authors. All rights reserved. |
| # Use of this source code is governed under the Apache License, Version 2.0 |
| # that can be found in the LICENSE file. |
| |
| import datetime |
| import re |
| import urlparse |
| |
| from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2 |
| |
| |
| # UTC datetime corresponding to zero Unix timestamp. |
| EPOCH = datetime.datetime.utcfromtimestamp(0) |
| |
| |
| def parse_http_host_and_path(url): |
| parsed = urlparse.urlparse(url) |
| if not parsed.scheme: |
| parsed = urlparse.urlparse('https://' + url) |
| if (parsed.scheme in ('http', 'https') and |
| not parsed.params and |
| not parsed.query and |
| not parsed.fragment): |
| return parsed.netloc, parsed.path |
| return None, None |
| |
| |
| def parse_gitiles_repo_url(repo_url): |
| host, project = parse_http_host_and_path(repo_url) |
| assert host and project and '+' not in project.split('/'), ( |
| 'invalid repo_url %s' % repo_url) |
| project = project.strip('/') |
| if project.startswith('a/'): |
| project = project[len('a/'):] |
| if project.endswith('.git'): |
| project = project[:-len('.git')] |
| return host, project |
| |
| |
| def is_sha1_hex(sha1): |
| return sha1 and re.match('^[0-9a-f]{40}$', sha1) |
| |
| |
| def _parse_build_set(bs_string): |
| """Parses a buildset string to GerritChange or GitilesCommit. |
| |
| A port of |
| https://chromium.googlesource.com/infra/luci/luci-go/+/fe4e304639d11ca00537768f8bfbf20ffecf73e6/buildbucket/buildset.go#105 |
| """ |
| assert isinstance(bs_string, basestring) |
| p = bs_string.split('/') |
| if '' in p: |
| return None |
| |
| n = len(p) |
| |
| if n == 5 and p[0] == 'patch' and p[1] == 'gerrit': |
| return common_pb2.GerritChange( |
| host=p[2], |
| change=int(p[3]), |
| patchset=int(p[4]) |
| ) |
| |
| if n >= 5 and p[0] == 'commit' and p[1] == 'gitiles': |
| if p[n-2] != '+' or not is_sha1_hex(p[n-1]): |
| return None |
| return common_pb2.GitilesCommit( |
| host=p[2], |
| project='/'.join(p[3:n-2]), # exclude plus |
| id=p[n-1], |
| ) |
| |
| return None |
| |
| |
| def _parse_buildset_tags(tags): |
| bs_prefix = 'buildset:' |
| for t in tags: |
| if t.startswith(bs_prefix): |
| bs = _parse_build_set(t[len(bs_prefix):]) |
| if bs: |
| yield bs |
| |
| |
| def timestamp_to_datetime(value): |
| """Converts integer timestamp in microseconds since epoch to UTC datetime.""" |
| assert isinstance(value, (int, long, float)), value |
| return EPOCH + datetime.timedelta(microseconds=value) |
| |
| |
| def tags(**tags): |
| """Helper method to generate a list of StringPair messages. |
| |
| This method is useful to prepare tags argument for ci/try_build above and |
| schedule methods in the api.py. |
| |
| Args: |
| * tags: Dict mapping keys to values. A value can be a list of values in |
| which case multiple tags for the same key will be created. |
| |
| Returns: |
| List of common_pb2.StringPair messages. |
| """ |
| messages = [] |
| for key, values in tags.iteritems(): |
| if not isinstance(values, list): |
| values = [values] |
| for value in values: |
| messages.append(common_pb2.StringPair(key=key, value=value)) |
| return messages |