aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml1
-rw-r--r--README.md9
-rw-r--r--src/cli.rs5
-rw-r--r--src/config.rs5
-rw-r--r--src/dots.rs46
-rw-r--r--src/main.rs6
7 files changed, 55 insertions, 24 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 70f66c6..7e7b949 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index bab7836..848d526 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/README.md b/README.md
index 3409e07..1367dd8 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/src/cli.rs b/src/cli.rs
index f43bda4..bb0c621 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -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
+}