OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Creates a directory with with the unpacked contents of the remoting webapp. | 6 """Creates a directory with with the unpacked contents of the remoting webapp. |
7 | 7 |
8 The directory will contain a copy-of or a link-to to all remoting webapp | 8 The directory will contain a copy-of or a link-to to all remoting webapp |
9 resources. This includes HTML/JS and any plugin binaries. The script also | 9 resources. This includes HTML/JS and any plugin binaries. The script also |
10 massages resulting files appropriately with host plugin data. Finally, | 10 massages resulting files appropriately with host plugin data. Finally, |
11 a zip archive for all of the above is produced. | 11 a zip archive for all of the above is produced. |
12 """ | 12 """ |
13 | 13 |
14 # Python 2.5 compatibility | 14 # Python 2.5 compatibility |
15 from __future__ import with_statement | 15 from __future__ import with_statement |
16 | 16 |
17 import argparse | |
17 import io | 18 import io |
18 import os | 19 import os |
19 import platform | 20 import platform |
20 import re | 21 import re |
21 import shutil | 22 import shutil |
22 import subprocess | 23 import subprocess |
23 import sys | 24 import sys |
24 import time | 25 import time |
25 import zipfile | 26 import zipfile |
26 | 27 |
(...skipping 28 matching lines...) Expand all Loading... | |
55 rel_path = os.path.relpath(full_path, directory) | 56 rel_path = os.path.relpath(full_path, directory) |
56 zip.write(full_path, os.path.join(zipfile_base, rel_path)) | 57 zip.write(full_path, os.path.join(zipfile_base, rel_path)) |
57 zip.close() | 58 zip.close() |
58 | 59 |
59 | 60 |
60 def replaceString(destination, placeholder, value): | 61 def replaceString(destination, placeholder, value): |
61 findAndReplace(os.path.join(destination, 'plugin_settings.js'), | 62 findAndReplace(os.path.join(destination, 'plugin_settings.js'), |
62 "'" + placeholder + "'", "'" + value + "'") | 63 "'" + placeholder + "'", "'" + value + "'") |
63 | 64 |
64 | 65 |
66 def replaceBool(destination, placeholder, value): | |
67 findAndReplace(os.path.join(destination, 'plugin_settings.js'), | |
68 "!!'" + placeholder + "'", 'true' if value else 'false') | |
Sergey Ulanov
2015/03/25 18:56:43
Why do you need !! here?
John Williams
2015/03/25 20:32:19
The JS code is typechecked before being processed
Sergey Ulanov
2015/03/25 20:50:50
Right, but type is explicitly specified there anyw
John Williams
2015/03/25 22:54:51
Done.
| |
69 | |
70 | |
65 def processJinjaTemplate(input_file, include_paths, output_file, context): | 71 def processJinjaTemplate(input_file, include_paths, output_file, context): |
66 jinja2_path = os.path.normpath( | 72 jinja2_path = os.path.normpath( |
67 os.path.join(os.path.abspath(__file__), | 73 os.path.join(os.path.abspath(__file__), |
68 '../../../third_party/jinja2')) | 74 '../../../third_party/jinja2')) |
69 sys.path.append(os.path.split(jinja2_path)[0]) | 75 sys.path.append(os.path.split(jinja2_path)[0]) |
70 import jinja2 | 76 import jinja2 |
71 (template_path, template_name) = os.path.split(input_file) | 77 (template_path, template_name) = os.path.split(input_file) |
72 include_paths = [template_path] + include_paths | 78 include_paths = [template_path] + include_paths |
73 env = jinja2.Environment(loader=jinja2.FileSystemLoader(include_paths)) | 79 env = jinja2.Environment(loader=jinja2.FileSystemLoader(include_paths)) |
74 template = env.get_template(template_name) | 80 template = env.get_template(template_name) |
75 rendered = template.render(context) | 81 rendered = template.render(context) |
76 io.open(output_file, 'w', encoding='utf-8').write(rendered) | 82 io.open(output_file, 'w', encoding='utf-8').write(rendered) |
77 | 83 |
78 def buildWebApp(buildtype, version, destination, zip_path, | 84 def buildWebApp(buildtype, version, destination, zip_path, |
79 manifest_template, webapp_type, app_id, app_name, | 85 manifest_template, webapp_type, appid, app_name, |
80 app_description, app_capabilities, files, locales, jinja_paths, | 86 app_description, app_capabilities, files, locales_listfile, |
81 service_environment): | 87 jinja_paths, service_environment, use_gcd): |
82 """Does the main work of building the webapp directory and zipfile. | 88 """Does the main work of building the webapp directory and zipfile. |
83 | 89 |
84 Args: | 90 Args: |
85 buildtype: the type of build ("Official", "Release" or "Dev"). | 91 buildtype: the type of build ("Official", "Release" or "Dev"). |
86 destination: A string with path to directory where the webapp will be | 92 destination: A string with path to directory where the webapp will be |
87 written. | 93 written. |
88 zipfile: A string with path to the zipfile to create containing the | 94 zipfile: A string with path to the zipfile to create containing the |
89 contents of |destination|. | 95 contents of |destination|. |
90 manifest_template: jinja2 template file for manifest. | 96 manifest_template: jinja2 template file for manifest. |
91 webapp_type: webapp type ("v1", "v2", "v2_pnacl" or "app_remoting"). | 97 webapp_type: webapp type ("v1", "v2", "v2_pnacl" or "app_remoting"). |
92 app_id: A string with the Remoting Application Id (only used for app | 98 appid: A string with the Remoting Application Id (only used for app |
93 remoting webapps). If supplied, it defaults to using the | 99 remoting webapps). If supplied, it defaults to using the |
94 test API server. | 100 test API server. |
95 app_name: A string with the name of the application. | 101 app_name: A string with the name of the application. |
96 app_description: A string with the description of the application. | 102 app_description: A string with the description of the application. |
97 app_capabilities: A set of strings naming the capabilities that should be | 103 app_capabilities: A set of strings naming the capabilities that should be |
98 enabled for this application. | 104 enabled for this application. |
99 files: An array of strings listing the paths for resources to include | 105 files: An array of strings listing the paths for resources to include |
100 in this webapp. | 106 in this webapp. |
101 locales: An array of strings listing locales, which are copied, along | 107 locales_listfile: The name of a file containing a list of locales, one per |
102 with their directory structure from the _locales directory down. | 108 line, which are copied, along with their directory structure, from |
109 the _locales directory down. | |
103 jinja_paths: An array of paths to search for {%include} directives in | 110 jinja_paths: An array of paths to search for {%include} directives in |
104 addition to the directory containing the manifest template. | 111 addition to the directory containing the manifest template. |
105 service_environment: Used to point the webApp to one of the | 112 service_environment: Used to point the webApp to one of the |
106 dev/test/staging/prod environments | 113 dev/test/staging/prod environments |
114 use_gcd: True if GCD support should be enabled. | |
107 """ | 115 """ |
116 | |
117 # Load the locales files from the locales_listfile. | |
118 if not locales_listfile: | |
119 raise Exception('You must specify a locales_listfile') | |
120 locales = [] | |
121 with open(locales_listfile) as input: | |
122 for s in input: | |
123 locales.append(s.rstrip()) | |
124 | |
108 # Ensure a fresh directory. | 125 # Ensure a fresh directory. |
109 try: | 126 try: |
110 shutil.rmtree(destination) | 127 shutil.rmtree(destination) |
111 except OSError: | 128 except OSError: |
112 if os.path.exists(destination): | 129 if os.path.exists(destination): |
113 raise | 130 raise |
114 else: | 131 else: |
115 pass | 132 pass |
116 os.mkdir(destination, 0775) | 133 os.mkdir(destination, 0775) |
117 | 134 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 # apps for release (no impersonation) instead of dev. | 200 # apps for release (no impersonation) instead of dev. |
184 if service_environment == 'prod' and buildtype == 'Dev': | 201 if service_environment == 'prod' and buildtype == 'Dev': |
185 raise Exception("Prod environment cannot be built for 'dev' builds") | 202 raise Exception("Prod environment cannot be built for 'dev' builds") |
186 | 203 |
187 if buildtype != 'Dev': | 204 if buildtype != 'Dev': |
188 if service_environment != 'prod': | 205 if service_environment != 'prod': |
189 raise Exception('Invalid service_environment targeted for ' | 206 raise Exception('Invalid service_environment targeted for ' |
190 + buildtype + ': ' + service_environment) | 207 + buildtype + ': ' + service_environment) |
191 if 'out/Release' not in destination and 'out\Release' not in destination: | 208 if 'out/Release' not in destination and 'out\Release' not in destination: |
192 raise Exception('Prod builds must be placed in the out/Release folder') | 209 raise Exception('Prod builds must be placed in the out/Release folder') |
193 if app_id != None: | 210 if appid != None: |
194 raise Exception('Cannot pass in an app_id for ' | 211 raise Exception('Cannot pass in an appid for ' |
195 + buildtype + ' builds: ' + service_environment) | 212 + buildtype + ' builds: ' + service_environment) |
196 if appRemotingApiHost != None: | 213 if appRemotingApiHost != None: |
197 raise Exception('Cannot set APP_REMOTING_API_HOST env var for ' | 214 raise Exception('Cannot set APP_REMOTING_API_HOST env var for ' |
198 + buildtype + ' builds') | 215 + buildtype + ' builds') |
199 if appRemotingApplicationId != None: | 216 if appRemotingApplicationId != None: |
200 raise Exception('Cannot set APP_REMOTING_APPLICATION_ID env var for ' | 217 raise Exception('Cannot set APP_REMOTING_APPLICATION_ID env var for ' |
201 + buildtype + ' builds') | 218 + buildtype + ' builds') |
202 | 219 |
203 # If an Application ID was set (either from service_environment variable or | 220 # If an Application ID was set (either from service_environment variable or |
204 # from a command line argument), hardcode it, otherwise get it at runtime. | 221 # from a command line argument), hardcode it, otherwise get it at runtime. |
205 effectiveAppId = appRemotingApplicationId or app_id | 222 effectiveAppId = appRemotingApplicationId or appid |
206 if effectiveAppId: | 223 if effectiveAppId: |
207 appRemotingApplicationId = "'" + effectiveAppId + "'" | 224 appRemotingApplicationId = "'" + effectiveAppId + "'" |
208 else: | 225 else: |
209 appRemotingApplicationId = "chrome.i18n.getMessage('@@extension_id')" | 226 appRemotingApplicationId = "chrome.i18n.getMessage('@@extension_id')" |
210 findAndReplace(os.path.join(destination, 'plugin_settings.js'), | 227 findAndReplace(os.path.join(destination, 'plugin_settings.js'), |
211 "'APP_REMOTING_APPLICATION_ID'", appRemotingApplicationId) | 228 "'APP_REMOTING_APPLICATION_ID'", appRemotingApplicationId) |
212 | 229 |
213 oauth2BaseUrl = oauth2AccountsHost + '/o/oauth2' | 230 oauth2BaseUrl = oauth2AccountsHost + '/o/oauth2' |
214 oauth2ApiBaseUrl = oauth2ApiHost + '/oauth2' | 231 oauth2ApiBaseUrl = oauth2ApiHost + '/oauth2' |
215 directoryApiBaseUrl = directoryApiHost + '/chromoting/v1' | 232 directoryApiBaseUrl = directoryApiHost + '/chromoting/v1' |
(...skipping 13 matching lines...) Expand all Loading... | |
229 elif service_environment == 'staging': | 246 elif service_environment == 'staging': |
230 appRemotingServicePath = '/appremoting/v1beta1_staging' | 247 appRemotingServicePath = '/appremoting/v1beta1_staging' |
231 elif service_environment == 'prod': | 248 elif service_environment == 'prod': |
232 appRemotingServicePath = '/appremoting/v1beta1' | 249 appRemotingServicePath = '/appremoting/v1beta1' |
233 else: | 250 else: |
234 raise Exception('Unknown service environment: ' + service_environment) | 251 raise Exception('Unknown service environment: ' + service_environment) |
235 appRemotingApiBaseUrl = appRemotingApiHost + appRemotingServicePath | 252 appRemotingApiBaseUrl = appRemotingApiHost + appRemotingServicePath |
236 else: | 253 else: |
237 appRemotingApiBaseUrl = '' | 254 appRemotingApiBaseUrl = '' |
238 | 255 |
256 replaceBool(destination, 'USE_GCD', use_gcd) | |
239 replaceString(destination, 'OAUTH2_BASE_URL', oauth2BaseUrl) | 257 replaceString(destination, 'OAUTH2_BASE_URL', oauth2BaseUrl) |
240 replaceString(destination, 'OAUTH2_API_BASE_URL', oauth2ApiBaseUrl) | 258 replaceString(destination, 'OAUTH2_API_BASE_URL', oauth2ApiBaseUrl) |
241 replaceString(destination, 'DIRECTORY_API_BASE_URL', directoryApiBaseUrl) | 259 replaceString(destination, 'DIRECTORY_API_BASE_URL', directoryApiBaseUrl) |
242 if webapp_type == 'app_remoting': | 260 if webapp_type == 'app_remoting': |
243 replaceString(destination, 'APP_REMOTING_API_BASE_URL', | 261 replaceString(destination, 'APP_REMOTING_API_BASE_URL', |
244 appRemotingApiBaseUrl) | 262 appRemotingApiBaseUrl) |
245 | 263 |
246 # Substitute hosts in the manifest's CSP list. | 264 # Substitute hosts in the manifest's CSP list. |
247 # Ensure we list the API host only once if it's the same for multiple APIs. | 265 # Ensure we list the API host only once if it's the same for multiple APIs. |
248 googleApiHosts = ' '.join(set([oauth2ApiHost, directoryApiHost])) | 266 googleApiHosts = ' '.join(set([oauth2ApiHost, directoryApiHost])) |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
315 # Use a consistent extension id for dev builds. | 333 # Use a consistent extension id for dev builds. |
316 # AppRemoting builds always use the dev app id - the correct app id gets | 334 # AppRemoting builds always use the dev app id - the correct app id gets |
317 # written into the manifest later. | 335 # written into the manifest later. |
318 if buildtype != 'Official' or webapp_type == 'app_remoting': | 336 if buildtype != 'Official' or webapp_type == 'app_remoting': |
319 manifestKey = '"key": "remotingdevbuild",' | 337 manifestKey = '"key": "remotingdevbuild",' |
320 else: | 338 else: |
321 manifestKey = '' | 339 manifestKey = '' |
322 | 340 |
323 # Generate manifest. | 341 # Generate manifest. |
324 if manifest_template: | 342 if manifest_template: |
343 print 'args.use_gcd {!r}'.format(use_gcd) | |
Sergey Ulanov
2015/03/25 18:56:43
remove this?
John Williams
2015/03/25 20:32:19
Oops.
| |
325 context = { | 344 context = { |
326 'webapp_type': webapp_type, | 345 'webapp_type': webapp_type, |
327 'FULL_APP_VERSION': version, | 346 'FULL_APP_VERSION': version, |
328 'MANIFEST_KEY_FOR_UNOFFICIAL_BUILD': manifestKey, | 347 'MANIFEST_KEY_FOR_UNOFFICIAL_BUILD': manifestKey, |
329 'OAUTH2_REDIRECT_URL': oauth2RedirectUrlJson, | 348 'OAUTH2_REDIRECT_URL': oauth2RedirectUrlJson, |
330 'TALK_GADGET_HOST': talkGadgetHostJson, | 349 'TALK_GADGET_HOST': talkGadgetHostJson, |
331 'THIRD_PARTY_AUTH_REDIRECT_URL': thirdPartyAuthUrlJson, | 350 'THIRD_PARTY_AUTH_REDIRECT_URL': thirdPartyAuthUrlJson, |
332 'REMOTING_IDENTITY_API_CLIENT_ID': apiClientIdV2, | 351 'REMOTING_IDENTITY_API_CLIENT_ID': apiClientIdV2, |
333 'OAUTH2_BASE_URL': oauth2BaseUrl, | 352 'OAUTH2_BASE_URL': oauth2BaseUrl, |
334 'OAUTH2_API_BASE_URL': oauth2ApiBaseUrl, | 353 'OAUTH2_API_BASE_URL': oauth2ApiBaseUrl, |
335 'DIRECTORY_API_BASE_URL': directoryApiBaseUrl, | 354 'DIRECTORY_API_BASE_URL': directoryApiBaseUrl, |
336 'APP_REMOTING_API_BASE_URL': appRemotingApiBaseUrl, | 355 'APP_REMOTING_API_BASE_URL': appRemotingApiBaseUrl, |
337 'OAUTH2_ACCOUNTS_HOST': oauth2AccountsHost, | 356 'OAUTH2_ACCOUNTS_HOST': oauth2AccountsHost, |
338 'GOOGLE_API_HOSTS': googleApiHosts, | 357 'GOOGLE_API_HOSTS': googleApiHosts, |
339 'APP_NAME': app_name, | 358 'APP_NAME': app_name, |
340 'APP_DESCRIPTION': app_description, | 359 'APP_DESCRIPTION': app_description, |
341 'OAUTH_GDRIVE_SCOPE': '', | 360 'OAUTH_GDRIVE_SCOPE': '', |
361 'USE_GCD': use_gcd, | |
342 'XMPP_SERVER': xmppServer, | 362 'XMPP_SERVER': xmppServer, |
343 } | 363 } |
344 if 'GOOGLE_DRIVE' in app_capabilities: | 364 if 'GOOGLE_DRIVE' in app_capabilities: |
345 context['OAUTH_GDRIVE_SCOPE'] = ('https://docs.google.com/feeds/ ' | 365 context['OAUTH_GDRIVE_SCOPE'] = ('https://docs.google.com/feeds/ ' |
346 'https://www.googleapis.com/auth/drive') | 366 'https://www.googleapis.com/auth/drive') |
347 processJinjaTemplate(manifest_template, | 367 processJinjaTemplate(manifest_template, |
348 jinja_paths, | 368 jinja_paths, |
349 os.path.join(destination, 'manifest.json'), | 369 os.path.join(destination, 'manifest.json'), |
350 context) | 370 context) |
351 | 371 |
352 # Make the zipfile. | 372 # Make the zipfile. |
353 createZip(zip_path, destination) | 373 createZip(zip_path, destination) |
354 | 374 |
355 return 0 | 375 return 0 |
356 | 376 |
357 | 377 |
358 def main(): | 378 def main(): |
359 if len(sys.argv) < 6: | 379 parser = argparse.ArgumentParser() |
360 print ('Usage: build-webapp.py ' | 380 parser.add_argument('buildtype') |
361 '<build-type> <version> <dst> <zip-path> <manifest_template> ' | 381 parser.add_argument('version') |
362 '<webapp_type> <other files...> ' | 382 parser.add_argument('destination') |
363 '--app_name <name> ' | 383 parser.add_argument('zip_path') |
364 '--app_description <description> ' | 384 parser.add_argument('manifest_template') |
365 '--app_capabilities <capabilities...> ' | 385 parser.add_argument('webapp_type') |
366 '[--appid <appid>] ' | 386 parser.add_argument('files', nargs='*', metavar='file', default=[]) |
367 '[--locales_listfile <locales-listfile-name>] ' | 387 parser.add_argument('--app_name', metavar='NAME') |
368 '[--jinja_paths <paths...>] ' | 388 parser.add_argument('--app_description', metavar='TEXT') |
369 '[--service_environment <service_environment>]') | 389 parser.add_argument('--app_capabilities', |
370 return 1 | 390 nargs='*', default=[], metavar='CAPABILITY') |
391 parser.add_argument('--appid') | |
392 parser.add_argument('--locales_listfile', default='', metavar='PATH') | |
393 parser.add_argument('--jinja_paths', nargs='*', default=[], metavar='PATH') | |
394 parser.add_argument('--service_environment', default='', metavar='ENV') | |
395 parser.add_argument('--use_gcd', choices=['0', '1'], default='0') | |
371 | 396 |
372 arg_type = '' | 397 args = parser.parse_args() |
373 files = [] | 398 args.use_gcd = (args.use_gcd != '0') |
374 locales_listfile = '' | 399 args.app_capabilities = set(args.app_capabilities) |
375 jinja_paths = [] | 400 return buildWebApp(**args.__dict__) |
Sergey Ulanov
2015/03/25 18:56:43
Use dict(args) instead of args.__dict__
John Williams
2015/03/25 20:32:19
Using |dict| doesn't work, but |vars| does.
| |
376 app_id = None | |
377 app_name = None | |
378 app_description = None | |
379 app_capabilities = set([]) | |
380 service_environment = '' | |
381 | |
382 for arg in sys.argv[7:]: | |
383 if arg in ['--locales_listfile', | |
384 '--jinja_paths', | |
385 '--appid', | |
386 '--app_name', | |
387 '--app_description', | |
388 '--app_capabilities', | |
389 '--service_environment']: | |
390 arg_type = arg | |
391 elif arg_type == '--locales_listfile': | |
392 locales_listfile = arg | |
393 arg_type = '' | |
394 elif arg_type == '--jinja_paths': | |
395 jinja_paths.append(arg) | |
396 elif arg_type == '--appid': | |
397 app_id = arg | |
398 arg_type = '' | |
399 elif arg_type == '--app_name': | |
400 app_name = arg | |
401 arg_type = '' | |
402 elif arg_type == '--app_description': | |
403 app_description = arg | |
404 arg_type = '' | |
405 elif arg_type == '--app_capabilities': | |
406 app_capabilities.add(arg) | |
407 elif arg_type == '--service_environment': | |
408 service_environment = arg | |
409 arg_type = '' | |
410 else: | |
411 files.append(arg) | |
412 | |
413 # Load the locales files from the locales_listfile. | |
414 if not locales_listfile: | |
415 raise Exception('You must specify a locales_listfile') | |
416 locales = [] | |
417 with open(locales_listfile) as input: | |
418 for s in input: | |
419 locales.append(s.rstrip()) | |
420 | |
421 return buildWebApp(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], | |
422 sys.argv[5], sys.argv[6], app_id, app_name, | |
423 app_description, app_capabilities, files, locales, | |
424 jinja_paths, service_environment) | |
425 | 401 |
426 | 402 |
427 if __name__ == '__main__': | 403 if __name__ == '__main__': |
428 sys.exit(main()) | 404 sys.exit(main()) |
OLD | NEW |