modwire 9.0.0__tar.gz → 9.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modwire-9.0.0 → modwire-9.1.0}/.dev/modwire.egg-info/SOURCES.txt +17 -0
- {modwire-9.0.0 → modwire-9.1.0}/Makefile +4 -1
- {modwire-9.0.0 → modwire-9.1.0}/PKG-INFO +21 -1
- {modwire-9.0.0 → modwire-9.1.0}/README.md +20 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/application.py +39 -2
- modwire-9.1.0/src/modwire/cli/cache/application.py +183 -0
- modwire-9.1.0/src/modwire/cli/cache/domain.py +27 -0
- modwire-9.1.0/src/modwire/cli/cache/models/cache_entry.py +8 -0
- modwire-9.1.0/src/modwire/cli/cache/models/cache_key.py +11 -0
- modwire-9.1.0/src/modwire/cli/cache/models/cache_options.py +25 -0
- modwire-9.1.0/src/modwire/cli/cache/models/extraction_snapshot.py +8 -0
- modwire-9.1.0/src/modwire/cli/cache/models/source_entry.py +9 -0
- modwire-9.1.0/src/modwire/cli/cache/models/source_inventory.py +9 -0
- modwire-9.1.0/src/modwire/cli/cache/services/cache_codec.py +40 -0
- modwire-9.1.0/src/modwire/cli/cache/services/cache_identity.py +106 -0
- modwire-9.1.0/src/modwire/cli/cache/services/filesystem_cache_storage.py +147 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/facade.py +59 -6
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/domain.py +13 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/command_request.py +5 -1
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/batch_source_reader.py +57 -15
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/command_line.py +11 -1
- modwire-9.1.0/tests/application/test_07_cache.py +143 -0
- modwire-9.1.0/tests/extraction/cache_benchmark/run.py +155 -0
- modwire-9.1.0/tests/extraction/scan_benchmark/__init__.py +0 -0
- modwire-9.1.0/tests/shared/__init__.py +0 -0
- modwire-9.1.0/tests/shared/code/__init__.py +0 -0
- modwire-9.1.0/tests/support/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/.github/workflows/ci.yml +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/.github/workflows/release.yml +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/.gitignore +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/AGENTS.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/LICENSE +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/MANIFEST.in +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/docs/target-language-ownership.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/pyproject.toml +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/scripts/check_extractors.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/scripts/generate_docs.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/scripts/verify_consumer.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/setup.cfg +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/setup.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/__main__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/edge_rule_violation.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/flow_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/flow_violation.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/models/types.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/backward_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/boundaries_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/module_boundary_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/no_cycles_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/boundaries/services/no_reentry_flow_analyzer.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/architecture_config.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/boundaries_config.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/boundary_rule.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/configuration_value.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/flow_realm.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/flow_rules.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/shape_config.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/shape_realm.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/shape_rules.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/config/models/tag_rule.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/facade.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/callable_report_entry.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/callables_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/clusters_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/clusters_report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/coherence_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/exports_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/exports_report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/hotspots_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/hotspots_report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/models/insight_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/callables_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/clusters_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/coherence_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/exports_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/hotspots_reporter.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/insights/services/insight_report_field_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/architecture_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/architecture_realm.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/tag_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/models/tag_match.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/services/architecture_map_loader.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/map/services/tag_matcher.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/architecture_group.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/map_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_catalog.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_descriptor.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_item.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_metadata.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_node.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/models/report_section.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/report/services/map_report_collector.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/shape_realm_architecture_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/shape_report.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/models/shape_violation.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/abstract_class_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/callable_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/class_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/file_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/import_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/property_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/signature_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/architecture/shape/services/symbol_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/autowiring.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/__init__.py +0 -0
- {modwire-9.0.0/src/modwire/cli/resources/models → modwire-9.1.0/src/modwire/cli/cache}/__init__.py +0 -0
- {modwire-9.0.0/src/modwire/extraction → modwire-9.1.0/src/modwire/cli/cache/models}/__init__.py +0 -0
- {modwire-9.0.0/src/modwire/shared → modwire-9.1.0/src/modwire/cli/cache/services}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/documentation/services/documentation_generator.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/models/initialization_result.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/initialization/services/initialization_service.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/extractor_batch_input.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/extractor_command_input.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/extractor_source_input.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/report_pipeline_context.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/models/scan_policy.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/callables_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/clusters_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/coherence_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/configuration_loader.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/extractor_command.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/flow_violations.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/hotspots_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/map_tree.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/output_console.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/shape_violations.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/success.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/unknown_files_warning.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/pipeline/services/unused_exports_insight.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/application.py +0 -0
- {modwire-9.0.0/src/modwire/shared/values → modwire-9.1.0/src/modwire/cli/resources}/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/models/defaults.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/models/init_asset.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/AGENTS.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/ARCHITECTURE.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/INDEX.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/MODWIRE.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/RULES.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/TESTING.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/WORKFLOW.md +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/cli/resources/templates/architecture.yaml +0 -0
- {modwire-9.0.0/tests → modwire-9.1.0/src/modwire/extraction}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/graph_builder.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/import_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/dependency/services/suffix_index.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/batch_config.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/extraction_request.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/extractor_resource.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/extractor_runtime.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/models/python_call_context.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/build.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/build.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/composer.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/composer.lock +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/script.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/php/script.src.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/python/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/python/script.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/build.mjs +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/build.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/package-lock.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/package.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/script.js +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/script.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/resources/typescript/tsconfig.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/php_extractor.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/python_call_reader.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/python_extractor.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/python_syntax_parser.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/extractors/services/type_script_extractor.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/extraction/facade.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/py.typed +0 -0
- {modwire-9.0.0/tests/application → modwire-9.1.0/src/modwire/shared}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/application.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/domain.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/code_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/code_package.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/dependency_edge_result.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/dependency_graph.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/dependency_node_result.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/duplicate_identity_error.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/edge.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/edge_resolution.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/identity.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/node.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/query_builder.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/query_types.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/queryable_code_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_abstract_class.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_call.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_callable.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_callable_symbol.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_class.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_class_method.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_class_property.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_export.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_extraction.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_file.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_file_result.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_function.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_import.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_imported_symbol.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_interface.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_item_result.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_parameter.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_signature.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_symbol.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_type.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/source_value.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/models/types.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/services/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/services/glob_path_matcher.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/code/services/identity_resolver.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/values/__init__.py +0 -0
- {modwire-9.0.0/tests/architecture → modwire-9.1.0/src/modwire/shared/values/models}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/src/modwire/shared/values/models/value_model.py +0 -0
- {modwire-9.0.0/tests/architecture/boundaries → modwire-9.1.0/tests}/__init__.py +0 -0
- {modwire-9.0.0/tests/architecture/config → modwire-9.1.0/tests/application}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/application/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/application/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/application/test_06_happy_path.py +0 -0
- {modwire-9.0.0/tests/architecture/insights → modwire-9.1.0/tests/architecture}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/base_test.py +0 -0
- {modwire-9.0.0/tests/architecture/map → modwire-9.1.0/tests/architecture/boundaries}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_03_public_api.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/boundaries/test_04_paths.py +0 -0
- {modwire-9.0.0/tests/architecture/report → modwire-9.1.0/tests/architecture/config}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/config/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/config/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/architecture/shape → modwire-9.1.0/tests/architecture/insights}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/insights/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/insights/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/cli → modwire-9.1.0/tests/architecture/map}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/map/test_02_patterns.py +0 -0
- {modwire-9.0.0/tests/cli/documentation → modwire-9.1.0/tests/architecture/report}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/report/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/cli/initialization → modwire-9.1.0/tests/architecture/shape}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/shape/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/shape/test_01_limits.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/architecture/shape/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/cli/pipeline → modwire-9.1.0/tests/cli}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/base_test.py +0 -0
- {modwire-9.0.0/tests/extraction → modwire-9.1.0/tests/cli/documentation}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/documentation/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/extraction/big_projects → modwire-9.1.0/tests/cli/initialization}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_03_interruption.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_04_cleanup.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/initialization/test_05_recovery.py +0 -0
- {modwire-9.0.0/tests/extraction/dependency → modwire-9.1.0/tests/cli/pipeline}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_03_interruption.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_04_command_transport.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_05_recovery.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/cli/pipeline/test_06_happy_path.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/conftest.py +0 -0
- {modwire-9.0.0/tests/extraction/extractors → modwire-9.1.0/tests/extraction}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/base_test.py +0 -0
- {modwire-9.0.0/tests/extraction/scan_benchmark → modwire-9.1.0/tests/extraction/big_projects}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/project.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/projects.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/resolution_results.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/results.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/big_projects/run.py +0 -0
- {modwire-9.0.0/tests/shared → modwire-9.1.0/tests/extraction/cache_benchmark}/__init__.py +0 -0
- {modwire-9.0.0/tests/shared/code → modwire-9.1.0/tests/extraction/dependency}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/dependency/test_02_invariants.py +0 -0
- {modwire-9.0.0/tests/support → modwire-9.1.0/tests/extraction/extractors}/__init__.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/extractors/test_01_attacks.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/extractors/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/extractors/test_03_native_symbols.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/scan_benchmark/prepare.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/scan_benchmark/results.json +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/extraction/scan_benchmark/run.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/ignored/example_generated.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_application/example_actions/example_action.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_domain/example_model/example_record.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_domain/example_services/example_policy.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/php/src/example_interfaces/example_http/example_controller.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/ignored/example_generated.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_application/example_actions/example_action.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_domain/example_model/example_record.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_domain/example_services/example_policy.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/python/src/example_interfaces/example_http/example_controller.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/ignored/example_generated.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_application/example_actions/example_action.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_record.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_model/example_view.tsx +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_audit.js +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_callables.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_domain/example_services/example_policy.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_controller.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/languages/typescript/src/example_interfaces/example_http/example_view.jsx +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/syntax/php/example_shapes.php +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/syntax/python/example_shapes.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/fixtures/syntax/typescript/example_shapes.ts +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/shared/code/test_02_invariants.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/support/base_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/support/code_map.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/tests/support/service_test.py +0 -0
- {modwire-9.0.0 → modwire-9.1.0}/uv.lock +0 -0
|
@@ -112,6 +112,20 @@ src/modwire/architecture/shape/services/signature_resolver.py
|
|
|
112
112
|
src/modwire/architecture/shape/services/symbol_resolver.py
|
|
113
113
|
src/modwire/cli/__init__.py
|
|
114
114
|
src/modwire/cli/facade.py
|
|
115
|
+
src/modwire/cli/cache/__init__.py
|
|
116
|
+
src/modwire/cli/cache/application.py
|
|
117
|
+
src/modwire/cli/cache/domain.py
|
|
118
|
+
src/modwire/cli/cache/models/__init__.py
|
|
119
|
+
src/modwire/cli/cache/models/cache_entry.py
|
|
120
|
+
src/modwire/cli/cache/models/cache_key.py
|
|
121
|
+
src/modwire/cli/cache/models/cache_options.py
|
|
122
|
+
src/modwire/cli/cache/models/extraction_snapshot.py
|
|
123
|
+
src/modwire/cli/cache/models/source_entry.py
|
|
124
|
+
src/modwire/cli/cache/models/source_inventory.py
|
|
125
|
+
src/modwire/cli/cache/services/__init__.py
|
|
126
|
+
src/modwire/cli/cache/services/cache_codec.py
|
|
127
|
+
src/modwire/cli/cache/services/cache_identity.py
|
|
128
|
+
src/modwire/cli/cache/services/filesystem_cache_storage.py
|
|
115
129
|
src/modwire/cli/documentation/__init__.py
|
|
116
130
|
src/modwire/cli/documentation/application.py
|
|
117
131
|
src/modwire/cli/documentation/services/__init__.py
|
|
@@ -253,6 +267,7 @@ tests/application/__init__.py
|
|
|
253
267
|
tests/application/base_test.py
|
|
254
268
|
tests/application/test_01_attacks.py
|
|
255
269
|
tests/application/test_06_happy_path.py
|
|
270
|
+
tests/application/test_07_cache.py
|
|
256
271
|
tests/architecture/__init__.py
|
|
257
272
|
tests/architecture/base_test.py
|
|
258
273
|
tests/architecture/boundaries/__init__.py
|
|
@@ -301,6 +316,8 @@ tests/extraction/big_projects/projects.json
|
|
|
301
316
|
tests/extraction/big_projects/resolution_results.json
|
|
302
317
|
tests/extraction/big_projects/results.json
|
|
303
318
|
tests/extraction/big_projects/run.py
|
|
319
|
+
tests/extraction/cache_benchmark/__init__.py
|
|
320
|
+
tests/extraction/cache_benchmark/run.py
|
|
304
321
|
tests/extraction/dependency/__init__.py
|
|
305
322
|
tests/extraction/dependency/test_02_invariants.py
|
|
306
323
|
tests/extraction/extractors/__init__.py
|
|
@@ -7,7 +7,7 @@ PROJECT_ROOT := $(CURDIR)
|
|
|
7
7
|
export PYTHONPYCACHEPREFIX := $(PROJECT_ROOT)/$(DEV_DIR)/cache/python
|
|
8
8
|
export UV_CACHE_DIR := $(PROJECT_ROOT)/$(DEV_DIR)/cache/uv
|
|
9
9
|
|
|
10
|
-
.PHONY: big-projects build ci docs docs-check extractor-check format format-check host-check lint package-check scan-benchmark scan-benchmark-fixture test type-check
|
|
10
|
+
.PHONY: big-projects build cache-benchmark ci docs docs-check extractor-check format format-check host-check lint package-check scan-benchmark scan-benchmark-fixture test type-check
|
|
11
11
|
|
|
12
12
|
format:
|
|
13
13
|
uv run ruff format src tests scripts
|
|
@@ -34,6 +34,9 @@ scan-benchmark-fixture:
|
|
|
34
34
|
scan-benchmark:
|
|
35
35
|
uv run python -m tests.extraction.scan_benchmark.run --root .dev/benchmarks/scan-project --language "$(SCAN_BENCHMARK_LANGUAGE)" --excluded-pattern 'example_excluded/**'
|
|
36
36
|
|
|
37
|
+
cache-benchmark:
|
|
38
|
+
uv run python -m tests.extraction.cache_benchmark.run --root "$(CACHE_BENCHMARK_ROOT)" --language "$(CACHE_BENCHMARK_LANGUAGE)" --cache-directory .dev/benchmarks/cache --incremental-source "$(CACHE_BENCHMARK_SOURCE)" --replacement-source "$(CACHE_BENCHMARK_REPLACEMENT)"
|
|
39
|
+
|
|
37
40
|
docs-check:
|
|
38
41
|
uv run python scripts/generate_docs.py --check
|
|
39
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modwire
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.1.0
|
|
4
4
|
Summary: Code extraction, architecture analysis and the Modwire CLI.
|
|
5
5
|
Author: Tomasz Szpak
|
|
6
6
|
License-Expression: MIT
|
|
@@ -48,6 +48,10 @@ Return the available architecture reports.
|
|
|
48
48
|
|
|
49
49
|
Analyze a code map with a validated architecture configuration.
|
|
50
50
|
|
|
51
|
+
### `analyze_cached`
|
|
52
|
+
|
|
53
|
+
Analyze a code map, reusing reports for an exact map and configuration identity.
|
|
54
|
+
|
|
51
55
|
### `discover`
|
|
52
56
|
|
|
53
57
|
Discover supported source languages beneath a root using the caller's scan policy.
|
|
@@ -64,6 +68,18 @@ descendants are deliberately unobserved and are not included in file counts.
|
|
|
64
68
|
|
|
65
69
|
Extract source files and return a queryable code map.
|
|
66
70
|
|
|
71
|
+
### `generate_map_cached`
|
|
72
|
+
|
|
73
|
+
Return a code map with content-addressed source and complete-manifest reuse.
|
|
74
|
+
|
|
75
|
+
### `generate_queryable_map_cached`
|
|
76
|
+
|
|
77
|
+
Return a queryable code map with content-addressed persistent reuse.
|
|
78
|
+
|
|
79
|
+
### `clear_cache`
|
|
80
|
+
|
|
81
|
+
Clear only the Modwire-owned directory for one cache namespace.
|
|
82
|
+
|
|
67
83
|
### `load_configuration`
|
|
68
84
|
|
|
69
85
|
Load and validate an architecture configuration from a directory.
|
|
@@ -84,6 +100,10 @@ Run the native extractor transport for one supported language.
|
|
|
84
100
|
|
|
85
101
|
Run the Modwire command line interface and return its process status.
|
|
86
102
|
|
|
103
|
+
## `CacheOptions`
|
|
104
|
+
|
|
105
|
+
Generic persistent-cache settings supplied by a caller.
|
|
106
|
+
|
|
87
107
|
## `ScanPolicy`
|
|
88
108
|
|
|
89
109
|
Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
|
|
@@ -20,6 +20,10 @@ Return the available architecture reports.
|
|
|
20
20
|
|
|
21
21
|
Analyze a code map with a validated architecture configuration.
|
|
22
22
|
|
|
23
|
+
### `analyze_cached`
|
|
24
|
+
|
|
25
|
+
Analyze a code map, reusing reports for an exact map and configuration identity.
|
|
26
|
+
|
|
23
27
|
### `discover`
|
|
24
28
|
|
|
25
29
|
Discover supported source languages beneath a root using the caller's scan policy.
|
|
@@ -36,6 +40,18 @@ descendants are deliberately unobserved and are not included in file counts.
|
|
|
36
40
|
|
|
37
41
|
Extract source files and return a queryable code map.
|
|
38
42
|
|
|
43
|
+
### `generate_map_cached`
|
|
44
|
+
|
|
45
|
+
Return a code map with content-addressed source and complete-manifest reuse.
|
|
46
|
+
|
|
47
|
+
### `generate_queryable_map_cached`
|
|
48
|
+
|
|
49
|
+
Return a queryable code map with content-addressed persistent reuse.
|
|
50
|
+
|
|
51
|
+
### `clear_cache`
|
|
52
|
+
|
|
53
|
+
Clear only the Modwire-owned directory for one cache namespace.
|
|
54
|
+
|
|
39
55
|
### `load_configuration`
|
|
40
56
|
|
|
41
57
|
Load and validate an architecture configuration from a directory.
|
|
@@ -56,6 +72,10 @@ Run the native extractor transport for one supported language.
|
|
|
56
72
|
|
|
57
73
|
Run the Modwire command line interface and return its process status.
|
|
58
74
|
|
|
75
|
+
## `CacheOptions`
|
|
76
|
+
|
|
77
|
+
Generic persistent-cache settings supplied by a caller.
|
|
78
|
+
|
|
59
79
|
## `ScanPolicy`
|
|
60
80
|
|
|
61
81
|
Caller-owned filesystem traversal policy with explicit exclusions and opt-in symlink following.
|
|
@@ -10,13 +10,14 @@ from .architecture.config.models.architecture_config import ArchitectureConfig
|
|
|
10
10
|
from .architecture.facade import ArchitectureFacade
|
|
11
11
|
from .architecture.report.models.report_catalog import ReportCatalog
|
|
12
12
|
from .architecture.report.models.report_node import ReportNode
|
|
13
|
+
from .cli.cache.models.cache_options import CacheOptions
|
|
13
14
|
from .cli.facade import CliFacade
|
|
14
15
|
from .cli.pipeline.models.scan_policy import ScanPolicy
|
|
15
16
|
from .extraction.facade import ExtractionFacade
|
|
16
17
|
from .shared.code.models.code_map import CodeMap
|
|
17
18
|
from .shared.code.models.queryable_code_map import QueryableCodeMap
|
|
18
19
|
|
|
19
|
-
__all__ = ["CodeMap", "ModwireApplication", "QueryableCodeMap", "ScanPolicy"]
|
|
20
|
+
__all__ = ["CacheOptions", "CodeMap", "ModwireApplication", "QueryableCodeMap", "ScanPolicy"]
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
@dataclass(frozen=True)
|
|
@@ -56,6 +57,18 @@ class ModwireApplication:
|
|
|
56
57
|
|
|
57
58
|
return self.architecture.analyze(code_map, config)
|
|
58
59
|
|
|
60
|
+
def analyze_cached(
|
|
61
|
+
self, code_map: QueryableCodeMap, config: ArchitectureConfig, options: CacheOptions
|
|
62
|
+
) -> tuple[ReportNode, ...]:
|
|
63
|
+
"""Analyze a code map, reusing reports for an exact map and configuration identity."""
|
|
64
|
+
|
|
65
|
+
cached = self.cli.cached_reports(code_map.code_map, config, options)
|
|
66
|
+
if cached is not None:
|
|
67
|
+
return cached
|
|
68
|
+
reports = self.architecture.analyze(code_map, config)
|
|
69
|
+
self.cli.store_reports(code_map.code_map, config, reports, options)
|
|
70
|
+
return reports
|
|
71
|
+
|
|
59
72
|
def discover(self, root: str, policy: ScanPolicy) -> tuple[str, ...]:
|
|
60
73
|
"""Discover supported source languages beneath a root using the caller's scan policy."""
|
|
61
74
|
|
|
@@ -81,6 +94,30 @@ class ModwireApplication:
|
|
|
81
94
|
|
|
82
95
|
return QueryableCodeMap(code_map=self.generate_map(language, root, policy))
|
|
83
96
|
|
|
97
|
+
def generate_map_cached(self, language: str, root: str, policy: ScanPolicy, options: CacheOptions) -> CodeMap:
|
|
98
|
+
"""Return a code map with content-addressed source and complete-manifest reuse."""
|
|
99
|
+
|
|
100
|
+
request = self.extraction.request(language, str(root))
|
|
101
|
+
snapshot = self.cli.extract_cached(request, policy, options)
|
|
102
|
+
cached = self.cli.cached_code_map(snapshot, options)
|
|
103
|
+
if cached is not None:
|
|
104
|
+
return cached
|
|
105
|
+
code_map = self.extraction.generate_map(language, snapshot.extraction)
|
|
106
|
+
self.cli.store_code_map(snapshot, code_map, options)
|
|
107
|
+
return code_map
|
|
108
|
+
|
|
109
|
+
def generate_queryable_map_cached(
|
|
110
|
+
self, language: str, root: str, policy: ScanPolicy, options: CacheOptions
|
|
111
|
+
) -> QueryableCodeMap:
|
|
112
|
+
"""Return a queryable code map with content-addressed persistent reuse."""
|
|
113
|
+
|
|
114
|
+
return QueryableCodeMap(code_map=self.generate_map_cached(language, root, policy, options))
|
|
115
|
+
|
|
116
|
+
def clear_cache(self, options: CacheOptions) -> None:
|
|
117
|
+
"""Clear only the Modwire-owned directory for one cache namespace."""
|
|
118
|
+
|
|
119
|
+
self.cli.clear_cache(options)
|
|
120
|
+
|
|
84
121
|
def load_configuration(self, dot_dir: str) -> ArchitectureConfig:
|
|
85
122
|
"""Load and validate an architecture configuration from a directory."""
|
|
86
123
|
|
|
@@ -94,7 +131,7 @@ class ModwireApplication:
|
|
|
94
131
|
def generate_documentation(self, readme: str, check: bool) -> int:
|
|
95
132
|
"""Generate this README from the published interface docstrings, or check that it is current."""
|
|
96
133
|
|
|
97
|
-
return self.cli.generate_documentation(str(readme), (type(self), ScanPolicy), check)
|
|
134
|
+
return self.cli.generate_documentation(str(readme), (type(self), CacheOptions, ScanPolicy), check)
|
|
98
135
|
|
|
99
136
|
def run_extractor(self, language: str) -> int:
|
|
100
137
|
"""Run the native extractor transport for one supported language."""
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ValidationError
|
|
6
|
+
from wireup import injectable
|
|
7
|
+
|
|
8
|
+
from ...architecture.config.models.architecture_config import ArchitectureConfig
|
|
9
|
+
from ...architecture.report.models.report_node import ReportNode
|
|
10
|
+
from ...extraction.extractors.models.extraction_request import ExtractionRequest
|
|
11
|
+
from ...shared.code.models.code_map import CodeMap
|
|
12
|
+
from ...shared.code.models.duplicate_identity_error import DuplicateIdentityError
|
|
13
|
+
from ...shared.code.models.identity import FileId, ModuleId
|
|
14
|
+
from ...shared.code.models.source_extraction import SourceExtraction
|
|
15
|
+
from ...shared.code.models.source_file import SourceFile
|
|
16
|
+
from ..pipeline.domain import SourceReader
|
|
17
|
+
from ..pipeline.models.scan_policy import ScanPolicy
|
|
18
|
+
from .domain import CacheStorage
|
|
19
|
+
from .models.cache_key import CacheKey
|
|
20
|
+
from .models.cache_options import CacheOptions
|
|
21
|
+
from .models.extraction_snapshot import ExtractionSnapshot
|
|
22
|
+
from .services.cache_codec import CacheCodec
|
|
23
|
+
from .services.cache_identity import CacheIdentity
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@injectable
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class CacheApplication:
|
|
29
|
+
reader: SourceReader
|
|
30
|
+
storage: CacheStorage
|
|
31
|
+
identity: CacheIdentity
|
|
32
|
+
codec: CacheCodec
|
|
33
|
+
|
|
34
|
+
def has_source_files(self, request: ExtractionRequest, policy: ScanPolicy) -> bool:
|
|
35
|
+
return self.reader.has_source_files(request, policy)
|
|
36
|
+
|
|
37
|
+
def extract(self, request: ExtractionRequest, policy: ScanPolicy) -> SourceExtraction:
|
|
38
|
+
self.reader.ensure_available(request.runtime)
|
|
39
|
+
return self.reader.extract_source(request, policy)
|
|
40
|
+
|
|
41
|
+
def extract_cached(
|
|
42
|
+
self, request: ExtractionRequest, policy: ScanPolicy, options: CacheOptions
|
|
43
|
+
) -> ExtractionSnapshot:
|
|
44
|
+
inventory = self.reader.inventory(request, policy)
|
|
45
|
+
keys = {entry.source_id: self.identity.source(request, policy, entry) for entry in inventory.entries}
|
|
46
|
+
files: dict[FileId, SourceFile] = {}
|
|
47
|
+
misses: list[FileId] = []
|
|
48
|
+
for entry in inventory.entries:
|
|
49
|
+
key = keys[entry.source_id]
|
|
50
|
+
value = self._read(options, key)
|
|
51
|
+
try:
|
|
52
|
+
source_file = SourceFile.model_validate(value)
|
|
53
|
+
if source_file.file_id != entry.source_id:
|
|
54
|
+
raise ValueError("Cached source identity does not match its key.")
|
|
55
|
+
files[entry.source_id] = source_file
|
|
56
|
+
except (TypeError, ValueError, ValidationError):
|
|
57
|
+
self.storage.delete(options, key)
|
|
58
|
+
misses.append(entry.source_id)
|
|
59
|
+
|
|
60
|
+
if misses or not inventory.entries:
|
|
61
|
+
self.reader.ensure_available(request.runtime)
|
|
62
|
+
extracted = self.reader.extract_entries(request, inventory, tuple(misses))
|
|
63
|
+
for source_id in misses:
|
|
64
|
+
source_file = extracted.get(source_id)
|
|
65
|
+
if source_file is None:
|
|
66
|
+
raise RuntimeError(f"Extractor omitted a requested source file: {source_id}")
|
|
67
|
+
files[source_id] = source_file
|
|
68
|
+
self._write(options, keys[source_id], source_file.model_dump(mode="json"))
|
|
69
|
+
|
|
70
|
+
ordered_files = {entry.source_id: files[entry.source_id] for entry in inventory.entries}
|
|
71
|
+
modules: dict[ModuleId, FileId] = {}
|
|
72
|
+
for file_id, source_file in ordered_files.items():
|
|
73
|
+
existing = modules.get(source_file.module_id)
|
|
74
|
+
if existing is not None:
|
|
75
|
+
raise DuplicateIdentityError("module", source_file.module_id, existing, file_id)
|
|
76
|
+
modules[source_file.module_id] = file_id
|
|
77
|
+
|
|
78
|
+
extraction = SourceExtraction(
|
|
79
|
+
files=ordered_files,
|
|
80
|
+
modules=modules,
|
|
81
|
+
files_found=inventory.files_found,
|
|
82
|
+
files_excluded=inventory.files_excluded,
|
|
83
|
+
directories_pruned=inventory.directories_pruned,
|
|
84
|
+
)
|
|
85
|
+
manifest = self.identity.manifest(request, policy, inventory.entries)
|
|
86
|
+
self._write(
|
|
87
|
+
options,
|
|
88
|
+
manifest,
|
|
89
|
+
{
|
|
90
|
+
"sources": [
|
|
91
|
+
{
|
|
92
|
+
"relative_path": entry.relative_path,
|
|
93
|
+
"content_digest": entry.content_digest,
|
|
94
|
+
"source_key": keys[entry.source_id].digest,
|
|
95
|
+
}
|
|
96
|
+
for entry in inventory.entries
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
self.prune(options)
|
|
101
|
+
return ExtractionSnapshot(extraction=extraction, manifest=manifest)
|
|
102
|
+
|
|
103
|
+
def code_map(self, snapshot: ExtractionSnapshot, options: CacheOptions) -> CodeMap | None:
|
|
104
|
+
key = self.identity.code_map("", snapshot.manifest)
|
|
105
|
+
value = self._read(options, key)
|
|
106
|
+
try:
|
|
107
|
+
return CodeMap.model_validate(value)
|
|
108
|
+
except (TypeError, ValueError, ValidationError):
|
|
109
|
+
self.storage.delete(options, key)
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
def store_code_map(self, snapshot: ExtractionSnapshot, code_map: CodeMap, options: CacheOptions) -> None:
|
|
113
|
+
self._write(options, self.identity.code_map("", snapshot.manifest), code_map.model_dump(mode="json"))
|
|
114
|
+
self.prune(options)
|
|
115
|
+
|
|
116
|
+
def reports(
|
|
117
|
+
self, code_map: CodeMap, config: ArchitectureConfig, options: CacheOptions
|
|
118
|
+
) -> tuple[ReportNode, ...] | None:
|
|
119
|
+
key = self.identity.reports(code_map, config)
|
|
120
|
+
value = self._read(options, key)
|
|
121
|
+
try:
|
|
122
|
+
if not isinstance(value, list):
|
|
123
|
+
raise ValueError("Cached reports must be a list.")
|
|
124
|
+
reports = tuple(self._report(item) for item in cast(list[object], value))
|
|
125
|
+
return tuple(sorted(reports, key=lambda item: (item.metadata.order, item.metadata.id)))
|
|
126
|
+
except (AttributeError, ImportError, KeyError, TypeError, ValueError, ValidationError):
|
|
127
|
+
self.storage.delete(options, key)
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
def store_reports(
|
|
131
|
+
self,
|
|
132
|
+
code_map: CodeMap,
|
|
133
|
+
config: ArchitectureConfig,
|
|
134
|
+
reports: tuple[ReportNode, ...],
|
|
135
|
+
options: CacheOptions,
|
|
136
|
+
) -> None:
|
|
137
|
+
value = [
|
|
138
|
+
{
|
|
139
|
+
"model": f"{type(report).__module__}.{type(report).__qualname__}",
|
|
140
|
+
"payload": report.model_dump(mode="json", exclude_computed_fields=True),
|
|
141
|
+
}
|
|
142
|
+
for report in reports
|
|
143
|
+
]
|
|
144
|
+
self._write(options, self.identity.reports(code_map, config), value)
|
|
145
|
+
self.prune(options)
|
|
146
|
+
|
|
147
|
+
def clear(self, options: CacheOptions) -> None:
|
|
148
|
+
self.storage.clear(options)
|
|
149
|
+
|
|
150
|
+
def prune(self, options: CacheOptions) -> None:
|
|
151
|
+
entries = self.storage.entries(options)
|
|
152
|
+
total = sum(entry.size for entry in entries)
|
|
153
|
+
for entry in sorted(entries, key=lambda item: (item.last_access_ns, item.key.kind, item.key.digest)):
|
|
154
|
+
if total <= options.max_bytes:
|
|
155
|
+
break
|
|
156
|
+
self.storage.delete(options, entry.key)
|
|
157
|
+
total -= entry.size
|
|
158
|
+
|
|
159
|
+
def _read(self, options: CacheOptions, key: CacheKey) -> object | None:
|
|
160
|
+
payload = self.storage.read(options, key)
|
|
161
|
+
if payload is None:
|
|
162
|
+
return None
|
|
163
|
+
value = self.codec.decode(key, payload)
|
|
164
|
+
if value is None:
|
|
165
|
+
self.storage.delete(options, key)
|
|
166
|
+
return value
|
|
167
|
+
|
|
168
|
+
def _write(self, options: CacheOptions, key: CacheKey, value: object) -> None:
|
|
169
|
+
self.storage.write(options, key, self.codec.encode(key, value))
|
|
170
|
+
|
|
171
|
+
def _report(self, value: object) -> ReportNode:
|
|
172
|
+
if not isinstance(value, dict):
|
|
173
|
+
raise ValueError("Cached report entry must be an object.")
|
|
174
|
+
entry = cast(dict[str, object], value)
|
|
175
|
+
model_name = entry["model"]
|
|
176
|
+
payload = entry["payload"]
|
|
177
|
+
if not isinstance(model_name, str) or not model_name.startswith("modwire.architecture."):
|
|
178
|
+
raise ValueError("Cached report model is outside the architecture package.")
|
|
179
|
+
module_name, _, class_name = model_name.rpartition(".")
|
|
180
|
+
model: Any = getattr(importlib.import_module(module_name), class_name)
|
|
181
|
+
if not isinstance(model, type) or not issubclass(model, BaseModel) or not issubclass(model, ReportNode):
|
|
182
|
+
raise ValueError("Cached report model is not a report node.")
|
|
183
|
+
return model.model_validate(payload)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from .models.cache_entry import CacheEntry
|
|
4
|
+
from .models.cache_key import CacheKey
|
|
5
|
+
from .models.cache_options import CacheOptions
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CacheStorage(ABC):
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def read(self, options: CacheOptions, key: CacheKey) -> bytes | None:
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def write(self, options: CacheOptions, key: CacheKey, payload: bytes) -> None:
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def entries(self, options: CacheOptions) -> tuple[CacheEntry, ...]:
|
|
19
|
+
raise NotImplementedError
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def delete(self, options: CacheOptions, key: CacheKey) -> None:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def clear(self, options: CacheOptions) -> None:
|
|
27
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from ....shared.values.models.value_model import ValueModel
|
|
4
|
+
|
|
5
|
+
type CacheKind = Literal["source", "manifest", "code-map", "reports"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CacheKey(ValueModel):
|
|
9
|
+
schema_version: Literal[1] = 1
|
|
10
|
+
kind: CacheKind
|
|
11
|
+
digest: str
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from pydantic import field_validator
|
|
2
|
+
|
|
3
|
+
from ....shared.values.models.value_model import ValueModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CacheOptions(ValueModel):
|
|
7
|
+
"""Generic persistent-cache settings supplied by a caller."""
|
|
8
|
+
|
|
9
|
+
directory: str
|
|
10
|
+
namespace: str
|
|
11
|
+
max_bytes: int
|
|
12
|
+
|
|
13
|
+
@field_validator("directory", "namespace")
|
|
14
|
+
@classmethod
|
|
15
|
+
def _non_empty(cls, value: str) -> str:
|
|
16
|
+
if not value.strip():
|
|
17
|
+
raise ValueError("Cache directory and namespace must not be empty.")
|
|
18
|
+
return value
|
|
19
|
+
|
|
20
|
+
@field_validator("max_bytes")
|
|
21
|
+
@classmethod
|
|
22
|
+
def _positive_size(cls, value: int) -> int:
|
|
23
|
+
if value < 1:
|
|
24
|
+
raise ValueError("Cache max_bytes must be at least one.")
|
|
25
|
+
return value
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import json
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, cast
|
|
5
|
+
|
|
6
|
+
from wireup import injectable
|
|
7
|
+
|
|
8
|
+
from ..models.cache_key import CacheKey
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@injectable
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class CacheCodec:
|
|
14
|
+
def encode(self, key: CacheKey, value: object) -> bytes:
|
|
15
|
+
payload = json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
|
|
16
|
+
envelope = {
|
|
17
|
+
"schema_version": key.schema_version,
|
|
18
|
+
"key": key.model_dump(mode="json"),
|
|
19
|
+
"payload_digest": hashlib.sha256(payload).hexdigest(),
|
|
20
|
+
"payload": value,
|
|
21
|
+
}
|
|
22
|
+
return json.dumps(envelope, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
|
|
23
|
+
|
|
24
|
+
def decode(self, key: CacheKey, payload: bytes) -> object | None:
|
|
25
|
+
try:
|
|
26
|
+
parsed: Any = json.loads(payload)
|
|
27
|
+
if not isinstance(parsed, dict):
|
|
28
|
+
return None
|
|
29
|
+
envelope = cast(dict[str, object], parsed)
|
|
30
|
+
if envelope.get("schema_version") != key.schema_version:
|
|
31
|
+
return None
|
|
32
|
+
if envelope.get("key") != key.model_dump(mode="json"):
|
|
33
|
+
return None
|
|
34
|
+
value = envelope["payload"]
|
|
35
|
+
serialized = json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
|
|
36
|
+
if envelope.get("payload_digest") != hashlib.sha256(serialized).hexdigest():
|
|
37
|
+
return None
|
|
38
|
+
return value
|
|
39
|
+
except (KeyError, TypeError, ValueError, UnicodeDecodeError):
|
|
40
|
+
return None
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import json
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from functools import lru_cache
|
|
5
|
+
from importlib import metadata, resources
|
|
6
|
+
from typing import Any, ClassVar
|
|
7
|
+
|
|
8
|
+
from wireup import injectable
|
|
9
|
+
|
|
10
|
+
from ....architecture.config.models.architecture_config import ArchitectureConfig
|
|
11
|
+
from ....extraction.extractors.models.extraction_request import ExtractionRequest
|
|
12
|
+
from ....shared.code.models.code_map import CodeMap
|
|
13
|
+
from ...cache.models.cache_key import CacheKey, CacheKind
|
|
14
|
+
from ...cache.models.source_entry import SourceEntry
|
|
15
|
+
from ...pipeline.models.scan_policy import ScanPolicy
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@injectable
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class CacheIdentity:
|
|
21
|
+
SOURCE_VERSION: ClassVar[int] = 1
|
|
22
|
+
MANIFEST_VERSION: ClassVar[int] = 1
|
|
23
|
+
CODE_MAP_VERSION: ClassVar[int] = 1
|
|
24
|
+
REPORT_VERSION: ClassVar[int] = 1
|
|
25
|
+
|
|
26
|
+
def source(self, request: ExtractionRequest, policy: ScanPolicy, entry: SourceEntry) -> CacheKey:
|
|
27
|
+
return self._key(
|
|
28
|
+
"source",
|
|
29
|
+
{
|
|
30
|
+
"version": self.SOURCE_VERSION,
|
|
31
|
+
"package": self._package_version(),
|
|
32
|
+
"runtime": self._runtime_identity(request),
|
|
33
|
+
"scan_policy": policy.model_dump(mode="json"),
|
|
34
|
+
"relative_path": entry.relative_path,
|
|
35
|
+
"source_id": entry.source_id,
|
|
36
|
+
"content_digest": entry.content_digest,
|
|
37
|
+
},
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def manifest(self, request: ExtractionRequest, policy: ScanPolicy, entries: tuple[SourceEntry, ...]) -> CacheKey:
|
|
41
|
+
sources = tuple(
|
|
42
|
+
{
|
|
43
|
+
"relative_path": entry.relative_path,
|
|
44
|
+
"content_digest": entry.content_digest,
|
|
45
|
+
"source_key": self.source(request, policy, entry).digest,
|
|
46
|
+
}
|
|
47
|
+
for entry in sorted(entries, key=lambda item: item.relative_path)
|
|
48
|
+
)
|
|
49
|
+
return self._key(
|
|
50
|
+
"manifest",
|
|
51
|
+
{
|
|
52
|
+
"version": self.MANIFEST_VERSION,
|
|
53
|
+
"package": self._package_version(),
|
|
54
|
+
"runtime": self._runtime_identity(request),
|
|
55
|
+
"scan_policy": policy.model_dump(mode="json"),
|
|
56
|
+
"sources": sources,
|
|
57
|
+
},
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def code_map(self, language: str, manifest: CacheKey) -> CacheKey:
|
|
61
|
+
return self._key(
|
|
62
|
+
"code-map",
|
|
63
|
+
{
|
|
64
|
+
"version": self.CODE_MAP_VERSION,
|
|
65
|
+
"package": self._package_version(),
|
|
66
|
+
"code_map_schema": CodeMap.schema_version,
|
|
67
|
+
"language": language,
|
|
68
|
+
"manifest": manifest.model_dump(mode="json"),
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def reports(self, code_map: CodeMap, config: ArchitectureConfig) -> CacheKey:
|
|
73
|
+
return self._key(
|
|
74
|
+
"reports",
|
|
75
|
+
{
|
|
76
|
+
"version": self.REPORT_VERSION,
|
|
77
|
+
"package": self._package_version(),
|
|
78
|
+
"code_map": code_map.model_dump(mode="json"),
|
|
79
|
+
"configuration": config.model_dump(mode="json"),
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def _runtime_identity(self, request: ExtractionRequest) -> dict[str, object]:
|
|
84
|
+
runtime = request.runtime
|
|
85
|
+
return {
|
|
86
|
+
"runtime": runtime.model_dump(mode="json"),
|
|
87
|
+
"batch": request.batch_config.model_dump(mode="json"),
|
|
88
|
+
"resource_digest": self._resource_digest(runtime.resource.package, runtime.resource.path),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@lru_cache(maxsize=32)
|
|
92
|
+
def _resource_digest(self, package: str, path: str) -> str:
|
|
93
|
+
resource = resources.files(package).joinpath(path)
|
|
94
|
+
return hashlib.sha256(resource.read_bytes()).hexdigest()
|
|
95
|
+
|
|
96
|
+
@lru_cache(maxsize=1)
|
|
97
|
+
def _package_version(self) -> str:
|
|
98
|
+
try:
|
|
99
|
+
return metadata.version("modwire")
|
|
100
|
+
except metadata.PackageNotFoundError:
|
|
101
|
+
return "0+unknown"
|
|
102
|
+
|
|
103
|
+
def _key(self, kind: CacheKind, value: object) -> CacheKey:
|
|
104
|
+
payload: Any = value
|
|
105
|
+
serialized = json.dumps(payload, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
|
|
106
|
+
return CacheKey(kind=kind, digest=hashlib.sha256(serialized).hexdigest())
|