1.9.30 sync.
[gae.git] / python / wrapper_util.py
blob70e0badab980522895612324720c9d981ff5ce22
1 #!/usr/bin/env python
3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """Finds the directory and target script name for App Engine SDK scripts."""
19 import os
20 import sys
23 def reject_old_python_versions(minimum_version):
24 """Guard against old python versions.
26 Args:
27 minimum_version: a tuple that indicates the minimum Python version.
28 """
29 minimum_version_string = '.'.join(str(x) for x in minimum_version)
30 if not hasattr(sys, 'version_info'):
31 sys.stderr.write('Very old versions of Python are not supported. Please '
32 'use version %s.\n' % minimum_version_string)
33 sys.exit(1)
34 version_tuple = tuple(sys.version_info[:2])
35 if version_tuple < minimum_version:
36 sys.stderr.write('Error: Python %d.%d is not supported. Please use '
37 'version %s.\n' % (version_tuple[0], version_tuple[1],
38 minimum_version_string))
39 sys.exit(1)
42 def get_dir_path(script_file, sibling):
43 """Get a path to the directory of the script script_file.
45 By default, the canonical path (symlinks resolved) will be returned. In some
46 environments the canonical directory is not sufficient because different
47 parts of the SDK are referenced by symlinks, including script_file.
48 In this case, the non-canonical path to script_file's directory will be
49 returned (i.e., the directory where the symlink lives, not the directory
50 where it points).
52 Args:
53 script_file: The script file whose directory is wanted.
54 sibling: Relative path to a sibling of script_file. Choose a sibling
55 that is potentially symlinked into the parent directory.
57 Returns:
58 A directory name.
60 Raises:
61 ValueError: If no proper path could be determined.
62 """
63 if 'GAE_SDK_ROOT' in os.environ:
64 gae_sdk_root = os.path.abspath(os.environ['GAE_SDK_ROOT'])
68 os.environ['GAE_SDK_ROOT'] = gae_sdk_root
69 for dir_path in [gae_sdk_root,
70 os.path.join(gae_sdk_root, 'google_appengine')]:
71 if os.path.exists(os.path.join(dir_path, sibling)):
72 return dir_path
73 raise ValueError('GAE_SDK_ROOT %r does not refer to a valid SDK '
74 'directory' % gae_sdk_root)
75 else:
76 py_file = script_file.replace('.pyc', '.py')
77 dir_paths = [os.path.abspath(os.path.dirname(os.path.realpath(py_file))),
78 os.path.abspath(os.path.dirname(py_file))]
79 for dir_path in dir_paths:
80 sibling_path = os.path.join(dir_path, sibling)
81 if os.path.exists(sibling_path):
82 return dir_path
83 raise ValueError('Could not determine SDK root; please set GAE_SDK_ROOT '
84 'environment variable.')
92 class Paths(object):
93 """Encapsulates the path and unwrapped script details for a wrapper script.
95 Most of the attributes of this object are there so that wrapper_script_v1
96 can continue to export the same global variables it historically has, in case
97 any end-users are referencing those.
99 Attributes:
100 default_script_dir: the path where the corresponding unwrapped script will
101 be found, apart from a few exceptional scripts.
104 def __init__(self, dir_path):
105 """Make a new Paths object.
107 Args:
108 dir_path: the directory path where the calling script is to be found.
109 This directory should have a lib subdirectory.
113 self.v1_extra_paths = [
114 dir_path,
115 os.path.join(dir_path, 'lib', 'antlr3'),
116 os.path.join(dir_path, 'lib', 'django-0.96'),
117 os.path.join(dir_path, 'lib', 'fancy_urllib'),
118 os.path.join(dir_path, 'lib', 'ipaddr'),
119 os.path.join(dir_path, 'lib', 'jinja2-2.6'),
120 os.path.join(dir_path, 'lib', 'protorpc-1.0'),
121 os.path.join(dir_path, 'lib', 'PyAMF'),
122 os.path.join(dir_path, 'lib', 'markupsafe'),
123 os.path.join(dir_path, 'lib', 'webob_0_9'),
124 os.path.join(dir_path, 'lib', 'webapp2-2.5.2'),
125 os.path.join(dir_path, 'lib', 'yaml', 'lib'),
126 os.path.join(dir_path, 'lib', 'simplejson'),
128 os.path.join(dir_path, 'lib', 'rsa'),
129 os.path.join(dir_path, 'lib', 'pyasn1'),
130 os.path.join(dir_path, 'lib', 'pyasn1_modules'),
133 self.api_server_extra_paths = [
134 os.path.join(dir_path, 'lib', 'argparse'),
140 self.endpointscfg_extra_paths = [
141 os.path.join(dir_path, 'lib', 'cherrypy'),
142 os.path.join(dir_path, 'lib', 'concurrent'),
143 os.path.join(dir_path, 'lib', 'endpoints-1.0'),
147 self.oauth_client_extra_paths = [
148 os.path.join(dir_path, 'lib', 'google-api-python-client'),
149 os.path.join(dir_path, 'lib', 'httplib2'),
150 os.path.join(dir_path, 'lib', 'python-gflags'),
154 self.google_sql_extra_paths = self.oauth_client_extra_paths + [
155 os.path.join(dir_path, 'lib', 'deprecated_enum'),
156 os.path.join(dir_path, 'lib', 'grizzled'),
157 os.path.join(dir_path, 'lib', 'oauth2'),
158 os.path.join(dir_path, 'lib', 'prettytable'),
159 os.path.join(dir_path, 'lib', 'sqlcmd'),
162 devappserver2_dir = os.path.join(
163 dir_path, 'google', 'appengine', 'tools', 'devappserver2')
164 php_runtime_dir = os.path.join(devappserver2_dir, 'php')
165 python_runtime_dir = os.path.join(devappserver2_dir, 'python')
167 stub_paths = [
168 os.path.join(dir_path, 'lib', 'antlr3'),
169 os.path.join(dir_path, 'lib', 'fancy_urllib'),
170 os.path.join(dir_path, 'lib', 'ipaddr'),
171 os.path.join(dir_path, 'lib', 'yaml-3.10'),
173 os.path.join(dir_path, 'lib', 'rsa'),
174 os.path.join(dir_path, 'lib', 'pyasn1'),
175 os.path.join(dir_path, 'lib', 'pyasn1_modules'),
182 self.v2_extra_paths = stub_paths + [
183 dir_path,
185 os.path.join(dir_path, 'lib', 'simplejson'),
189 os.path.join(dir_path, 'lib', 'django-1.4'),
190 os.path.join(dir_path, 'lib', 'endpoints-1.0'),
191 os.path.join(dir_path, 'lib', 'jinja2-2.6'),
192 os.path.join(dir_path, 'lib', 'protorpc-1.0'),
193 os.path.join(dir_path, 'lib', 'PyAMF-0.6.1'),
194 os.path.join(dir_path, 'lib', 'markupsafe-0.15'),
195 os.path.join(dir_path, 'lib', 'webob-1.2.3'),
196 os.path.join(dir_path, 'lib', 'webapp2-2.5.2'),
199 devappserver2_paths = stub_paths + [
200 dir_path,
201 os.path.join(dir_path, 'lib', 'concurrent'),
202 os.path.join(dir_path, 'lib', 'cherrypy'),
204 os.path.join(dir_path, 'lib', 'distutils'),
205 os.path.join(dir_path, 'lib', 'requests'),
206 os.path.join(dir_path, 'lib', 'six'),
207 os.path.join(dir_path, 'lib', 'websocket'),
208 os.path.join(dir_path, 'lib', 'docker'),
209 os.path.join(dir_path, 'lib', 'jinja2-2.6'),
210 os.path.join(dir_path, 'lib', 'webob-1.2.3'),
211 os.path.join(dir_path, 'lib', 'webapp2-2.5.1'),
214 php_runtime_paths = [
215 dir_path,
216 os.path.join(dir_path, 'lib', 'concurrent'),
217 os.path.join(dir_path, 'lib', 'cherrypy'),
218 os.path.join(dir_path, 'lib', 'yaml-3.10'),
221 python_runtime_paths = [
222 dir_path,
223 os.path.join(dir_path, 'lib', 'concurrent'),
224 os.path.join(dir_path, 'lib', 'cherrypy'),
225 os.path.join(dir_path, 'lib', 'fancy_urllib'),
226 os.path.join(dir_path, 'lib', 'protorpc-1.0'),
227 os.path.join(dir_path, 'lib', 'yaml-3.10'),
230 self._script_to_paths = {
231 'api_server.py': self.v1_extra_paths + self.api_server_extra_paths,
232 'appcfg.py': self.v1_extra_paths + self.oauth_client_extra_paths,
233 'backends_conversion.py': self.v1_extra_paths,
234 'bulkload_client.py': self.v1_extra_paths,
235 'bulkloader.py': self.v1_extra_paths + self.oauth_client_extra_paths,
236 'dev_appserver.py': devappserver2_paths,
237 'download_appstats.py': self.v1_extra_paths,
238 'endpointscfg.py': self.v1_extra_paths + self.endpointscfg_extra_paths,
239 'gen_protorpc.py': self.v1_extra_paths,
240 'google_sql.py': self.v1_extra_paths + self.google_sql_extra_paths,
241 'old_dev_appserver.py': self.v1_extra_paths,
242 'php_cli.py': devappserver2_paths,
243 'remote_api_shell.py': self.v1_extra_paths,
244 'vmboot.py': self.v1_extra_paths,
245 '_php_runtime.py': php_runtime_paths,
246 '_python_runtime.py': python_runtime_paths,
249 self._wrapper_name_to_real_name = {
250 'old_dev_appserver.py': 'dev_appserver_main.py',
251 'dev_appserver.py': 'devappserver2.py',
252 '_php_runtime.py': 'runtime.py',
253 '_python_runtime.py': 'runtime.py',
256 self.default_script_dir = os.path.join(
257 dir_path, 'google', 'appengine', 'tools')
259 self.google_sql_dir = os.path.join(
260 dir_path, 'google', 'storage', 'speckle', 'python', 'tool')
262 self._script_to_dir = {
263 'google_sql.py': self.google_sql_dir,
264 'dev_appserver.py': devappserver2_dir,
265 '_php_runtime.py': php_runtime_dir,
266 '_python_runtime.py': python_runtime_dir,
282 self._sys_paths_to_scrub = {
283 'dev_appserver.py':
284 [os.path.normcase(os.path.join(dir_path, 'launcher'))],
287 def script_paths(self, script_name):
288 """Returns the sys.path prefix appropriate for this script.
290 Args:
291 script_name: the basename of the script, for example 'appcfg.py'.
293 try:
294 return self._script_to_paths[script_name]
295 except KeyError:
296 raise KeyError('Script name %s not recognized' % script_name)
298 def script_file(self, script_name):
299 """Returns the absolute name of the wrapped script.
301 Args:
302 script_name: the basename of the script, for example 'appcfg.py'.
304 script_dir = self._script_to_dir.get(script_name, self.default_script_dir)
305 script_name = self._wrapper_name_to_real_name.get(script_name, script_name)
306 return os.path.join(script_dir, script_name)
308 def scrub_path(self, script_name, paths):
309 """Removes bad paths from a list of paths.
311 Args:
312 script_name: the basename of the script, for example 'appcfg.py'.
313 paths: a list of paths
315 Returns:
316 The list of paths with any bad paths removed.
318 sys_paths_to_scrub = self._sys_paths_to_scrub.get(script_name, [])
321 return [path for path in paths
322 if os.path.normcase(path) not in sys_paths_to_scrub]