Self-Update Feature Analysis & Implementation Plan
Executive Summary
After analyzing the self_update crate from crates.io, we can significantly reduce implementation complexity by leveraging existing functionality instead of reinventing the wheel. The crate provides ~70% of what we need, allowing us to focus on value-add features.
Estimated Effort Reduction: 40-60 hours (down from 60-80 hours)
Feature Matrix
✅ Provided by self_update (Use Directly)
| Feature | Implementation | Notes |
|---------|---------------|-------|
| Update Checking | self_update::backends::github::Update::configure() | Supports GitHub, releases API |
| Version Comparison | Internal semver (via self_update::should_update() - deprecated but logic exists) | Uses semver crate internally |
| Download | self_update::Download::from_url().download_to() | Handles retries, chunked downloads |
| Archive Extraction | self_update::Extract::from_source().archive().extract_file() | Supports .tar.gz, .zip |
| Binary Replacement | self_replace::self_replace() (re-exported) | Cross-platform, atomic |
| Progress Display | indicatif crate integration | Built-in progress bars |
| Signature Verification | signatures feature with zipsign crate | Key finding: PGP already supported! |
| Release Info | Release struct with assets, tags, notes | GitHub API integration |
| Target Detection | get_target() helper | Linux/macOS/Windows detection |
🔨 Build Custom (Value-Add Features)
| Feature | Purpose | Complexity |
|---------|---------|------------|
| Configuration Management | UpdateConfig struct, validation, defaults | Medium |
| Scheduling | Tokio-based interval scheduler, cron-like triggers | High |
| State Persistence | Save/load UpdateHistory to disk | Medium |
| In-App Notifications | Format and display update messages | Medium |
| Binary Backup/Rollback | Backup before update, restore on failure | High |
| Interactive Prompts | User confirmation dialogs (CLI/GUI) | Medium |
| Platform-Specific Paths | Linux/macOS binary locations, permissions | Low |
| Permission Handling | Check write permissions, elevate if needed | High |
| Update Policies | Auto-update, notify-only, manual modes | Medium |
| Telemetry/Logging | Update success/failure tracking | Low |
Updated Implementation Plan
Step 1: Setup & Configuration (4 hours)
Use self_update:
# terraphim_update/Cargo.toml
[dependencies]
self_update = { version = "0.41", features = ["signatures"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
anyhow = "1"Build custom:
UpdateConfigstruct with update policy, schedule, backup settings- Validation logic (URLs, version formats, intervals)
- Default configuration for development/production
Step 2: Update Checker (2 hours - significantly reduced)
Use self_update:
use ;
let updater = configure
.repo_owner
.repo_name
.bin_name
.current_version
.build?;
let releases = updater.get_latest_release?;
let should_update = version_bump_semver;Build custom:
- Caching logic (don't check GitHub too frequently)
- Schedule integration (check only when due)
Step 3: Version Comparison (0 hours - eliminated)
Use self_update directly. The crate uses semver internally and provides:
version_bump_semver()for semantic version comparisonversion_bump_patch(),version_bump_minor(), etc.
Action: Remove custom semver code from plan.
Step 4: Downloader (1 hour - simplified)
Use self_update:
use Download;
from_url
.download_to
.show_progress?;Build custom:
- Retry logic (already in self_update but may need custom backoff)
- Resume support (if needed for large binaries)
Step 5: Extractor (0 hours - eliminated)
Use self_update directly. Supports:
.tar.gzarchives.ziparchives- Automatic binary detection
use Extract;
from_source
.archive
.extract_file?;Action: Remove custom extraction code from plan.
Step 6: Signature Verification (2 hours - simplified)
Use self_update (with signatures feature):
self_update = { version = "0.41", features = ["signatures"] }// self_update uses zipsign internally for signature verification
// No custom PGP implementation needed!
use Update;
let updater = configure
.repo_owner
.repo_name
.build?;
// Self_update verifies signatures automatically when signature file is present
updater.download_and_replace?;Build custom:
- Public key management (where to store, how to distribute)
- Signature key rotation handling
- Fallback behavior when verification fails
Action: Remove custom PGP/GPG implementation plan entirely.
Step 7: Installer (2 hours - simplified)
Use self_update:
use self_replace;
self_replace?;Build custom:
- Binary backup before replacement:
- Rollback on failure
- Permission checking
Step 8: Configuration Manager (4 hours)
Build custom (not in self_update):
UpdateConfigstruct (from Step 1)UpdateHistorytracking:
- Save/load to
~/.config/terraphim/update_config.toml - Schema validation
- Migration support
Step 9: Scheduler (6 hours)
Build custom (not in self_update):
- Tokio-based interval scheduler:
- Graceful shutdown
- Skip if update already checked recently
- Integration with UpdateConfig
Step 10: Notifier (4 hours)
Build custom (not in self_update):
- Format update messages:
- CLI prompts:
use Confirm;
let confirmed = new
.with_prompt
.interact?;- GUI notifications (future work)
Step 11: Backup & Rollback (6 hours)
Build custom (not in self_update):
- Pre-update backup:
- Post-update verification (run binary, check version)
- Rollback on failure:
- Cleanup old backups (keep last N)
Step 12: Platform Paths (2 hours)
Build custom (not in self_update):
- Write permission checks
- Fallback to
~/.local/binif no sudo access
Step 13: Tests (8 hours)
Test self_update integration:
- Mock GitHub releases for testing
- Test signature verification with test keys
- Test rollback scenarios
Test custom components:
- Configuration serialization/deserialization
- Scheduler interval logic
- Backup/rollback flows
- Permission handling
Recommendations: Use vs. Custom
Use self_update for:
- Update checking - GitHub API integration is robust
- Version comparison - semver implementation is battle-tested
- Downloading - Handles retries, progress bars
- Extraction - Supports multiple archive formats
- Binary replacement - Cross-platform atomic replacement
- Progress display - Built-in
indicatifintegration - Signature verification -
zipsignintegration viasignaturesfeature - Release info - Parsed from GitHub API
Build custom for:
- Configuration - Our specific policies, schedules, defaults
- Scheduling - Tokio integration, cron-like triggers
- State persistence - Update history, config files
- Notifications - In-app formatting, user prompts
- Backup/rollback - Safety net for failed updates
- Platform paths - Our specific installation locations
- Permission handling - Check and elevate privileges
- Update policies - Auto-update, notify-only, manual modes
Risk Mitigation
| Risk | Mitigation | |------|------------| | self_update dependency version | Pin to specific version, test upgrades | | Signature key management | Document key rotation, embed in release | | Backup conflicts | Timestamp backup files, limit count | | Permission issues | Graceful fallback to user directory | | GitHub API rate limits | Cache results, respect headers | | Rollback failures | Verify backup integrity before update |
Complexity Breakdown by Step
| Step | Use self_update | Custom Code | Hours |
|------|-----------------|-------------|-------|
| 1. Setup | ✅ Feature flags | Config struct | 4 |
| 2. Update Checker | ✅ Update::configure() | Caching, scheduling | 2 |
| 3. Version Comparison | ✅ Eliminated | - | 0 |
| 4. Downloader | ✅ Download::from_url() | Retry logic | 1 |
| 5. Extractor | ✅ Eliminated | - | 0 |
| 6. Signature Verification | ✅ signatures feature | Key management | 2 |
| 7. Installer | ✅ self_replace() | Backup, rollback | 2 |
| 8. Config Manager | ❌ | Full implementation | 4 |
| 9. Scheduler | ❌ | Full implementation | 6 |
| 10. Notifier | ❌ | Full implementation | 4 |
| 11. Backup & Rollback | ❌ | Full implementation | 6 |
| 12. Platform Paths | ❌ | Full implementation | 2 |
| 13. Tests | Mixed | Full test suite | 8 |
| Total | 7 steps leveraged | 8 steps custom | 41 |
Effort reduction: 33-49 hours (45-61% reduction)
Implementation Order (Optimized)
-
Phase 1: Core (8 hours)
- Step 1: Setup (config struct, feature flags)
- Step 2: Update Checker (integrate self_update)
- Step 7: Installer (self_replace, basic backup)
-
Phase 2: Safety (8 hours)
- Step 11: Backup & Rollback (robust backup system)
- Step 6: Signature Verification (key management)
- Step 4: Downloader (custom retry logic)
-
Phase 3: Automation (10 hours)
- Step 8: Config Manager (persistence)
- Step 9: Scheduler (Tokio integration)
- Step 10: Notifier (user prompts)
-
Phase 4: Polish (7 hours)
- Step 12: Platform Paths (macOS/Linux)
- Step 13: Tests (comprehensive suite)
-
Phase 5: Integration (8 hours)
- Wire into terraphim-ai main binary
- CLI flags for update commands
- Documentation
Total: 41 hours
Key Takeaways
- Eliminate redundant code: Don't rebuild version comparison, downloading, extraction
- Leverage signature verification: self_update's
signaturesfeature uses zipsign - Focus on value-add: Build only what's missing (config, scheduling, backup, rollback)
- Reduce complexity: 45-61% effort reduction
- Maintain safety: Backup/rollback is critical, even with atomic replacement
- Test thoroughly: Mock self_update calls for isolated testing
Next Steps
- ✅ Add
signaturesfeature toterraphim_update/Cargo.toml - ✅ Create
UpdateConfigstruct - ✅ Implement update checker using self_update
- ✅ Build backup/rollback system
- ✅ Add scheduler with Tokio
- ✅ Integrate into main binary
- ✅ Write tests for custom components
- ✅ Document usage and configuration