Revert "[autotest] Standardize label logic"

This reverts commit fda3e23ce60251c17bdc213d72b0b575251ea6d1.

Speculatively reverting to un-break push-to-prod

BUG=chromium:665538
TEST=push-to-prod test passes (maybe?). This is a speculative revert.

Change-Id: Ia435c3e220ce0bd3fceabf786b685355bc0488d1
Reviewed-on: https://chromium-review.googlesource.com/411388
Reviewed-by: Prathmesh Prabhu <pprabhu@chromium.org>
Tested-by: Prathmesh Prabhu <pprabhu@chromium.org>
diff --git a/server/cros/provision.py b/server/cros/provision.py
index a6c3cd9..5e7608d 100644
--- a/server/cros/provision.py
+++ b/server/cros/provision.py
@@ -2,8 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import collections
-import re
+
 import sys
 
 import common
@@ -25,212 +24,38 @@
 FLAKY_DEVSERVER_ATTEMPTS = 2
 
 
-def label_from_str(label_string):
-    """Return a proper Label instance from a label string.
-
-    This function is for converting an existing label string into a Label
-    instance of the proper type.  For constructing a specific type of label,
-    don't use this.  Instead, instantiate the specific Label subclass.
-
-    @param label_string: Label string.
-    @returns: An instance of Label or a subclass.
+### Helpers to convert value to label
+def cros_version_to_label(image):
     """
-    if NamespaceLabel.SEP in label_string:
-        label = NamespaceLabel.from_str(label_string)
-        namespaces = _PresetNamespaceLabelMeta.namespaces
-        if label.namespace in namespaces:
-            return namespaces[label.namespace](label.value)
-        else:
-            return label
-    else:
-        return Label(label_string)
+    Returns the proper label name for a ChromeOS build of |image|.
 
+    @param image: A string of the form 'lumpy-release/R28-3993.0.0'
+    @returns: A string that is the appropriate label name.
 
-class Label(str):
-    """A string that is explicitly typed as a label."""
-
-    def __repr__(self):
-        return '{cls}({label})'.format(
-            cls=type(self).__name__,
-            label=super(Label, self).__repr__())
-
-    @property
-    def action(self):
-        """Return the action represented by the label.
-
-        This is used for determine actions to perform based on labels, for
-        example for provisioning or repair.
-
-        @return: An Action instance.
-        """
-        return Action(self, '')
-
-
-Action = collections.namedtuple('Action', 'name,value')
-
-
-class NamespaceLabel(Label):
-    """Label with namespace and value separated by a colon."""
-
-    SEP = ':'
-
-    def __new__(cls, namespace, value):
-        return super(NamespaceLabel, cls).__new__(
-            cls, cls.SEP.join((namespace, value)))
-
-    @classmethod
-    def from_str(cls, label):
-        """Make NamespaceLabel instance from full string.
-
-        @param label: Label string.
-        @returns: NamespaceLabel instance.
-        """
-        namespace, value = label.split(cls.SEP, 1)
-        return cls(namespace, value)
-
-    @property
-    def namespace(self):
-        """The label's namespace (before colon).
-
-        @returns: string
-        """
-        return self.split(self.SEP, 1)[0]
-
-    @property
-    def value(self):
-        """The label's value (after colon).
-
-        @returns: string
-        """
-        return self.split(self.SEP, 1)[1]
-
-    @property
-    def action(self):
-        """Return the action represented by the label.
-
-        See docstring on overridden method.
-
-        @return: An Action instance.
-        """
-        return Action(self.namespace, self.value)
-
-
-class _PresetNamespaceLabelMeta(type):
-    """Metaclass for PresetNamespaceLabelMeta and subclasses.
-
-    This automatically tracks the NAMESPACE for concrete classes that define
-    it.  The namespaces attribute is a dict mapping namespace strings to the
-    corresponding NamespaceLabel subclass.
     """
-
-    namespaces = {}
-
-    def __init__(cls, name, bases, dict_):
-        if hasattr(cls, 'NAMESPACE'):
-            type(cls).namespaces[cls.NAMESPACE] = cls
+    return CROS_VERSION_PREFIX + ':' + image
 
 
-class _PresetNamespaceLabel(NamespaceLabel):
-    """NamespaceLabel with preset namespace.
-
-    This class is abstract.  Concrete subclasses must set a NAMESPACE class
-    attribute.
+def fwro_version_to_label(image):
     """
+    Returns the proper label name for a RO firmware build of |image|.
 
-    __metaclass__ = _PresetNamespaceLabelMeta
+    @param image: A string of the form 'lumpy-release/R28-3993.0.0'
+    @returns: A string that is the appropriate label name.
 
-    def __new__(cls, value):
-        return super(_PresetNamespaceLabel, cls).__new__(cls, cls.NAMESPACE, value)
-
-
-class CrosVersionLabel(_PresetNamespaceLabel):
-    """cros-version label."""
-    NAMESPACE = CROS_VERSION_PREFIX
-
-    @property
-    def value(self):
-        """The label's value (after colon).
-
-        @returns: string
-        """
-        return CrosVersion(super(CrosVersionLabel, self).value)
-
-
-class FWROVersionLabel(_PresetNamespaceLabel):
-    """Read-only firmware version label."""
-    NAMESPACE = FW_RO_VERSION_PREFIX
-
-
-class FWRWVersionLabel(_PresetNamespaceLabel):
-    """Read-write firmware version label."""
-    NAMESPACE = FW_RW_VERSION_PREFIX
-
-
-class CrosVersion(str):
-    """The name of a CrOS image version (e.g. lumpy-release/R27-3773.0.0).
-
-    Parts of the image name are exposed via properties.  In case the name is
-    not well-formed, these properties return INVALID_STR, which is not a valid value
-    for any part.
-
-    Class attributes:
-        INVALID_STR -- String returned if the version is not well-formed.
-
-    Properties:
-        group
-        milestone
-        version
-        rc
     """
