thirdparty/google_appengine/google/appengine/tools/dev_appserver_info.py
changeset 109 620f9b141567
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thirdparty/google_appengine/google/appengine/tools/dev_appserver_info.py	Tue Aug 26 21:49:54 2008 +0000
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""CGI for displaying info about the currently running app in dev_appserver.
+
+This serves pages under /_ah/info/ that display information about the app
+currently running in the dev_appserver. It currently serves on these URLs:
+
+  /_ah/info/queries:
+    A list of datastore queries run so far, grouped by kind. Used to suggest
+    composite indices that should be built.
+
+  /_ah/info/index.yaml:
+    Produces an index.yaml file that can be uploaded to the real app
+    server by appcfg.py.  This information is derived from the query
+    history above, by removing queries that don't need any indexes to
+    be built and by combining queries that can use the same index.
+"""
+
+
+
+import cgi
+import wsgiref.handlers
+
+from google.appengine.api import apiproxy_stub_map
+from google.appengine.datastore import datastore_pb
+from google.appengine.ext import webapp
+from google.appengine.tools import dev_appserver_index
+
+
+class QueriesHandler(webapp.RequestHandler):
+  """A handler that displays a list of the datastore queries run so far.
+  """
+
+  HEADER = """<html>
+<head><title>Query History</title></head>
+
+<body>
+<h3>Query History</h3>
+
+<p>This is a list of datastore queries your app has run.  You have to
+make composite indices for these queries before deploying your app.
+This is normally done automatically by running dev_appserver, which
+will write the file index.yaml into your app's root directory, and
+then deploying your app with appcfg, which will upload that
+index.yaml.</p>
+
+<p>You can also view a 'clean' <a href="index.yaml">index.yaml</a>
+file and save that to your app's root directory.</p>
+
+<table>
+<tr><th>Times run</th><th>Query</th></tr>
+"""
+
+  ROW = """<tr><td>%(count)s</td><td>%(query)s</td></tr>"""
+
+  FOOTER = """
+</table>
+</body>
+</html>"""
+
+  def Render(self):
+    """Renders and returns the query history page HTML.
+
+    Returns:
+      A string, formatted as an HTML page.
+    """
+    history = apiproxy_stub_map.apiproxy.GetStub('datastore_v3').QueryHistory()
+    history_items = [(count, query) for query, count in history.items()]
+    history_items.sort(reverse=True)
+    rows = [self.ROW % {'query': _FormatQuery(query),
+                        'count': count}
+            for count, query in history_items]
+    return self.HEADER + '\n'.join(rows) + self.FOOTER
+
+  def get(self):
+    """Handle a GET.  Just calls Render()."""
+    self.response.out.write(self.Render())
+
+
+class IndexYamlHandler(webapp.RequestHandler):
+  """A handler that renders an index.yaml file suitable for upload."""
+
+  def Render(self):
+    """Renders and returns the index.yaml file.
+
+    Returns:
+      A string, formatted as an index.yaml file.
+    """
+    datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')
+    query_history = datastore_stub.QueryHistory()
+    body = dev_appserver_index.GenerateIndexFromHistory(query_history)
+    return 'indexes:\n' + body
+
+  def get(self):
+    """Handle a GET.  Just calls Render()."""
+    self.response.headers['Content-Type'] = 'text/plain'
+    self.response.out.write(self.Render())
+
+
+def _FormatQuery(query):
+  """Format a Query protobuf as (very simple) HTML.
+
+  Args:
+    query: A datastore_pb.Query instance.
+
+  Returns:
+    A string containing formatted HTML.  This is mostly the output of
+    str(query) with '<' etc. escaped, and '<br>' inserted in front of
+    Order and Filter parts.
+  """
+  res = cgi.escape(str(query))
+  res = res.replace('Order', '<br>Order')
+  res = res.replace('Filter', '<br>Filter')
+  return res
+
+
+def _DirectionToString(direction):
+  """Turn a direction enum into a string.
+
+  Args:
+    direction: ASCENDING or DESCENDING
+
+  Returns:
+    Either 'asc' or 'descending'.
+  """
+  if direction == datastore_pb.Query_Order.DESCENDING:
+    return 'descending'
+  else:
+    return 'asc'
+
+
+URL_MAP = {
+  '/_ah/info/queries': QueriesHandler,
+  '/_ah/info/index.yaml': IndexYamlHandler,
+
+}
+
+
+def main():
+  application = webapp.WSGIApplication(URL_MAP.items())
+  wsgiref.handlers.CGIHandler().run(application)
+
+
+if __name__ == '__main__':
+  main()