Download Service
The Download Service provides comprehensive HTTP download capabilities for SpecifyX template management. It handles GitHub repository downloads, archive extraction, template validation, and progress tracking with robust error handling and retry logic.
Overview
The service is built around two main components:
- DownloadService (abstract interface) - Defines the contract for download operations
- HttpxDownloadService (concrete implementation) - Implements HTTP-based downloads using httpx
Key Features
HTTP Download Capabilities
- GitHub repository and release downloads
- Generic URL downloads with progress tracking
- Automatic redirect handling and timeout management
- Support for streaming downloads with progress bars
Archive Handling
- ZIP and TAR archive extraction with format auto-detection
- GitHub-style archive flattening (removes nested root directories)
- Cross-platform archive support (ZIP, TAR, TAR.GZ, TAR.BZ2)
- Atomic extraction with cleanup on failure
Template Management
- SpecifyX template package downloads from GitHub releases
- Template validation and structure verification
- AI-assistant-aware template discovery
- Backward compatibility with legacy template formats
Progress & Feedback
- Rich console integration with colored output
- Progress bars for large downloads with size tracking
- Spinner animations for indeterminate operations
- Detailed error reporting with context
Core Classes
DownloadService (Abstract)
class DownloadService(ABC):
def download_template(self, template_url: str, destination_path: Path) -> bool
def download_github_repo(self, repo_url: str, destination_path: Path, branch: str = "main") -> bool
def extract_archive(self, archive_path: Path, destination_path: Path) -> bool
def validate_template_package(self, template_path: Path) -> Tuple[bool, Optional[str]]
def get_available_templates(self, repo_url: str) -> List[str]
def download_specific_template(self, repo_url: str, template_name: str, destination_path: Path) -> bool
HttpxDownloadService (Implementation)
service = HttpxDownloadService(
console=console,
timeout=30,
default_repo_owner="barisgit",
default_repo_name="spec-kit-improved"
)
success = service.download_github_repo("owner/repo", destination_path)
Download Operations
Basic Downloads
# Download from any URL
success = service.download_template(
"https://example.com/template.zip",
Path("/path/to/template.zip")
)
# Download GitHub repository
success = service.download_github_repo(
"owner/repository",
Path("/path/to/destination"),
branch="main"
)
SpecifyX Template Downloads
# Download SpecifyX templates from releases
success, metadata = service.download_github_release_template(
ai_assistant="claude",
destination_path=Path("/path/to/templates")
)
if success:
print(f"Downloaded: {metadata['filename']}")
print(f"Release: {metadata['release']}")
print(f"Size: {metadata['size']} bytes")
Template Discovery
# Get available templates from repository
templates = service.get_available_templates("owner/template-repo")
print(f"Available templates: {templates}")
# Download specific template
success = service.download_specific_template(
"owner/template-repo",
"claude",
Path("/path/to/destination")
)
Archive Extraction
Supported Formats
- ZIP:
.zip
files with automatic compression detection - TAR:
.tar
,.tar.gz
,.tgz
,.tar.bz2
files - Auto-detection: Format determined by file extension
Extraction Features
# Extract any supported archive
success = service.extract_archive(
Path("/path/to/archive.zip"),
Path("/path/to/destination")
)
# Automatic GitHub-style flattening
# Input: archive.zip containing "repo-main/" directory
# Output: Contents extracted directly to destination (flattened)
Archive Handling
- Nested Directory Flattening: Removes single root directories common in GitHub archives
- Atomic Operations: Ensures clean state on extraction failure
- Permission Preservation: Maintains file permissions where supported
- Cross-Platform: Handles path separators and file systems appropriately
Template Validation
Structure Validation
# Validate template package structure
is_valid, error_message = service.validate_template_package(
Path("/path/to/template")
)
if not is_valid:
print(f"Template validation failed: {error_message}")
Expected Template Structure
Templates are validated for essential files:
README.md
- Template documentationCONSTITUTION.md
- Template constitution and guidelines
Configuration & Customization
Service Configuration
service = HttpxDownloadService(
console=Console(), # Rich console for output
timeout=30, # Request timeout in seconds
default_repo_owner="barisgit", # Default GitHub repo owner
default_repo_name="spec-kit-improved" # Default GitHub repo name
)
Download Patterns
The service supports multiple template discovery patterns:
# Template asset patterns (searched in order)
patterns = [
"specifyx-templates", # New SpecifyX format
f"spec-kit-template-{ai_assistant}", # Legacy per-AI format
"spec-kit-template" # Generic format
]
Progress Tracking
Download Progress
# Downloads show progress bars for files with known size
# Progress includes:
# - Spinner animation
# - Percentage completion
# - Transfer speed (implicit in progress updates)
# Example output:
# ⠋ Downloading... 45%
Console Integration
from rich.console import Console
console = Console()
service = HttpxDownloadService(console=console)
# All download operations will use the provided console
# for progress bars, status messages, and error reporting
Error Handling
Network Errors
- Connection Timeouts: Configurable timeout with clear error messages
- HTTP Errors: Status code validation with error propagation
- Redirect Handling: Automatic redirect following with loop detection
File System Errors
- Permission Errors: Clear messages for write permission issues
- Disk Space: Implicit handling through OS error reporting
- Path Validation: Directory creation and path normalization
Archive Errors
- Corrupt Archives: ZIP/TAR corruption detection and reporting
- Extraction Failures: Cleanup of partial extractions
- Format Detection: Unsupported format identification
Error Reporting
# Errors are reported through Rich console with color coding
# [red]Error downloading template:[/red] Connection timeout
# [red]Error extracting archive:[/red] Corrupt ZIP file
# [yellow]Available assets:[/yellow] [list of alternatives]
Usage Examples
Basic Template Download
from specify_cli.services.download_service import create_download_service
from pathlib import Path
service = create_download_service()
# Download and extract SpecifyX templates
success, metadata = service.download_github_release_template(
ai_assistant="claude",
destination_path=Path("./templates")
)
if success:
# Extract the downloaded archive
zip_path = Path("./templates") / metadata["filename"]
success = service.extract_archive(zip_path, Path("./extracted"))
if success:
# Validate the template structure
is_valid, error = service.validate_template_package(Path("./extracted"))
if not is_valid:
print(f"Template validation failed: {error}")
Custom Repository Download
# Download from custom GitHub repository
custom_service = HttpxDownloadService(
default_repo_owner="my-org",
default_repo_name="my-templates"
)
success = custom_service.download_github_repo(
"my-org/custom-templates",
Path("./custom-templates"),
branch="development"
)
Template Discovery Workflow
# Discover and download specific template
repo_url = "organization/template-repository"
# List available templates
available = service.get_available_templates(repo_url)
print(f"Available templates: {available}")
# Download specific template
if "claude" in available:
success = service.download_specific_template(
repo_url,
"claude",
Path("./claude-template")
)
Integration Points
The Download Service integrates with:
- Project Manager: For template acquisition during project initialization
- Template Service: For providing template packages for rendering
- Config Service: For repository and download configuration settings
Performance Considerations
- Streaming Downloads: Large files are streamed to avoid memory issues
- Concurrent Safety: Service instances are thread-safe for read operations
- Cleanup Operations: Temporary files are cleaned up automatically
- Progress Feedback: Progress bars provide user feedback for long operations
File System Integration
Download Locations
- Temporary Files: Created in system temp directory with automatic cleanup
- Destination Handling: Automatic directory creation for download destinations
- Archive Extraction: In-place extraction with atomic operations
Path Handling
- Cross-Platform: Proper path separator handling for Windows/Unix
- Directory Creation: Recursive directory creation as needed
- Permission Setting: Maintains file permissions during extraction
Factory Function
def create_download_service(console: Optional[Console] = None) -> DownloadService:
"""Factory function to create an HttpxDownloadService instance"""
return HttpxDownloadService(console=console)
Use this factory function to get a properly configured download service instance with sensible defaults for SpecifyX template management.