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
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
,
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.
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
52 The full text of the app.yaml generated from the xml files.
55 AppEngineConfigException: raised in processing stage for illegal XML.
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()
73 class AppYamlTranslator(object):
74 """Object that contains relevant information for generating app.yaml.
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
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
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
)]:
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
)]:
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
:
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
)
151 statements
.append(' %s: %s' % (setting
, value
))
154 def TranslateBasicScaling(self
):
155 if not self
.app_engine_web_xml
.basic_scaling
:
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
)
165 def TranslateManualScaling(self
):
166 if not self
.app_engine_web_xml
.manual_scaling
:
169 statements
= ['manual_scaling:']
170 statements
.append(' instances: ' +
171 self
.app_engine_web_xml
.manual_scaling
.instances
)
174 def TranslatePrecompilationEnabled(self
):
175 if self
.app_engine_web_xml
.precompilation_enabled
:
176 return ['derived_file_type:', '- java_precompiled']
179 def TranslateAdminConsolePages(self
):
180 if not self
.app_engine_web_xml
.admin_console_pages
:
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
)
188 def TranslateApiConfig(self
):
190 if not self
.app_engine_web_xml
.api_config
:
192 return ['api_config:', ' url: %s' % self
.app_engine_web_xml
.api_config
.url
,
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
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
)]:
210 statements
.append(' %s:' % title
)
211 statements
+= [' - %s' % url
for url
in urls
]
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
):
220 settings
= self
.app_engine_web_xml
.vm_settings
221 statements
= ['vm_settings:']
222 for name
in sorted(settings
):
225 self
.SanitizeForYaml(name
), self
.SanitizeForYaml(settings
[name
])))
228 def TranslateInboundServices(self
):
229 services
= self
.app_engine_web_xml
.inbound_services
233 statements
= ['inbound_services:']
234 for service
in sorted(services
):
235 statements
.append('- %s' % service
)
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
:
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('/'):
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
)
257 statements
.append(' mime_type: %s' % mime_type
)
261 def TranslateBackendsXml(self
):
262 """Translates backends.xml backends settings to yaml."""
263 if not self
.backends_xml
:
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
)))
277 options_str
= ', '.join(sorted(list(backend
.options
)))
278 statements
.append(' options: %s' % options_str
)
281 def TranslateHandlers(self
):
282 return handler_generator
.GenerateYamlHandlersList(
283 self
.app_engine_web_xml
,
287 def VerifyRequiredEntriesPresent(self
):
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
]
296 raise AppEngineConfigException('Missing required fields: %s' %