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

Unified Diff: appengine/swarming/cipd.py

Issue 2267363004: Add CIPD pin reporting to swarming. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: Fix bottest 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | appengine/swarming/cipd_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/swarming/cipd.py
diff --git a/appengine/swarming/cipd.py b/appengine/swarming/cipd.py
index d04a087800194dca5f81e7745c39a40cc395ec40..7c8734e57a4abf5a2b06372701a8554592877515 100644
--- a/appengine/swarming/cipd.py
+++ b/appengine/swarming/cipd.py
@@ -4,6 +4,8 @@
"""CIPD-specific code is concentrated here."""
+import contextlib
+import logging
import re
# Regular expressions below are copied from
@@ -26,13 +28,99 @@ TAG_MAX_LEN = 400
# os can be "linux", "mac" or "windows" and arch can be "386", "amd64" or
# "armv6l".
PARAM_PLATFORM = '${platform}'
+PARAM_PLATFORM_ESC = re.escape(PARAM_PLATFORM)
# OS version parameter defines major and minor version of the OS distribution.
# It is useful if package depends on .dll/.so libraries provided by the OS.
# Example values: "ubuntu14_04", "mac10_9", "win6_1".
PARAM_OS_VER = '${os_ver}'
+PARAM_OS_VER_ESC = re.escape(PARAM_OS_VER)
ALL_PARAMS = (PARAM_PLATFORM, PARAM_OS_VER)
+@contextlib.contextmanager
+def pin_check_fn(platform, os_ver):
+ """Yields a function that verifies that an input CipdPackage could have been
+ plausibly expanded, via pinning, to another CipdPackage. Repeated invocations
+ of the function will retain knowledge of any resolved name template paramters
+ like ${platform} and ${os_ver}.
+
+ Args:
+ platform - a pre-defined expansion of ${platform}, or None to learn from the
+ first valid checked CipdPackage containing ${platform}.
+ os_ver - a pre-defined expansion of ${os_ver}, or None to learn from the
+ first valid checked CipdPackage containing ${os_ver}.
+
+ Args of yielded function:
+ original - a CipdPackage which may contain template params like ${platform}
+ expanded - a CipdPackage which is nominally an expansion of original.
+
+ CipdPackage is a duck-typed object which has three string properties:
+ 'package_name', 'path' and 'version'.
+
+ Yielded function raises:
+ ValueError if expanded is not a valid derivation of original.
+
+ Example:
+ with pin_check_fn(None, None) as check:
+ check(CipdPackage('', '${platform}', 'ref'),
+ CipdPackage('', 'windows-amd64', 'deadbeef'*5))
+ check(CipdPackage('', '${platform}', 'ref'),
+ CipdPackage('', 'linux-amd64', 'deadbeef'*5)) ## will raise ValueError
+ """
+ plat_ref = [platform]
+ os_ver_ref = [os_ver]
+ def _check_fn(original, expanded):
+ if original.path != expanded.path:
+ logging.warn('Mismatched path: %r v %r', original.path, expanded.path)
+ raise ValueError('Mismatched path')
+
+ def sub_param(regex, param_esc, param_re, param_const):
+ # This is validated at task creation time as well, but just to make sure.
+ if regex.count(param_esc) > 1:
+ logging.warn('Duplicate template param %r: %r', param_esc, regex)
+ raise ValueError('%s occurs more than once in name.' % param_esc)
+
+ ret = False
+ if param_const is None:
+ ret = param_esc in regex
+ if ret:
+ regex = regex.replace(param_esc, param_re, 1)
+ else:
+ regex = regex.replace(param_esc, param_const, 1)
+ return regex, ret
+
+ name_regex = re.escape(original.package_name)
+ name_regex, scan_plat = sub_param(
+ name_regex, PARAM_PLATFORM_ESC, r'(?P<platform>\w+-[a-z0-9]+)',
+ plat_ref[0])
+ name_regex, scan_os_ver = sub_param(
+ name_regex, PARAM_OS_VER_ESC, r'(?P<os_ver>[_a-z0-9]+)',
+ os_ver_ref[0])
+
+ match = re.match(name_regex, expanded.package_name)
+ if not match:
+ logging.warn('Mismatched package_name: %r | %r v %r',
+ original.package_name, name_regex, expanded.package_name)
+ raise ValueError('Mismatched package_name')
+
+ if is_valid_instance_id(original.version):
+ if original.version != expanded.version:
+ logging.warn('Mismatched pins: %r v %r', original.version,
+ expanded.version)
+ raise ValueError('Mismatched pins')
+ else:
+ if not is_valid_instance_id(expanded.version):
+ logging.warn('Pin not a pin: %r', expanded.version)
+ raise ValueError('Pin value is not a pin')
+
+ if scan_plat:
+ plat_ref[0] = re.escape(match.group('platform'))
+ if scan_os_ver:
+ os_ver_ref[0] = re.escape(match.group('os_ver'))
+
+ yield _check_fn
+
+
def is_valid_package_name(package_name):
"""Returns True if |package_name| is a valid CIPD package name."""
return bool(PACKAGE_NAME_RE.match(package_name))
@@ -43,13 +131,15 @@ def is_valid_package_name_template(template):
# Render known parameters first.
for p in ALL_PARAMS:
template = template.replace(p, 'x')
+ if template.count(p) > 1:
+ return False
return is_valid_package_name(template)
def is_valid_version(version):
"""Returns True if |version| is a valid CIPD package version."""
return bool(
- INSTANCE_ID_RE.match(version) or
+ is_valid_instance_id(version) or
is_valid_tag(version) or
REF_RE.match(version)
)
@@ -63,6 +153,11 @@ def is_valid_tag(tag):
return bool(TAG_KEY_RE.match(tag.split(':', 1)[0]))
+def is_valid_instance_id(version):
+ """Returns True if |version| is an insance_id."""
+ return bool(INSTANCE_ID_RE.match(version))
+
+
def is_pinned_version(version):
"""Returns True if |version| is pinned."""
- return bool(INSTANCE_ID_RE.match(version)) or is_valid_tag(version)
+ return is_valid_instance_id(version) or is_valid_tag(version)
« no previous file with comments | « no previous file | appengine/swarming/cipd_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698