|
41 | 41 | from ucis.sqlite import schema_manager |
42 | 42 |
|
43 | 43 |
|
| 44 | +def _convert_to_sqlite(source_ucis: UCIS) -> 'SqliteUCIS': |
| 45 | + """ |
| 46 | + Convert a non-SQLite UCIS database to SqliteUCIS. |
| 47 | + |
| 48 | + This creates a temporary in-memory SQLite database and copies all |
| 49 | + scopes, coverage items, and history nodes from the source. |
| 50 | + |
| 51 | + Args: |
| 52 | + source_ucis: The source UCIS database to convert |
| 53 | + |
| 54 | + Returns: |
| 55 | + A SqliteUCIS instance with the copied data |
| 56 | + """ |
| 57 | + # Create in-memory SQLite database |
| 58 | + sqlite_db = SqliteUCIS() |
| 59 | + |
| 60 | + # Copy metadata |
| 61 | + sqlite_db.setWrittenBy(source_ucis.getWrittenBy()) |
| 62 | + sqlite_db.setWrittenTime(source_ucis.getWrittenTime()) |
| 63 | + |
| 64 | + # Copy file handles |
| 65 | + file_handle_map = {} |
| 66 | + if hasattr(source_ucis, 'file_handle_m'): |
| 67 | + for filename, src_fh in source_ucis.file_handle_m.items(): |
| 68 | + file_handle_map[filename] = sqlite_db.createFileHandle(filename, None) |
| 69 | + |
| 70 | + # Copy history nodes |
| 71 | + for src_hist in source_ucis.historyNodes(-1): |
| 72 | + _copy_history_node(src_hist, sqlite_db, None) |
| 73 | + |
| 74 | + # Copy scopes recursively from root |
| 75 | + _copy_scope_recursive(source_ucis, sqlite_db, file_handle_map) |
| 76 | + |
| 77 | + return sqlite_db |
| 78 | + |
| 79 | + |
| 80 | +def _copy_history_node(src_node, dst_db: 'SqliteUCIS', parent): |
| 81 | + """Copy a history node from source to destination database""" |
| 82 | + dst_node = dst_db.createHistoryNode( |
| 83 | + parent, |
| 84 | + src_node.getLogicalName(), |
| 85 | + src_node.getPhysicalName(), |
| 86 | + src_node.getKind() |
| 87 | + ) |
| 88 | + |
| 89 | + # Copy metadata |
| 90 | + if hasattr(src_node, 'getTestStatus'): |
| 91 | + dst_node.setTestStatus(src_node.getTestStatus()) |
| 92 | + if hasattr(src_node, 'getSeed'): |
| 93 | + dst_node.setSeed(src_node.getSeed()) |
| 94 | + if hasattr(src_node, 'getCmd'): |
| 95 | + dst_node.setCmd(src_node.getCmd()) |
| 96 | + if hasattr(src_node, 'getCpuTime'): |
| 97 | + dst_node.setCpuTime(src_node.getCpuTime()) |
| 98 | + if hasattr(src_node, 'getDate'): |
| 99 | + dst_node.setDate(src_node.getDate()) |
| 100 | + if hasattr(src_node, 'getUserName'): |
| 101 | + dst_node.setUserName(src_node.getUserName()) |
| 102 | + |
| 103 | + return dst_node |
| 104 | + |
| 105 | + |
| 106 | +def _copy_scope_recursive(src_scope, dst_scope, file_handle_map): |
| 107 | + """Recursively copy scopes and coverage items from source to destination""" |
| 108 | + |
| 109 | + # Copy coverage items for this scope |
| 110 | + for src_cover in src_scope.coverItems(-1): |
| 111 | + # Map source file handle to destination file handle |
| 112 | + src_info = src_cover.getSourceInfo() |
| 113 | + dst_info = src_info |
| 114 | + if src_info and src_info.file and hasattr(src_info.file, 'filename'): |
| 115 | + filename = src_info.file.filename |
| 116 | + if filename in file_handle_map: |
| 117 | + from ucis.source_info import SourceInfo |
| 118 | + dst_info = SourceInfo( |
| 119 | + file_handle_map[filename], |
| 120 | + src_info.line, |
| 121 | + src_info.token |
| 122 | + ) |
| 123 | + |
| 124 | + dst_scope.createNextCover( |
| 125 | + src_cover.getName(), |
| 126 | + src_cover.getCoverData(), |
| 127 | + dst_info |
| 128 | + ) |
| 129 | + |
| 130 | + # Recursively copy child scopes |
| 131 | + for src_child in src_scope.scopes(-1): |
| 132 | + # Map source file handle to destination file handle |
| 133 | + src_info = src_child.getSourceInfo() |
| 134 | + dst_info = src_info |
| 135 | + if src_info and src_info.file and hasattr(src_info.file, 'filename'): |
| 136 | + filename = src_info.file.filename |
| 137 | + if filename in file_handle_map: |
| 138 | + from ucis.source_info import SourceInfo |
| 139 | + dst_info = SourceInfo( |
| 140 | + file_handle_map[filename], |
| 141 | + src_info.line, |
| 142 | + src_info.token |
| 143 | + ) |
| 144 | + |
| 145 | + # Get flags - MemScope stores it in m_flags but doesn't implement getFlags() |
| 146 | + try: |
| 147 | + flags = src_child.getFlags() |
| 148 | + except (NotImplementedError, AttributeError): |
| 149 | + flags = getattr(src_child, 'm_flags', 0) |
| 150 | + |
| 151 | + dst_child = dst_scope.createScope( |
| 152 | + src_child.getScopeName(), |
| 153 | + dst_info, |
| 154 | + src_child.getWeight(), |
| 155 | + 0, # source |
| 156 | + src_child.getScopeType(), |
| 157 | + flags |
| 158 | + ) |
| 159 | + |
| 160 | + # Recursively copy children |
| 161 | + _copy_scope_recursive(src_child, dst_child, file_handle_map) |
| 162 | + |
| 163 | + |
44 | 164 | class SqliteUCIS(SqliteScope, UCIS): |
45 | 165 | """SQLite-backed UCIS database""" |
46 | 166 |
|
@@ -307,13 +427,26 @@ def merge(self, source_ucis, create_history: bool = True): |
307 | 427 | Merge coverage from another UCIS database |
308 | 428 | |
309 | 429 | Args: |
310 | | - source_ucis: Source SqliteUCIS database to merge from |
| 430 | + source_ucis: Source UCIS database to merge from (can be any UCIS type) |
311 | 431 | create_history: Whether to create merge history node |
312 | 432 | |
313 | 433 | Returns: |
314 | 434 | MergeStats object with statistics |
315 | 435 | """ |
316 | 436 | from ucis.sqlite.sqlite_merge import SqliteMerger |
317 | 437 |
|
318 | | - merger = SqliteMerger(self) |
319 | | - return merger.merge(source_ucis, create_history) |
| 438 | + # If source is not a SqliteUCIS, convert it first |
| 439 | + if not isinstance(source_ucis, SqliteUCIS): |
| 440 | + source_ucis = _convert_to_sqlite(source_ucis) |
| 441 | + temp_source = source_ucis # Keep reference to close later |
| 442 | + else: |
| 443 | + temp_source = None |
| 444 | + |
| 445 | + try: |
| 446 | + merger = SqliteMerger(self) |
| 447 | + result = merger.merge(source_ucis, create_history) |
| 448 | + return result |
| 449 | + finally: |
| 450 | + # Clean up temporary SQLite database if we created one |
| 451 | + if temp_source is not None: |
| 452 | + temp_source.close() |
0 commit comments