• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import os
6import sys
7import subprocess
8import tempfile
9import StringIO
10
11from py_vulcanize import html_generation_controller
12
13
14html_warning_message = """
15
16
17<!--
18WARNING: This file is auto generated.
19
20         Do not edit directly.
21-->
22"""
23
24js_warning_message = """
25// Copyright 2015 The Chromium Authors. All rights reserved.
26// Use of this source code is governed by a BSD-style license that can be
27// found in the LICENSE file.
28
29/* WARNING: This file is auto generated.
30 *
31 * Do not edit directly.
32 */
33"""
34
35css_warning_message = """
36/* Copyright 2015 The Chromium Authors. All rights reserved.
37 * Use of this source code is governed by a BSD-style license that can be
38 * found in the LICENSE file. */
39
40/* WARNING: This file is auto-generated.
41 *
42 * Do not edit directly.
43 */
44"""
45
46
47def _AssertIsUTF8(f):
48  if isinstance(f, StringIO.StringIO):
49    return
50  assert f.encoding == 'utf-8'
51
52
53def _MinifyJS(input_js):
54  py_vulcanize_path = os.path.abspath(os.path.join(
55      os.path.dirname(__file__), '..'))
56  rjsmin_path = os.path.abspath(
57      os.path.join(py_vulcanize_path, 'third_party', 'rjsmin', 'rjsmin.py'))
58
59  with tempfile.NamedTemporaryFile() as _:
60    args = [
61        'python',
62        rjsmin_path
63    ]
64    p = subprocess.Popen(args,
65                         stdin=subprocess.PIPE,
66                         stdout=subprocess.PIPE,
67                         stderr=subprocess.PIPE)
68    res = p.communicate(input=input_js)
69    errorcode = p.wait()
70    if errorcode != 0:
71      sys.stderr.write('rJSmin exited with error code %d' % errorcode)
72      sys.stderr.write(res[1])
73      raise Exception('Failed to minify, omgah')
74    return res[0]
75
76
77def GenerateJS(load_sequence,
78               use_include_tags_for_scripts=False,
79               dir_for_include_tag_root=None,
80               minify=False,
81               report_sizes=False):
82  f = StringIO.StringIO()
83  GenerateJSToFile(f,
84                   load_sequence,
85                   use_include_tags_for_scripts,
86                   dir_for_include_tag_root,
87                   minify=minify,
88                   report_sizes=report_sizes)
89
90  return f.getvalue()
91
92
93def GenerateJSToFile(f,
94                     load_sequence,
95                     use_include_tags_for_scripts=False,
96                     dir_for_include_tag_root=None,
97                     minify=False,
98                     report_sizes=False):
99  _AssertIsUTF8(f)
100  if use_include_tags_for_scripts and dir_for_include_tag_root is None:
101    raise Exception('Must provide dir_for_include_tag_root')
102
103  f.write(js_warning_message)
104  f.write('\n')
105
106  if not minify:
107    flatten_to_file = f
108  else:
109    flatten_to_file = StringIO.StringIO()
110
111  for module in load_sequence:
112    module.AppendJSContentsToFile(flatten_to_file,
113                                  use_include_tags_for_scripts,
114                                  dir_for_include_tag_root)
115  if minify:
116    js = flatten_to_file.getvalue()
117    minified_js = _MinifyJS(js)
118    f.write(minified_js)
119    f.write('\n')
120
121  if report_sizes:
122    for module in load_sequence:
123      s = StringIO.StringIO()
124      module.AppendJSContentsToFile(s,
125                                    use_include_tags_for_scripts,
126                                    dir_for_include_tag_root)
127
128      # Add minified size info.
129      js = s.getvalue()
130      min_js_size = str(len(_MinifyJS(js)))
131
132      # Print names for this module. Some domain-specific simplifications
133      # are included to make pivoting more obvious.
134      parts = module.name.split('.')
135      if parts[:2] == ['base', 'ui']:
136        parts = ['base_ui'] + parts[2:]
137      if parts[:2] == ['tracing', 'importer']:
138        parts = ['importer'] + parts[2:]
139      tln = parts[0]
140      sln = '.'.join(parts[:2])
141
142      # Output
143      print '%i\t%s\t%s\t%s\t%s' % (len(js), min_js_size, module.name, tln, sln)
144      sys.stdout.flush()
145
146
147class ExtraScript(object):
148
149  def __init__(self, script_id=None, text_content=None, content_type=None):
150    if script_id is not None:
151      assert script_id[0] != '#'
152    self.script_id = script_id
153    self.text_content = text_content
154    self.content_type = content_type
155
156  def WriteToFile(self, output_file):
157    _AssertIsUTF8(output_file)
158    attrs = []
159    if self.script_id:
160      attrs.append('id="%s"' % self.script_id)
161    if self.content_type:
162      attrs.append('content-type="%s"' % self.content_type)
163
164    if len(attrs) > 0:
165      output_file.write('<script %s>\n' % ' '.join(attrs))
166    else:
167      output_file.write('<script>\n')
168    if self.text_content:
169      output_file.write(self.text_content)
170    output_file.write('</script>\n')
171
172
173def _MinifyCSS(css_text):
174  py_vulcanize_path = os.path.abspath(os.path.join(
175      os.path.dirname(__file__), '..'))
176  rcssmin_path = os.path.abspath(
177      os.path.join(py_vulcanize_path, 'third_party', 'rcssmin', 'rcssmin.py'))
178
179  with tempfile.NamedTemporaryFile() as _:
180    rcssmin_args = ['python', rcssmin_path]
181    p = subprocess.Popen(rcssmin_args,
182                         stdin=subprocess.PIPE,
183                         stdout=subprocess.PIPE,
184                         stderr=subprocess.PIPE)
185    res = p.communicate(input=css_text)
186    errorcode = p.wait()
187    if errorcode != 0:
188      sys.stderr.write('rCSSmin exited with error code %d' % errorcode)
189      sys.stderr.write(res[1])
190      raise Exception('Failed to generate css for %s.' % css_text)
191    return res[0]
192
193
194def GenerateStandaloneHTMLAsString(*args, **kwargs):
195  f = StringIO.StringIO()
196  GenerateStandaloneHTMLToFile(f, *args, **kwargs)
197  return f.getvalue()
198
199
200def GenerateStandaloneHTMLToFile(output_file,
201                                 load_sequence,
202                                 title=None,
203                                 flattened_js_url=None,
204                                 extra_scripts=None,
205                                 minify=False,
206                                 report_sizes=False,
207                                 output_html_head_and_body=True):
208  """Writes a HTML file with the content of all modules in a load sequence.
209
210  The load_sequence is a list of (HTML or JS) Module objects; the order that
211  they're inserted into the file depends on their type and position in the load
212  sequence.
213  """
214  _AssertIsUTF8(output_file)
215  extra_scripts = extra_scripts or []
216
217  if output_html_head_and_body:
218    output_file.write(
219        '<!DOCTYPE html>\n'
220        '<html>\n'
221        '  <head i18n-values="dir:textdirection;">\n'
222        '  <meta http-equiv="Content-Type" content="text/html;'
223        'charset=utf-8">\n')
224    if title:
225      output_file.write('  <title>%s</title>\n  ' % title)
226  else:
227    assert title is None
228
229  loader = load_sequence[0].loader
230
231  written_style_sheets = set()
232
233  class HTMLGenerationController(
234      html_generation_controller.HTMLGenerationController):
235
236    def __init__(self, module):
237      self.module = module
238
239    def GetHTMLForStylesheetHRef(self, href):
240      resource = self.module.HRefToResource(
241          href, '<link rel="stylesheet" href="%s">' % href)
242      style_sheet = loader.LoadStyleSheet(resource.name)
243
244      if style_sheet in written_style_sheets:
245        return None
246      written_style_sheets.add(style_sheet)
247
248      text = style_sheet.contents_with_inlined_images
249      if minify:
250        text = _MinifyCSS(text)
251      return '<style>\n%s\n</style>' % text
252
253  for module in load_sequence:
254    controller = HTMLGenerationController(module)
255    module.AppendHTMLContentsToFile(output_file, controller, minify=minify)
256
257  if flattened_js_url:
258    output_file.write('<script src="%s"></script>\n' % flattened_js_url)
259  else:
260    output_file.write('<script>\n')
261    js = GenerateJS(load_sequence, minify=minify, report_sizes=report_sizes)
262    output_file.write(js)
263    output_file.write('</script>\n')
264
265  for extra_script in extra_scripts:
266    extra_script.WriteToFile(output_file)
267
268  if output_html_head_and_body:
269    output_file.write('</head>\n  <body>\n  </body>\n</html>\n')
270