thirdparty/google_appengine/google/appengine/tools/dev_appserver_main.py
changeset 1278 a7766286a7be
parent 828 f5fd65cc3bf3
child 2172 ac7bd3b467ff
--- a/thirdparty/google_appengine/google/appengine/tools/dev_appserver_main.py	Thu Feb 12 10:24:37 2009 +0000
+++ b/thirdparty/google_appengine/google/appengine/tools/dev_appserver_main.py	Thu Feb 12 12:30:36 2009 +0000
@@ -65,14 +65,24 @@
 import getopt
 import logging
 import os
+import re
 import sys
 import traceback
 import tempfile
 
-from google.appengine.api import yaml_errors
-from google.appengine.tools import appcfg
-from google.appengine.tools import appengine_rpc
-from google.appengine.tools import dev_appserver
+
+def SetGlobals():
+  """Set various global variables involving the 'google' package.
+
+  This function should not be called until sys.path has been properly set.
+  """
+  global yaml_errors, appcfg, appengine_rpc, dev_appserver, os_compat
+  from google.appengine.api import yaml_errors
+  from google.appengine.tools import appcfg
+  from google.appengine.tools import appengine_rpc
+  from google.appengine.tools import dev_appserver
+  from google.appengine.tools import os_compat
+
 
 
 DEFAULT_ADMIN_CONSOLE_SERVER = 'appengine.google.com'
@@ -98,9 +108,13 @@
 ARG_STATIC_CACHING = 'static_caching'
 ARG_TEMPLATE_DIR = 'template_dir'
 
-
-BASE_PATH = os.path.abspath(
-  os.path.join(os.path.dirname(dev_appserver.__file__), '../../../'))
+SDK_PATH = os.path.dirname(
+             os.path.dirname(
+               os.path.dirname(
+                 os.path.dirname(os_compat.__file__)
+               )
+             )
+           )
 
 DEFAULT_ARGS = {
   ARG_PORT: 8080,
@@ -112,7 +126,7 @@
   ARG_LOGIN_URL: '/_ah/login',
   ARG_CLEAR_DATASTORE: False,
   ARG_REQUIRE_INDEXES: False,
-  ARG_TEMPLATE_DIR: os.path.join(BASE_PATH, 'templates'),
+  ARG_TEMPLATE_DIR: os.path.join(SDK_PATH, 'templates'),
   ARG_SMTP_HOST: '',
   ARG_SMTP_PORT: 25,
   ARG_SMTP_USER: '',
@@ -126,6 +140,74 @@
   ARG_STATIC_CACHING: True,
 }
 
