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

Unified Diff: appengine/chrome_infra_packages/cipd/impl.py

Issue 1194803002: Add a package listing API to cipd. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 6 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
Index: appengine/chrome_infra_packages/cipd/impl.py
diff --git a/appengine/chrome_infra_packages/cipd/impl.py b/appengine/chrome_infra_packages/cipd/impl.py
index 451a0377cef1445f1698575efb196aa621fb0940..dbb9695287e4fd46a95e63474e14998bad4f3021 100644
--- a/appengine/chrome_infra_packages/cipd/impl.py
+++ b/appengine/chrome_infra_packages/cipd/impl.py
@@ -83,6 +83,7 @@ builders should not be allowed to set by other WRITERs.
import collections
import hashlib
+import itertools
import json
import logging
import re
@@ -165,6 +166,83 @@ class RepoService(object):
"""
return package_key(package_name).get()
+ @staticmethod
+ def _is_in_directory(directory, path, recursive):
+ """Tests is the path is under the given directory.
Vadim Sh. 2015/06/23 00:08:34 typo: if
estaab 2015/06/23 02:26:13 Done.
+
+ This assumes directory is a prefix of path.
+
+ Args:
+ directory: String, directory the path should fall under.
Vadim Sh. 2015/06/23 00:08:35 nit: start arg desc with lower case letter
estaab 2015/06/23 02:26:13 Done.
+ path: String, full path to test.
+ recursive: Whether the path can be in a subdirectory.
+
+ Returns:
+ True if the path is under the directory.
+ """
+ start = len(directory)
+ logging.info('processing %s in %s', path, directory)
Vadim Sh. 2015/06/23 00:08:34 remove logging if it doesn't provide any additiona
estaab 2015/06/23 02:26:13 Sorry, also not supposed to be in the CL.
+
+ # The directory itself or anything shorter is not a match.
+ if len(path) <= start:
+ logging.info('shorter.')
+ return False
+
+ # The root doesn't begin with slash so only check non-root searches.
+ if start:
+ if path[start] != '/':
+ logging.info('next isnt /.')
+ return False
+ start += 1
+
+ # A subdirectory was found and we're not looking for recursive matches.
+ if not recursive and '/' in path[start:]:
+ logging.info('next after is /.')
+ return False
+ return True
+
+ def list_packages(self, dir_path, recursive):
+ """Returns lists of package names and directory names with the given prefix.
+
+ Args:
+ dir_path: string directory from which to list packages.
+ recursive: boolean whether to list contents of subdirectories.
+
+ Returns:
+ [package name, ...], [directory name, ...]
+ """
+ query = Package.query()
+
+ # Normalize directory to simplify matching logic later.
+ dir_path = dir_path.rstrip('/')
+
+ # Only apply the filtering if a prefix was given. The empty string isn't a
+ # valid key and will result in an exception.
+ if dir_path:
+ query = query.filter(
+ # Prefix match using the operators available to us. Packages can only
+ # contain lowercase ascii, numbers, and '/' so '\uffff' will always
+ # be larger.
+ ndb.AND(Package.key >= ndb.Key(Package, dir_path),
+ Package.key <= ndb.Key(Package, dir_path + u'\uffff')))
+ pkgs = []
+ dirs = set()
+ for key in query.iter(keys_only=True):
Vadim Sh. 2015/06/23 00:08:35 non-ancestor queries are eventually consistent: th
estaab 2015/06/23 02:26:13 Good to know, done. I couldn't think of an easy wa
+ pkg = key.string_id()
+ pkgs.append(pkg)
+
+ # Add in directories derived from full package path if it's not an exact
+ # match.
+ if '/' in pkg and len(dir_path) != len(pkg):
Vadim Sh. 2015/06/23 00:08:35 I don't understand len(dir_path) != len(pkg) condi
estaab 2015/06/23 02:26:13 Removed, this was from some older logic.
+ parts = pkg.split('/')
+ dirs.update('/'.join(parts[:n]) for n in xrange(1, len(parts)))
+ logging.info(str(['/'.join(parts[:n]) for n in xrange(1, len(parts))]))
Vadim Sh. 2015/06/23 00:08:34 remove logging, it's probably not helpful in relea
estaab 2015/06/23 02:26:13 Done, also a mistake.
+
+ dirs = [d for d in dirs if self._is_in_directory(dir_path, d, recursive)]
+ pkgs = [p for p in pkgs if self._is_in_directory(dir_path, p, recursive)
+ or len(dir_path) == len(p)]
+ return pkgs, dirs
+
def get_processing_result(self, package_name, instance_id, processor_name):
"""Returns results of some asynchronous processor or None if not ready.

Powered by Google App Engine
This is Rietveld 408576698