|
| 1 | +# Self Update Architecture |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This document outlines the architecture for implementing a self-update feature in deepctl. The feature will: |
| 6 | + |
| 7 | +1. Check for newer versions on PyPI |
| 8 | +2. Detect how deepctl was installed |
| 9 | +3. Remember installation method |
| 10 | +4. Provide appropriate update commands |
| 11 | + |
| 12 | +## Key Components |
| 13 | + |
| 14 | +### 1. Version Checking |
| 15 | + |
| 16 | +#### PyPI API Integration |
| 17 | + |
| 18 | +- Use the PyPI JSON API to check for the latest version |
| 19 | +- Compare with current version using semantic versioning |
| 20 | +- Cache version check results to avoid excessive API calls |
| 21 | + |
| 22 | +```python |
| 23 | +# Example API endpoint |
| 24 | +https://pypi.org/pypi/deepctl/json |
| 25 | + |
| 26 | +# Response includes: |
| 27 | +- info.version (latest stable version) |
| 28 | +- releases (all available versions) |
| 29 | +``` |
| 30 | + |
| 31 | +#### Version Check Strategy |
| 32 | + |
| 33 | +- Check on startup (configurable frequency) |
| 34 | +- Provide explicit `deepctl version --check` command |
| 35 | +- Store last check timestamp in config |
| 36 | +- Respect user preference to disable checks |
| 37 | + |
| 38 | +### 2. Installation Method Detection |
| 39 | + |
| 40 | +#### Detection Methods |
| 41 | + |
| 42 | +1. **pip/uv Detection** |
| 43 | + |
| 44 | + - Check `sys.prefix` and package metadata |
| 45 | + - Look for `.dist-info` directory |
| 46 | + - Check if installed in virtual environment |
| 47 | + |
| 48 | +2. **pipx Detection** |
| 49 | + |
| 50 | + - Check for pipx metadata in installation path |
| 51 | + - Look for pipx-specific directory structure |
| 52 | + - Check environment variable markers |
| 53 | + |
| 54 | +3. **System Package Manager** |
| 55 | + |
| 56 | + - Check common system paths (/usr/bin, /usr/local/bin) |
| 57 | + - Look for package manager metadata (dpkg, rpm, etc.) |
| 58 | + |
| 59 | +4. **Development Installation** |
| 60 | + - Check for editable installation markers |
| 61 | + - Look for git repository in parent directories |
| 62 | + |
| 63 | +#### Installation Metadata Storage |
| 64 | + |
| 65 | +Store in the configuration system: |
| 66 | + |
| 67 | +```yaml |
| 68 | +installation: |
| 69 | + method: "pip" # pip, pipx, uv, system, development, unknown |
| 70 | + path: "/path/to/installation" |
| 71 | + version: "0.1.5" |
| 72 | + installed_at: "2024-01-20T10:00:00Z" |
| 73 | + virtual_env: true |
| 74 | + editable: false |
| 75 | +``` |
| 76 | +
|
| 77 | +### 3. Update Commands |
| 78 | +
|
| 79 | +#### Update Strategies by Installation Method |
| 80 | +
|
| 81 | +1. **pip** |
| 82 | +
|
| 83 | + ```bash |
| 84 | + pip install --upgrade deepctl |
| 85 | + ``` |
| 86 | + |
| 87 | +2. **pipx** |
| 88 | + |
| 89 | + ```bash |
| 90 | + pipx upgrade deepctl |
| 91 | + ``` |
| 92 | + |
| 93 | +3. **uv** |
| 94 | + |
| 95 | + ```bash |
| 96 | + uv pip install --upgrade deepctl |
| 97 | + ``` |
| 98 | + |
| 99 | +4. **System Package Manager** |
| 100 | + |
| 101 | + - Display message: "Please use your system package manager to update" |
| 102 | + - Provide specific commands for detected OS |
| 103 | + |
| 104 | +5. **Development Installation** |
| 105 | + - Display message: "Development installation detected. Please pull latest changes." |
| 106 | + |
| 107 | +### 4. Implementation Plan |
| 108 | + |
| 109 | +#### Phase 1: Core Infrastructure |
| 110 | + |
| 111 | +1. Create version checking module |
| 112 | +2. Implement PyPI API client |
| 113 | +3. Add version comparison logic |
| 114 | +4. Create installation detector |
| 115 | + |
| 116 | +#### Phase 2: Command Implementation |
| 117 | + |
| 118 | +1. Add `deepctl version` command with `--check` flag |
| 119 | +2. Add `deepctl update` command |
| 120 | +3. Implement update confirmation workflow |
| 121 | + |
| 122 | +#### Phase 3: Configuration & Preferences |
| 123 | + |
| 124 | +1. Add update preferences to config |
| 125 | +2. Implement check frequency control |
| 126 | +3. Add option to disable auto-checks |
| 127 | + |
| 128 | +#### Phase 4: User Experience |
| 129 | + |
| 130 | +1. Add progress indicators |
| 131 | +2. Implement rollback mechanism |
| 132 | +3. Add update notifications |
| 133 | + |
| 134 | +## Detailed Design |
| 135 | + |
| 136 | +### Version Checking Module (`deepctl_core/version_check.py`) |
| 137 | + |
| 138 | +```python |
| 139 | +from typing import Optional, Dict, Any |
| 140 | +import httpx |
| 141 | +from packaging import version |
| 142 | +from datetime import datetime, timedelta |
| 143 | +from pydantic import BaseModel |
| 144 | + |
| 145 | +class VersionInfo(BaseModel): |
| 146 | + """Version information from PyPI.""" |
| 147 | + latest_version: str |
| 148 | + current_version: str |
| 149 | + update_available: bool |
| 150 | + release_date: Optional[datetime] |
| 151 | + release_notes_url: Optional[str] |
| 152 | + |
| 153 | +class VersionChecker: |
| 154 | + """Handles version checking against PyPI.""" |
| 155 | + |
| 156 | + PYPI_API_URL = "https://pypi.org/pypi/deepctl/json" |
| 157 | + CACHE_DURATION = timedelta(hours=24) |
| 158 | + |
| 159 | + def __init__(self, config: Config): |
| 160 | + self.config = config |
| 161 | + self.current_version = self._get_current_version() |
| 162 | + |
| 163 | + async def check_version(self, force: bool = False) -> VersionInfo: |
| 164 | + """Check for newer version on PyPI.""" |
| 165 | + # Implementation details... |
| 166 | + |
| 167 | + def should_check(self) -> bool: |
| 168 | + """Determine if version check should run.""" |
| 169 | + # Check user preferences and last check time |
| 170 | +``` |
| 171 | + |
| 172 | +### Installation Detector (`deepctl_core/installation.py`) |
| 173 | + |
| 174 | +```python |
| 175 | +import sys |
| 176 | +import os |
| 177 | +from pathlib import Path |
| 178 | +from enum import Enum |
| 179 | +from typing import Optional |
| 180 | + |
| 181 | +class InstallMethod(str, Enum): |
| 182 | + """Supported installation methods.""" |
| 183 | + PIP = "pip" |
| 184 | + PIPX = "pipx" |
| 185 | + UV = "uv" |
| 186 | + SYSTEM = "system" |
| 187 | + DEVELOPMENT = "development" |
| 188 | + UNKNOWN = "unknown" |
| 189 | + |
| 190 | +class InstallationDetector: |
| 191 | + """Detects how deepctl was installed.""" |
| 192 | + |
| 193 | + def detect(self) -> InstallMethod: |
| 194 | + """Detect installation method.""" |
| 195 | + # Check various markers and paths |
| 196 | + |
| 197 | + def get_update_command(self, method: InstallMethod) -> Optional[str]: |
| 198 | + """Get appropriate update command for installation method.""" |
| 199 | + # Return command based on method |
| 200 | +``` |
| 201 | + |
| 202 | +### Update Command (`deepctl_cmd_update/`) |
| 203 | + |
| 204 | +Create a new command package for updates: |
| 205 | + |
| 206 | +```python |
| 207 | +# deepctl_cmd_update/command.py |
| 208 | +from deepctl_core import BaseCommand |
| 209 | +from deepctl_core.version_check import VersionChecker |
| 210 | +from deepctl_core.installation import InstallationDetector |
| 211 | + |
| 212 | +class UpdateCommand(BaseCommand): |
| 213 | + """Check for and install updates.""" |
| 214 | + |
| 215 | + name = "update" |
| 216 | + help = "Check for and install updates" |
| 217 | + |
| 218 | + def add_arguments(self, parser): |
| 219 | + parser.add_argument( |
| 220 | + "--check-only", |
| 221 | + action="store_true", |
| 222 | + help="Only check for updates without installing" |
| 223 | + ) |
| 224 | + parser.add_argument( |
| 225 | + "--force", |
| 226 | + action="store_true", |
| 227 | + help="Force update even if up to date" |
| 228 | + ) |
| 229 | + |
| 230 | + async def run(self, args): |
| 231 | + """Run update command.""" |
| 232 | + # Check version |
| 233 | + # Detect installation method |
| 234 | + # Prompt for confirmation |
| 235 | + # Execute update |
| 236 | +``` |
| 237 | + |
| 238 | +### Version Command Enhancement |
| 239 | + |
| 240 | +Enhance existing version command: |
| 241 | + |
| 242 | +```python |
| 243 | +@cli.command() |
| 244 | +@click.option("--check", is_flag=True, help="Check for updates") |
| 245 | +def version(check: bool): |
| 246 | + """Show version information.""" |
| 247 | + # Show current version |
| 248 | + # If --check, also check for updates |
| 249 | +``` |
| 250 | + |
| 251 | +## Configuration Schema Update |
| 252 | + |
| 253 | +Add to `DeepgramConfig`: |
| 254 | + |
| 255 | +```python |
| 256 | +class UpdateConfig(BaseModel): |
| 257 | + """Update preferences.""" |
| 258 | + check_enabled: bool = True |
| 259 | + check_frequency: str = "daily" # daily, weekly, never |
| 260 | + last_check: Optional[datetime] = None |
| 261 | + installation_method: Optional[str] = None |
| 262 | + installation_path: Optional[str] = None |
| 263 | + |
| 264 | +class DeepgramConfig(BaseModel): |
| 265 | + # ... existing fields ... |
| 266 | + update: UpdateConfig = Field(default_factory=UpdateConfig) |
| 267 | +``` |
| 268 | + |
| 269 | +## Security Considerations |
| 270 | + |
| 271 | +1. **HTTPS Only**: Always use HTTPS for PyPI API |
| 272 | +2. **Signature Verification**: Consider verifying package signatures |
| 273 | +3. **Rollback Support**: Keep previous version for rollback |
| 274 | +4. **User Confirmation**: Always require user confirmation for updates |
| 275 | +5. **Privilege Escalation**: Handle cases where admin rights needed |
| 276 | + |
| 277 | +## User Experience |
| 278 | + |
| 279 | +### Update Flow |
| 280 | + |
| 281 | +1. **Automatic Check** (on startup, respecting frequency): |
| 282 | + |
| 283 | + ``` |
| 284 | + ╭─────────────────────────────────────╮ |
| 285 | + │ Update available: deepctl 0.2.0 │ |
| 286 | + │ Run 'deepctl update' to upgrade │ |
| 287 | + ╰─────────────────────────────────────╯ |
| 288 | + ``` |
| 289 | + |
| 290 | +2. **Manual Check**: |
| 291 | + |
| 292 | + ```bash |
| 293 | + $ deepctl version --check |
| 294 | + Current version: 0.1.5 |
| 295 | + Latest version: 0.2.0 |
| 296 | + Update available! Run 'deepctl update' to upgrade. |
| 297 | + ``` |
| 298 | + |
| 299 | +3. **Update Command**: |
| 300 | + |
| 301 | + ```bash |
| 302 | + $ deepctl update |
| 303 | + Current version: 0.1.5 |
| 304 | + Latest version: 0.2.0 |
| 305 | + |
| 306 | + Installation method: pip |
| 307 | + Update command: pip install --upgrade deepctl |
| 308 | + |
| 309 | + Do you want to proceed? [y/N]: y |
| 310 | + Updating deepctl... |
| 311 | + ✓ Successfully updated to version 0.2.0 |
| 312 | + ``` |
| 313 | + |
| 314 | +### Error Handling |
| 315 | + |
| 316 | +1. **Network Errors**: Graceful fallback, don't block CLI usage |
| 317 | +2. **Permission Errors**: Provide clear instructions |
| 318 | +3. **Unknown Installation**: Provide manual update instructions |
| 319 | + |
| 320 | +## Testing Strategy |
| 321 | + |
| 322 | +1. **Unit Tests**: |
| 323 | + |
| 324 | + - Version comparison logic |
| 325 | + - Installation detection |
| 326 | + - API response parsing |
| 327 | + |
| 328 | +2. **Integration Tests**: |
| 329 | + |
| 330 | + - Mock PyPI API responses |
| 331 | + - Test various installation scenarios |
| 332 | + - Test update workflows |
| 333 | + |
| 334 | +3. **Manual Testing**: |
| 335 | + - Test on different platforms |
| 336 | + - Test with different installation methods |
| 337 | + - Test error scenarios |
| 338 | + |
| 339 | +## Implementation Timeline |
| 340 | + |
| 341 | +1. **Week 1**: Core version checking infrastructure |
| 342 | +2. **Week 2**: Installation detection logic |
| 343 | +3. **Week 3**: Update command implementation |
| 344 | +4. **Week 4**: Testing and documentation |
| 345 | + |
| 346 | +## Future Enhancements |
| 347 | + |
| 348 | +1. **Plugin Updates**: Check and update plugins |
| 349 | +2. **Batch Updates**: Update all deepctl packages together |
| 350 | +3. **Beta Channel**: Support pre-release versions |
| 351 | +4. **Offline Mode**: Work without internet connection |
| 352 | +5. **Update History**: Track update history |
| 353 | +6. **Automatic Updates**: Optional automatic updates (with user consent) |
| 354 | + |
| 355 | +## Conclusion |
| 356 | + |
| 357 | +The self-update feature is highly feasible and will significantly improve the user experience. By detecting installation methods and providing appropriate update commands, we can support various deployment scenarios while maintaining security and reliability. |
0 commit comments