# Version TUI Documentation ## Overview The `version_tui.py` script is an interactive terminal interface for managing package versions in a NixOS repository. It provides a unified way to update version.json files, Python packages, and Home Assistant components. ## Architecture ### Core Components 1. **Package Discovery**: Scans the repository for different package types 2. **Version Management**: Handles version.json, Python default.nix, and Home Assistant components 3. **Hash Computation**: Uses modern Nix commands for reliable hash generation 4. **Interactive Interface**: Curses-based TUI with color support and keyboard navigation ## Package Types Supported ### 1. Regular Packages (`packages/**/version.json`) - Standard version.json format with variables and sources - Support for variants (base + overrides) - Multiple fetcher types: github, git, url ### 2. Python Packages (`packages/python/*/default.nix`) - Parses version, pname, and source info from default.nix - Supports fetchFromGitHub and fetchPypi patterns - Updates version, hash, tag, and rev fields ### 3. Home Assistant Components (`packages/homeassistant/*/default.nix`) - Specialized parsing for HA component structure - Handles domain, version, owner, and repo extraction - GitHub-aware source management ## Fetcher Types ### GitHub Fetcher ```json { "fetcher": "github", "owner": "owner", "repo": "repo", "tag": "v1.0.0", "rev": "commit-hash", "hash": "sha256-..." } ``` ### Git Fetcher ```json { "fetcher": "git", "url": "https://github.com/user/repo.git", "rev": "commit-hash", "hash": "sha256-..." } ``` ### URL Fetcher ```json { "fetcher": "url", "url": "https://example.com/file.tar.gz", "hash": "sha256-..." } ``` ## Key Functions ### Hash Computation #### `nix_prefetch_url(url: str)` **Purpose**: Compute SHA256 SRI hash for URL sources **Method**: 1. Try `nix store prefetch-file` (modern, SRI output) 2. Fallback to `nix-prefetch-url` (legacy, needs conversion) 3. Convert to SRI format if needed #### `nix_prefetch_git(url: str, rev: str)` **Purpose**: Compute SHA256 SRI hash for Git repositories **Method**: 1. Use `nix eval` with `builtins.fetchGit` to get store path 2. Hash the store path with `nix hash path --type sha256` 3. Fallback to `nix-prefetch-git` if available ### API Functions #### `gh_latest_release(owner, repo, token)` - Gets latest release from GitHub API - Returns tag_name of latest release - Handles API errors gracefully #### `gh_latest_tag(owner, repo, token)` - Gets all tags and returns the first one - Limited to 100 tags per page - Sorts by GitHub's default ordering #### `gh_head_commit(owner, repo)` - Uses `git ls-remote` to get HEAD commit - No API token required - Fallback for when GitHub API fails ### Special Cases #### Raspberry Pi Linux - Prefers `stable_YYYYMMDD` tags over latest - Falls back to series-specific tags (`rpi-X.Y`) - Maintains compatibility with existing tagging schemes #### CachyOS Linux - Fetches latest version from upstream PKGBUILD - Supports different suffixes (rc, hardened, lts) - Handles both .SRCINFO and PKGBUILD parsing ## UI Navigation ### Main Package List ``` ↑/k/j : Navigate up/down g/G : Go to top/bottom Enter : Open package details f : Cycle filters (all → regular → python → all) q/ESC : Quit ``` ### Package Details Screen ``` ←/h/l : Switch variants (if available) ↑/k/j : Navigate sources r : Refresh candidates h : Recompute hash e : Edit field (path=value) s : Save changes i : Show full URL (URL sources) Enter : Action menu for selected source Backspace : Return to package list q/ESC : Quit ``` ### Action Menu ``` ↑/k/j : Select option Enter : Execute selected action Backspace : Cancel ``` ## File Structure Analysis ### version.json Format ```json { "schemaVersion": 1, "variables": { "key": "value" }, "sources": { "name": { "fetcher": "type", "...": "..." } }, "variants": { "variant-name": { "sources": { "name": { "override": "value" } } } } } ``` ### Python Package Parsing The script extracts information from patterns like: ```nix { pname = "package-name"; version = "1.0.0"; src = fetchFromGitHub { owner = "user"; repo = "repo"; rev = "v1.0.0"; sha256 = "..."; }; } ``` ### Home Assistant Component Parsing ```nix { domain = "component_name"; version = "1.0.0"; src = fetchFromGitHub { owner = "user"; repo = "repo"; rev = "v1.0.0"; sha256 = "..."; }; } ``` ## Error Handling ### Network Errors - Timeouts: 10-second timeout on HTTP requests - HTTP status codes: Proper handling of 4xx/5xx responses - Retry logic: Graceful fallback when APIs fail ### API Rate Limiting - Uses `GITHUB_TOKEN` environment variable if available - Provides clear error messages when rate limited - Falls back to git commands when API fails ### Git Command Failures - Robust error handling for git ls-remote - Validation of git command output - Clear error messages for debugging ## Configuration ### Environment Variables - `GITHUB_TOKEN`: GitHub personal access token (optional) - Increases API rate limits from 60/hour to 5000/hour ### Dependencies - **Required**: `nix` command with experimental features - **Optional**: `nix-prefetch-git`, `git` commands - **Python**: Standard library + curses ## Troubleshooting ### Hash Mismatches 1. Check if using correct Nix version 2. Verify network connectivity to GitHub 3. Try manual hash computation: ```bash nix store prefetch-file --hash-type sha256 ``` ### Missing Candidates 1. Check GitHub token availability 2. Verify repository exists and is accessible 3. Check network connectivity 4. Try manual API calls with curl ### Display Issues 1. Ensure terminal supports colors and Unicode 2. Check terminal size (minimum 80x24 recommended) 3. Try resizing terminal window 4. Use `-r` flag to force redraw ## Development ### Adding New Fetcher Types 1. Update `fetch_candidates_for()` method 2. Add parsing logic to appropriate `parse_*()` function 3. Update hash computation methods 4. Add UI handling for new type ### Testing Changes ```bash # Test individual functions python3 -c " from scripts.version_tui import nix_prefetch_url print(nix_prefetch_url('https://example.com/file.tar.gz')) " # Test package parsing python3 -c " from scripts.version_tui import parse_python_package print(parse_python_package(Path('packages/python/example/default.nix'))) " ``` ## Architecture Decisions ### Why Multiple Hash Methods? - Different Nix versions have different available commands - Modern Nix uses `nix store prefetch-file` and `nix eval` - Legacy systems use `nix-prefetch-url` and `nix-prefetch-git` - Script tries modern methods first, falls back gracefully ### Why Template Rendering? - Variables allow flexible version specifications - Supports `${variable}` substitution in URLs and tags - Enables consistent updates across variants - Reduces duplication in version.json files ### Why Two-Step Git Hash? - `builtins.fetchGit` provides store paths, not hashes - `nix hash path` works reliably on store paths - More consistent than trying to parse git command output - Works with all git repository formats ## File Organization ``` scripts/ ├── version_tui.py # Main script ├── __pycache__/ # Python cache └── README_tui.md # This documentation ``` ## Security Considerations - No sensitive data is logged - GitHub tokens are handled securely via environment - Hash computation uses read-only operations - No credentials are stored or transmitted unnecessarily ## Performance - Lazy loading of candidates (only when needed) - Caching of computed hashes during session - Parallel network requests where possible - Efficient terminal rendering with minimal refreshes