| #!/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. |
| # |
| """Invoke PHP after setting up the App Engine environment.""" |
| |
| |
| import argparse |
| import os |
| import subprocess |
| import sys |
| import tempfile |
| import wsgiref.util |
| |
| import google |
| from google.appengine.api import request_info |
| from google.appengine.datastore import datastore_stub_util |
| from google.appengine.tools.devappserver2 import api_server |
| from google.appengine.tools.devappserver2 import gcs_server |
| from google.appengine.tools.devappserver2.php import runtime |
| |
| |
| def _get_gcs_server(): |
| server = gcs_server.GCSServer('localhost', 0) |
| server.start() |
| return server |
| |
| |
| class APIRequestInfo(request_info.RequestInfo): |
| """Allows stubs to lookup state linked to the request making the API call.""" |
| |
| def __init__(self): |
| self._environ = {} |
| wsgiref.util.setup_testing_defaults(self._environ) |
| |
| def get_request_url(self, request_id): |
| """Returns the URL the request e.g. 'http://localhost:8080/foo?bar=baz'. |
| |
| Args: |
| request_id: The string id of the request making the API call. |
| |
| Returns: |
| The URL of the request as a string. |
| """ |
| return wsgiref.util.request_uri(self._environ) |
| |
| def get_request_environ(self, request_id): |
| """Returns a dict containing the WSGI environ for the request.""" |
| return self._environ |
| |
| def get_module(self, request_id): |
| """Returns the name of the module serving this request. |
| |
| Args: |
| request_id: The string id of the request making the API call. |
| |
| Returns: |
| A str containing the module name. |
| """ |
| return 'default' |
| |
| def get_version(self, request_id): |
| """Returns the version of the module serving this request. |
| |
| Args: |
| request_id: The string id of the request making the API call. |
| |
| Returns: |
| A str containing the version. |
| """ |
| return '1' |
| |
| def get_instance(self, request_id): |
| """Returns the instance serving this request. |
| |
| Args: |
| request_id: The string id of the request making the API call. |
| |
| Returns: |
| An opaque representation of the instance serving this request. It should |
| only be passed to dispatcher methods expecting an instance. |
| """ |
| return object() |
| |
| def get_dispatcher(self): |
| """Returns the Dispatcher. |
| |
| Returns: |
| The Dispatcher instance. |
| """ |
| return request_info._LocalFakeDispatcher() |
| |
| |
| def _get_api_server(app_id): |
| """Return a configured and started api_server.APIServer.""" |
| tmp_dir = tempfile.mkdtemp() |
| os.environ['APPLICATION_ID'] = app_id |
| api_server.setup_stubs( |
| request_data=APIRequestInfo(), |
| app_id=app_id, |
| application_root=os.getcwd(), |
| trusted=False, |
| appidentity_email_address=None, |
| appidentity_private_key_path=None, |
| blobstore_path=tmp_dir, |
| datastore_consistency= |
| datastore_stub_util.PseudoRandomHRConsistencyPolicy(), |
| datastore_path=':memory:', |
| datastore_require_indexes=False, |
| datastore_auto_id_policy=datastore_stub_util.SCATTERED, |
| images_host_prefix='http://localhost:8080', |
| logs_path=':memory:', |
| mail_smtp_host='', |
| mail_smtp_port=25, |
| mail_smtp_user='', |
| mail_smtp_password='', |
| mail_enable_sendmail=False, |
| mail_show_mail_body=False, |
| matcher_prospective_search_path=tmp_dir, |
| search_index_path=None, |
| taskqueue_auto_run_tasks=False, |
| taskqueue_default_http_server='http://localhost:8080', |
| user_login_url='/_ah/login?continue=%s', |
| user_logout_url='/_ah/login?continue=%s', |
| default_gcs_bucket_name=None) |
| |
| server = api_server.APIServer('localhost', 0, app_id) |
| server.start() |
| return server |
| |
| |
| def _get_default_php_cli_path(): |
| """Returns the path to the siloed php cli binary or None if not present.""" |
| default_php_executable_path = None |
| google_package_directory = os.path.dirname(google.__file__) |
| sdk_directory = os.path.dirname(google_package_directory) |
| |
| if sys.platform == 'win32': |
| default_php_executable_path = os.path.abspath( |
| os.path.join(sdk_directory, 'php/php-5.4-Win32-VC9-x86/php.exe')) |
| elif sys.platform == 'darwin': |
| default_php_executable_path = os.path.abspath( |
| os.path.join(os.path.dirname(sdk_directory), 'php')) |
| |
| if (default_php_executable_path and |
| os.path.exists(default_php_executable_path)): |
| return default_php_executable_path |
| return None |
| |
| |
| def _parse_path(value): |
| """Returns the given path with ~ and environment variables expanded.""" |
| return os.path.expanduser(os.path.expandvars(value)) |
| |
| |
| def _create_command_line_parser(): |
| """Returns an argparse.ArgumentParser to parse command line arguments.""" |
| parser = argparse.ArgumentParser( |
| usage='usage: %(prog)s [execution options] <script> [script_args]', |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| parser.add_argument( |
| 'script', |
| help='the path to the PHP script that should be executed') |
| parser.add_argument( |
| 'script_args', |
| help='the command arguments that will be passed to the script', |
| nargs=argparse.REMAINDER) |
| |
| execution_group = parser.add_argument_group('Execution Options') |
| |
| php_cli_path = _get_default_php_cli_path() |
| execution_group.add_argument('--php_executable_path', metavar='PATH', |
| type=_parse_path, |
| default=php_cli_path, |
| required=php_cli_path is None, |
| help='path to the PHP executable') |
| return parser |
| |
| |
| def main(): |
| parser = _create_command_line_parser() |
| options = parser.parse_args() |
| |
| if not options.php_executable_path: |
| parser.error('--php_executable_path must be set') |
| elif not os.path.exists(options.php_executable_path): |
| parser.error('--php_executable_path=%s, %s does not exist' % ( |
| options.php_executable_path, options.php_executable_path)) |
| |
| php_script = os.path.abspath(_parse_path(options.script)) |
| if not os.path.exists(php_script): |
| parser.error('%s does not exist' % php_script) |
| |
| api_srver = _get_api_server(app_id='dummy_app_id') |
| gcs_srver = _get_gcs_server() |
| |
| include_paths = [runtime.SDK_PATH] |
| if sys.platform == 'win32': |
| |
| include_path = 'include_path="%s"' % ';'.join(include_paths) |
| else: |
| include_path = 'include_path=%s' % ':'.join(include_paths) |
| |
| php_args = [options.php_executable_path, |
| '-d', include_path, |
| '-f', runtime.SETUP_PHP_PATH,] |
| php_args.extend(options.script_args) |
| |
| |
| env = dict(HTTP_HOST='localhost:%d' % gcs_srver.port, |
| SERVER_SOFTWARE='Development/CLI', |
| REAL_SCRIPT_FILENAME=php_script, |
| REMOTE_API_HOST='localhost', |
| REMOTE_API_PORT=str(api_srver.port), |
| REMOTE_REQUEST_ID='51', |
| APPLICATION_ROOT=os.path.dirname(php_script)) |
| if 'SYSTEMROOT' in os.environ: |
| env['SYSTEMROOT'] = os.environ['SYSTEMROOT'] |
| |
| php_process = subprocess.Popen(php_args, env=env) |
| script_return = php_process.wait() |
| |
| api_srver.quit() |
| gcs_srver.quit() |
| sys.exit(script_return) |
| |
| |
| if __name__ == '__main__': |
| main() |