Add recurselist DEPS var setting.

Previously, recursion overrides were only available by setting
a numeric 'depth' value in a DEPS file.  This meant that it
was not possible to control recursion per-dependency entry.

This change adds a recurselist variable with a list structure.
If a named dependency is present in the list, then gclient will
recurse into that dependency's DEPS.

As part of this change, I move the recursion controls off of
DependencySetting and onto Dependency.  The new setup of being
based on Dependency allows access to the dependency's name.

The controls are only called from Dependency instances.  They
have always needed access to self.parent (in the Dependency
context), so this should be more correct than the previous setup.

BUG=390246

Review URL: https://codereview.chromium.org/331373009

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@280690 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gclient.py b/gclient.py
index 6a7b0e4..8d67b5a 100755
--- a/gclient.py
+++ b/gclient.py
@@ -178,10 +178,6 @@
     # recursion limit and controls gclient's behavior so it does not misbehave.
     self._managed = managed
     self._should_process = should_process
-    # This is a mutable value that overrides the normal recursion limit for this
-    # dependency.  It is read from the actual DEPS file so cannot be set on
-    # class instantiation.
-    self.recursion_override = None
     # This is a mutable value which has the list of 'target_os' OSes listed in
     # the current deps file.
     self.local_target_os = None
@@ -259,13 +255,6 @@
     return self._url
 
   @property
-  def recursion_limit(self):
-    """Returns > 0 if this dependency is not too recursed to be processed."""
-    if self.recursion_override is not None:
-      return self.recursion_override
-    return max(self.parent.recursion_limit - 1, 0)
-
-  @property
   def target_os(self):
     if self.local_target_os is not None:
       return tuple(set(self.local_target_os).union(self.parent.target_os))
@@ -318,6 +307,15 @@
     # unavailable
     self._got_revision = None
 
+    # This is a mutable value that overrides the normal recursion limit for this
+    # dependency.  It is read from the actual DEPS file so cannot be set on
+    # class instantiation.
+    self.recursion_override = None
+    # recurselist is a mutable value that selectively overrides the default
+    # 'no recursion' setting on a dep-by-dep basis.  It will replace
+    # recursion_override.
+    self.recurselist = None
+
     if not self.name and self.parent:
       raise gclient_utils.Error('Dependency without name')
 
@@ -357,6 +355,26 @@
     logging.info('Dependency(%s).requirements = %s' % (self.name, requirements))
     return requirements
 
+  @property
+  def try_recurselist(self):
+    """Returns False if recursion_override is ever specified."""
+    if self.recursion_override is not None:
+      return False
+    return self.parent.try_recurselist
+
+  @property
+  def recursion_limit(self):
+    """Returns > 0 if this dependency is not too recursed to be processed."""
+    # We continue to support the absence of recurselist until tools and DEPS
+    # using recursion_override are updated.
+    if self.try_recurselist and self.parent.recurselist != None:
+      if self.name in self.parent.recurselist:
+        return 1
+
+    if self.recursion_override is not None:
+      return self.recursion_override
+    return max(self.parent.recursion_limit - 1, 0)
+
   def verify_validity(self):
     """Verifies that this Dependency is fine to add as a child of another one.
 
@@ -563,6 +581,9 @@
       self.recursion_override = local_scope.get('recursion')
       logging.warning(
           'Setting %s recursion to %d.', self.name, self.recursion_limit)
+    self.recurselist = local_scope.get('recurselist', None)
+    if 'recurselist' in local_scope:
+      logging.warning('Found recurselist %r.', repr(self.recurselist))
     # If present, save 'target_os' in the local_target_os property.
     if 'target_os' in local_scope:
       self.local_target_os = local_scope['target_os']
@@ -1457,6 +1478,11 @@
     return self._recursion_limit
 
   @property
+  def try_recurselist(self):
+    """Whether to attempt using recurselist-style recursion processing."""
+    return True
+
+  @property
   def target_os(self):
     return self._enforced_os