-
Notifications
You must be signed in to change notification settings - Fork 62
524 bug 0143b7 #525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
524 bug 0143b7 #525
Conversation
- Fixed nested src/src/ directory structure that was causing duplicate module definitions - When copying source files, don't append 'src' to output_dir since relative paths already include it - This resolves Vivado synthesis errors about overwriting module definitions and unresolved hierarchical names - Fixes issue where files were being added twice to Vivado project (once from src/ and once from src/src/) Root cause: _copy_source_files was preserving directory structure from board_path, which included 'src/', but was also being given an output_dir of 'board_output_dir/src', resulting in files being placed at 'board_output_dir/src/src/file.sv'.
- test_copy_source_files_no_nested_src_directory: Verifies files aren't copied to src/src/ - test_unified_build_script_no_duplicate_source_files: Ensures build script doesn't add duplicate files These tests prevent regression of GitHub issue #524 where duplicate module definitions were causing Vivado synthesis to fail due to nested src/src/ directory structure.
E2E Integration Test SummaryWorkflow Run: 767 Test ResultsEnd-to-End Tests❌ E2E Tests: FAILED Artifacts
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request fixes a bug (GitHub Issue #524) where source files were being copied to a nested src/src/ directory structure instead of a flat src/ structure, causing duplicate module definition errors in Vivado builds.
Key Changes:
- Refactored
_copy_source_filesto use a flat file structure, placing all source files directly inoutput_dir/src/regardless of repository structure - Removed directory structure preservation logic that was creating nested
src/src/paths - Added comprehensive regression tests to prevent nested directory issues and verify flat structure behavior
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/vivado_handling/pcileech_build_integration.py |
Refactored _copy_source_files to implement flat directory structure (all files go to output_dir/src/), removed dest_path.parent.mkdir call, and added detailed documentation explaining the design principle |
tests/test_pcileech_build_integration.py |
Updated existing tests for flat structure behavior, added 6 new test cases covering nested directory prevention, filename collisions, manifest tracker integration, empty file lists, IO error handling, and TCL script deduplication |
Comments suppressed due to low confidence (6)
tests/test_pcileech_build_integration.py:601
- Variable script_path is not used.
script_path = integration.create_unified_build_script("artix7")
tests/test_pcileech_build_integration.py:633
- Variable script_path is not used.
script_path = integration.create_unified_build_script("artix7")
tests/test_pcileech_build_integration.py:663
- Variable script_path is not used.
script_path = integration.create_unified_build_script("artix7")
tests/test_pcileech_build_integration.py:690
- Variable script_path is not used.
script_path = integration.create_unified_build_script("pcileech_100t484_x1")
tests/test_pcileech_build_integration.py:734
- Variable script_path is not used.
script_path = integration.create_unified_build_script(board_name)
tests/test_pcileech_build_integration.py:844
- Variable result is not used.
result = integrate_pcileech_build("artix7", self.output_dir, device_config)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Copy source files from repository | ||
| # Don't append "src" to output_dir as it will be preserved from the board path |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says "Don't append 'src' to output_dir as it will be preserved from the board path", but the new implementation actually does the opposite - it explicitly appends 'src' internally within the _copy_source_files method. The comment should be clarified to say something like "Pass base output_dir directly; the method will create and use output_dir/src/ internally" to accurately reflect the implementation.
| # Copy source files from repository | |
| # Don't append "src" to output_dir as it will be preserved from the board path | |
| # Copy source files from repository. | |
| # Pass base board_output_dir; _copy_source_files will create and use board_output_dir / "src" internally. |
| src_count = str(result_path).count('/src/') | ||
| self.assertEqual(src_count, 1, | ||
| f"Path should have exactly one 'src' directory, found {src_count}: {result_path}") |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test counts occurrences of '/src/' in the path string, which will fail on Windows systems where paths use backslashes. Consider using Path(result_path).parts and counting 'src' occurrences in the parts list instead, which is platform-independent.
| src_count = str(result_path).count('/src/') | |
| self.assertEqual(src_count, 1, | |
| f"Path should have exactly one 'src' directory, found {src_count}: {result_path}") | |
| path_parts = Path(result_path).parts | |
| src_count = sum(1 for part in path_parts if part == "src") | |
| self.assertEqual( | |
| src_count, | |
| 1, | |
| f"Path should have exactly one 'src' directory, found {src_count}: {result_path}", | |
| ) |
| # Both files should be copied (last one overwrites) | ||
| self.assertEqual(len(result), 2) | ||
|
|
||
| # Both should target the same destination path | ||
| expected_dest = board_output_dir / "src" / "common.sv" | ||
| for call_args in mock_copy2.call_args_list: | ||
| dest_path = call_args[0][1] | ||
| self.assertEqual(dest_path, expected_dest, | ||
| "All files with same name should map to same destination") |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test expects all files with the same name to be copied to the same destination path (line 310-311), but the implementation actually allows this and just overwrites. The assertion on line 304 checks len(result) == 2, which is correct, but the comment on line 303 says "Both files should be copied (last one overwrites)" which contradicts the test behavior. The test should verify that both copy operations were attempted, not that the result list contains 2 items with the same destination.
| # Both files should be copied (last one overwrites) | |
| self.assertEqual(len(result), 2) | |
| # Both should target the same destination path | |
| expected_dest = board_output_dir / "src" / "common.sv" | |
| for call_args in mock_copy2.call_args_list: | |
| dest_path = call_args[0][1] | |
| self.assertEqual(dest_path, expected_dest, | |
| "All files with same name should map to same destination") | |
| # Both files should be copied (two copy operations; last one overwrites) | |
| self.assertEqual(len(result), 2) | |
| self.assertEqual(mock_copy2.call_count, 2) | |
| # Both copy operations should target the same destination path | |
| expected_dest = board_output_dir / "src" / "common.sv" | |
| for call_args in mock_copy2.call_args_list: | |
| dest_path = call_args[0][1] | |
| self.assertEqual( | |
| dest_path, | |
| expected_dest, | |
| "All files with same name should map to same destination", | |
| ) |
| def test_copy_source_files_with_manifest_tracker_duplicate_prevention(self, mock_copy2): | ||
| """Test that manifest tracker prevents actual duplicate file copies.""" | ||
| # Create a mock manifest tracker that rejects the second file | ||
| mock_manifest = MagicMock() | ||
| mock_manifest.add_copy_operation.side_effect = [True, False] # Accept first, reject second | ||
|
|
||
| integration = PCILeechBuildIntegration( | ||
| self.output_dir, | ||
| self.repo_root, | ||
| manifest_tracker=mock_manifest | ||
| ) | ||
|
|
||
| src_files = [ | ||
| Path("/tmp/test_repo/boards/board1/src/file1.sv"), | ||
| Path("/tmp/test_repo/boards/board1/src/file2.sv"), | ||
| ] | ||
| self.mock_template_discovery.get_source_files.return_value = src_files | ||
| self.mock_template_discovery.get_pcileech_core_files.return_value = {} | ||
|
|
||
| result = integration._copy_source_files("board1", Path("/tmp/output/board1")) | ||
|
|
||
| # Only first file should be copied (second rejected by manifest) | ||
| self.assertEqual(len(result), 1) | ||
| self.assertEqual(mock_copy2.call_count, 1) | ||
| self.assertEqual(result[0].name, "file1.sv") |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test documentation says "Test that manifest tracker prevents actual duplicate file copies" but the implementation doesn't check if copy2 was called only once. If manifest tracker rejects the second file, shutil.copy2 should only be called once, but the test only verifies the result length and doesn't assert that mock_copy2.call_count equals 1. Add an assertion to verify that copy2 is only invoked once when manifest tracker rejects duplicates.
| }) | ||
|
|
||
| # Call create_unified_build_script and capture the script content | ||
| script_path = integration.create_unified_build_script("pcileech_100t484_x1") |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable script_path is not used.
| script_path = integration.create_unified_build_script("pcileech_100t484_x1") | |
| integration.create_unified_build_script("pcileech_100t484_x1") |
No description provided.