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 codecs 6import base64 7import gzip 8import json 9import optparse 10import os 11import StringIO 12import sys 13 14tracing_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 15 '..', '..')) 16if tracing_path not in sys.path: 17 sys.path.append(tracing_path) 18 19from tracing import tracing_project 20from tvcm import generate 21 22 23def Main(args): 24 25 parser = optparse.OptionParser( 26 usage="%prog <options> trace_file1 [trace_file2 ...]", 27 epilog="""Takes the provided trace file and produces a standalone html 28file that contains both the trace and the trace viewer.""") 29 30 project = tracing_project.TracingProject() 31 project.AddConfigNameOptionToParser(parser) 32 33 parser.add_option( 34 "--output", dest="output", 35 help='Where to put the generated result. If not ' + 36 'given, the trace filename is used, with an html suffix.') 37 parser.add_option( 38 "--quiet", action='store_true', 39 help='Dont print the output file name') 40 options, args = parser.parse_args(args) 41 if len(args) == 0: 42 parser.error('At least one trace file required') 43 44 if options.output: 45 output_filename = options.output 46 elif len(args) > 1: 47 parser.error('Must specify --output if >1 trace file') 48 else: 49 namepart = os.path.splitext(args[0])[0] 50 output_filename = namepart + '.html' 51 52 with codecs.open(output_filename, mode='w', encoding='utf-8') as f: 53 WriteHTMLForTracesToFile(args, f, config_name=options.config_name) 54 55 if not options.quiet: 56 print output_filename 57 return 0 58 59 60class ViewerDataScript(generate.ExtraScript): 61 62 def __init__(self, trace_data_string, mime_type): 63 super(ViewerDataScript, self).__init__() 64 self._trace_data_string = trace_data_string 65 self._mime_type = mime_type 66 67 def WriteToFile(self, output_file): 68 output_file.write('<script id="viewer-data" type="%s">\n' % self._mime_type) 69 compressed_trace = StringIO.StringIO() 70 with gzip.GzipFile(fileobj=compressed_trace, mode='w') as f: 71 f.write(self._trace_data_string) 72 b64_content = base64.b64encode(compressed_trace.getvalue()) 73 output_file.write(b64_content) 74 output_file.write('\n</script>\n') 75 76 77def WriteHTMLForTraceDataToFile(trace_data_list, 78 title, output_file, 79 config_name=None): 80 project = tracing_project.TracingProject() 81 82 if config_name is None: 83 config_name = project.GetDefaultConfigName() 84 85 modules = [ 86 'trace2html', 87 'extras.importer.gzip_importer', # Must have this regardless of config. 88 project.GetModuleNameForConfigName(config_name) 89 ] 90 91 load_sequence = project.CalcLoadSequenceForModuleNames(modules) 92 93 scripts = [] 94 for trace_data in trace_data_list: 95 # If the object was previously decoded from valid JSON data (e.g., in 96 # WriteHTMLForTracesToFile), it will be a JSON object at this point and we 97 # should re-serialize it into a string. Other types of data will be already 98 # be strings. 99 if not isinstance(trace_data, basestring): 100 trace_data = json.dumps(trace_data) 101 mime_type = 'application/json' 102 else: 103 mime_type = 'text/plain' 104 scripts.append(ViewerDataScript(trace_data, mime_type)) 105 generate.GenerateStandaloneHTMLToFile( 106 output_file, load_sequence, title, extra_scripts=scripts) 107 108 109def WriteHTMLForTracesToFile(trace_filenames, output_file, config_name=None): 110 trace_data_list = [] 111 for filename in trace_filenames: 112 with open(filename, 'r') as f: 113 trace_data = f.read() 114 try: 115 trace_data = json.loads(trace_data) 116 except ValueError: 117 pass 118 trace_data_list.append(trace_data) 119 120 title = "Trace from %s" % ','.join(trace_filenames) 121 WriteHTMLForTraceDataToFile(trace_data_list, title, output_file, config_name) 122