dotenvx-rs 0.4.31

Dotenvx is a Rust command-line/library to encrypt your .env files - limiting their attack vector while retaining their benefits
Documentation
use clap::ArgMatches;
use colored::Colorize;
use std::fs::Permissions;
use std::path::{Path, PathBuf};
use symlink::symlink_file;

pub fn link_command(command_matches: &ArgMatches, dotenvx_name: &str) {
    let command_name = command_matches
        .get_one::<String>("command")
        .map(|s| s.as_str())
        .unwrap();
    if command_name.ends_with("venv/bin/python") {
        link_uv_python(command_name);
        return;
    }
    let target_path = PathBuf::from(command_name);
    if target_path.exists() {
        eprintln!("The target path already exists: {}", target_path.display());
        std::process::exit(1);
    }
    if let Some(parent) = target_path.parent() {
        if !parent.exists() {
            std::fs::create_dir_all(parent).unwrap();
        }
    }
    let dotenvx_path = if dotenvx_name.contains("/") || dotenvx_name.contains("\\") {
        PathBuf::from(dotenvx_name)
    } else {
        which::which(dotenvx_name).unwrap()
    };
    symlink_file(dotenvx_path, target_path).unwrap();
    println!(
        "{}",
        format!("${command_name} created and linked to dotenvx executable").green()
    );
}

fn link_uv_python(command_name: &str) {
    let canonical_path = std::fs::canonicalize(command_name).unwrap();
    let real_path = canonical_path.to_string_lossy().to_string();
    std::fs::remove_file(command_name).unwrap();
    let python3_script = format!(
        r#"
#!/bin/bash

# load .env by dotenvx
eval $( dotenvx decrypt --stdout --format shell )
# Execute python3 command with arguments
exec "{real_path}" "$@"
"#
    );
    std::fs::write(command_name, python3_script).unwrap();
    set_executable(command_name);
    println!(
        "{command_name} replaced with dotenvx and python3"
    );
}

#[cfg(unix)]
fn set_executable<P: AsRef<Path>>(path: P) {
    use std::os::unix::fs::PermissionsExt;
    std::fs::set_permissions(path, Permissions::from_mode(0o755)).unwrap();
}

#[cfg(not(unix))]
fn set_executable<P: AsRef<Path>>(path: P) {}

#[cfg(test)]
mod tests {
    #[test]
    fn test_resolve_link() {}
}