get: archive download fallback for non-git packages
This commit is contained in:
@@ -22,6 +22,8 @@ indicatif = "0.17"
|
|||||||
indicatif-log-bridge = "0.2.3"
|
indicatif-log-bridge = "0.2.3"
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
futures-util = { version = "0.3.31", features = ["tokio-io"] }
|
futures-util = { version = "0.3.31", features = ["tokio-io"] }
|
||||||
|
tar = "0.4"
|
||||||
|
xz2 = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.10.1"
|
tempfile = "3.10.1"
|
||||||
|
|||||||
78
src/get.rs
78
src/get.rs
@@ -62,6 +62,28 @@ use std::fs::File;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use futures_util::StreamExt;
|
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>> {
|
fn checkout_pristine_tar(package_dir: &Path, filename: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let output = Command::new("pristine-tar")
|
let output = Command::new("pristine-tar")
|
||||||
@@ -181,6 +203,42 @@ async fn fetch_orig_tarball(info: &PackageInfo, cwd: Option<&Path>, progress: Pr
|
|||||||
Ok(())
|
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>> {
|
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 {
|
if let Some(cb) = progress {
|
||||||
cb(&format!("Resolving package info for {}...", package), "", 0, 0);
|
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?;
|
fetch_orig_tarball(&info, Some(&package_dir), progress).await?;
|
||||||
} else {
|
} 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(())
|
Ok(())
|
||||||
@@ -227,9 +288,9 @@ mod tests {
|
|||||||
|
|
||||||
let package_dir = cwd.join(package);
|
let package_dir = cwd.join(package);
|
||||||
assert!(package_dir.exists(), "Package directory not created");
|
assert!(package_dir.exists(), "Package directory not created");
|
||||||
let git_repo_dir = package_dir.join(package);
|
let package_source_dir = package_dir.join(package);
|
||||||
assert!(git_repo_dir.exists(), "Package git repo directory not created");
|
assert!(package_source_dir.exists(), "Package git repo directory not created");
|
||||||
assert!(git_repo_dir.join(".git").exists(), "Git repo not cloned");
|
assert!(package_source_dir.join("debian").exists(), "debian directory not present");
|
||||||
|
|
||||||
// Check for orig tarball in package dir
|
// Check for orig tarball in package dir
|
||||||
let mut found_tarball = false;
|
let mut found_tarball = false;
|
||||||
@@ -255,12 +316,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[should_panic(expected = "No VCS URL found for package agg")]
|
async fn test_get_agg_svn_fallback_ok() {
|
||||||
async fn test_get_agg_svn_should_fail() {
|
test_get_package_end_to_end("agg", "sid").await;
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user