get: clone the right branch for series, better testing
All checks were successful
CI / build (push) Successful in 1m50s

This commit is contained in:
2025-11-30 11:26:26 +01:00
parent ef1d8f05bf
commit c813823a1a

View File

@@ -13,7 +13,7 @@ use regex::Regex;
use pkh::ProgressCallback;
fn clone_repo(url: &str, package: &str, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box<dyn Error>> {
fn clone_repo(url: &str, package: &str, branch: Option<&str>, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box<dyn Error>> {
let target_path = if let Some(path) = cwd {
path.join(package)
} else {
@@ -46,6 +46,10 @@ fn clone_repo(url: &str, package: &str, cwd: Option<&Path>, progress: ProgressCa
let mut builder = git2::build::RepoBuilder::new();
builder.fetch_options(fetch_options);
if let Some(b) = branch {
builder.branch(b);
}
return match builder.clone(url, &target_path) {
Ok(_repo) => {
@@ -239,7 +243,7 @@ async fn fetch_archive_sources(info: &PackageInfo, cwd: Option<&Path>, progress:
Ok(())
}
pub async fn get(package: &str, _version: &str, series: Option<&str>, pocket: &str, _ppa: &str, dist: Option<&str>, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box<dyn Error>> {
pub async fn get(package: &str, _version: &str, series: Option<&str>, pocket: &str, _ppa: &str, dist: Option<&str>, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<PackageInfo, Box<dyn Error>> {
let version_opt = if _version.is_empty() { None } else { Some(_version) };
/* Obtain the package information, either directly in a series or with a search in all series */
@@ -279,11 +283,26 @@ pub async fn get(package: &str, _version: &str, series: Option<&str>, pocket: &s
if let Some(ref url) = package_info.preferred_vcs {
// We have found a preferred VCS (git repository) for the package, so
// we fetch the package from that repo.
if let Some(cb) = progress {
cb(&format!("Cloning {}...", url), "", 0, 0);
}
clone_repo(url.as_str(), package, Some(&package_dir), progress)?;
// Depending on target series, we pick target branch; if no series is specified,
// we target the development branch, i.e. the default branch
let branch_name = if let Some(s) = series {
if package_info.dist == "ubuntu" {
Some(format!("{}/{}", package_info.dist, s))
} else {
// Debian does not have reliable branch naming...
// For now, we skip that part and clone default
// TODO: Inspect remote branches and tags for matches
None
}
} else {
None
};
if let Some(cb) = progress {
cb(&format!("Cloning {}{}...", url, if let Some(b) = &branch_name { format!(" (branch {})", b) } else { String::new() }), "", 0, 0);
}
clone_repo(url.as_str(), package, branch_name.as_deref(), Some(&package_dir), progress)?;
if let Some(cb) = progress {
cb("Fetching orig tarball...", "", 0, 0);
}
@@ -296,28 +315,55 @@ pub async fn get(package: &str, _version: &str, series: Option<&str>, pocket: &s
fetch_archive_sources(&package_info, Some(cwd.unwrap_or(Path::new("."))), progress).await?;
}
Ok(())
Ok(package_info)
}
#[cfg(test)]
mod tests {
use super::*;
async fn test_get_package_end_to_end(package: &str, series: Option<&str>) {
async fn test_get_package_end_to_end(package: &str, series: Option<&str>, dist: Option<&str>) {
// This test verifies that 'pkh get' clones the repo and fetches the tarball.
// For determinism, we require for tests that either a distro or series is specified,
// as no distribution would mean fallback to system distro
assert!(dist != None || series != None);
// Use a temp directory as working directory
let temp_dir = tempfile::tempdir().unwrap();
let cwd = temp_dir.path();
// Main 'get' command: the one we want to test
get(package, "", series, "", "", None, Some(cwd), None).await.unwrap();
let info = get(package, "", series, "", "", dist, Some(cwd), None).await.unwrap();
let package_dir = cwd.join(package);
assert!(package_dir.exists());
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");
if package_source_dir.join(".git").exists() {
// Verify we are on the correct branch
let repo = git2::Repository::open(&package_source_dir).unwrap();
let head = repo.head().unwrap();
let name = head.name().unwrap();
if let Some(s) = series {
// The local branch should be named dist/series
// We skip debian for now as it does not have a reliable naming scheme
if info.dist == "ubuntu" {
assert_eq!(name, format!("refs/heads/{0}/{s}", info.dist));
}
} else {
// The local branch should be named ubuntu/devel for Ubuntu
// Debian unfortunately does not have a reliable naming scheme
// Given that there was no series specified, and this is a test,
// we require to have a distribution specified
if dist.unwrap() == "ubuntu" {
assert_eq!(name, "refs/heads/ubuntu/devel");
}
}
}
// Check for orig tarball in package dir
let mut found_tarball = false;
@@ -335,29 +381,33 @@ mod tests {
#[tokio::test]
async fn test_get_hello_ubuntu_end_to_end() {
test_get_package_end_to_end("hello", Some("noble")).await;
test_get_package_end_to_end("hello", Some("noble"), None).await;
}
#[tokio::test]
async fn test_get_hello_debian_end_to_end() {
test_get_package_end_to_end("hello", Some("bookworm")).await;
test_get_package_end_to_end("hello", Some("bookworm"), None).await;
}
#[tokio::test]
async fn test_get_2048_universe_ubuntu_end_to_end() {
test_get_package_end_to_end("2048", Some("noble")).await;
test_get_package_end_to_end("2048", Some("noble"), None).await;
}
#[tokio::test]
async fn test_get_1oom_contrib_debian_end_to_end() {
test_get_package_end_to_end("1oom", Some("trixie")).await;
test_get_package_end_to_end("1oom", Some("trixie"), None).await;
}
#[tokio::test]
async fn test_get_agg_svn_fallback_ok() {
test_get_package_end_to_end("agg", Some("trixie")).await;
test_get_package_end_to_end("agg", Some("trixie"), None).await;
}
#[tokio::test]
async fn test_get_hello_latest_end_to_end() {
test_get_package_end_to_end("hello", None).await;
async fn test_get_hello_debian_latest_end_to_end() {
test_get_package_end_to_end("hello", None, Some("debian")).await;
}
#[tokio::test]
async fn test_get_hello_ubuntu_latest_end_to_end() {
test_get_package_end_to_end("hello", None, Some("ubuntu")).await;
}
}