aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.rs20
-rw-r--r--src/dots.rs48
-rw-r--r--src/main.rs52
3 files changed, 81 insertions, 39 deletions
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 0000000..f43bda4
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,20 @@
+use std::path::PathBuf;
+use clap::{Parser, Subcommand};
+
+#[derive(Parser)]
+#[clap(author = "Max Bossing", version, about = "System-agnostic dotfile deployer", long_about = None)]
+pub struct Cli {
+ #[arg(short, long, default_value = "dots.toml")]
+ pub config: Option<PathBuf>,
+
+ #[command(subcommand)]
+ pub command: CliCommand
+}
+
+#[derive(Subcommand)]
+pub enum CliCommand {
+ #[clap(about = "Deploys a dots set")]
+ Deploy,
+ #[clap(about = "Unlinks (tries to remove) a dots deployment")]
+ Unlink
+} \ No newline at end of file
diff --git a/src/dots.rs b/src/dots.rs
new file mode 100644
index 0000000..5b75254
--- /dev/null
+++ b/src/dots.rs
@@ -0,0 +1,48 @@
+use std::fs::{remove_file, symlink_metadata};
+use std::os::unix::fs::symlink;
+use std::path::PathBuf;
+use dirs::home_dir;
+use crate::config::Dot;
+
+pub fn deploy_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!("linking from {} to {}", dot.source.display(), dot.destination.display());
+ let _ = symlink(&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());
+ 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|
+ eprintln!("failed to remove symlink: {}", err)
+ );
+ }
+ }
+}
+
+fn prepend_user_dir(path: &PathBuf) -> PathBuf {
+ home_dir().unwrap().join(path)
+} \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 8fc22c0..c2c103d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,30 +1,17 @@
-use std::env;
-use std::os::unix::fs::symlink;
-use std::path::PathBuf;
use std::process::exit;
-use dirs::{home_dir};
-use crate::config::{Config, ConfigLoadError, Dot};
+use clap::Parser;
+use crate::cli::{Cli, CliCommand};
+use crate::config::{Config, ConfigLoadError};
+use crate::dots::{deploy_dots, unlink_dots};
mod config;
+mod cli;
+mod dots;
fn main() {
- let args = env::args().skip(1).collect::<Vec<String>>();
-
- if args.len() > 1 {
- eprintln!("usage: {} [config]", args[0]);
- exit(1);
- }
-
- if args.len() == 1 && (args[0] == "-h" || args[0] == "--help") {
- println!("Usage: {} [config]", args[0]);
- println!("options:");
- println!(" -h, --help Print help information");
- println!("By default, dots will look for a bummsdots.toml file in the current directory");
- println!("This can be changed by passing the filename");
- exit(0);
- }
-
- let config = Config::load(args.get(0).map(|o| PathBuf::from(o))).map_err(|err|
+ let cli = Cli::parse();
+
+ let config = Config::load(cli.config).map_err(|err|
match err {
ConfigLoadError::IOError(err) => {
eprintln!("failed to load config file: {}", err);
@@ -36,22 +23,9 @@ fn main() {
}
}
).unwrap();
-
- let prepended_mappings = config.dots.iter().map(|m|
- Dot {
- source: config.dots_dir.join(&m.source),
- destination: prepend_user_dir(&m.destination)
- }
- );
-
- for dot in prepended_mappings {
- println!("linking from {} to {}", dot.source.display(), dot.destination.display());
- let _ = symlink(&dot.source, &dot.destination).map_err(|err|
- eprintln!("failed to symlink: {}", err.to_string())
- );
+
+ match cli.command {
+ CliCommand::Deploy => deploy_dots(config.dots, config.dots_dir),
+ CliCommand::Unlink => unlink_dots(config.dots, config.dots_dir),
}
-}
-
-fn prepend_user_dir(path: &PathBuf) -> PathBuf {
- home_dir().unwrap().join(path)
} \ No newline at end of file