14 # Description: |
14 # Description: |
15 # |
15 # |
16 |
16 |
17 import os, logging, pickle |
17 import os, logging, pickle |
18 import time |
18 import time |
|
19 import types |
19 from time import strftime |
20 from time import strftime |
20 from cone.public import api, exceptions, utils, plugin |
21 from cone.public import api, exceptions, utils, plugin |
21 from cone.confml import model |
22 from cone.confml import model |
22 from cone.report import report_util |
23 from cone.report import report_util |
23 |
24 |
24 ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) |
25 ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) |
25 SERIALISATION_FORMAT = 'pickle' |
26 SERIALISATION_FORMAT = 'pickle' |
26 |
27 |
|
28 def pickle_persistent_id(obj): |
|
29 """ |
|
30 Prepare report data for pickler. |
|
31 """ |
|
32 if isinstance(obj, (logging.Logger, types.ModuleType)): |
|
33 return "" |
|
34 elif isinstance(obj, (api.Configuration, api.ConfigurationProxy)): |
|
35 try: project_path = os.path.abspath(obj.get_project().get_storage().get_path()) |
|
36 except: project_path = None |
|
37 return "conf:" + repr(pickle.dumps((project_path, obj.path))) |
|
38 else: |
|
39 return None |
|
40 |
|
41 def persistent_load(persid): |
|
42 """ |
|
43 Prepare pickler for unpickling report data. |
|
44 """ |
|
45 global loaded_project |
|
46 if persid.startswith("impl:"): |
|
47 type_id, ref, lineno = pickle.loads(eval(persid[5:])) |
|
48 impl = plugin.ImplBase(ref, None) |
|
49 impl.IMPL_TYPE_ID = type_id |
|
50 impl.lineno = lineno |
|
51 return impl |
|
52 elif persid.startswith("conf:"): |
|
53 project_path, config_path = pickle.loads(eval(persid[5:])) |
|
54 configuration = api.ConfigurationProxy(config_path) |
|
55 if project_path: |
|
56 if not loaded_project: |
|
57 loaded_project = api.Project(api.Storage.open(project_path)) |
|
58 configuration._set_parent(loaded_project) |
|
59 return configuration |
|
60 else: |
|
61 return None |
|
62 |
27 def save_report_data(rep_data, file_path): |
63 def save_report_data(rep_data, file_path): |
28 """ |
64 """ |
29 Save report data into an intermediary report data file. |
65 Save report data into an intermediary report data file. |
30 """ |
66 """ |
31 dir = os.path.dirname(file_path) |
67 dir = os.path.dirname(file_path) |
32 if dir != '' and not os.path.exists(dir): |
68 if dir != '' and not os.path.exists(dir): |
33 os.makedirs(dir) |
69 os.makedirs(dir) |
34 f = open(file_path, 'wb') |
70 f = open(file_path, 'wb') |
|
71 |
35 try: |
72 try: |
36 if SERIALISATION_FORMAT == 'yaml': |
73 if SERIALISATION_FORMAT == 'yaml': |
37 yaml.dump(rep_data, f) |
74 yaml.dump(rep_data, f) |
38 elif SERIALISATION_FORMAT == 'pickle': |
75 elif SERIALISATION_FORMAT == 'pickle': |
39 pickle.dump(rep_data, f) |
76 pickler = pickle.Pickler(f) |
|
77 pickler.persistent_id = pickle_persistent_id |
|
78 pickler.dump(rep_data) |
40 elif SERIALISATION_FORMAT == 'pickle/2': |
79 elif SERIALISATION_FORMAT == 'pickle/2': |
41 pickle.dump(rep_data, f, 2) |
80 pickler = pickle.Pickler(f, 2) |
|
81 pickler.persistent_id = pickle_persistent_id |
|
82 pickler.dump(rep_data) |
42 finally: |
83 finally: |
43 f.close() |
84 f.close() |
44 |
85 |
45 def load_report_data(file_path): |
86 def load_report_data(file_path): |
46 """ |
87 """ |
47 Load report data from an intermediary report data file. |
88 Load report data from an intermediary report data file. |
48 """ |
89 """ |
49 try: |
90 try: |
50 f = open(file_path, "rb") |
91 f = open(file_path, "rb") |
|
92 unpickler = pickle.Unpickler(f) |
|
93 global loaded_project |
|
94 loaded_project = None |
|
95 unpickler.persistent_load = persistent_load |
|
96 |
51 if SERIALISATION_FORMAT == 'yaml': |
97 if SERIALISATION_FORMAT == 'yaml': |
52 data = yaml.load(f) |
98 data = yaml.load(f) |
53 elif SERIALISATION_FORMAT == 'pickle': |
99 elif SERIALISATION_FORMAT == 'pickle': |
54 data = pickle.load(f) |
100 data = unpickler.load() |
55 elif SERIALISATION_FORMAT == 'pickle/2': |
101 elif SERIALISATION_FORMAT == 'pickle/2': |
56 data = pickle.load(f) |
102 data = unpickler.load() |
57 finally: |
103 finally: |
58 f.close() |
104 f.close() |
59 |
105 |
60 data.label = get_generation_run_label(file_path) |
106 data.label = get_generation_run_label(file_path) |
61 return data |
107 return data |
86 """ |
132 """ |
87 # Determine the template file and directory to use |
133 # Determine the template file and directory to use |
88 if template_file_path is None: |
134 if template_file_path is None: |
89 template_file_path = 'gen_report_template.html' |
135 template_file_path = 'gen_report_template.html' |
90 contexts = [report_data.context for report_data in rep_data] |
136 contexts = [report_data.context for report_data in rep_data] |
|
137 merged_context = plugin.MergedContext(contexts) |
91 report_data = {'rep_data' : rep_data, |
138 report_data = {'rep_data' : rep_data, |
92 'report_options' : report_options, |
139 'report_options' : report_options, |
93 'merged_context' : plugin.MergedContext(contexts)} |
140 'merged_context' : merged_context} |
94 report_util.generate_report(template_file_path, report_file_path, report_data, template_paths) |
141 report_util.generate_report(template_file_path, report_file_path, report_data, template_paths) |
95 |
142 |
96 def normalize_slash(path): |
143 def normalize_slash(path): |
97 """ |
144 """ |
98 Normalize backslashes to slashes to make testing easier (no differences |
145 Normalize backslashes to slashes to make testing easier (no differences |
133 return "ReportData(%s)" % [self.generation_timestamp, |
180 return "ReportData(%s)" % [self.generation_timestamp, |
134 self.generation_time, |
181 self.generation_time, |
135 self.options, |
182 self.options, |
136 self.duration, |
183 self.duration, |
137 self.output_dir, |
184 self.output_dir, |
138 self.project_dir] |
185 self.project_dir] |
|
186 |
|
187 def __getstate__(self): |
|
188 state = self.__dict__.copy() |
|
189 if self.project: |
|
190 state['project_path'] = os.path.abspath(self.project.get_path()) |
|
191 else: |
|
192 state['project_path'] = None |
|
193 del state['project'] |
|
194 return state |
|
195 |
|
196 def __setstate__(self, dict): |
|
197 project_path = dict['project_path'] |
|
198 if project_path is None: |
|
199 self.project = None |
|
200 else: |
|
201 self.project = api.Project(api.Storage.open(project_path)) |
|
202 |
|
203 self.__dict__.update(dict) |
139 |
204 |
140 |
205 |
141 class RefLine(object): |
206 class RefLine(object): |
142 """ |
207 """ |
143 Data object that stores information for one ref in report generation. |
208 Data object that stores information for one ref in report generation. |