Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pre-commit run --files $(git diff --name-only --diff-filter=ACMR HEAD)

## Tech Stack

Python with venv, pip, and pytest (Unix-only)
Python 3.10 with venv, pip, and pytest (Unix-only)

## Code Principles

Expand Down
100 changes: 96 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ python3 -m dependency_resolver --pretty-print

### Programmatic Interface

The dependency-resolver can also be used as a Python library in other projects. Here are some examples:
The dependency-resolver can be used as a Python library in other projects with both functional and class-based interfaces:

#### Functional Interface (Simple Usage)

```python
import dependency_resolver
Expand All @@ -75,8 +77,89 @@ docker_deps = dependency_resolver.resolve_docker_dependencies(
container_identifier="nginx",
working_dir="/app"
)
```

#### Class-Based Interface (Advanced Usage)

For complex scenarios and when you need environment-specific configuration:

```python
from dependency_resolver import DependencyResolver, ResolveRequest

# Create resolver for specific environment with configuration
host_resolver = DependencyResolver(
environment_type="host",
debug=True,
skip_system_scope=False,
max_workers=4 # Parallel processing
)

# Docker resolver with container-specific options
docker_resolver = DependencyResolver(
environment_type="docker",
only_container_info=True, # Only valid for docker environment
debug=True
)

# Single environment analysis
host_result = host_resolver.resolve(
working_dir="/path/to/project",
venv_path="/opt/venv"
)

docker_result = docker_resolver.resolve(
environment_identifier="nginx",
working_dir="/app"
)

# Parallel multi-environment analysis (same environment type)
# For host environments
host_requests = [
ResolveRequest(working_dir="/path/to/project1"),
ResolveRequest(working_dir="/path/to/project2", venv_path="/opt/venv"),
ResolveRequest(working_dir="/path/to/project3")
]

# For docker containers
docker_requests = [
ResolveRequest(environment_identifier="nginx", working_dir="/app"),
ResolveRequest(environment_identifier="redis", working_dir="/data"),
ResolveRequest(environment_identifier="postgres")
]

def progress_callback(completed, total, result):
print(f"Progress: {completed}/{total} ({'✓' if result.success else '✗'})")

# Execute in parallel with progress tracking
host_results = host_resolver.resolve_batch(
host_requests,
progress_callback=progress_callback,
fail_fast=False # Continue processing even if some fail
)

docker_results = docker_resolver.resolve_batch(
docker_requests,
progress_callback=progress_callback,
fail_fast=False
)

# Process results
for result in host_results:
if result.success:
print(f"Found {len(result.dependencies)} detectors")
else:
print(f"Error: {result.error}")

# Advanced usage with direct access to core classes
# Get results as dictionary format
host_dict_results = host_resolver.resolve_batch_as_dict(host_requests)
docker_dict_results = docker_resolver.resolve_batch_as_dict(docker_requests)
```

#### Low-Level Interface

For maximum control, access core classes directly:

