50 short programs in Rust, #5 - symlinks
March 14, 2020
I can almost never remember how to create symlinks - that is, which way round the arguments to 'ln' go. So I wrote a Rust equivalent, called symlink
, which you invoke as symlink file-a --pointing-to file-b
- more characters, but if I don't have to look it up every time, quicker overall.
Here's the code:
use clap::{App, Arg}; use std::io::{Error, ErrorKind}; use std::os::unix::fs; use std::path::Path; fn main() -> std::io::Result<()> { let matches = App::new("symlink") .version("1.0") .author("rkd@rkd.me.uk") .about("'ln' replacement that's more intuitive") .arg( Arg::with_name("pointing-to") .short("p") .long("pointing-to") .value_name("FILE") .required(true) .help("Existing file for symlink to point to") .takes_value(true), ) .arg( Arg::with_name("LINK") .help("Symlink file to create") .required(true) .index(1), ) .get_matches(); let symlink = Path::new(matches.value_of("LINK").unwrap()); let pointing_to = Path::new(matches.value_of("pointing-to").unwrap()); // Convert the source file from a relative to absolute path if necessary. let mut path = std::env::current_dir()?; let src_file = if pointing_to.is_absolute() { &pointing_to } else { path.push(pointing_to); path.as_path() }; if symlink.exists() { Err(Error::new( ErrorKind::AlreadyExists, format!("{} already exists", symlink.display()), )) } else if !src_file.exists() { Err(Error::new( ErrorKind::NotFound, format!("{} does not exist", src_file.display()), )) } else { fs::symlink(src_file, symlink) } }
and here it is in action:
$ symlink ~/.local/bin/code --pointing-to ~/.local/VSCode-linux-x64/bin/code $ file ~/.local/bin/code /home/rkd/.local/bin/code: symbolic link to /home/rkd/.local/VSCode-linux-x64/bin/code $ symlink ~/.local/bin/code --pointing-to ~/.local/VSCode-linux-x64/bin/code Error: Custom { kind: AlreadyExists, error: "/home/rkd/.local/bin/code already exists" } $ symlink ~/.local/bin/code3 --pointing-to /nowhere Error: Custom { kind: NotFound, error: "/nowhere does not exist" }