use anyhow::{Context, Result};
use cnf_lib::util::CommandLine;
use serde_derive::{Deserialize, Serialize};
use std::{io::Write, os::unix::fs::PermissionsExt};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub(crate) struct Alias {
pub source_env: String,
pub target_env: String,
pub command: String,
pub alias: CommandLine,
}
impl Alias {
pub(crate) fn to_shell_wrapper(&self) -> Result<()> {
let mut alias_path = crate::directories::get().aliases();
let command_name = std::path::Path::new(&self.command)
.file_name()
.unwrap_or(std::ffi::OsStr::new(&self.command));
alias_path.push(command_name);
let alias_path_str = alias_path.display().to_string();
tracing::info!(alias = ?self, "writing new alias to '{}'", alias_path_str);
std::fs::File::create(alias_path)
.with_context(|| format!("failed to write alias script to '{}'", alias_path_str))
.and_then(|mut fd| {
writeln!(fd, "#!/bin/sh")?;
writeln!(
fd,
"${{{cnf_environment_exe}:-\"{cnf_current_exe}\"}} \\",
cnf_environment_exe = crate::Env::AliasExecutable,
cnf_current_exe = std::env::current_exe()
.context("cannot determine current execution environment")?
.display()
)?;
writeln!(
fd,
" --alias-target-env {} \\",
shlex::quote(&self.target_env)
)?;
if self.alias.get_privileged() {
writeln!(fd, " --alias-privileged \\")?;
}
if self.alias.get_interactive() {
writeln!(fd, " --alias-interactive \\")?;
}
writeln!(fd, " {} \\", shlex::quote(&self.alias.command()))?;
for arg in self.alias.args() {
writeln!(fd, " {} \\", shlex::quote(arg))?;
}
writeln!(fd, " \"$@\"")?;
Ok(fd)
})
.context("failed to write contents of alias script")
.and_then(|fd| {
let mut permissions = fd
.metadata()
.context("cannot determine metadata of alias script")?
.permissions();
permissions.set_mode(0o755);
fd.set_permissions(permissions)?;
Ok(())
})
.context("failed to mark alias script as executable")
}
}