pub fn target_file_name(file_name: &str, tag_name: Option<&str>) -> String {
let (name, _, ext) = split_file_name(file_name);
let mut result = String::new();
result.push_str(name);
if let Some(tag_name) = tag_name {
result.push('-');
result.push_str(tag_name);
}
if let Some(ext) = ext {
result.push('.');
result.push_str(ext);
}
result
}
pub fn split_file_name(input: &str) -> (&str, Option<&str>, Option<&str>) {
const EXTENSIONS: [&str; 4] = [".exe", ".so", ".dylib", ".dll"];
const RUSTC_HASH_LENGTH: usize = 16;
let mut file_name = input;
let mut extension = None;
for ext in EXTENSIONS {
if let Some(name) = input.strip_suffix(ext) {
file_name = name;
extension = Some(&ext[1..]);
break;
}
}
let idx = match file_name.rfind('-') {
Some(idx) if idx > 0 => idx,
_ => return (file_name, None, extension),
};
let hash = &file_name[idx + 1..];
if hash.len() == RUSTC_HASH_LENGTH && hash.chars().all(|c| c.is_ascii_hexdigit()) {
(&file_name[..idx], Some(hash), extension)
} else {
(file_name, None, extension)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_target_file_name() {
let cases = vec![
("app-ebb8dd5b587f73a1", None, "app"),
("app-ebb8dd5b587f73a1", Some("tag"), "app-tag"),
("app-ebb8dd5b587f73a1.exe", None, "app.exe"),
("app-ebb8dd5b587f73a1.dll", None, "app.dll"),
("app-ebb8dd5b587f73a1.exe", Some("tag"), "app-tag.exe"),
];
for (input, tag, expected) in cases {
assert_eq!(target_file_name(input, tag), expected);
}
}
}