diff -r 261778de26ff -r 620f9b141567 thirdparty/google_appengine/google/appengine/tools/dev_appserver_info.py --- /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 = """ +Query History + + +

Query History

+ +

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.

+ +

You can also view a 'clean' index.yaml +file and save that to your app's root directory.

+ + + +""" + + ROW = """""" + + FOOTER = """ +
Times runQuery
%(count)s%(query)s
+ +""" + + 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 '
' inserted in front of + Order and Filter parts. + """ + res = cgi.escape(str(query)) + res = res.replace('Order', '
Order') + res = res.replace('Filter', '
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()