Skip to content

Conversation

@ishaksebsib
Copy link
Contributor

@ishaksebsib ishaksebsib commented Oct 29, 2025

Description

Adds a complete template system to the Helix CLI, allowing users to initialize projects from Git-based templates with Handlebars variable substitution and caching.

Key Features

Template Sources:

  • Official templates: helix init --template <template-name>
  • With version/branch: helix init --template <template-name>@v1.0
  • HTTPS URLs: helix init --template https://github.com/user/repo@main
  • SSH URLs: helix init --template [email protected]:user/repo.git@v2

Caching System:

  • Commit-hash based caching for immutability and reliability
  • Two-level cache structure: ~/.helix/templates/<url_hash>/<commit_hash>/
  • Caches unrendered templates
  • Cache invalidation via git ls-remote to check for updates
  • Network failure resilience: falls back to cached version when offline

Template Processing:

  • Handlebars variable substitution (e.g., {{project_name}})
  • .hbs file extension support for template files

User Experience:

# Initialize from official template
helix init --template basic

# Initialize from specific version
helix init --template [email protected]

# Initialize from custom GitHub repo
helix init --template https://github.com/user/custom-template

# Use SSH URL
helix int --template [email protected]:user/template.git@main

Implementation Details

New Files:

  • commands/templates/mod.rs - Template source parsing and configuration
  • commands/templates/fetcher.rs - Git operations, caching, and cache validation
  • commands/templates/processor.rs - Handlebars rendering and file copying

Dependencies:

  • Added handlebars = "6.3.2" for template rendering
  • Added tempfile = "3.23.0" for temporary files

Modified Files:

  • commands/init.rs - Integrated template processing into the init flow
  • commands/mod.rs - Exposed templates module

Related Issues

None

Checklist when merging to main

  • No compiler warnings (if applicable)
  • Code is formatted with rustfmt
  • No useless or dead code (if applicable)
  • Code is easy to understand
  • Doc comments are used for all functions, enums, structs, and fields (where appropriate)
  • All tests pass
  • Performance has not regressed (assuming change was not to fix a bug)
  • Version number has been updated in helix-cli/Cargo.toml and helixdb/Cargo.toml

Additional Notes

None

Greptile Overview

Updated On: 2025-11-07 07:59:38 UTC

Greptile Summary

Implements a complete Git-based template system for the Helix CLI that enables project initialization from official or custom templates with Handlebars variable substitution. The implementation includes a sophisticated commit-hash based caching mechanism with network resilience and atomic operations.

Key Implementation Highlights:

  • Three-module architecture: mod.rs handles URL parsing for official templates and Git URLs (including SSH URLs with multiple @ symbols), fetcher.rs manages Git operations with atomic caching using TempDir, and processor.rs handles Handlebars rendering
  • Two-level cache structure: ~/.helix/templates/{url_hash}/{commit_hash}/ ensures immutability and proper cache invalidation based on upstream commits
  • Cache validation: Uses git ls-remote to check for updates, with graceful fallback to cached versions when network is unavailable (lines 43-48 in fetcher.rs)
  • Atomic operations: Uses TempDir::new_in() within the base cache directory followed by atomic rename to prevent race conditions (lines 126-140 in fetcher.rs)
  • Proper edge case handling: Symlinks explicitly skipped (processor.rs:45), hidden files filtered except .gitignore (processor.rs:40), template validation ensures helix.toml or helix.toml.hbs exists (fetcher.rs:179-185)

Previous Review Comments Addressed:

  • Race condition fixed with atomic rendering using temp directories and atomic rename (commit db4d905c)
  • Symlinks now explicitly checked and skipped during rendering (commit 723a8865)
  • Temp cleanup properly handled by TempDir RAII pattern - directory is automatically cleaned up on drop if not explicitly kept

Code Quality:

  • Comprehensive error handling distinguishes between network errors (allows cache fallback) and auth/not-found errors (fails with clear message)
  • URL parsing correctly handles edge cases like HTTPS URLs with @ in usernames and SSH URLs
  • Unit tests cover URL parsing and hashing consistency
  • Integration with init.rs maintains existing project protection (checks for existing helix.toml before processing)

