261 lines
6.2 KiB
Markdown
261 lines
6.2 KiB
Markdown
|
|
# Nickel Roundtrip Example
|
||
|
|
|
||
|
|
Complete example demonstrating the roundtrip workflow: load existing configuration, edit via interactive form, and regenerate with diff viewer.
|
||
|
|
|
||
|
|
## Scenario
|
||
|
|
|
||
|
|
CI configuration management - edit GitHub Actions settings through a form interface while preserving the Nickel structure.
|
||
|
|
|
||
|
|
## Files
|
||
|
|
|
||
|
|
- **config.ncl** - Input/output Nickel configuration
|
||
|
|
- **ci-form.toml** - Form definition with `nickel_path` mappings
|
||
|
|
- **config.ncl.j2** - Tera template for generating output
|
||
|
|
- **01-generate-initial-config.sh** - Create initial config
|
||
|
|
- **02-roundtrip-cli.sh** - Edit via CLI backend
|
||
|
|
- **03-roundtrip-tui.sh** - Edit via TUI backend
|
||
|
|
- **04-roundtrip-web.sh** - Edit via Web backend
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Generate initial configuration
|
||
|
|
./01-generate-initial-config.sh
|
||
|
|
|
||
|
|
# 2. Edit with your preferred backend:
|
||
|
|
|
||
|
|
# CLI (command-line prompts)
|
||
|
|
./02-roundtrip-cli.sh
|
||
|
|
|
||
|
|
# TUI (full-screen terminal UI)
|
||
|
|
./03-roundtrip-tui.sh
|
||
|
|
|
||
|
|
# Web (browser-based form)
|
||
|
|
./04-roundtrip-web.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
## Key Features
|
||
|
|
|
||
|
|
### `nickel_path` Mapping
|
||
|
|
|
||
|
|
Every field in `ci-form.toml` has a `nickel_path` attribute mapping to the Nickel structure:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[[elements]]
|
||
|
|
name = "parallel_jobs"
|
||
|
|
type = "text"
|
||
|
|
prompt = "Parallel Jobs"
|
||
|
|
default = "4"
|
||
|
|
nickel_path = ["ci", "github_actions", "parallel_jobs"]
|
||
|
|
```
|
||
|
|
|
||
|
|
Maps to:
|
||
|
|
|
||
|
|
```nickel
|
||
|
|
{
|
||
|
|
ci = {
|
||
|
|
github_actions = {
|
||
|
|
parallel_jobs = 4
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Template Rendering
|
||
|
|
|
||
|
|
The `config.ncl.j2` template uses form values to generate valid Nickel:
|
||
|
|
|
||
|
|
```jinja2
|
||
|
|
{
|
||
|
|
project = {
|
||
|
|
name = "{{ project_name }}",
|
||
|
|
description = "{{ project_description }}",
|
||
|
|
},
|
||
|
|
|
||
|
|
ci = {
|
||
|
|
github_actions = {
|
||
|
|
enabled = {{ enable_github_actions }},
|
||
|
|
parallel_jobs = {{ parallel_jobs }},
|
||
|
|
timeout_minutes = {{ timeout_minutes }},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Summary with Diff
|
||
|
|
|
||
|
|
After editing, see what changed:
|
||
|
|
|
||
|
|
```text
|
||
|
|
╔════════════════════════════════════════════════════════════╗
|
||
|
|
║ ✅ Configuration Saved Successfully! ║
|
||
|
|
╠════════════════════════════════════════════════════════════╣
|
||
|
|
║ 📄 File: config.ncl ║
|
||
|
|
║ ✓ Validation: ✓ PASSED ║
|
||
|
|
║ 📊 Fields: 3/12 changed, 9 unchanged ║
|
||
|
|
╠════════════════════════════════════════════════════════════╣
|
||
|
|
║ 📋 What Changed: ║
|
||
|
|
║ ├─ parallel_jobs: 4 → 8 ║
|
||
|
|
║ ├─ timeout_minutes: 60 → 120 ║
|
||
|
|
║ ├─ enable_cache: false → true ║
|
||
|
|
╠════════════════════════════════════════════════════════════╣
|
||
|
|
║ 💡 Next Steps: ║
|
||
|
|
║ • Review: cat config.ncl ║
|
||
|
|
║ • Apply CI tools: ./setup-ci.sh ║
|
||
|
|
║ • Re-configure: ./ci-configure.sh ║
|
||
|
|
╚════════════════════════════════════════════════════════════╝
|
||
|
|
```
|
||
|
|
|
||
|
|
## Workflow Details
|
||
|
|
|
||
|
|
### 1. Load Defaults
|
||
|
|
|
||
|
|
Roundtrip reads `config.ncl` and extracts values using `nickel_path`:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
// Internally:
|
||
|
|
nickel export config.ncl // → JSON
|
||
|
|
extract_value_by_path(json, ["ci", "github_actions", "parallel_jobs"]) // → 4
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Populate Form
|
||
|
|
|
||
|
|
Form fields get pre-filled with current values:
|
||
|
|
|
||
|
|
- Text fields show current text
|
||
|
|
- Numbers show current numbers
|
||
|
|
- Booleans show current true/false
|
||
|
|
- Select fields pre-select current option
|
||
|
|
|
||
|
|
### 3. Edit Interactively
|
||
|
|
|
||
|
|
User edits via chosen backend (CLI/TUI/Web).
|
||
|
|
|
||
|
|
### 4. Generate Output
|
||
|
|
|
||
|
|
Template renders with new values:
|
||
|
|
|
||
|
|
```jinja2
|
||
|
|
parallel_jobs = {{ parallel_jobs }}, // User changed 4 → 8
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5. Validate
|
||
|
|
|
||
|
|
Automatic validation:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
nickel typecheck config.ncl
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6. Show Summary
|
||
|
|
|
||
|
|
Terminal summary (all backends) + HTML summary (web only).
|
||
|
|
|
||
|
|
## Backend Comparison
|
||
|
|
|
||
|
|
| Feature | CLI | TUI | Web |
|
||
|
|
|---------|-----|-----|-----|
|
||
|
|
| Terminal UI | ✓ | ✓ | ✓ (summary only) |
|
||
|
|
| Browser UI | ✗ | ✗ | ✓ |
|
||
|
|
| Pre-populated values | ✓ | ✓ | ✓ |
|
||
|
|
| Real-time validation | ✗ | ✓ | ✓ |
|
||
|
|
| HTML diff viewer | ✗ | ✗ | ✓ |
|
||
|
|
| Download button | ✗ | ✗ | ✓ |
|
||
|
|
|
||
|
|
## Customization
|
||
|
|
|
||
|
|
### Add More Fields
|
||
|
|
|
||
|
|
1. **Update form:**
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[[elements]]
|
||
|
|
name = "rust_version"
|
||
|
|
type = "select"
|
||
|
|
prompt = "Rust Version"
|
||
|
|
options = [
|
||
|
|
{ value = "stable", label = "Stable" },
|
||
|
|
{ value = "nightly", label = "Nightly" }
|
||
|
|
]
|
||
|
|
nickel_path = ["ci", "rust", "version"]
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Update template:**
|
||
|
|
|
||
|
|
```jinja2
|
||
|
|
ci = {
|
||
|
|
rust = {
|
||
|
|
version = "{{ rust_version }}",
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Update initial config:**
|
||
|
|
|
||
|
|
```nickel
|
||
|
|
{
|
||
|
|
ci = {
|
||
|
|
rust = {
|
||
|
|
version = "stable"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Change Template Logic
|
||
|
|
|
||
|
|
Add conditionals:
|
||
|
|
|
||
|
|
```jinja2
|
||
|
|
{% if enable_cache %}
|
||
|
|
cache = {
|
||
|
|
enabled = true,
|
||
|
|
paths = {{ cache_paths | json }},
|
||
|
|
},
|
||
|
|
{% endif %}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Disable Validation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
typedialog nickel-roundtrip \
|
||
|
|
--input config.ncl \
|
||
|
|
--form ci-form.toml \
|
||
|
|
--output config.ncl \
|
||
|
|
--ncl-template config.ncl.j2 \
|
||
|
|
--no-validate # ← Skip nickel typecheck
|
||
|
|
```
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
**No defaults loaded:**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Check nickel export works
|
||
|
|
nickel export config.ncl
|
||
|
|
|
||
|
|
# Verify all fields have nickel_path
|
||
|
|
grep "nickel_path" ci-form.toml | wc -l
|
||
|
|
```
|
||
|
|
|
||
|
|
**Template errors:**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Test template separately
|
||
|
|
echo '{"project_name": "test"}' | \
|
||
|
|
tera --template config.ncl.j2
|
||
|
|
```
|
||
|
|
|
||
|
|
**Validation fails:**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Check manually
|
||
|
|
nickel typecheck config.ncl
|
||
|
|
```
|
||
|
|
|
||
|
|
## Learn More
|
||
|
|
|
||
|
|
- [nickel.md](../../docs/nickel.md) - Full roundtrip documentation
|
||
|
|
- [Nickel Language](https://nickel-lang.org) - Nickel reference
|
||
|
|
- [Tera Templates](https://tera.netlify.app) - Template syntax
|