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 tvcm 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 (c) 2014 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 (c) 2014 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 tvcm_path = os.path.abspath(os.path.join( 55 os.path.dirname(__file__), '..')) 56 rjsmin_path = os.path.abspath( 57 os.path.join(tvcm_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 pt_parts(self): 94 sl = ['unicode and 8-bit string parts of above page template'] 95 for x in self.buflist: 96 if type(x) == type(''): 97 maxcode = 0 98 for c in x: 99 maxcode = max(ord(c), maxcode) 100 # show only unicode objects and non-ascii strings 101 if type(x) == type('') and maxcode > 127: 102 t = '****NonAsciiStr: ' 103 elif type(x) == type(u''): 104 t = '*****UnicodeStr: ' 105 else: 106 t = None 107 if t: 108 sl.append(t + repr(x)) 109 s = '\n'.join(sl) 110 return s 111 112 113def GenerateJSToFile(f, 114 load_sequence, 115 use_include_tags_for_scripts=False, 116 dir_for_include_tag_root=None, 117 minify=False, 118 report_sizes=False): 119 _AssertIsUTF8(f) 120 if use_include_tags_for_scripts and dir_for_include_tag_root is None: 121 raise Exception('Must provide dir_for_include_tag_root') 122 123 f.write(js_warning_message) 124 f.write('\n') 125 126 loader = load_sequence[0].loader 127 128 polymer_script = loader.LoadRawScript('components/polymer/polymer.min.js') 129 f.write(polymer_script.contents) 130 131 if not minify: 132 flatten_to_file = f 133 else: 134 flatten_to_file = StringIO.StringIO() 135 136 for module in load_sequence: 137 module.AppendJSContentsToFile(flatten_to_file, 138 use_include_tags_for_scripts, 139 dir_for_include_tag_root) 140 if minify: 141 js = flatten_to_file.getvalue() 142 minified_js = _MinifyJS(js) 143 f.write(minified_js) 144 f.write('\n') 145 146 if report_sizes: 147 for module in load_sequence: 148 s = StringIO.StringIO() 149 module.AppendJSContentsToFile(s, 150 use_include_tags_for_scripts, 151 dir_for_include_tag_root) 152 153 # Add minified size info. 154 js = s.getvalue() 155 min_js_size = str(len(_MinifyJS(js))) 156 157 # Print names for this module. Some domain-specific simplifciations 158 # are included to make pivoting more obvious. 159 parts = module.name.split('.') 160 if parts[:2] == ['base', 'ui']: 161 parts = ['base_ui'] + parts[2:] 162 if parts[:2] == ['tracing', 'importer']: 163 parts = ['importer'] + parts[2:] 164 tln = parts[0] 165 sln = '.'.join(parts[:2]) 166 167 # Ouptut 168 print '%i\t%s\t%s\t%s\t%s' % (len(js), min_js_size, module.name, tln, sln) 169 sys.stdout.flush() 170 171 172class ExtraScript(object): 173 def __init__(self, script_id=None, text_content=None, content_type=None): 174 if script_id is not None: 175 assert script_id[0] != '#' 176 self.script_id = script_id 177 self.text_content = text_content 178 self.content_type = content_type 179 180 def WriteToFile(self, output_file): 181 _AssertIsUTF8(output_file) 182 attrs = [] 183 if self.script_id: 184 attrs.append('id="%s"' % self.script_id) 185 if self.content_type: 186 attrs.append('content-type="%s"' % self.content_type) 187 188 if len(attrs) > 0: 189 output_file.write('<script %s>\n' % ' '.join(attrs)) 190 else: 191 output_file.write('<script>\n') 192 if self.text_content: 193 output_file.write(self.text_content) 194 output_file.write('</script>\n') 195 196 197def _MinifyCSS(css_text): 198 tvcm_path = os.path.abspath(os.path.join( 199 os.path.dirname(__file__), '..')) 200 rcssmin_path = os.path.abspath( 201 os.path.join(tvcm_path, 'third_party', 'rcssmin', 'rcssmin.py')) 202 203 with tempfile.NamedTemporaryFile() as _: 204 rcssmin_args = ['python', rcssmin_path] 205 p = subprocess.Popen(rcssmin_args, 206 stdin=subprocess.PIPE, 207 stdout=subprocess.PIPE, 208 stderr=subprocess.PIPE) 209 res = p.communicate(input=css_text) 210 errorcode = p.wait() 211 if errorcode != 0: 212 sys.stderr.write('rCSSmin exited with error code %d' % errorcode) 213 sys.stderr.write(res[1]) 214 raise Exception('Failed to generate css for %s.' % css_text) 215 return res[0] 216 217 218def GenerateStandaloneHTMLAsString(*args, **kwargs): 219 f = StringIO.StringIO() 220 GenerateStandaloneHTMLToFile(f, *args, **kwargs) 221 return f.getvalue() 222 223 224def GenerateStandaloneHTMLToFile(output_file, 225 load_sequence, 226 title=None, 227 flattened_js_url=None, 228 extra_scripts=None, 229 minify=False, 230 report_sizes=False, 231 output_html_head_and_body=True): 232 _AssertIsUTF8(output_file) 233 extra_scripts = extra_scripts or [] 234 235 if output_html_head_and_body: 236 output_file.write("""<!DOCTYPE HTML> 237<html> 238 <head i18n-values="dir:textdirection;"> 239 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 240 """) 241 if title: 242 output_file.write(""" <title>%s</title> 243 """ % title) 244 else: 245 assert title is None 246 247 loader = load_sequence[0].loader 248 249 written_style_sheets = set() 250 251 class HTMLGenerationController( 252 html_generation_controller.HTMLGenerationController): 253 254 def __init__(self, module): 255 self.module = module 256 257 def GetHTMLForStylesheetHRef(self, href): 258 resource = self.module.HRefToResource( 259 href, '<link rel="stylesheet" href="%s">' % href) 260 style_sheet = loader.LoadStyleSheet(resource.name) 261 262 if style_sheet in written_style_sheets: 263 return None 264 written_style_sheets.add(style_sheet) 265 266 text = style_sheet.contents_with_inlined_images 267 if minify: 268 text = _MinifyCSS(text) 269 return '<style>\n%s\n</style>' % text 270 271 for module in load_sequence: 272 ctl = HTMLGenerationController(module) 273 module.AppendHTMLContentsToFile(output_file, ctl, minify=minify) 274 275 if flattened_js_url: 276 output_file.write('<script src="%s"></script>\n' % flattened_js_url) 277 else: 278 output_file.write('<script>\n') 279 x = GenerateJS(load_sequence, minify=minify, report_sizes=report_sizes) 280 output_file.write(x) 281 output_file.write('</script>\n') 282 283 for extra_script in extra_scripts: 284 extra_script.WriteToFile(output_file) 285 286 if output_html_head_and_body: 287 output_file.write("""</head> 288 <body> 289 </body> 290</html> 291""") 292