No critical issues found. Implementation is production-ready.

Important Files Changed

File Analysis

Filename Score Overview
helix-cli/src/commands/templates/fetcher.rs 5/5 Implements Git-based template fetching with atomic caching using TempDir, commit-hash validation via git ls-remote, and network resilience with proper fallback to cached versions
helix-cli/src/commands/templates/processor.rs 5/5 Handles Handlebars template rendering with proper .hbs extension removal, correctly skips symlinks (line 45) and hidden files except .gitignore, filters .git directories during recursion
helix-cli/src/commands/templates/mod.rs 5/5 Defines TemplateSource enum for parsing official templates and Git URLs, handles SSH URLs with multiple @ symbols correctly (line 36), includes comprehensive unit tests
helix-cli/src/commands/init.rs 5/5 Integrates template system into init command, changes template parameter from unused String to functional Option<String>, maintains existing project protection check

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as helix init
    participant Init as init.rs
    participant Parser as TemplateSource::parse
    participant Fetcher as TemplateFetcher
    participant Git as Git Commands
    participant Cache as ~/.helix/templates
    participant Processor as TemplateProcessor
    participant HBS as Handlebars
    participant Project as Project Directory

    User->>CLI: helix init --template [email protected]
    CLI->>Init: run(template: Some("[email protected]"))
    
    Init->>Init: Check helix.toml doesn't exist
    Init->>Init: Create project directory
    
    Init->>Parser: parse("[email protected]")
    Parser-->>Init: TemplateSource::Official{name: "basic", git_ref: Some("v1.0")}
    
    Init->>Fetcher: fetch(source)
    
    Fetcher->>Git: git --version
    Git-->>Fetcher: version info
    
    Fetcher->>Fetcher: check_cache_validity(source)
    Fetcher->>Git: git ls-remote https://github.com/HelixDB/basic v1.0
    
    alt Network Success
        Git-->>Fetcher: commit_hash: abc123...
        Fetcher->>Cache: Check if abc123 exists
        
        alt Cache Valid
            Cache-->>Fetcher: Cache exists
            Fetcher-->>Init: Return cache_path
        else Cache Invalid
            Fetcher->>Fetcher: fetch_and_cache(source)
            Fetcher->>Cache: Create TempDir in base_cache_dir
            
            Fetcher->>Git: git clone --depth 1 --branch v1.0
            Git-->>Fetcher: Clone to temp directory
            
            Fetcher->>Fetcher: validate_template (check helix.toml exists)
            
            Fetcher->>Fetcher: Atomic rename temp to abc123
            Fetcher-->>Init: Return cache_path
        end
    else Network Error
        Git-->>Fetcher: Network error
        Fetcher->>Cache: Check for any cached version
        
        alt Cache Exists
            Cache-->>Fetcher: Return latest cached version
            Fetcher-->>Init: Return cache_path (with warning)
        else No Cache
            Fetcher-->>Init: Error: network error and no cache
        end
    end
    
    Init->>Processor: render_to_dir(cache_dir, project_dir, variables)
    
    loop For each file in cache
        alt Is symlink
            Processor->>Processor: Skip (line 45)
        else Is hidden file (except .gitignore)
            Processor->>Processor: Skip (line 40)
        else Is directory
            Processor->>Processor: Recurse into directory
        else File ends with .hbs
            Processor->>HBS: render_template(content, variables)
            HBS-->>Processor: rendered content
            Processor->>Project: Write file (remove .hbs extension)
        else Regular file
            Processor->>Project: Copy file as-is
        end
    end
    
    Processor-->>Init: Rendering complete
    Init-->>User: Success message with next steps
Loading

@ishaksebsib ishaksebsib marked this pull request as ready for review October 29, 2025 15:43
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@ishaksebsib
Copy link
Contributor Author

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@xav-db
Copy link
Member

xav-db commented Nov 7, 2025

@ishaksebsib conflicts!

@xav-db xav-db closed this Nov 7, 2025
@xav-db xav-db reopened this Nov 7, 2025
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants