Add debug flag and config init support

Introduce a `--debug` option and an `Init` subcommand to the CLI.
Add a new `config` module with loader and schema types for reading and
creating a default `veil.yaml` (supporting a local debug config path).
Update `.gitignore`, `default.nix`, and `flake.nix` comments to
reference
the templates directory.
Provide an example configuration template and integrate it into the
application’s entry point.
This commit is contained in:
2026-06-06 11:53:22 +02:00
parent 6e46e26f7a
commit 3813eaabb3
10 changed files with 227 additions and 6 deletions
+1
View File
@@ -1,4 +1,5 @@
/target /target
/result /result
/local-config
veil-rs.log veil-rs.log
+1 -1
View File
@@ -33,7 +33,7 @@ in
passthru.updateScript = nix-update-script {}; passthru.updateScript = nix-update-script {};
# postInstall = '' # postInstall = ''
# cp static files # cp -r templates $out/bin
# ''; # '';
meta = { meta = {
+2 -2
View File
@@ -45,11 +45,11 @@
src = ./.; src = ./.;
# buildInputs = with pkgs; []; # buildInputs = with pkgs; [];
#
nativeBuildInputs = with pkgs; [pkg-config]; nativeBuildInputs = with pkgs; [pkg-config];
# postInstall = '' # postInstall = ''
# cp static files # cp -r templates $out/bin
# ''; # '';
}; };
}; };
+9
View File
@@ -16,12 +16,21 @@ pub struct Cli {
)] )]
pub log: bool, pub log: bool,
#[arg(
long,
short = 'd',
help = "Run in debug mode look for config in ./local-config/veil.yaml",
default_value_t = false
)]
pub debug: bool,
#[command(subcommand)] #[command(subcommand)]
pub command: Cmds, pub command: Cmds,
} }
#[derive(Subcommand, Clone, Debug)] #[derive(Subcommand, Clone, Debug)]
pub enum Cmds { pub enum Cmds {
Init,
Sync, Sync,
Add, Add,
Rm, Rm,
+91
View File
@@ -0,0 +1,91 @@
use crate::config::VeilConfig;
use anyhow::{Context, Result as AnyhowResult};
use std::{
fs::{File, create_dir_all, read_to_string},
io::{Error, ErrorKind, Result, Write},
path::{Path, PathBuf},
};
pub struct VeilFile;
impl VeilFile {
/// Load a config from an explicit `path`.
pub fn load(path: &Path) -> AnyhowResult<VeilConfig> {
let content: String = read_to_string(path)
.with_context(|| format!("Cannot read config: {}", path.display()))?;
serde_yaml::from_str(&content).with_context(|| "Failed to parse veil.yaml")
}
/// Find the default configuration file.
///
/// * If `debug` is true → tries `./local-config/veil.yaml`.
/// * Otherwise → looks inside `$XDG_CONFIG_HOME/veil/` (or `$HOME/.config/veil/`).
/// * The three accepted names are: `veil.yaml`, `.veil.yaml`, `veil.yml`.
///
/// Returns `Some(PathBuf)` when a file is found, otherwise `None`.
pub fn find_default(debug: bool) -> Option<PathBuf> {
if debug {
let debug_path: &Path = Path::new("./local-config/veil.yaml");
if debug_path.exists() {
return Some(debug_path.to_path_buf());
}
}
let candidates: [&str; 3] = ["veil.yaml", ".veil.yaml", "veil.yml"];
if let Some(base) = dirs::config_dir() {
let veil_dir: PathBuf = base.join("veil");
for name in &candidates {
let candidate: PathBuf = veil_dir.join(name);
if candidate.exists() {
return Some(candidate);
}
}
}
None
}
/// Create a default configuration file based on the bundled example template.
///
/// * `debug` if `true` we use the debug location (`./local-config/veil.yaml`);
/// otherwise we use the XDG config directory (`$XDG_CONFIG_HOME/veil/veil.yaml`).
pub fn init_config(debug: bool) -> Result<()> {
let dest_dir: PathBuf = if debug {
PathBuf::from("./local-config")
} else {
let base: PathBuf = dirs::config_dir().ok_or_else(|| {
Error::new(ErrorKind::NotFound, "Unable to locate XDG config directory")
})?;
base.join("veil")
};
create_dir_all(&dest_dir)?;
let dest_file: PathBuf = dest_dir.join("veil.yaml");
if dest_file.exists() {
println!("⚙️ Config already exists at {}", dest_file.display());
return Ok(());
}
let template_path: PathBuf = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("templates")
.join("example.veil.yaml");
let template: String = read_to_string(&template_path).map_err(|e| {
Error::new(
e.kind(),
format!("Failed to read template {}: {}", template_path.display(), e),
)
})?;
let mut file: File = File::create(&dest_file)?;
file.write_all(template.as_bytes())?;
file.flush()?;
println!("✅ Created new config at {}", dest_file.display());
Ok(())
}
}
+5
View File
@@ -0,0 +1,5 @@
pub mod loader;
pub mod schema;
pub use loader::VeilFile;
pub use schema::{AppConfig, VeilConfig, WindowConfig};
+91
View File
@@ -0,0 +1,91 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct VeilConfig {
pub apps: Vec<AppConfig>,
}
impl VeilConfig {
pub fn new(apps: Vec<AppConfig>) -> Self {
Self { apps }
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AppConfig {
pub id: String,
pub name: String,
pub title: String,
pub url: String,
pub icon: String,
#[serde(default)]
pub window: WindowConfig,
}
impl AppConfig {
pub fn new(
id: String,
name: String,
url: String,
title: String,
icon: String,
window: WindowConfig,
) -> Self {
Self {
id,
name,
title,
url,
icon,
window,
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(default)]
pub struct WindowConfig {
pub width: u32,
pub height: u32,
pub resizable: bool,
pub fullscreen: bool,
pub decorations: bool,
pub always_on_top: bool,
pub center: bool,
}
impl WindowConfig {
pub fn new(
width: u32,
height: u32,
resizable: bool,
fullscreen: bool,
decorations: bool,
always_on_top: bool,
center: bool,
) -> Self {
Self {
width,
height,
resizable,
fullscreen,
decorations,
always_on_top,
center,
}
}
}
impl Default for WindowConfig {
fn default() -> Self {
Self {
width: 1280,
height: 800,
resizable: true,
fullscreen: false,
decorations: true,
always_on_top: false,
center: true,
}
}
}
+1
View File
@@ -1,2 +1,3 @@
pub mod cli; pub mod cli;
pub mod config;
pub mod logs; pub mod logs;
+12 -3
View File
@@ -1,8 +1,17 @@
use std::io::Result; use std::io::Result;
use veil_rs::cli::Cli; use veil_rs::{
cli::{Cli, Cmds},
config::VeilFile,
};
fn main() -> Result<()> { fn main() -> Result<()> {
let _args: Cli = Cli::get_args(); let args: Cli = Cli::get_args();
Ok(()) match args.command {
Cmds::Init => VeilFile::init_config(args.debug),
Cmds::Sync => Ok(()),
Cmds::Add => Ok(()),
Cmds::Rm => Ok(()),
Cmds::Ls => Ok(()),
}
} }
+14
View File
@@ -0,0 +1,14 @@
apps:
- id: com.veil.jellyfin
name: jellyfin
title: Jellyfin
url: https://jellyfin.example.com
icon: https://jellyfin.example.com/favicon.ico
window:
width: 1280
height: 800
resizable: true
fullscreen: false
decorations: true
always_on_top: false
center: true