Skip to content

Commit b2be899

Browse files
committed
Add new flag --select-detectors
1 parent 8517a0a commit b2be899

File tree

11 files changed

+271
-19
lines changed

11 files changed

+271
-19
lines changed

TODOS.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
- Rename CLI flag '--only-container-info' to '--only-source-info'
44
- Publish package to PyPI
55
- Add host_info_detector (similar to docker_info_detector)
6-
- Add CLI flag to select a subset of detectors (see how Syft does it: <https://github.com/anchore/syft/wiki/package-cataloger-selection>)
76
- Extend the set of supported package managers with the common ones for Go, PHP and Java
87
- Add Dockerfile
98
- Add support for Podman

dependency_resolver/__main__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def parse_arguments() -> argparse.Namespace:
3737
%(prog)s --debug # Enable debug output
3838
%(prog)s --skip-system-scope # Skip system scope package managers
3939
%(prog)s --skip-hash-collection # Skip hash collection for improved performance
40+
%(prog)s --select-detectors "pip,dpkg" # Use only pip and dpkg detectors
4041
""",
4142
)
4243

@@ -85,6 +86,12 @@ def parse_arguments() -> argparse.Namespace:
8586
help="Skip hash collection for packages and project locations to improve performance",
8687
)
8788

89+
parser.add_argument(
90+
"--select-detectors",
91+
type=str,
92+
help="Comma-separated list of detectors to use (e.g., 'pip,dpkg'). Available: pip, npm, dpkg, apk, maven, docker-info",
93+
)
94+
8895
return parser.parse_args()
8996

9097

@@ -133,6 +140,7 @@ def main() -> None:
133140
skip_system_scope=args.skip_system_scope,
134141
venv_path=args.venv_path,
135142
skip_hash_collection=args.skip_hash_collection,
143+
selected_detectors=args.select_detectors,
136144
)
137145
dependencies = orchestrator.resolve_dependencies(executor, args.working_dir, args.only_container_info)
138146
formatter = OutputFormatter(debug=args.debug)

dependency_resolver/core/orchestrator.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ def __init__(
1717
skip_system_scope: bool = False,
1818
venv_path: str | None = None,
1919
skip_hash_collection: bool = False,
20+
selected_detectors: str | None = None,
2021
):
2122
self.debug = debug
2223
self.skip_system_scope = skip_system_scope
2324
self.skip_hash_collection = skip_hash_collection
2425

25-
# Create detector instances
26-
self.detectors: list[PackageManagerDetector] = [
26+
# Create all detector instances
27+
all_detectors: list[PackageManagerDetector] = [
2728
DockerInfoDetector(),
2829
DpkgDetector(),
2930
ApkDetector(),
@@ -32,6 +33,26 @@ def __init__(
3233
NpmDetector(debug=debug),
3334
]
3435

36+
# Filter detectors based on selection
37+
if selected_detectors:
38+
selected_names = [name.strip() for name in selected_detectors.split(",")]
39+
available_names = {detector.NAME for detector in all_detectors}
40+
41+
# Validate detector names
42+
invalid_names = [name for name in selected_names if name not in available_names]
43+
if invalid_names:
44+
raise ValueError(
45+
f"Invalid detector names: {', '.join(invalid_names)}. Available detectors: {', '.join(sorted(available_names))}"
46+
)
47+
48+
# Filter to only selected detectors
49+
self.detectors = [detector for detector in all_detectors if detector.NAME in selected_names]
50+
if self.debug:
51+
selected_detector_names = [detector.NAME for detector in self.detectors]
52+
print(f"Selected detectors: {', '.join(selected_detector_names)}")
53+
else:
54+
self.detectors = all_detectors
55+
3556
def resolve_dependencies(
3657
self, executor: EnvironmentExecutor, working_dir: Optional[str] = None, only_container_info: bool = False
3758
) -> dict[str, Any]:

docs/guides/troubleshooting.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,10 @@ npm --version
171171

172172
1. Use `--skip-system-scope` to skip system package managers
173173
2. Use `--skip-hash-collection` to skip hash generation for packages and locations
174-
3. Use `--only-container-info` for Docker metadata only
175-
4. Specify working directory to limit scope
176-
5. Check if system has many installed packages
174+
3. Use `--select-detectors` to analyze only specific package managers (e.g., `--select-detectors "pip,npm"`)
175+
4. Use `--only-container-info` for Docker metadata only
176+
5. Specify working directory to limit scope
177+
6. Check if system has many installed packages
177178

178179
## Getting Help
179180

docs/usage/cli-guide.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,35 @@ python3 -m dependency_resolver --skip-system-scope
4646

4747
# Skip hash collection for improved performance
4848
python3 -m dependency_resolver --skip-hash-collection
49+
50+
# Select specific detectors to run
51+
python3 -m dependency_resolver --select-detectors "pip,dpkg"
4952
```
5053

54+
## Detector Selection
55+
56+
Control which package managers are analyzed with the `--select-detectors` flag:
57+
58+
```bash
59+
# Use only pip and dpkg detectors
60+
python3 -m dependency_resolver --select-detectors "pip,dpkg"
61+
62+
# Use only npm detector for Node.js projects
63+
python3 -m dependency_resolver --select-detectors "npm"
64+
65+
# Use multiple detectors with debug output
66+
python3 -m dependency_resolver --select-detectors "pip,npm,maven" --debug
67+
```
68+
69+
**Available detectors:**
70+
71+
- `pip` - Python packages (pip/PyPI)
72+
- `npm` - Node.js packages (npm/yarn)
73+
- `dpkg` - Debian/Ubuntu system packages
74+
- `apk` - Alpine Linux system packages
75+
- `maven` - Java Maven dependencies
76+
- `docker-info` - Docker container metadata
77+
5178
## Common Usage Patterns
5279

5380
### Analyzing a Specific Project
@@ -60,6 +87,9 @@ python3 -m dependency_resolver --working-dir /path/to/python/project
6087

6188
# Analyze Node.js project
6289
python3 -m dependency_resolver --working-dir /path/to/nodejs/project
90+
91+
# Analyze only Python dependencies in a project
92+
python3 -m dependency_resolver --working-dir /path/to/python/project --select-detectors "pip"
6393
```
6494

6595
### Comprehensive Docker Analysis

docs/usage/programmatic-api.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ from dependency_resolver import Orchestrator, HostExecutor, DockerExecutor, Outp
6868

6969
# Host system analysis with custom settings
7070
executor = HostExecutor()
71-
orchestrator = Orchestrator(debug=True, skip_system_scope=True, skip_hash_collection=True)
71+
orchestrator = Orchestrator(
72+
debug=True,
73+
skip_system_scope=True,
74+
skip_hash_collection=True,
75+
selected_detectors="pip,npm" # Only analyze Python and Node.js dependencies
76+
)
7277
dependencies = orchestrator.resolve_dependencies(executor)
7378

7479
# Format output
@@ -84,7 +89,12 @@ from dependency_resolver import Orchestrator, DockerExecutor, OutputFormatter
8489
# Docker container analysis
8590
container_id = "nginx"
8691
executor = DockerExecutor(container_id)
87-
orchestrator = Orchestrator(debug=False, skip_system_scope=False, skip_hash_collection=False)
92+
orchestrator = Orchestrator(
93+
debug=False,
94+
skip_system_scope=False,
95+
skip_hash_collection=False,
96+
selected_detectors="dpkg,docker-info" # Analyze system packages and container info only
97+
)
8898

8999
dependencies = orchestrator.resolve_dependencies(executor, working_dir="/app")
90100

@@ -119,10 +129,30 @@ orchestrator = Orchestrator(
119129
debug=True, # Enable debug output
120130
skip_system_scope=False, # Skip system-wide package managers
121131
venv_path="/path/to/venv", # Specify Python virtual environment path
122-
skip_hash_collection=False # Skip hash collection for improved performance
132+
skip_hash_collection=False, # Skip hash collection for improved performance
133+
selected_detectors="pip,npm" # Use only specific detectors
123134
)
124135
```
125136

137+
### Detector Selection
138+
139+
Control which package managers are analyzed by specifying the `selected_detectors` parameter:
140+
141+
```python
142+
from dependency_resolver import Orchestrator, HostExecutor
143+
144+
# Use only Python pip detector
145+
orchestrator = Orchestrator(selected_detectors="pip")
146+
147+
# Use multiple specific detectors
148+
orchestrator = Orchestrator(selected_detectors="pip,npm,maven")
149+
150+
# Use all detectors (default behavior)
151+
orchestrator = Orchestrator(selected_detectors=None)
152+
```
153+
154+
**Available detectors:** `pip`, `npm`, `dpkg`, `apk`, `maven`, `docker-info`
155+
126156
### Executor Options
127157

128158
```python

performance-analysis/detector-benchmarks.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ show_usage() {
8989
echo " --profiling Enable detailed profiling (slower, for analysis)"
9090
echo " --interface TYPE Interface type: 'cli' or 'programmatic' (default: cli)"
9191
echo " --scenario TYPE Specific scenario: varies by detector type"
92+
echo " --select-detectors LIST Comma-separated list of detectors to use (e.g., 'pip,dpkg')"
9293
echo ""
9394
echo "Specific scenario types by detector:"
9495
echo " host: skip-system, full-system, all (default: all)"
@@ -105,6 +106,7 @@ show_usage() {
105106
echo " $0 --interface programmatic host # Run host detector with programmatic interface"
106107
echo " $0 --scenario small npm # Run only small NPM scenario"
107108
echo " $0 --scenario skip-system host # Run only skip-system host scenario"
109+
echo " $0 --select-detectors 'pip,dpkg' host # Run host detector with only pip and dpkg"
108110
}
109111

110112
# Parse command line arguments
@@ -115,6 +117,7 @@ SKIP_SYSTEM_CHECK=false
115117
SKIP_HASH_COLLECTION=false
116118
ENABLE_PROFILING=false
117119
INTERFACE="cli"
120+
SELECT_DETECTORS=""
118121

119122
while [[ $# -gt 0 ]]; do
120123
case $1 in
@@ -158,6 +161,16 @@ while [[ $# -gt 0 ]]; do
158161
exit 1
159162
fi
160163
;;
164+
--select-detectors)
165+
if [[ -n $2 ]]; then
166+
SELECT_DETECTORS="$2"
167+
shift 2
168+
else
169+
print_error "--select-detectors requires a comma-separated list of detectors"
170+
show_usage
171+
exit 1
172+
fi
173+
;;
161174
all|host|npm|pip)
162175
DETECTOR_TYPE="$1"
163176
shift
@@ -177,6 +190,7 @@ SESSION_ID=$(date +%Y-%m-%d_%H-%M-%S)
177190
export ENABLE_PROFILING
178191
export SKIP_HASH_COLLECTION
179192
export SESSION_ID
193+
export SELECT_DETECTORS
180194

181195
# Function to display enhanced results with current vs historical separation
182196
display_enhanced_results() {
@@ -365,6 +379,7 @@ main() {
365379
echo "Detector type: $DETECTOR_TYPE"
366380
echo "Specific scenario: $SPECIFIC_SCENARIO"
367381
echo "Interface: $INTERFACE"
382+
echo "Selected detectors: ${SELECT_DETECTORS:-all}"
368383
echo "Profiles directory: $PROFILES_DIR"
369384
echo "Profiling enabled: ${ENABLE_PROFILING}"
370385
echo ""

performance-analysis/detectors/common.sh

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,26 @@ run_docker_benchmark() {
322322
echo "Hash collection disabled for faster execution"
323323
fi
324324

325+
# Prepare select detectors flag
326+
local select_flag=""
327+
local select_arg=""
328+
if [[ -n "${SELECT_DETECTORS:-}" ]]; then
329+
select_flag="--select-detectors '$SELECT_DETECTORS'"
330+
select_arg=", selected_detectors='$SELECT_DETECTORS'"
331+
echo "Using selected detectors: $SELECT_DETECTORS"
332+
fi
333+
325334
echo "Measuring execution time..."
326335
start_time=$(date +%s.%N)
327336

328337
local cmd_result=0
329338
if [[ "$interface" == "cli" ]]; then
330-
result=$(cd "$PROJECT_ROOT" && python3 -m dependency_resolver docker "$container_name" $hash_flag) || cmd_result=$?
339+
local cmd="cd '$PROJECT_ROOT' && python3 -m dependency_resolver docker '$container_name'"
340+
[[ -n "$hash_flag" ]] && cmd="$cmd $hash_flag"
341+
[[ -n "$select_flag" ]] && cmd="$cmd $select_flag"
342+
result=$(eval "$cmd") || cmd_result=$?
331343
else
332-
result=$(cd "$PROJECT_ROOT" && python3 -c "import dependency_resolver; print(dependency_resolver.resolve_docker_dependencies('$container_name'$hash_arg))") || cmd_result=$?
344+
result=$(cd "$PROJECT_ROOT" && python3 -c "import dependency_resolver; print(dependency_resolver.resolve_docker_dependencies('$container_name'$hash_arg$select_arg))") || cmd_result=$?
333345
fi
334346

335347
end_time=$(date +%s.%N)

performance-analysis/detectors/host-benchmarks.sh

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,47 +56,68 @@ if [[ "${SKIP_HASH_COLLECTION:-false}" == "true" ]]; then
5656
echo "Hash collection disabled for faster execution"
5757
fi
5858

59+
# Prepare select detectors flag
60+
SELECT_FLAG=""
61+
SELECT_ARG=""
62+
if [[ -n "${SELECT_DETECTORS:-}" ]]; then
63+
SELECT_FLAG="--select-detectors '$SELECT_DETECTORS'"
64+
SELECT_ARG=", selected_detectors='$SELECT_DETECTORS'"
65+
echo "Using selected detectors: $SELECT_DETECTORS"
66+
fi
67+
5968
# Run selected scenarios based on scenario type and interface
6069
case $SCENARIO_TYPE in
6170
"skip-system")
6271
if [[ "$INTERFACE" == "cli" ]]; then
72+
cmd="cd '$PROJECT_ROOT' && python3 -m dependency_resolver host --skip-system-scope"
73+
[[ -n "$HASH_FLAG" ]] && cmd="$cmd $HASH_FLAG"
74+
[[ -n "$SELECT_FLAG" ]] && cmd="$cmd $SELECT_FLAG"
6375
host_benchmark_scenario "Host Skip System Scope ($INTERFACE)" \
64-
"cd '$PROJECT_ROOT' && python3 -m dependency_resolver host --skip-system-scope $HASH_FLAG" \
76+
"$cmd" \
6577
30
6678
else
6779
host_benchmark_scenario "Host Skip System Scope ($INTERFACE)" \
68-
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies(skip_system_scope=True$HASH_ARG))'" \
80+
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies(skip_system_scope=True$HASH_ARG$SELECT_ARG))'" \
6981
30
7082
fi
7183
;;
7284
"full-system")
7385
if [[ "$INTERFACE" == "cli" ]]; then
86+
cmd="cd '$PROJECT_ROOT' && python3 -m dependency_resolver host"
87+
[[ -n "$HASH_FLAG" ]] && cmd="$cmd $HASH_FLAG"
88+
[[ -n "$SELECT_FLAG" ]] && cmd="$cmd $SELECT_FLAG"
7489
host_benchmark_scenario "Host Full System ($INTERFACE)" \
75-
"cd '$PROJECT_ROOT' && python3 -m dependency_resolver host $HASH_FLAG" \
90+
"$cmd" \
7691
60
7792
else
7893
host_benchmark_scenario "Host Full System ($INTERFACE)" \
79-
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies($HASH_ARG))'" \
94+
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies($HASH_ARG$SELECT_ARG))'" \
8095
60
8196
fi
8297
;;
8398
"all")
8499
if [[ "$INTERFACE" == "cli" ]]; then
100+
cmd1="cd '$PROJECT_ROOT' && python3 -m dependency_resolver host --skip-system-scope"
101+
[[ -n "$HASH_FLAG" ]] && cmd1="$cmd1 $HASH_FLAG"
102+
[[ -n "$SELECT_FLAG" ]] && cmd1="$cmd1 $SELECT_FLAG"
85103
host_benchmark_scenario "Host Skip System Scope ($INTERFACE)" \
86-
"cd '$PROJECT_ROOT' && python3 -m dependency_resolver host --skip-system-scope $HASH_FLAG" \
104+
"$cmd1" \
87105
30
88106

107+
cmd2="cd '$PROJECT_ROOT' && python3 -m dependency_resolver host"
108+
[[ -n "$HASH_FLAG" ]] && cmd2="$cmd2 $HASH_FLAG"
109+
[[ -n "$SELECT_FLAG" ]] && cmd2="$cmd2 $SELECT_FLAG"
89110
host_benchmark_scenario "Host Full System ($INTERFACE)" \
90-
"cd '$PROJECT_ROOT' && python3 -m dependency_resolver host $HASH_FLAG" \
111+
"$cmd2" \
91112
60
92113
else
93114
# Programmatic interface
94115
host_benchmark_scenario "Host Skip System Scope ($INTERFACE)" \
95-
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies(skip_system_scope=True$HASH_ARG))'" \
116+
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies(skip_system_scope=True$HASH_ARG$SELECT_ARG))'" \
96117
30
97118

98119
host_benchmark_scenario "Host Full System ($INTERFACE)" \
99-
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies($HASH_ARG))'" \
120+
"cd '$PROJECT_ROOT' && python3 -c 'import dependency_resolver; print(dependency_resolver.resolve_host_dependencies($HASH_ARG$SELECT_ARG))'" \
100121
60
101122
fi
102123
;;

0 commit comments

Comments
 (0)