get: archive download fallback for non-git packages

This commit is contained in:
2025-11-28 15:20:16 +01:00
parent 3367f2a35a
commit 32705b4b35
2 changed files with 69 additions and 11 deletions

View File

@@ -22,6 +22,8 @@ indicatif = "0.17"
indicatif-log-bridge = "0.2.3"
env_logger = "0.11.8"
futures-util = { version = "0.3.31", features = ["tokio-io"] }
tar = "0.4"
xz2 = "0.1"
[dev-dependencies]
tempfile = "3.10.1"

View File

@@ -62,6 +62,28 @@ use std::fs::File;
use std::io::Write;
use futures_util::StreamExt;
use flate2::read::GzDecoder;
use xz2::read::XzDecoder;
use tar::Archive;
fn extract_archive(path: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
let file = File::open(path)?;
let filename = path.file_name().unwrap().to_string_lossy();
if filename.ends_with(".tar.gz") || filename.ends_with(".tgz") {
let tar = GzDecoder::new(file);
let mut archive = Archive::new(tar);
archive.unpack(dest)?;
} else if filename.ends_with(".tar.xz") || filename.ends_with(".txz") {
let tar = XzDecoder::new(file);
let mut archive = Archive::new(tar);
archive.unpack(dest)?;
} else {
return Err(format!("Unsupported archive format: {}", filename).into());
}
Ok(())
}
fn checkout_pristine_tar(package_dir: &Path, filename: &str) -> Result<(), Box<dyn Error>> {
let output = Command::new("pristine-tar")
@@ -181,6 +203,42 @@ async fn fetch_orig_tarball(info: &PackageInfo, cwd: Option<&Path>, progress: Pr
Ok(())
}
async fn fetch_archive_sources(info: &PackageInfo, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box<dyn Error>> {
let package_dir = if let Some(path) = cwd {
path.join(&info.stanza.package)
} else {
Path::new(&info.stanza.package).to_path_buf()
};
std::fs::create_dir_all(&package_dir)?;
for file in &info.stanza.files {
let url = format!("{}/{}", info.archive_url, file.name);
download_file_checksum(&url, &file.sha256, &package_dir, progress).await?;
}
// Extract the debian tarball or diff
let debian_file = info.stanza.files.iter().find(|f| {
f.name.contains(".debian.tar.") || f.name.contains(".diff.gz")
});
if let Some(file) = debian_file {
let path = package_dir.join(&file.name);
let extract_dir = package_dir.join(&info.stanza.package);
if file.name.ends_with(".tar.xz") || file.name.ends_with(".tar.gz") {
if let Err(e) = extract_archive(&path, &extract_dir) {
return Err(format!("Failed to extract {}: {}", file.name, e).into());
}
}
// Remove archive after extraction
std::fs::remove_file(&path)?;
}
Ok(())
}
pub async fn get(package: &str, _version: &str, series: &str, pocket: &str, _ppa: &str, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box<dyn Error>> {
if let Some(cb) = progress {
cb(&format!("Resolving package info for {}...", package), "", 0, 0);
@@ -205,7 +263,10 @@ pub async fn get(package: &str, _version: &str, series: &str, pocket: &str, _ppa
}
fetch_orig_tarball(&info, Some(&package_dir), progress).await?;
} else {
return Err(format!("No VCS URL found for package {}", package).into());
if let Some(cb) = progress {
cb("Downloading from archive...", "", 0, 0);
}
fetch_archive_sources(&info, Some(cwd.unwrap_or(Path::new("."))), progress).await?;
}
Ok(())
@@ -227,9 +288,9 @@ mod tests {
let package_dir = cwd.join(package);
assert!(package_dir.exists(), "Package directory not created");
let git_repo_dir = package_dir.join(package);
assert!(git_repo_dir.exists(), "Package git repo directory not created");
assert!(git_repo_dir.join(".git").exists(), "Git repo not cloned");
let package_source_dir = package_dir.join(package);
assert!(package_source_dir.exists(), "Package git repo directory not created");
assert!(package_source_dir.join("debian").exists(), "debian directory not present");
// Check for orig tarball in package dir
let mut found_tarball = false;
@@ -255,12 +316,7 @@ mod tests {
}
#[tokio::test]
#[should_panic(expected = "No VCS URL found for package agg")]
async fn test_get_agg_svn_should_fail() {
// agg uses Vcs-Svn, which is not supported.
// We expect this to fail with "No VCS URL found".
let temp_dir = tempfile::tempdir().unwrap();
let cwd = temp_dir.path();
get("agg", "", "sid", "", "", Some(cwd), None).await.unwrap();
async fn test_get_agg_svn_fallback_ok() {
test_get_package_end_to_end("agg", "sid").await;
}
}