Layer 3: Templates as pure data, weather template, .anvilignore refresh system
Templates are now composed declaratively via template.toml -- no Rust code changes needed to add new templates. The weather station is the first composed template, demonstrating the full pattern. Template engine: - Composed templates declare base, required libraries, and per-board pins - Overlay mechanism replaces base files (app, sketch, tests) cleanly - Generic orchestration: extract base, apply overlay, install libs, assign pins - Template name tracked in .anvil.toml for refresh awareness Weather template (--template weather): - WeatherApp with 2-second polling, C/F conversion, serial output - TMP36 driver: TempSensor interface, Tmp36 impl, Tmp36Mock, Tmp36Sim - Managed example tests in test_weather.cpp (unit + system) - Minimal student starters in test_unit.cpp and test_system.cpp - Per-board pin defaults (A0 for uno, A0 for mega, A0 for nano) .anvilignore system: - Glob pattern matching (*, ?) with comments and backslash normalization - Default patterns protect student tests, app code, sketch, config - anvil refresh --force respects .anvilignore - anvil refresh --force --file <path> overrides ignore for one file - anvil refresh --ignore/--unignore manages patterns from CLI - Missing managed files always recreated even without --force - .anvilignore itself is in NEVER_REFRESH (cannot be overwritten) Refresh rewrite: - Discovers all template-produced files dynamically (no hardcoded list) - Extracts fresh template + libraries into temp dir for byte comparison - Config template field drives which files are managed - Separated missing-file creation from changed-file updates 428 tests passing on Windows MSVC, 0 warnings.
This commit is contained in:
37
src/main.rs
37
src/main.rs
@@ -81,9 +81,21 @@ enum Commands {
|
||||
/// Path to project directory (defaults to current directory)
|
||||
dir: Option<String>,
|
||||
|
||||
/// Overwrite scripts even if they have been modified
|
||||
/// Overwrite managed files even if they have been modified
|
||||
#[arg(long)]
|
||||
force: bool,
|
||||
|
||||
/// Override .anvilignore for a specific file (use with --force)
|
||||
#[arg(long, value_name = "PATH")]
|
||||
file: Option<String>,
|
||||
|
||||
/// Add a pattern to .anvilignore (protect a file from refresh)
|
||||
#[arg(long, value_name = "PATTERN", conflicts_with_all = ["unignore", "force"])]
|
||||
ignore: Option<String>,
|
||||
|
||||
/// Remove a pattern from .anvilignore (allow refresh to update it)
|
||||
#[arg(long, value_name = "PATTERN", conflicts_with_all = ["ignore", "force"])]
|
||||
unignore: Option<String>,
|
||||
},
|
||||
|
||||
/// Manage board profiles in .anvil.toml
|
||||
@@ -264,11 +276,24 @@ fn main() -> Result<()> {
|
||||
commands::devices::scan_devices()
|
||||
}
|
||||
}
|
||||
Commands::Refresh { dir, force } => {
|
||||
commands::refresh::run_refresh(
|
||||
dir.as_deref(),
|
||||
force,
|
||||
)
|
||||
Commands::Refresh { dir, force, file, ignore, unignore } => {
|
||||
if let Some(pattern) = ignore {
|
||||
commands::refresh::add_ignore(
|
||||
dir.as_deref(),
|
||||
&pattern,
|
||||
)
|
||||
} else if let Some(pattern) = unignore {
|
||||
commands::refresh::remove_ignore(
|
||||
dir.as_deref(),
|
||||
&pattern,
|
||||
)
|
||||
} else {
|
||||
commands::refresh::run_refresh(
|
||||
dir.as_deref(),
|
||||
force,
|
||||
file.as_deref(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Commands::Board { name, add, remove, default, listall, id, baud, dir } => {
|
||||
if listall {
|
||||
|
||||
Reference in New Issue
Block a user