Add regex matching to repo list command

The repo list -r command will execute a regex search for every
argument provided on both the project name and the project
worktree path.

Useful for finding rarely used gits.

Change-Id: Iaff90dd36c240b3d5d74817d11469be22d77ae03
diff --git a/subcmds/list.py b/subcmds/list.py
index 2be8257..6058a75 100644
--- a/subcmds/list.py
+++ b/subcmds/list.py
@@ -13,13 +13,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import re
+
 from command import Command, MirrorSafeCommand
 
 class List(Command, MirrorSafeCommand):
   common = True
   helpSummary = "List projects and their associated directories"
   helpUsage = """
-%prog [<project>...]
+%prog [-f] [<project>...]
+%prog [-f] -r str1 [str2]..."
 """
   helpDescription = """
 List all projects; pass '.' to list the project for the cwd.
@@ -27,6 +30,14 @@
 This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'.
 """
 
+  def _Options(self, p, show_smart=True):
+    p.add_option('-r', '--regex',
+                 dest='regex', action='store_true',
+                 help="Filter the project list based on regex or wildcard matching of strings")
+    p.add_option('-f', '--fullpath',
+                 dest='fullpath', action='store_true',
+                 help="Display the full work tree path instead of the relative path")
+
   def Execute(self, opt, args):
     """List all projects and the associated directories.
 
@@ -35,14 +46,33 @@
     discoverable.
 
     Args:
-      opt: The options.  We don't take any.
+      opt: The options.
       args: Positional args.  Can be a list of projects to list, or empty.
     """
-    projects = self.GetProjects(args)
+    if not opt.regex:
+      projects = self.GetProjects(args)
+    else:
+      projects = self.FindProjects(args)
+
+    def _getpath(x):
+      if opt.fullpath:
+        return x.worktree
+      return x.relpath
 
     lines = []
     for project in projects:
-      lines.append("%s : %s" % (project.relpath, project.name))
+      lines.append("%s : %s" % (_getpath(project), project.name))
 
     lines.sort()
     print '\n'.join(lines)
+
+  def FindProjects(self, args):
+    result = []
+    for project in self.GetProjects(''):
+      for arg in args:
+        pattern = re.compile(r'%s' % arg, re.IGNORECASE)
+        if pattern.search(project.name) or pattern.search(project.relpath):
+          result.append(project)
+          break
+    result.sort(key=lambda project: project.relpath)
+    return result