```python
from dependency_resolver import Orchestrator, HostExecutor, OutputFormatter

executor = HostExecutor()
Expand All @@ -92,12 +175,21 @@ json_output = formatter.format_json(dependencies, pretty_print=True)
- `resolve_docker_dependencies()` - Analyze Docker container, returns JSON string
- `resolve_dependencies_as_dict()` - Generic analysis, returns Python dictionary

**Available classes for advanced usage:**
**Available classes:**

- `Orchestrator` - Main dependency resolution coordinator
- `DependencyResolver` - Main class for single and batch operations with parallel processing
- `ResolveRequest` - Configuration for individual resolution requests
- `ResolveResult` - Result object containing dependencies, errors, and execution metadata
- `Orchestrator` - Core dependency resolution coordinator
- `HostExecutor`, `DockerExecutor`, `DockerComposeExecutor` - Environment adapters
- `OutputFormatter` - JSON formatting utilities

**When to use each interface:**

- **Functional Interface**: Simple one-off dependency resolution
- **Class-Based Interface**: Multiple environments, parallel processing, shared configuration, progress tracking
- **Low-Level Interface**: Custom orchestration, advanced error handling, integration with existing frameworks

### Supported Environments

- **host** - Host system analysis (default)
Expand Down
24 changes: 8 additions & 16 deletions dependency_resolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .core.interfaces import EnvironmentExecutor
from .core.orchestrator import Orchestrator
from .core.output_formatter import OutputFormatter
from .core.resolver import DependencyResolver, ResolveRequest, ResolveResult
from .executors import HostExecutor, DockerExecutor, DockerComposeExecutor

from typing import Optional, Any
Expand Down Expand Up @@ -90,22 +91,13 @@ def resolve_dependencies_as_dict(
Returns:
Dictionary containing all discovered dependencies
"""
executor: EnvironmentExecutor
if environment_type == "host":
executor = HostExecutor()
elif environment_type == "docker":
if not environment_identifier:
raise ValueError("Docker environment requires container identifier")
executor = DockerExecutor(environment_identifier)
elif environment_type == "docker_compose":
if not environment_identifier:
raise ValueError("Docker Compose environment requires service identifier")
executor = DockerComposeExecutor(environment_identifier)
else:
raise ValueError(f"Unsupported environment type: {environment_type}")

orchestrator = Orchestrator(debug=debug, skip_system_scope=skip_system_scope, venv_path=venv_path)
return orchestrator.resolve_dependencies(executor, working_dir, only_container_info)
resolver = DependencyResolver(
environment_type=environment_type,
only_container_info=only_container_info,
debug=debug,
skip_system_scope=skip_system_scope,
)
return resolver.resolve(environment_identifier=environment_identifier, working_dir=working_dir, venv_path=venv_path)


def main() -> None:
Expand Down
35 changes: 9 additions & 26 deletions dependency_resolver/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

import sys
import argparse
from .executors import HostExecutor, DockerExecutor, DockerComposeExecutor
from .core.interfaces import EnvironmentExecutor
from .core.orchestrator import Orchestrator
from .core.resolver import DependencyResolver
from .core.output_formatter import OutputFormatter


Expand Down Expand Up @@ -95,37 +93,22 @@ def validate_arguments(
sys.exit(1)


def create_executor(environment_type: str, environment_identifier: str | None) -> EnvironmentExecutor:
"""Create executor based on environment type."""
if environment_type == "host":
return HostExecutor()
elif environment_type == "docker":
if environment_identifier is None:
print("Error: Docker environment requires container identifier", file=sys.stderr)
sys.exit(1)
return DockerExecutor(environment_identifier)
elif environment_type == "docker_compose":
if environment_identifier is None:
print("Error: Docker Compose environment requires service identifier", file=sys.stderr)
sys.exit(1)
return DockerComposeExecutor(environment_identifier)
else:
print(f"Error: Unsupported environment type: {environment_type}", file=sys.stderr)
sys.exit(1)


def main() -> None:
"""Main entry point."""
args = parse_arguments()

validate_arguments(args.environment_type, args.environment_identifier, args.only_container_info)

try:
executor = create_executor(args.environment_type, args.environment_identifier)
orchestrator = Orchestrator(
debug=args.debug, skip_system_scope=args.skip_system_scope, venv_path=args.venv_path
resolver = DependencyResolver(
environment_type=args.environment_type,
only_container_info=args.only_container_info,
debug=args.debug,
skip_system_scope=args.skip_system_scope,
)
dependencies = resolver.resolve(
environment_identifier=args.environment_identifier, working_dir=args.working_dir, venv_path=args.venv_path
)
dependencies = orchestrator.resolve_dependencies(executor, args.working_dir, args.only_container_info)
formatter = OutputFormatter(debug=args.debug)
result = formatter.format_json(dependencies, pretty_print=args.pretty_print)
print(result)
Expand Down
Loading