diff options
| -rw-r--r-- | Cargo.lock | 7 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | README.md | 9 | ||||
| -rw-r--r-- | src/cli.rs | 5 | ||||
| -rw-r--r-- | src/config.rs | 5 | ||||
| -rw-r--r-- | src/dots.rs | 46 | ||||
| -rw-r--r-- | src/main.rs | 6 |
7 files changed, 55 insertions, 24 deletions
@@ -138,6 +138,7 @@ dependencies = [ "clap", "dirs", "serde", + "symlink", "toml", ] @@ -279,6 +280,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + +[[package]] name = "syn" version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -8,4 +8,5 @@ edition = "2024" clap = { version = "4.5.41", features = ["derive"] } dirs = "6.0.0" serde = { version = "1.0.219", features = ["derive"] } +symlink = "0.1.0" toml = "0.9.2" @@ -36,6 +36,7 @@ src = "nvim" # Resolved against dots_dir dest = ".config/nvim" # Relative paths are resolved against $HOME [[dot]] +host = "hermes" # You can specify on which hosts this dot should be deployed src = "Xmodmap" dest = "/etc/X11" # Absolute paths are respected @@ -51,10 +52,16 @@ If you want to use a different file (for example a different machine but based o dots deploy --config some_file.dots.toml ``` +If you want to skip the hostname check: +```bash +dots --no-hostname-check --deploy +``` + ## Todo - [x] Allow to "undeploy", eg. to automatically remove symlinks created by `dots` - [x] Absolute Paths in dest field -- [ ] Windows Support +- [x] Hostname condition for deployment +- [ ] Windows Support (should work in theory but I haven't tested it yet) ## License This is licensed under the [MIT](LICENSE) license. @@ -6,7 +6,8 @@ use clap::{Parser, Subcommand}; pub struct Cli { #[arg(short, long, default_value = "dots.toml")] pub config: Option<PathBuf>, - + #[arg(short, long)] + pub no_hostname_check: bool, #[command(subcommand)] pub command: CliCommand } @@ -17,4 +18,4 @@ pub enum CliCommand { Deploy, #[clap(about = "Unlinks (tries to remove) a dots deployment")] Unlink -}
\ No newline at end of file +} diff --git a/src/config.rs b/src/config.rs index 6fed687..4be977b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -16,6 +16,8 @@ pub struct Dot { pub source: PathBuf, #[serde(rename = "dest")] pub destination: PathBuf, + #[serde(default = "default_host")] + pub host: String, } pub enum ConfigLoadError { @@ -42,3 +44,6 @@ fn default_dots_dir() -> PathBuf { env::current_dir().expect("failed to get current dir") } +fn default_host() -> String { + "*".to_string() +} diff --git a/src/dots.rs b/src/dots.rs index 0259c0c..29059a1 100644 --- a/src/dots.rs +++ b/src/dots.rs @@ -1,42 +1,52 @@ -use std::fs::{remove_file, symlink_metadata}; -use std::os::unix::fs::symlink; +use std::process::Command; +use std::fs::symlink_metadata; use std::path::PathBuf; use dirs::home_dir; use crate::config::Dot; +use symlink::{symlink_auto, remove_symlink_auto}; -pub fn deploy_dots(dots: Vec<Dot>, dots_dir: PathBuf) { - let prepended_dots = dots.iter().map(|m| + +fn prepare_dots(dots: Vec<Dot>, dots_dir: PathBuf, no_hostname_check: bool) -> Vec<Dot> { + let mut hostname = "*".to_string(); + if !no_hostname_check { + // Deeply saddened there is no better way to do this :( + let hostname_cmd = Command::new("hostname").output().expect("failed to get hostname: command \"hostname\" failed"); + let hostname_stdout = hostname_cmd.stdout; + let mut new_hostname = String::from_utf8(hostname_stdout.clone()).expect("failed to get hostname: unknown hostname encoding"); + new_hostname.pop(); // stdout contains a newline + hostname = new_hostname; + } + + let prepared_dots = dots.iter().filter(|dot| if no_hostname_check { true } else { dot.host == "*" || dot.host == hostname }).map(|m| Dot { source: dots_dir.join(&m.source), - destination: if m.destination.is_absolute() { m.destination.clone() } else { prepend_user_dir(&m.destination) } + destination: if m.destination.is_absolute() { m.destination.clone() } else { prepend_user_dir(&m.destination) }, + host: m.host.clone() } ); - for dot in prepended_dots { + prepared_dots.collect() +} + +pub fn deploy_dots(dots: Vec<Dot>, dots_dir: PathBuf, no_hostname_check: bool) { + for dot in prepare_dots(dots, dots_dir, no_hostname_check) { println!("linking from {} to {}", dot.source.display(), dot.destination.display()); - let _ = symlink(&dot.source, &dot.destination).map_err(|err| + let _ = symlink_auto(&dot.source, &dot.destination).map_err(|err| eprintln!("failed to symlink: {}", err.to_string()) ); } } -pub fn unlink_dots(dots: Vec<Dot>, dots_dir: PathBuf) { - let prepended_dots = dots.iter().map(|m| - Dot { - source: dots_dir.join(&m.source), - destination: prepend_user_dir(&m.destination) - } - ); - - for dot in prepended_dots { - println!("unlinking {}", dot.destination.display()); +pub fn unlink_dots(dots: Vec<Dot>, dots_dir: PathBuf, no_hostname_check: bool) { + for dot in prepare_dots(dots, dots_dir, no_hostname_check) { + println!("unlinking {}", dot.destination.display()); let metadata = symlink_metadata(dot.destination.clone()); if metadata.is_err() { eprintln!("failed to query metadata for {}: {}", dot.destination.display(), metadata.err().unwrap()); continue } if metadata.ok().unwrap().is_symlink() { - let _ = remove_file(dot.destination).map_err(|err| + let _ = remove_symlink_auto(dot.destination).map_err(|err| eprintln!("failed to remove symlink: {}", err) ); } diff --git a/src/main.rs b/src/main.rs index c2c103d..e07ff28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ fn main() { ).unwrap(); match cli.command { - CliCommand::Deploy => deploy_dots(config.dots, config.dots_dir), - CliCommand::Unlink => unlink_dots(config.dots, config.dots_dir), + CliCommand::Deploy => deploy_dots(config.dots, config.dots_dir, cli.no_hostname_check), + CliCommand::Unlink => unlink_dots(config.dots, config.dots_dir, cli.no_hostname_check), } -}
\ No newline at end of file +} |
