devserver: add back the /doc/ for /check_health
The old implementation of /doc of devserver doesn't work when we
refactor devserver functions into apps. This CL enables devserver to get
exposed methods from mounted apps.
BUG=chromium:993621
TEST=Started devserver locally, and ran below two commands:
1. curl http://localhost:8080
Verified that /check_health is listed.
2. curl http://localhost:8080/doc/check_health
Verified that the doc string of /check_health is displayed.
Change-Id: Iec8ad5890b655069fdf5cff17196a147e3b9e147
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/1763029
Reviewed-by: C Shapiro <shapiroc@chromium.org>
Tested-by: Congbin Guo <guocb@chromium.org>
Commit-Queue: Congbin Guo <guocb@chromium.org>
Auto-Submit: Congbin Guo <guocb@chromium.org>
diff --git a/devserver.py b/devserver.py
index bdf73e2..3640ac0 100755
--- a/devserver.py
+++ b/devserver.py
@@ -397,23 +397,24 @@
return hasattr(name, 'exposed') and name.exposed
-def _GetExposedMethod(root, nested_member, ignored=None):
+def _GetExposedMethod(nested_member):
"""Returns a CherryPy-exposed method, if such exists.
Args:
- root: the root object for searching
nested_member: a slash-joined path to the nested member
- ignored: method paths to be ignored
Returns:
- A function object corresponding to the path defined by |member_list| from
- the |root| object, if the function is exposed and not ignored; None
- otherwise.
+ A function object corresponding to the path defined by |nested_member| from
+ the app root object registered, if the function is exposed; None otherwise.
"""
- method = (not (ignored and nested_member in ignored) and
- _GetRecursiveMemberObject(root, nested_member.split('/')))
- if method and isinstance(method, types.FunctionType) and _IsExposed(method):
- return method
+ for app in cherrypy.tree.apps.values():
+ # Use the 'index' function doc as the doc of the app.
+ if nested_member == app.script_name.lstrip('/'):
+ nested_member = 'index'
+
+ method = _GetRecursiveMemberObject(app.root, nested_member.split('/'))
+ if method and isinstance(method, types.FunctionType) and _IsExposed(method):
+ return method
def _FindExposedMethods(root, prefix, unlisted=None):
@@ -428,14 +429,19 @@
List of exposed URLs that are not unlisted.
"""
method_list = []
- for member in sorted(root.__class__.__dict__.keys()):
+ for member in root.__class__.__dict__.keys():
prefixed_member = prefix + '/' + member if prefix else member
if unlisted and prefixed_member in unlisted:
continue
member_obj = root.__class__.__dict__[member]
if _IsExposed(member_obj):
if isinstance(member_obj, types.FunctionType):
- method_list.append(prefixed_member)
+ # Regard the app name as exposed "method" name if it exposed 'index'
+ # function.
+ if prefix and member == 'index':
+ method_list.append(prefix)
+ else:
+ method_list.append(prefixed_member)
else:
method_list += _FindExposedMethods(
member_obj, prefixed_member, unlisted)
@@ -1468,15 +1474,22 @@
@cherrypy.expose
def index(self):
"""Presents a welcome message and documentation links."""
- return ('Welcome to the Dev Server!<br>\n'
- '<br>\n'
- 'Here are the available methods, click for documentation:<br>\n'
- '<br>\n'
- '%s' %
- '<br>\n'.join(
- [('<a href=doc/%s>%s</a>' % (name, name))
- for name in _FindExposedMethods(
- self, '', unlisted=self._UNLISTED_METHODS)]))
+ html_template = (
+ 'Welcome to the Dev Server!<br>\n'
+ '<br>\n'
+ 'Here are the available methods, click for documentation:<br>\n'
+ '<br>\n'
+ '%s')
+
+ exposed_methods = []
+ for app in cherrypy.tree.apps.values():
+ exposed_methods += _FindExposedMethods(
+ app.root, app.script_name.lstrip('/'),
+ unlisted=self._UNLISTED_METHODS)
+
+ return html_template % '<br>\n'.join(
+ ['<a href=doc/%s>%s</a>' % (name, name)
+ for name in sorted(exposed_methods)])
@cherrypy.expose
def doc(self, *args):
@@ -1486,7 +1499,7 @@
http://myhost/doc/update
"""
name = '/'.join(args)
- method = _GetExposedMethod(self, name)
+ method = _GetExposedMethod(name)
if not method:
raise devserver_exceptions.DevServerError(
"No exposed method named `%s'" % name)