diff options
| author | [object Object] <max@bossi.ng> | 2025-07-29 16:52:39 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-29 16:52:39 +0200 | 
| commit | 5b2e7756e808151b5487f7e67b53accc745bee07 (patch) | |
| tree | b4b603501db9f659ff237cb1536c1e1c5759b793 /src | |
| parent | 9c161a33c576b4ccb5908305b19c8e3e252e3a18 (diff) | |
* refactor: move platform-specifics into separate module
* feat: Windows Support (wip)
This is untested because I do not own Windows machines, and I think
there are some problems concerning unlinking.
* wip: inplementation of platform-agnostic deploying and removing etc...
* feat: host-based deployment condition
* feat: command flag to skip hostname checks
* simplyfing the whole preparation step quite a bit
Diffstat (limited to 'src')
| -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 | 
4 files changed, 39 insertions, 23 deletions
| @@ -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 +} | 
