diff --git a/src/get.rs b/src/get.rs index e8c7def..f029ada 100644 --- a/src/get.rs +++ b/src/get.rs @@ -13,7 +13,7 @@ use regex::Regex; use pkh::ProgressCallback; -fn clone_repo(url: &str, package: &str, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box> { +fn clone_repo(url: &str, package: &str, branch: Option<&str>, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result<(), Box> { 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> { +pub async fn get(package: &str, _version: &str, series: Option<&str>, pocket: &str, _ppa: &str, dist: Option<&str>, cwd: Option<&Path>, progress: ProgressCallback<'_>) -> Result> { 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; } }