Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions registry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,7 @@ backends = ["asdf:mise-plugins/mise-elixir-ls"]
description = "A frontend-independent IDE 'smartness' server for Elixir. Implements the 'Language Server Protocol' standard and provides debugger support via the 'Debug Adapter Protocol'"

[tools.elm]
backends = ["ubi:elm/compiler[exe=elm]", "asdf:asdf-community/asdf-elm"]
backends = ["github:elm/compiler[bin=elm]", "asdf:asdf-community/asdf-elm"]
description = "Compiler for Elm, a functional language for reliable webapps"
test = ["elm --version", "{{version}}"]

Expand Down Expand Up @@ -3446,7 +3446,10 @@ backends = ["aqua:open-policy-agent/opa", "asdf:tochukwuvictor/asdf-opa"]
description = "Open Policy Agent (OPA) is an open source, general-purpose policy engine"

[tools.opam]
backends = ["ubi:ocaml/opam", "asdf:asdf-community/asdf-opam"]
backends = [
"github:ocaml/opam[asset_pattern=opam-*-*-{os}]",
"asdf:asdf-community/asdf-opam",
]
description = "(ocaml) opam is a source-based package manager. It supports multiple simultaneous compiler installations, flexible package constraints, and a Git-friendly development workflow"
test = ["opam --version", "{{version}}"]

Expand Down Expand Up @@ -5226,7 +5229,7 @@ description = "yq is a portable command-line YAML processor"
test = ["yq --version", "version v{{version}}"]

[tools.yt-dlp]
backends = ["ubi:yt-dlp/yt-dlp[rename_exe=yt-dlp]", "asdf:duhow/asdf-yt-dlp"]
backends = ["github:yt-dlp/yt-dlp[rename_exe=yt-dlp]", "asdf:duhow/asdf-yt-dlp"]
description = "A feature-rich command-line audio/video downloader"
test = ["yt-dlp --version", "{{version}}"]

Expand Down
36 changes: 36 additions & 0 deletions src/backend/static_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,13 @@ pub fn install_artifact(

// Extract with determined strip_components
file::untar(file_path, &install_path, &tar_opts)?;

// Handle rename_exe option for archives
if let Some(rename_to) =
lookup_platform_key(opts, "rename_exe").or_else(|| opts.get("rename_exe").cloned())
{
rename_executable_in_dir(&install_path, &rename_to)?;
}
}
Ok(())
}
Expand Down Expand Up @@ -393,6 +400,35 @@ pub fn verify_checksum_str(
Ok(())
}

/// Renames the first executable file found in a directory to a new name.
/// Used by the `rename_exe` option to rename binaries after archive extraction.
fn rename_executable_in_dir(dir: &Path, new_name: &str) -> eyre::Result<()> {
// Find executables in the directory (non-recursive for top level)
for entry in std::fs::read_dir(dir)?.flatten() {
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using flatten() silently ignores read errors for individual directory entries. Consider handling these errors explicitly or logging them to avoid silently skipping files that fail to read.

Copilot uses AI. Check for mistakes.
let path = entry.path();
if path.is_file() && crate::file::is_executable(&path) {
let file_name = path.file_name().unwrap().to_string_lossy();
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using unwrap() on file_name() will panic if the path terminates in ... Consider using ok_or_else() with a descriptive error instead to handle this edge case gracefully.

Suggested change
let file_name = path.file_name().unwrap().to_string_lossy();
let file_name = path
.file_name()
.ok_or_else(|| eyre::eyre!("Path '{}' has no file name", path.display()))?
.to_string_lossy();

Copilot uses AI. Check for mistakes.
// Skip if already has the target name
if file_name == new_name {
return Ok(());
}
// Skip common non-binary files
if file_name.starts_with('.')
|| file_name.ends_with(".txt")
|| file_name.ends_with(".md")
{
continue;
}
// Rename this executable
let new_path = dir.join(new_name);
std::fs::rename(&path, &new_path)?;
debug!("Renamed {} to {}", path.display(), new_path.display());
return Ok(());
}
}
Ok(())
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function returns Ok(()) when no executable is found, which silently ignores the case where rename_exe was specified but no suitable executable exists. This should return an error to alert users that the rename operation failed.

Suggested change
Ok(())
bail!(
"No executable file found in directory '{}' to rename to '{}'",
dir.display(),
new_name
);

Copilot uses AI. Check for mistakes.
}

/// Cleans a binary name by removing OS/arch suffixes and version numbers.
/// This is useful when downloading single binaries that have platform-specific names.
/// Executable extensions (.exe, .bat, .sh, etc.) are preserved.
Expand Down
Loading