+    return FW_RO_VERSION_PREFIX + ':' + image
 
-    INVALID_STR = 'N/A'
-    _NAME_PATTERN = re.compile(
-        r'^'
-        r'(?P<group>[a-z0-9-]+)'
-        r'/'
-        r'(?P<milestone>R[0-9]+)'
-        r'-'
-        r'(?P<version>[0-9.]+)'
-        r'(-(?P<rc>rc[0-9]+))?'
-        r'$'
-    )
 
-    def __repr__(self):
-        return '{cls}({name})'.format(
-            cls=type(self).__name__,
-            name=super(CrosVersion, self).__repr__())
+def fwrw_version_to_label(image):
+    """
+    Returns the proper label name for a RW firmware build of |image|.
 
-    def _get_group(self, group):
-        """Get regex match group, or fall back to N/A.
+    @param image: A string of the form 'lumpy-release/R28-3993.0.0'
+    @returns: A string that is the appropriate label name.
 
-        @param group: Group name string.
-        @returns String.
-        """
-        match = self._NAME_PATTERN.search(self)
-        if match is None:
-            return self.INVALID_STR
-        else:
-            return match.group(group)
-
-    @property
-    def group(self):
-        """Cros image group (e.g. lumpy-release)."""
-        return self._get_group('group')
-
-    @property
-    def milestone(self):
-        """Cros image milestone (e.g. R27)."""
-        return self._get_group('milestone')
-
-    @property
-    def version(self):
-        """Cros image milestone (e.g. 3773.0.0)."""
-        return self._get_group('version')
-
-    @property
-    def rc(self):
-        """Cros image rc (e.g. rc2)."""
-        return self._get_group('rc')
+    """
+    return FW_RW_VERSION_PREFIX + ':' + image
 
 
 class _SpecialTaskAction(object):
@@ -252,17 +77,19 @@
     # across available label prefixes.
     _priorities = []
 
+
     @classmethod
-    def acts_on(cls, label_string):
+    def acts_on(cls, label):
         """
         Returns True if the label is a label that we recognize as something we
         know how to act on, given our _actions.
 
-        @param label_string: The label as a string.
+        @param label: The label as a string.
         @returns: True if there exists a test to run for this label.
+
         """
-        label = label_from_str(label_string)
-        return label.action.name in cls._actions
+        return label.split(':')[0] in cls._actions
+
 
     @classmethod
     def test_for(cls, label):
@@ -272,9 +99,11 @@
         @param label: The label for which the action is being requested.
         @returns: The string name of the test that should be run.
         @raises KeyError: If the name was not recognized as one we care about.
+
         """
         return cls._actions[label]
 
+
     @classmethod
     def partition(cls, labels):
         """
@@ -301,31 +130,30 @@
 
         return capabilities, configurations
 
+
     @classmethod
-    def get_sorted_actions(cls, configurations):
+    def sort_configurations(cls, configurations):
         """
         Sort configurations based on the priority defined in cls._priorities.
 
         @param configurations: A list of actionable labels.
-        @return: A list of Action instances sorted by the action name in
-            cls._priorities.
-        """
-        actions = (label_from_str(label_string).action
-                   for label_string in configurations)
-        return sorted(actions, key=cls._get_action_priority)
 
-    @classmethod
-    def _get_action_priority(cls, action):
+        @return: A sorted list of tuple of (label_prefix, value), the tuples are
+                sorted based on the label_prefix's index in cls._priorities.
         """
-        Return the priority of the action string.
+        # Split a list of labels into a dict mapping name to value.  All labels
+        # must be provisionable labels, or else a ValueError
+        # For example, label 'cros-version:lumpy-release/R28-3993.0.0' is split
+        # to  {'cros-version': 'lumpy-release/R28-3993.0.0'}
+        split_configurations = dict()
+        for label in configurations:
+            name, _, value = label.partition(':')
+            split_configurations[name] = value
 
-        @param action: An Action instance.
-        @return: An int.
-        """
-        if action.name in cls._priorities:
-            return cls._priorities.index(action.name)
-        else:
-            return sys.maxint
+        sort_key = (lambda config:
+                (cls._priorities.index(config[0])
+                 if (config[0] in cls._priorities) else sys.maxint))
+        return sorted(split_configurations.items(), key=sort_key)
 
 
 class Verify(_SpecialTaskAction):
@@ -438,6 +266,21 @@
             label == SKIP_PROVISION)
 
 
+def join(provision_type, provision_value):
+    """
+    Combine the provision type and value into the label name.
+
+    @param provision_type: One of the constants that are the label prefixes.
+    @param provision_value: A string of the value for this provision type.
+    @returns: A string that is the label name for this (type, value) pair.
+
+    >>> join(CROS_VERSION_PREFIX, 'lumpy-release/R27-3773.0.0')
+    'cros-version:lumpy-release/R27-3773.0.0'
+
+    """
+    return '%s:%s' % (provision_type, provision_value)
+
+
 class SpecialTaskActionException(Exception):
     """
     Exception raised when a special task fails to successfully run a test that
@@ -469,8 +312,8 @@
                    "Can't %s label '%s'." % (task.name, label))
 
     # Sort the configuration labels based on `task._priorities`.
-    actions = task.get_sorted_actions(configurations)
-    for name, value in actions:
+    sorted_configurations = task.sort_configurations(configurations)
+    for name, value in sorted_configurations:
         action_item = task.test_for(name)
         success = action_item.execute(job=job, host=host, value=value)
         if not success: