App Engine Python SDK version 1.8.9
[gae.git] / python / google / appengine / tools / yaml_translator.py
blobe85ea6ed0e7a988c52d316841ce18268322e38a7
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 """Performs XML-to-YAML translation.
19 TranslateXmlToYaml(): performs xml-to-yaml translation with
20 string inputs and outputs
21 AppYamlTranslator: Class that facilitates xml-to-yaml translation
22 """
24 from google.appengine.tools import app_engine_web_xml_parser as aewxp
25 from google.appengine.tools import backends_xml_parser
26 from google.appengine.tools import handler_generator
27 from google.appengine.tools import web_xml_parser
28 from google.appengine.tools.app_engine_web_xml_parser import AppEngineConfigException
31 NO_API_VERSION = 'none'
34 def TranslateXmlToYaml(app_engine_web_xml_str,
35 backends_xml_str,
36 web_xml_str,
37 static_files,
38 api_version):
39 """Does xml-string to yaml-string translation, given each separate file text.
41 Processes each xml string into an object representing the xml,
42 and passes these to the translator.
44 Args:
45 app_engine_web_xml_str: text from app_engine_web.xml
46 backends_xml_str: text from backends.xml
47 web_xml_str: text from web.xml
48 static_files: List of static files
49 api_version: current api version
51 Returns:
52 The full text of the app.yaml generated from the xml files.
54 Raises:
55 AppEngineConfigException: raised in processing stage for illegal XML.
56 """
57 aewx_parser = aewxp.AppEngineWebXmlParser()
58 backends_parser = backends_xml_parser.BackendsXmlParser()
59 web_parser = web_xml_parser.WebXmlParser()
60 app_engine_web_xml = aewx_parser.ProcessXml(app_engine_web_xml_str)
61 backends_xml = backends_parser.ProcessXml(backends_xml_str)
62 web_xml = web_parser.ProcessXml(web_xml_str)
63 translator = AppYamlTranslator(
64 app_engine_web_xml, backends_xml, web_xml, static_files, api_version)
65 return translator.GetYaml()
68 def GetRuntime():
70 return 'java7'
73 class AppYamlTranslator(object):
74 """Object that contains relevant information for generating app.yaml.
76 Attributes:
77 app_engine_web_xml: AppEngineWebXml object containing relevant information
78 from appengine-web.xml
79 backends_xml: BackendsXml object containing relevant info from backends.xml
80 """
82 def __init__(self,
83 app_engine_web_xml,
84 backends_xml,
85 web_xml,
86 static_files,
87 api_version):
89 self.app_engine_web_xml = app_engine_web_xml
90 self.backends_xml = backends_xml
91 self.web_xml = web_xml
92 self.static_files = static_files
93 self.api_version = api_version
95 def GetYaml(self):
96 """Returns full yaml text."""
97 self.VerifyRequiredEntriesPresent()
98 stmnt_list = self.TranslateBasicEntries()
99 stmnt_list += self.TranslateAutomaticScaling()
100 stmnt_list += self.TranslateBasicScaling()
101 stmnt_list += self.TranslateManualScaling()
102 stmnt_list += self.TranslatePrecompilationEnabled()
103 stmnt_list += self.TranslateInboundServices()
104 stmnt_list += self.TranslateAdminConsolePages()
105 stmnt_list += self.TranslateApiConfig()
106 stmnt_list += self.TranslatePagespeed()
107 stmnt_list += self.TranslateVmSettings()
108 stmnt_list += self.TranslateErrorHandlers()
109 stmnt_list += self.TranslateBackendsXml()
110 stmnt_list += self.TranslateApiVersion()
111 stmnt_list += self.TranslateHandlers()
112 return '\n'.join(stmnt_list) + '\n'
114 def SanitizeForYaml(self, the_string):
115 return "'%s'" % the_string.replace("'", "''")
117 def TranslateBasicEntries(self):
118 """Produces yaml for entries requiring little formatting."""
119 basic_statements = []
121 for entry_name, field in [
122 ('application', self.app_engine_web_xml.app_id),
123 ('source_language', self.app_engine_web_xml.source_language),
124 ('module', self.app_engine_web_xml.module),
125 ('version', self.app_engine_web_xml.version_id)]:
126 if field:
127 basic_statements.append(
128 '%s: %s' % (entry_name, self.SanitizeForYaml(field)))
129 for entry_name, field in [
130 ('runtime', GetRuntime()),
131 ('vm', self.app_engine_web_xml.vm),
132 ('threadsafe', self.app_engine_web_xml.threadsafe),
133 ('instance_class', self.app_engine_web_xml.instance_class),
134 ('auto_id_policy', self.app_engine_web_xml.auto_id_policy),
135 ('code_lock', self.app_engine_web_xml.codelock)]:
136 if field:
137 basic_statements.append('%s: %s' % (entry_name, field))
138 return basic_statements
140 def TranslateAutomaticScaling(self):
141 """Translates automatic scaling settings to yaml."""
142 if not self.app_engine_web_xml.automatic_scaling:
143 return []
144 statements = ['automatic_scaling:']
145 for setting in ['min_pending_latency',
146 'max_pending_latency',
147 'min_idle_instances',
148 'max_idle_instances']:
149 value = getattr(self.app_engine_web_xml.automatic_scaling, setting)
150 if value:
151 statements.append(' %s: %s' % (setting, value))
152 return statements
154 def TranslateBasicScaling(self):
155 if not self.app_engine_web_xml.basic_scaling:
156 return []
157 statements = ['basic_scaling:']
158 statements.append(' max_instances: ' +
159 self.app_engine_web_xml.basic_scaling.max_instances)
160 if self.app_engine_web_xml.basic_scaling.idle_timeout:
161 statements.append(' idle_timeout: ' +
162 self.app_engine_web_xml.basic_scaling.idle_timeout)
163 return statements
165 def TranslateManualScaling(self):
166 if not self.app_engine_web_xml.manual_scaling:
167 return []
169 statements = ['manual_scaling:']
170 statements.append(' instances: ' +
171 self.app_engine_web_xml.manual_scaling.instances)
172 return statements
174 def TranslatePrecompilationEnabled(self):
175 if self.app_engine_web_xml.precompilation_enabled:
176 return ['derived_file_type:', '- java_precompiled']
177 return []
179 def TranslateAdminConsolePages(self):
180 if not self.app_engine_web_xml.admin_console_pages:
181 return []
182 statements = ['admin_console:', ' pages:']
183 for admin_console_page in self.app_engine_web_xml.admin_console_pages:
184 statements.append(' - name: %s' % admin_console_page.name)
185 statements.append(' url: %s' % admin_console_page.url)
186 return statements
188 def TranslateApiConfig(self):
190 if not self.app_engine_web_xml.api_config:
191 return []
192 return ['api_config:', ' url: %s' % self.app_engine_web_xml.api_config.url,
193 ' script: unused']
195 def TranslateApiVersion(self):
196 return ['api_version: %s' % self.SanitizeForYaml(
197 self.api_version or NO_API_VERSION)]
199 def TranslatePagespeed(self):
200 """Translates pagespeed settings in appengine-web.xml to yaml."""
201 pagespeed = self.app_engine_web_xml.pagespeed
202 if not pagespeed:
203 return []
204 statements = ['pagespeed:']
205 for title, urls in [('domains_to_rewrite', pagespeed.domains_to_rewrite),
206 ('url_blacklist', pagespeed.url_blacklist),
207 ('enabled_rewriters', pagespeed.enabled_rewriters),
208 ('disabled_rewriters', pagespeed.disabled_rewriters)]:
209 if urls:
210 statements.append(' %s:' % title)
211 statements += [' - %s' % url for url in urls]
212 return statements
214 def TranslateVmSettings(self):
215 """Translates VM settings in appengine-web.xml to yaml."""
216 if (not self.app_engine_web_xml.vm or
217 not self.app_engine_web_xml.vm_settings):
218 return []
220 settings = self.app_engine_web_xml.vm_settings
221 statements = ['vm_settings:']
222 for name in sorted(settings):
223 statements.append(
224 ' %s: %s' % (
225 self.SanitizeForYaml(name), self.SanitizeForYaml(settings[name])))
226 return statements
228 def TranslateInboundServices(self):
229 services = self.app_engine_web_xml.inbound_services
230 if not services:
231 return []
233 statements = ['inbound_services:']
234 for service in sorted(services):
235 statements.append('- %s' % service)
236 return statements
238 def TranslateErrorHandlers(self):
239 """Translates error handlers specified in appengine-web.xml to yaml."""
240 if not self.app_engine_web_xml.static_error_handlers:
241 return []
242 statements = ['error_handlers:']
243 for error_handler in self.app_engine_web_xml.static_error_handlers:
244 name = error_handler.name
245 if not name.startswith('/'):
246 name = '/' + name
248 if ('__static__' + name) not in self.static_files:
249 raise AppEngineConfigException(
250 'No static file found for error handler: %s, out of %s' %
251 (name, self.static_files))
252 statements.append('- file: __static__%s' % name)
253 if error_handler.code:
254 statements.append(' error_code: %s' % error_handler.code)
255 mime_type = self.web_xml.GetMimeTypeForPath(name)
256 if mime_type:
257 statements.append(' mime_type: %s' % mime_type)
259 return statements
261 def TranslateBackendsXml(self):
262 """Translates backends.xml backends settings to yaml."""
263 if not self.backends_xml:
264 return []
265 statements = ['backends:']
267 for backend in self.backends_xml:
268 statements.append('- name: %s' % backend.name)
269 for entry, field in [('instances', backend.instances),
270 ('instance_class', backend.instance_class),
271 ('max_concurrent_requests',
272 backend.max_concurrent_requests)]:
273 if field is not None:
274 statements.append(' %s: %s' % (entry, str(field)))
276 if backend.options:
277 options_str = ', '.join(sorted(list(backend.options)))
278 statements.append(' options: %s' % options_str)
279 return statements
281 def TranslateHandlers(self):
282 return handler_generator.GenerateYamlHandlersList(
283 self.app_engine_web_xml,
284 self.web_xml,
285 self.static_files)
287 def VerifyRequiredEntriesPresent(self):
288 required = {
289 'app_id': self.app_engine_web_xml.app_id,
290 'version_id': self.app_engine_web_xml.version_id,
291 'runtime': GetRuntime(),
292 'threadsafe': self.app_engine_web_xml.threadsafe_value_provided,
294 missing = [field for (field, value) in required.items() if not value]
295 if missing:
296 raise AppEngineConfigException('Missing required fields: %s' %
297 ', '.join(missing))