Skip to main content

dodot_lib/commands/
init.rs

1//! `init` command — create a new pack with default structure.
2
3use serde::Serialize;
4
5use crate::packs::orchestration::ExecutionContext;
6use crate::{DodotError, Result};
7
8#[derive(Debug, Clone, Serialize)]
9pub struct InitResult {
10    pub message: String,
11    pub details: Vec<String>,
12}
13
14/// Create a new pack directory with default structure.
15pub fn init(pack_name: &str, ctx: &ExecutionContext) -> Result<InitResult> {
16    let pack_path = ctx.paths.pack_path(pack_name);
17
18    if ctx.fs.exists(&pack_path) {
19        return Err(DodotError::PackInvalid {
20            name: pack_name.into(),
21            reason: "directory already exists".into(),
22        });
23    }
24
25    ctx.fs.mkdir_all(&pack_path)?;
26
27    // Write default .dodot.toml
28    let config_content = format!(
29        r#"# dodot configuration for {pack_name}
30# See: dodot config gen --help
31
32[pack]
33# ignore = ["*.bak", "*.tmp"]
34
35[symlink]
36# force_home = []
37# protected_paths = []
38
39[mappings]
40# install = "install.sh"
41# shell = ["aliases.sh"]
42# homebrew = "Brewfile"
43# skip = []
44"#
45    );
46    ctx.fs
47        .write_file(&pack_path.join(".dodot.toml"), config_content.as_bytes())?;
48
49    let details = vec![
50        format!("Created {}", pack_path.display()),
51        format!("Created {}/.dodot.toml", pack_path.display()),
52    ];
53
54    Ok(InitResult {
55        message: format!("Pack '{pack_name}' initialized."),
56        details,
57    })
58}