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
18 changes: 6 additions & 12 deletions src/backend/asset_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use std::sync::LazyLock;

use super::platform_target::PlatformTarget;
use super::static_helpers::get_filename_from_url;
use crate::file::TarFormat;
use crate::http::HTTP;

// ========== Platform Detection Types (from asset_detector) ==========
Expand Down Expand Up @@ -164,11 +165,6 @@ static LIBC_PATTERNS: LazyLock<Vec<(AssetLibc, Regex)>> = LazyLock::new(|| {
]
});

static ARCHIVE_EXTENSIONS: &[&str] = &[
".tar.gz", ".tar.bz2", ".tar.xz", ".tar.zst", ".tgz", ".tbz2", ".txz", ".tzst", ".zip", ".7z",
".tar",
];

// ========== AssetPicker (from asset_detector) ==========

/// Automatically detects the best asset for the current platform
Expand Down Expand Up @@ -319,19 +315,17 @@ impl AssetPicker {
}

fn score_format_preferences(&self, asset: &str) -> i32 {
let asset = asset.to_lowercase();
if asset.ends_with(".zip") {
let format = TarFormat::from_file_name(&asset);
Comment thread
risu729 marked this conversation as resolved.
Outdated

if format == TarFormat::Zip {
if self.target_os == "windows" {
return 15;
} else {
return 5;
}
}
if ARCHIVE_EXTENSIONS.iter().any(|ext| asset.ends_with(ext)) {
10
} else {
0
}

if format.is_archive() { 10 } else { 0 }
}

fn score_build_penalties(&self, asset: &str) -> i32 {
Expand Down
45 changes: 28 additions & 17 deletions src/backend/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,26 @@ impl FileInfo {
file_path.to_path_buf()
};

let extension = effective_path
.extension()
.and_then(|s| s.to_str())
.unwrap_or("")
.to_string();

let format = file::TarFormat::from_ext(&extension);

let file_name = effective_path.file_name().unwrap().to_string_lossy();
let is_compressed_binary = !file_name.contains(".tar")
&& matches!(extension.as_str(), "gz" | "xz" | "bz2" | "zst");
let format = file::TarFormat::from_file_name(&file_name);

let extension = if file_name.ends_with(".tar.gz") {
"tar.gz".to_string()
} else if file_name.ends_with(".tar.xz") {
"tar.xz".to_string()
} else if file_name.ends_with(".tar.bz2") {
"tar.bz2".to_string()
} else if file_name.ends_with(".tar.zst") {
"tar.zst".to_string()
} else {
effective_path
.extension()
.and_then(|s| s.to_str())
.unwrap_or("")
.to_string()
};
Comment thread
risu729 marked this conversation as resolved.
Outdated
Comment thread
risu729 marked this conversation as resolved.
Outdated

let is_compressed_binary = !format.is_archive() && format != file::TarFormat::Raw;

Self {
effective_path,
Expand Down Expand Up @@ -325,13 +334,15 @@ impl HttpBackend {
pr.set_message(format!("extract {}", file_info.file_name()));
}

match file_info.extension.as_str() {
"gz" => file::un_gz(file_path, &dest_file)?,
"xz" => file::un_xz(file_path, &dest_file)?,
"bz2" => file::un_bz2(file_path, &dest_file)?,
"zst" => file::un_zst(file_path, &dest_file)?,
_ => unreachable!(),
}
file::untar(
file_path,
&dest_file,
&file::TarOptions {
format: file_info.format,
pr,
..Default::default()
},
)?;

file::make_executable(&dest_file)?;
Ok(ExtractionType::RawFile { filename })
Expand Down
51 changes: 31 additions & 20 deletions src/backend/static_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,27 +420,36 @@ pub fn install_artifact(

// Use TarFormat for format detection
// Check for explicit format option first, then fall back to file extension
let ext = if let Some(format_opt) = lookup_with_fallback(opts, "format") {
format_opt
let format = if let Some(format_opt) = lookup_with_fallback(opts, "format") {
file::TarFormat::from_ext(&format_opt)
} else {
file_path
.extension()
.and_then(|s| s.to_str())
.unwrap_or("")
.to_string()
file::TarFormat::from_file_name(
&file_path.file_name().unwrap_or_default().to_string_lossy(),
)
};
let format = file::TarFormat::from_ext(&ext);

// Get file extension and detect format
let file_name = file_path.file_name().unwrap().to_string_lossy();

// Check if it's a compressed binary (not a tar archive)
let is_compressed_binary =
!file_name.contains(".tar") && matches!(ext.as_str(), "gz" | "xz" | "bz2" | "zst");

if is_compressed_binary {
if !format.is_archive() {
Comment thread
risu729 marked this conversation as resolved.
Outdated
// Handle compressed single binary
let ext = if file_name.ends_with(".tar.gz") {
"tar.gz".to_string()
} else if file_name.ends_with(".tar.xz") {
"tar.xz".to_string()
} else if file_name.ends_with(".tar.bz2") {
"tar.bz2".to_string()
} else if file_name.ends_with(".tar.zst") {
"tar.zst".to_string()
} else {
Path::new(&*file_name)
.extension()
.and_then(|s| s.to_str())
.unwrap_or("")
.to_string()
};
Comment thread
risu729 marked this conversation as resolved.
Outdated
let decompressed_name = file_name.trim_end_matches(&format!(".{}", ext));

// Determine the destination path with support for bin_path
let dest = if let Some(bin_path_template) = lookup_with_fallback(opts, "bin_path") {
let bin_path = template_string(&bin_path_template, tv);
Expand All @@ -455,13 +464,15 @@ pub fn install_artifact(
install_path.join(cleaned_name)
};

match ext.as_str() {
"gz" => file::un_gz(file_path, &dest)?,
"xz" => file::un_xz(file_path, &dest)?,
"bz2" => file::un_bz2(file_path, &dest)?,
"zst" => file::un_zst(file_path, &dest)?,
_ => unreachable!(),
}
file::untar(
file_path,
&dest,
&file::TarOptions {
format,
pr,
..Default::default()
},
)?;

file::make_executable(&dest)?;
} else if format == file::TarFormat::Raw {
Expand Down
31 changes: 9 additions & 22 deletions src/cli/generate/tool_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ exec "$MISE_BIN" tool-stub "$0" "$@"
let checksum = format!("blake3:{}", blake3::hash(&bytes).to_hex());

// Detect binary path if this is an archive
let bin_path = if self.is_archive_format(url) {
let bin_path = if TarFormat::from_file_name(url).is_archive() {
Comment thread
risu729 marked this conversation as resolved.
Outdated
// Update progress message for extraction and reuse the same progress reporter
pr.set_message(format!("extract {filename}"));
match self
Expand Down Expand Up @@ -509,20 +509,21 @@ exec "$MISE_BIN" tool-stub "$0" "$@"

// Try extraction using mise's built-in extraction logic (reuse the passed progress reporter)
let tar_opts = TarOptions {
format: TarFormat::Auto,
format: TarFormat::from_file_name(
&archive_path
.file_name()
.unwrap_or_default()
.to_string_lossy(),
),
strip_components: 0,
pr: Some(pr),
..Default::default()
};
file::untar(archive_path, &extracted_dir, &tar_opts)?;

// Check if strip_components would be applied during actual installation
let format = TarFormat::from_ext(
&archive_path
.extension()
.unwrap_or_default()
.to_string_lossy(),
);
let format =
TarFormat::from_file_name(&archive_path.file_name().unwrap().to_string_lossy());
let will_strip = file::should_strip_components(archive_path, format)?;

// Find executable files
Expand Down Expand Up @@ -550,20 +551,6 @@ exec "$MISE_BIN" tool-stub "$0" "$@"
Ok(selected_exe)
}

fn is_archive_format(&self, url: &str) -> bool {
// Check if the URL appears to be an archive format that mise can extract
url.ends_with(".tar.gz")
|| url.ends_with(".tgz")
|| url.ends_with(".tar.xz")
|| url.ends_with(".txz")
|| url.ends_with(".tar.bz2")
|| url.ends_with(".tbz2")
|| url.ends_with(".tar.zst")
|| url.ends_with(".tzst")
|| url.ends_with(".zip")
|| url.ends_with(".7z")
}

fn find_executables(&self, dir: &std::path::Path) -> Result<Vec<String>> {
let mut executables = Vec::new();

Expand Down
Loading
Loading