|
1 # Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 # All rights reserved. |
|
3 # This component and the accompanying materials are made available |
|
4 # under the terms of the License "Eclipse Public License v1.0" |
|
5 # which accompanies this distribution, and is available |
|
6 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 # |
|
8 # Initial Contributors: |
|
9 # Nokia Corporation - initial contribution. |
|
10 # |
|
11 # Contributors: |
|
12 # |
|
13 from __future__ import with_statement |
|
14 try: |
|
15 from xml.etree import cElementTree as etree |
|
16 except ImportError: |
|
17 from xml.etree import ElementTree as etree |
|
18 from mapentry import MapEntry |
|
19 import logging |
|
20 import os |
|
21 |
|
22 |
|
23 logger = logging.getLogger('orb.mapcreators.packagelevel') |
|
24 |
|
25 |
|
26 class PackageLevelMapFilter(object): |
|
27 """ |
|
28 Takes a PackageLevelMap (a list of MapEntries) and filters out |
|
29 any that dont belong to a component |
|
30 """ |
|
31 def __init__(self, plm, href_loader, sdk_build=False): |
|
32 self._plm = plm |
|
33 self.sdk_build = sdk_build |
|
34 self.href_loader = href_loader |
|
35 |
|
36 def filter(self, exports_manager): |
|
37 component_map_entries = [] |
|
38 logging.debug("Mapentries: '%s'" % self._plm) |
|
39 for mapentry in [e for e in self._plm if e.href is not None]: |
|
40 header_file = self.href_loader.get(mapentry.href) |
|
41 export_path = exports_manager.get_export_path_for(header_file) |
|
42 logger.debug("Looking up href: '%s', exported as: '%s'" % (mapentry.href, export_path)) |
|
43 if export_path: |
|
44 if self.sdk_build and not exports_manager.is_public(export_path): |
|
45 logger.debug('Filtering out "%s". Not exported as public.' % (mapentry.navtitle)) |
|
46 else: |
|
47 component_map_entries.append(mapentry) |
|
48 else: # File was not exported so filter it out |
|
49 logger.debug('Filtering out "%s". Not exported in the sbs log file' % (mapentry.navtitle)) |
|
50 return component_map_entries |
|
51 |
|
52 |
|
53 class PackageLevelMapCreator(object): |
|
54 """ |
|
55 Reads all the target level maps created for a package by doxygen and |
|
56 returns the items in them as a list of MapEntry objects. |
|
57 """ |
|
58 def __init__(self, sysdef, build_dir): |
|
59 self.sysdef = sysdef |
|
60 self.build_dir = build_dir |
|
61 |
|
62 def _get_targetmap_paths_for_component(self, component_id): |
|
63 sbs_out_dir = self.sysdef.get_sbs_output_dir(component_id) |
|
64 logger.debug("Got sbs_out_dir: '%s'" % sbs_out_dir) |
|
65 if sbs_out_dir is None or sbs_out_dir == "": |
|
66 logger.warning("sbs_out_dir could not be retrieved for: '%s'" % component_id) |
|
67 return [] |
|
68 sbs_output_dir = os.path.abspath(self.build_dir + os.sep + sbs_out_dir) |
|
69 logger.debug("sbs_output_dir is: '%s'" % sbs_output_dir) |
|
70 if sbs_output_dir is None: |
|
71 logger.warning("No known build output directory for component '%s', no target maps discovered" % component_id) |
|
72 return [] |
|
73 if not os.path.exists(sbs_output_dir): |
|
74 logger.warning("Build output directory '%s' for component '%s' does not exist, no target maps discovered" % (sbs_output_dir, component_id)) |
|
75 return [] |
|
76 targetmaps = [] |
|
77 for root, _, files in os.walk(sbs_output_dir): |
|
78 for filename in (filename for filename in files if filename.lower().endswith(".ditamap")): |
|
79 targetmaps.append(os.path.join(root, filename)) |
|
80 logging.debug("Found the following targetmaps: '%s'" % targetmaps) |
|
81 return targetmaps |
|
82 |
|
83 def _get_targetmap(self, ditamap): |
|
84 try: |
|
85 return etree.parse(ditamap).getroot() |
|
86 except Exception, e: |
|
87 #except xml.parsers.expat.ExpatError, e: |
|
88 logger.error("Could not parse ditamap: %s, error was: %s " % (ditamap, e)) |
|
89 return None |
|
90 |
|
91 def _get_map_entries(self, elems): |
|
92 entries = set() |
|
93 for elem in elems: |
|
94 children = [] |
|
95 if len(elem) > 0: |
|
96 children = self._get_map_entries(elem.getchildren()) |
|
97 entries.add(MapEntry( |
|
98 tag = elem.tag, |
|
99 href = elem.get('href'), |
|
100 navtitle = elem.get('navtitle'), |
|
101 children = list(children) |
|
102 )) |
|
103 return entries |
|
104 |
|
105 def _get_targetmap_for(self, component_id): |
|
106 entries = set() |
|
107 for targetmap_path in self._get_targetmap_paths_for_component(component_id): |
|
108 logger.debug("Got target map path: '%s'" % targetmap_path) |
|
109 for entry in self._get_map_entries(self._get_targetmap(targetmap_path).getchildren()): |
|
110 entries.add(entry) |
|
111 return entries |
|
112 |
|
113 def get_package_level_map(self, package_id): |
|
114 """ |
|
115 Returns an etree map of topics for a package |
|
116 """ |
|
117 entries = set() |
|
118 for component in self.sysdef.get_components(package_id): |
|
119 logger.debug("Adding component: '%s'" % component.id) |
|
120 for targetmap in self._get_targetmap_for(component.id): |
|
121 logger.debug("Adding target map: '%s'" % targetmap.navtitle) |
|
122 entries.add(targetmap) |
|
123 return list(entries) |
|
124 |
|
125 |
|
126 ################################################################ |
|
127 # Unit test code |
|
128 ################################################################ |
|
129 import unittest |
|
130 import shutil |
|
131 from _shared import StubSysdef, StubPackageLevelMapCreator |
|
132 |
|
133 |
|
134 class HrefLoaderStub(object): |
|
135 def __init__(self, path): |
|
136 pass |
|
137 |
|
138 def get(self, href): |
|
139 if href.startswith("struct___array_util.xml"): |
|
140 return "W:/epoc32/include/mw/aknSoundinfo.h" |
|
141 elif href.startswith("class_b_trace.xml"): |
|
142 return "W:/epoc32/include/platform/mw/pslnfwappthemehandler.h" |
|
143 elif href.startswith("class_c_active.xml"): |
|
144 return "W:/sf/os/graphics/displayconfiguration.h" |
|
145 elif href.startswith("class_c_active_scheduler.xml"): |
|
146 return "W:/epoc32/include/mw/AiwServiceHandler.h" |
|
147 elif href.startswith("class_c_active_scheduler_wait.xml"): |
|
148 return "W:/epoc32/include/platform/mw/pslnfwappthemehandler.h" |
|
149 elif href.startswith("class_c_always_online_disk_space_observer.xml"): |
|
150 return "W:/sf/os/graphics/extensioncontainer.h" |
|
151 elif href.startswith("class_c_always_online_e_com_interface.xml"): |
|
152 return "W:/epoc32/include/mw/aknSoundinfo.h" |
|
153 elif href.startswith("class_c_always_online_manager.xml"): |
|
154 return "W:/epoc32/include/platform/mw/mpslnfwappthemeobserver.h" |
|
155 elif href.startswith("nested_and_removed.xml"): |
|
156 return "W:/epoc32/include/mw/foo/not_in_a_this_component.h" |
|
157 elif href.startswith("class_c_active_scheduler_1_1_t_cleanup_bundle.xml"): |
|
158 return "W:/epoc32/include/mw/bar/in_a_this_component.h" |
|
159 else: |
|
160 return "D:/no/header.h" |
|
161 |
|
162 |
|
163 class StubComponentExportsManager(object): |
|
164 def __init__(self, sdk=False): |
|
165 self.sdk = sdk |
|
166 |
|
167 def get_export_path_for(self, filepath): |
|
168 if filepath in ("W:/epoc32/include/mw/aknSoundinfo.h", |
|
169 "W:/epoc32/include/platform/mw/pslnfwappthemehandler.h", |
|
170 "W:/epoc32/include/mw/AiwServiceHandler.h"): |
|
171 return filepath |
|
172 elif filepath == "W:/sf/os/graphics/displayconfiguration.h": |
|
173 return "W:/epoc32/include/displayconfiguration.h" |
|
174 elif filepath == "W:/sf/os/graphics/extensioncontainer.h": |
|
175 return "W:/epoc32/include/extensioncontainer.h" |
|
176 else: |
|
177 return None |
|
178 |
|
179 def is_public(self, filepath): |
|
180 return "platform" in filepath |
|
181 |
|
182 |
|
183 class TestPackageLevelMapFilter(unittest.TestCase): |
|
184 def setUp(self): |
|
185 sysdef = StubSysdef() |
|
186 plmcreator = StubPackageLevelMapCreator(sysdef, "") |
|
187 self.plm = plmcreator.get_package_level_map('classicui') |
|
188 |
|
189 def test_i_correctly_filter_a_pdk_map(self): |
|
190 plmfilter = PackageLevelMapFilter(self.plm, HrefLoaderStub("."), sdk_build=False) |
|
191 filtered_map = plmfilter.filter(StubComponentExportsManager()) |
|
192 self.assertEqual(len(filtered_map), 7) |
|
193 |
|
194 def test_i_correctly_filter_a_sdk_map(self): |
|
195 plmfilter = PackageLevelMapFilter(self.plm, HrefLoaderStub("."), sdk_build=True) |
|
196 filtered_map = plmfilter.filter(StubComponentExportsManager(True)) |
|
197 self.assertEqual(len(filtered_map), 2) |
|
198 |
|
199 |
|
200 class TestPackageLevelMapCreator(unittest.TestCase): |
|
201 def setUp(self): |
|
202 self.test_dir = os.path.abspath("filter_orb_test_dir"+os.sep+"TestPackageLevelMapCreator_test_dir") |
|
203 self.build_dir = self.test_dir+os.sep+"build" |
|
204 self.plmc = PackageLevelMapCreator(StubSysdef(), self.build_dir) |
|
205 self._create_test_build_dir() |
|
206 |
|
207 def _create_test_build_dir(self): |
|
208 # Create test component directories |
|
209 akncapserver_ditamap_dir = os.path.join(self.build_dir, "aknglobalui", "c_f539995457c01233", "akncapserver_exe", "dox", "dita") |
|
210 commonui_ditamap_dir = os.path.join(self.build_dir, "commonui", "c_e0f69e4ef2e4676e", "commonui_dll", "dox", "dita") |
|
211 badly_formed_ditamap_dir = os.path.join(self.build_dir, "badly_formed") |
|
212 for dir in (akncapserver_ditamap_dir, commonui_ditamap_dir, badly_formed_ditamap_dir): |
|
213 os.makedirs(dir) |
|
214 # Create test ditamaps |
|
215 self.akncapserver_ditamap_path = os.path.join(akncapserver_ditamap_dir, "akncapserver.ditamap") |
|
216 self.commonui_ditamap_path = os.path.join(commonui_ditamap_dir, "commonui.ditamap") |
|
217 self.badly_formed_ditamap_path = os.path.join(badly_formed_ditamap_dir, "badly_formed.ditamap") |
|
218 with open(self.akncapserver_ditamap_path, "w") as adh: |
|
219 adh.write(akncapserver_ditamap) |
|
220 with open(self.commonui_ditamap_path, "w") as cdh: |
|
221 cdh.write(commonui_ditamap) |
|
222 with open(self.badly_formed_ditamap_path, "w") as bfdh: |
|
223 bfdh.write(badly_formed_ditamap) |
|
224 |
|
225 def tearDown(self): |
|
226 shutil.rmtree(self.test_dir) |
|
227 |
|
228 def test_i_can_return_targetmap_paths_for_a_component(self): |
|
229 targetmaps = self.plmc._get_targetmap_paths_for_component("aknglobalui") |
|
230 self.assertEquals(targetmaps, [self.akncapserver_ditamap_path]) |
|
231 |
|
232 def test_i_gracefully_handle_a_badly_formed_target_map(self): |
|
233 root = self.plmc._get_targetmap(self.badly_formed_ditamap_path) |
|
234 self.assertEquals(root, None) |
|
235 |
|
236 def test_the_list_of_mapentries_i_returned_is_filtered(self): |
|
237 plm = self.plmc.get_package_level_map("classicui") |
|
238 self.assertEquals(len(plm), 4) |
|
239 for entry in plm: |
|
240 self.assertTrue( |
|
241 entry.href in ( |
|
242 "class_c_akn_sound_info.xml#class_c_akn_sound_info", |
|
243 "class_c_aiw_service_handler.xml#class_c_aiw_service_handler", |
|
244 "class_c_active_scheduler.xml#class_c_active_scheduler", |
|
245 "class_c_service_handler.xml" |
|
246 ) |
|
247 ) |
|
248 self.assertTrue( |
|
249 entry.navtitle in ( |
|
250 "CAknSoundInfo", |
|
251 "CAiwServiceHandler", |
|
252 "class_c_active_scheduler", |
|
253 "CServiceHandler" |
|
254 ) |
|
255 ) |
|
256 |
|
257 |
|
258 akncapserver_ditamap = """\ |
|
259 <?xml version="1.0" encoding="UTF-8"?> |
|
260 <!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" > |
|
261 <cxxAPIMap id="akncapserver" title="akncapserver"> |
|
262 <cxxClassRef href="class_c_akn_sound_info.xml#class_c_akn_sound_info" navtitle="CAknSoundInfo" /> |
|
263 <cxxClassRef href="class_c_aiw_service_handler.xml#class_c_aiw_service_handler" navtitle="CAiwServiceHandler" /> |
|
264 <cxxClassRef href="class_c_active_scheduler.xml#class_c_active_scheduler" navtitle="class_c_active_scheduler"> |
|
265 <cxxClassRef href="class_c_active_sub.xml#class_c_active_scheduler" navtitle="class_c_active_scheduler_1_1_t_cleanup_bundle"/> |
|
266 </cxxClassRef> |
|
267 </cxxAPIMap>""" |
|
268 |
|
269 |
|
270 commonui_ditamap = """\ |
|
271 <?xml version="1.0" encoding="UTF-8"?> |
|
272 <!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" > |
|
273 <cxxAPIMap id="CommonUI" title="CommonUI"> |
|
274 <cxxClassRef href="class_c_aiw_service_handler.xml#class_c_aiw_service_handler" navtitle="CAiwServiceHandler" /> |
|
275 <cxxClassRef href="class_c_service_handler.xml" navtitle="CServiceHandler" /> |
|
276 </cxxAPIMap>""" |
|
277 |
|
278 |
|
279 badly_formed_ditamap = """\ |
|
280 <?xml version="1.0" encoding="UTF-8"?> |
|
281 <!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" > |
|
282 <cxxAPIMap id="BadlyFormed" title="BadlyFormed"> |
|
283 <cxxClassRef href="class_c_aiw_service_handler.xml#class_c_aiw_service_handler" navtitle="CAiwServiceHandler" /> |
|
284 </cxxAPIMap""" |