Architecture and Design
This guide provides a comprehensive overview of gist-cache-rs’s architecture, design patterns, and implementation details.
Project Overview
gist-cache-rs is a Rust CLI tool for efficiently caching, searching, and executing GitHub Gists. It offers fast incremental updates, multi-language script execution support, and content caching capabilities.
Supported Platforms: Linux, macOS, Windows 10 or later
Supported Interpreters: bash, sh, zsh, python3, ruby, node, php, perl, pwsh (PowerShell Core), TypeScript (ts-node, deno, bun), uv
Architecture Overview
Module Structure
The codebase follows a modular architecture with clear separation of concerns:
src/
├── cache/ # Cache management layer
│ ├── content.rs # Content cache (1001 lines)
│ ├── types.rs # Data type definitions (246 lines)
│ ├── update.rs # Incremental update logic (849 lines)
│ └── mod.rs
├── github/ # GitHub API integration
│ ├── api.rs # GitHub CLI wrapper (212 lines)
│ ├── client.rs # Trait definitions (104 lines)
│ └── mod.rs
├── execution/ # Script execution
│ ├── runner.rs # Multi-interpreter execution (758 lines)
│ └── mod.rs
├── search/ # Search functionality
│ ├── query.rs # Search query processing (420 lines)
│ └── mod.rs
├── cli.rs # CLI argument processing (967 lines)
├── config.rs # Configuration management (163 lines)
├── error.rs # Error type definitions (160 lines)
├── lib.rs # Library root
└── main.rs # Entry point
Total: 16 files, approx. 4,660 lines
Cache Module (cache/)
The cache layer implements a sophisticated 2-layer caching structure:
types.rs: Core data structures
GistCache: Main cache containerGistInfo: Individual gist metadataGistFile: File informationCacheMetadata: Cache metadata and timestamps
update.rs: CacheUpdater implementation
- Handles incremental metadata cache updates using GitHub API’s
sinceparameter - Automatically deletes corresponding content cache when Gist updates are detected
- Implements rate limit checking and warning system
content.rs: ContentCache implementation
- Manages individual Gist content files in
~/.cache/gist-cache/contents/{gist_id}/{filename} - Created on-demand during first execution
- Provides approximately 20x performance improvement for subsequent executions
- Implements cache cleaning functionality:
clean(): Remove old or orphaned cache entries--older-than: Delete entries based on Gist’supdated_attimestamp--orphaned: Remove content cache files without corresponding metadata--dry-run: Preview deletion without actually removing files
GitHub Module (github/)
Handles all GitHub API interactions:
api.rs: GitHubApi wrapper
- Wraps GitHub CLI (
gh) for authentication - Implements rate limit checks
- Handles gist retrieval operations
- All GitHub operations use
ghCLI instead of direct REST API calls
client.rs: Trait definitions
- Defines the
GitHubClienttrait for dependency injection - Enables testing with mock implementations
Search Module (search/)
Implements flexible search functionality:
query.rs: SearchQuery implementation
- Multiple search modes:
- Auto: Detects if query is a Gist ID (32-character hexadecimal), or searches filename/description
- ID: Direct ID search
- Filename: Searches filenames only
- Description: Searches descriptions only
- Interactive selection UI using numbered prompts
Execution Module (execution/)
Handles multi-interpreter script execution:
runner.rs: ScriptRunner implementation
- Supports multiple interpreters (bash, python, ruby, node, php, perl, pwsh, TypeScript, uv)
- Two execution modes:
- Stdin-based: Default for most interpreters
- File-based: Required for uv, php, pwsh, TypeScript interpreters
Special Interpreter Handling:
- uv: File-based execution for PEP 723 metadata support
- php: Forced file-based execution for reliable argument handling
- pwsh/powershell: File-based execution for script execution policy compatibility
- TypeScript interpreters (ts-node, deno, bun): File-based execution for module resolution
ts-node: Executes TypeScript on Node.jsdeno: Usesdeno runcommand in Deno runtimebun: Executes in Bun runtime
- Interactive mode: Uses
inherit()for stdio to support commands likeread
Configuration (config.rs)
Manages application configuration:
Cache paths (platform-specific):
- Overridable by environment variable
GIST_CACHE_DIR(for testing) - Unix:
~/.cache/gist-cache/cache.jsonand~/.cache/gist-cache/contents/ - Windows:
%LOCALAPPDATA%\gist-cache\cache.jsonand%LOCALAPPDATA%\gist-cache\contents\
Download path: Uses dirs::download_dir() to conform to OS standards
Test isolation: Can be tested without affecting actual user cache by setting GIST_CACHE_DIR
Error Handling (error.rs)
Centralized error handling using thiserror crate for type-safe error management.
Key Design Patterns
1. Incremental Updates
Metadata cache updates use GitHub API’s since parameter to fetch only changed gists. Timestamp stored in last_updated field of cache.json.
2. 2-Layer Caching (On-demand)
Metadata Cache:
- Stores gist metadata (id, description, files, updated_at) in
cache.json - Updated with the
updatecommand
Content Cache:
- Stores actual script body in
contents/{gist_id}/{filename} - Created on-demand during execution
- Automatically deleted when Gist updates
Cache Freshness Management:
The update command compares updated_at of new and old metadata, and deletes the content cache directory (contents/{gist_id}/) for updated Gists.
3. GitHub CLI Integration
Uses gh command for authentication and API access instead of direct REST API calls. This provides:
- Automatic authentication handling
- Consistent credential management
- Better error messages
4. Multi-Interpreter Support
The execution layer abstracts different interpreters and implements special handling:
- Shell scripts (bash/sh/zsh): Direct execution
- uv: File-based using
uv runcommand for PEP 723 support - php: Forced file-based execution for reliable argument handling
- pwsh/powershell: Forced file-based execution for script execution policy compatibility
- TypeScript (ts-node, deno, bun): Forced file-based execution for module resolution
- Others: Standard stdin-based execution
5. Search Modes
Supports flexible searching:
- Auto: Intelligent detection of query type
- ID: Direct ID search for exact matches
- Filename: Searches filenames only
- Description: Searches descriptions only
6. --force Option
When --force is specified with the run command:
- Automatically executes the
updatecommand (incremental update, notupdate --force) - If the Gist was updated, the content cache is deleted
- Fetches and executes the latest version
- Creates a new cache
This ensures that the latest version is always executed during active development.
7. --download Option
When --download is specified with the run command:
- Saves the Gist file to the download folder (
~/Downloads) - Convenient for saving files separately from executable script caches
- Content cache is also automatically created during download
- Can be used with other options (
--preview,--force,--interactive, etc.)
Important Implementation Details
Date and Time Handling
All timestamps use ISO 8601 format (%Y-%m-%dT%H:%M:%SZ) without sub-seconds to maintain compatibility with the original bash implementation. Custom serializer/deserializer is available in cache/types.rs.
Cache File Format
Structure of cache.json:
{
"metadata": {
"last_updated": "2024-01-01T12:00:00Z",
"total_count": 42,
"github_user": "username"
},
"gists": [...]
}
Execution Modes
- Stdin Mode (default): Pipes script content directly to the interpreter
- File Mode (uv, php, interactive): Creates a temporary file for execution
- Interactive Mode (
-i): Usesinherit()for stdio to supportreadcommand in scripts - Preview Mode (
-p/--preview): Displays Description, Files, and Gist content without execution
Platform-Specific Implementations
Windows Support:
- Permission Settings: Uses conditional compilation (
#[cfg(unix)]) to runchmodonly on Unix - Path Settings: Uses platform-specific cache directories
- Unix:
~/.cache/gist-cache - Windows:
%LOCALAPPDATA%\gist-cache
- Unix:
- Installation Script: Provides PowerShell version (
script/setup.ps1)
Cross-Platform Design:
- Explicit branching with conditional compilation (
cfgattributes) - Prioritizes platform-independent code
- Prevents degradation in existing Linux/macOS environments
Rate Limiting
The Updater checks the rate limit and warns if remaining requests are less than 50. Forced full updates via update --force can consume significant rate limits as it fetches all gists.
Content Cache Behavior Flow
- First Execution: Fetches content from GitHub API and creates a cache after execution
- Subsequent Executions: Reads from cache for faster execution (no network access, ~20x faster)
- Gist Update: The
updatecommand detects changes and automatically deletes the content cache - First Execution After Update: Fetches the latest version from API and creates a new cache
--force Option Behavior
When run --force is specified:
- Automatically executes the
updatecommand (incremental update) - If the Gist was updated, the content cache is deleted
- Fetches and executes the latest version
- Creates a new cache
This ensures that even when Gists are frequently updated during development, the latest version is always executed.
Cache Management
Content cache management functions implemented with cache subcommand:
cache list: Displays a list of cached Gists (ID, description, filename, update time)cache size: Displays the total size of the cache directorycache clean: Deletes orphaned caches (not yet implemented, planned for future)cache clear: Deletes all content caches (with confirmation prompt)
Methods provided by ContentCache struct:
list_cached_gists(): Get a list of cached Gist IDstotal_size(): Calculate the total size of the cache directoryclear_all(): Delete all cachesread(),write(),exists(): Read/write individual caches
Development Commands
Build and Test
# Development build
cargo build
# Release build (optimized)
cargo build --release
# Local installation
cargo install --path .
# Run tests
cargo test
# Run tests with verbose output
cargo test -- --nocapture
Code Quality Checks (via justfile)
# Run all checks (format, lint, test)
just check
# Format check only
just fmt-check
# Lint with clippy
just lint
# Run tests silently
just test
# Auto-format code
just fmt
# CI checks (treat warnings as errors)
just ci-check
Application Execution
# Cache update
cargo run -- update
cargo run -- update --force
cargo run -- update --verbose
# Gist execution
cargo run -- run <query> [interpreter] [args...]
cargo run -- run --preview <query>
cargo run -- run --interactive <query>
cargo run -- run --force <query> # Update cache before execution
cargo run -- run --download <query> # Save to download folder
# Cache management
cargo run -- cache list
cargo run -- cache size
cargo run -- cache clear
Dependencies
Primary Runtime Dependencies
tokio: Asynchronous runtimereqwest: HTTP client (unused, remnant from direct API implementation era)serde/serde_json: Serializationclap: CLI argument parsingchrono: Date and time handlinganyhow/thiserror: Error handlingdirs: Platform-specific directory detectioncolored: Terminal output coloring
Development Dependencies
mockall: Mocking library (for external dependency testing)tempfile: Temporary files/directories (for testing)assert_cmd: For CLI testing (for future integration tests)
Release Process
Automated Release Builds
When a tag is pushed, GitHub Actions automatically builds and releases platform-specific binaries.
# Update version
vim Cargo.toml CHANGELOG.md
git add Cargo.toml CHANGELOG.md
git commit -m "🔖 Bump version to 0.5.0"
# Create and push tag
git tag v0.5.0
git push origin main
git push origin v0.5.0
Build Target Platforms
- Linux (x86_64):
gist-cache-rs-linux-x86_64.tar.gz - macOS (x86_64):
gist-cache-rs-macos-x86_64.tar.gz - macOS (Apple Silicon):
gist-cache-rs-macos-aarch64.tar.gz - Windows (x86_64):
gist-cache-rs-windows-x86_64.zip
Workflow
Defined in .github/workflows/release.yml:
create-release: Creates release page, generates release notesbuild-release: Parallel builds (4 platforms), uploads assets