+API_PATHS = {'1':
+             {'google': (),
+              'antlr3': ('lib', 'antlr3'),
+              'django': ('lib', 'django'),
+              'webob': ('lib', 'webob'),
+              'yaml': ('lib', 'yaml', 'lib'),
+              }
+             }
+
+DEFAULT_API_VERSION = '1'
+
+API_PATHS['test'] = API_PATHS[DEFAULT_API_VERSION].copy()
+API_PATHS['test']['_test'] = ('nonexistent', 'test', 'path')
+
+
+def SetPaths(app_config_path):
+  """Set the interpreter to use the specified API version.
+
+  The app.yaml file is scanned for the api_version field and the value is
+  extracted. With that information, the paths in API_PATHS are added to the
+  front of sys.paths to make sure that they take precedent over any other paths
+  to older versions of a package. All modules for each package set are cleared
+  out of sys.modules to make sure only the newest version is used.
+
+  Args:
+    - app_config_path: Path to the app.yaml file.
+  """
+  api_version_re = re.compile(r'api_version:\s*(?P<api_version>[\w.]{1,32})')
+  api_version = None
+  app_config_file = open(app_config_path, 'r')
+  try:
+    for line in app_config_file:
+      re_match = api_version_re.match(line)
+      if re_match:
+        api_version = re_match.group('api_version')
+        break
+  finally:
+    app_config_file.close()
+
+  if api_version is None:
+    logging.error("Application configuration file missing an 'api_version' "
+                  "value:\n%s" % app_config_path)
+    sys.exit(1)
+  if api_version not in API_PATHS:
+    logging.error("Value of %r for 'api_version' from the application "
+                  "configuration file is not valid:\n%s" %
+                    (api_version, app_config_path))
+    sys.exit(1)
+
+  if api_version == DEFAULT_API_VERSION:
+    return DEFAULT_API_VERSION
+
+  sdk_path = os.path.dirname(
+      os.path.dirname(
+        os.path.dirname(
+          os.path.dirname(os_compat.__file__)
+          )
+        )
+      )
+  for pkg_name, path_parts in API_PATHS[api_version].iteritems():
+    for name in sys.modules.keys():
+      if name == pkg_name or name.startswith('%s.' % pkg_name):
+        del sys.modules[name]
+    pkg_path = os.path.join(sdk_path, *path_parts)
+    sys.path.insert(0, pkg_path)
+
+  return api_version
+
 
 def PrintUsageExit(code):
   """Prints usage information and exits with a status code.
@@ -205,10 +287,10 @@
       option_dict[ARG_ADDRESS] = value
 
     if option == '--datastore_path':
-      option_dict[ARG_DATASTORE_PATH] = value
+      option_dict[ARG_DATASTORE_PATH] = os.path.abspath(value)
 
     if option == '--history_path':
-      option_dict[ARG_HISTORY_PATH] = value
+      option_dict[ARG_HISTORY_PATH] = os.path.abspath(value)
 
     if option in ('-c', '--clear_datastore'):
       option_dict[ARG_CLEAR_DATASTORE] = True
@@ -241,10 +323,10 @@
       option_dict[ARG_SHOW_MAIL_BODY] = True
 
     if option == '--auth_domain':
-      dev_appserver.DEFAULT_ENV['AUTH_DOMAIN'] = value
+      option_dict['_DEFAULT_ENV_AUTH_DOMAIN'] = value
 
     if option == '--debug_imports':
-      dev_appserver.HardenedModulesHook.ENABLE_LOGGING = True
+      option_dict['_ENABLE_LOGGING'] = True
 
     if option == '--template_dir':
       option_dict[ARG_TEMPLATE_DIR] = value
@@ -291,6 +373,25 @@
     PrintUsageExit(1)
 
   root_path = args[0]
+  for suffix in ('yaml', 'yml'):
+    path = os.path.join(root_path, 'app.%s' % suffix)
+    if os.path.exists(path):
+      api_version = SetPaths(path)
+      break
+  else:
+    logging.error("Application configuration file not found in %s" % root_path)
+    return 1
+
+  SetGlobals()
+  dev_appserver.API_VERSION = api_version
+
+  if '_DEFAULT_ENV_AUTH_DOMAIN' in option_dict:
+    auth_domain = option_dict['_DEFAULT_ENV_AUTH_DOMAIN']
+    dev_appserver.DEFAULT_ENV['AUTH_DOMAIN'] = auth_domain
+  if '_ENABLE_LOGGING' in option_dict:
+    enable_logging = option_dict['_ENABLE_LOGGING']
+    dev_appserver.HardenedModulesHook.ENABLE_LOGGING = enable_logging
+
   log_level = option_dict[ARG_LOG_LEVEL]
   port = option_dict[ARG_PORT]
   datastore_path = option_dict[ARG_DATASTORE_PATH]
@@ -335,6 +436,7 @@
                                            login_url,
                                            port,
                                            template_dir,
+                                           sdk_dir=SDK_PATH,
                                            serve_address=serve_address,
                                            require_indexes=require_indexes,
                                            static_caching=static_caching)
@@ -359,3 +461,5 @@
 
 if __name__ == '__main__':
   sys.exit(main(sys.argv))
+else:
+  SetGlobals()