pull: allow pulling from ppa
This commit is contained in:
@@ -82,7 +82,7 @@ Missing features:
|
|||||||
- [ ] `pkh pull`
|
- [ ] `pkh pull`
|
||||||
- [x] Obtain package sources from git
|
- [x] Obtain package sources from git
|
||||||
- [x] Obtain package sources from the archive (fallback)
|
- [x] Obtain package sources from the archive (fallback)
|
||||||
- [ ] Obtain package source from PPA (--ppa)
|
- [x] Obtain package source from PPA (--ppa)
|
||||||
- [ ] Obtain a specific version of the package
|
- [ ] Obtain a specific version of the package
|
||||||
- [x] Fetch the correct git branch for series on Ubuntu
|
- [x] Fetch the correct git branch for series on Ubuntu
|
||||||
- [ ] Try to fetch the correct git branch for series on Debian, or fallback to the archive
|
- [ ] Try to fetch the correct git branch for series on Debian, or fallback to the archive
|
||||||
|
|||||||
@@ -212,9 +212,10 @@ mod tests {
|
|||||||
log::debug!("Created temporary directory: {}", cwd.display());
|
log::debug!("Created temporary directory: {}", cwd.display());
|
||||||
|
|
||||||
log::info!("Pulling package {} from {}...", package, series);
|
log::info!("Pulling package {} from {}...", package, series);
|
||||||
let package_info = crate::package_info::lookup(package, None, Some(series), "", dist, None)
|
let package_info =
|
||||||
.await
|
crate::package_info::lookup(package, None, Some(series), "", dist, None, None)
|
||||||
.expect("Cannot lookup package information");
|
.await
|
||||||
|
.expect("Cannot lookup package information");
|
||||||
crate::pull::pull(&package_info, Some(cwd), None, true)
|
crate::pull::pull(&package_info, Some(cwd), None, true)
|
||||||
.await
|
.await
|
||||||
.expect("Cannot pull package");
|
.expect("Cannot pull package");
|
||||||
|
|||||||
17
src/main.rs
17
src/main.rs
@@ -94,14 +94,22 @@ fn main() {
|
|||||||
let series = sub_matches.get_one::<String>("series").map(|s| s.as_str());
|
let series = sub_matches.get_one::<String>("series").map(|s| s.as_str());
|
||||||
let dist = sub_matches.get_one::<String>("dist").map(|s| s.as_str());
|
let dist = sub_matches.get_one::<String>("dist").map(|s| s.as_str());
|
||||||
let version = sub_matches.get_one::<String>("version").map(|s| s.as_str());
|
let version = sub_matches.get_one::<String>("version").map(|s| s.as_str());
|
||||||
let _ppa = sub_matches
|
let ppa = sub_matches.get_one::<String>("ppa").map(|s| s.as_str());
|
||||||
.get_one::<String>("ppa")
|
|
||||||
.map(|s| s.as_str())
|
|
||||||
.unwrap_or("");
|
|
||||||
let archive = sub_matches.get_one::<bool>("archive").unwrap_or(&false);
|
let archive = sub_matches.get_one::<bool>("archive").unwrap_or(&false);
|
||||||
|
|
||||||
let (pb, progress_callback) = ui::create_progress_bar(&multi);
|
let (pb, progress_callback) = ui::create_progress_bar(&multi);
|
||||||
|
|
||||||
|
// Convert PPA to base URL if provided
|
||||||
|
let base_url = ppa.and_then(|ppa_str| {
|
||||||
|
// PPA format: user/ppa_name
|
||||||
|
let parts: Vec<&str> = ppa_str.split('/').collect();
|
||||||
|
if parts.len() == 2 {
|
||||||
|
Some(pkh::package_info::ppa_to_base_url(parts[0], parts[1]))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Since pull is async, we need to block on it
|
// Since pull is async, we need to block on it
|
||||||
if let Err(e) = rt.block_on(async {
|
if let Err(e) = rt.block_on(async {
|
||||||
let package_info = pkh::package_info::lookup(
|
let package_info = pkh::package_info::lookup(
|
||||||
@@ -110,6 +118,7 @@ fn main() {
|
|||||||
series,
|
series,
|
||||||
"",
|
"",
|
||||||
dist,
|
dist,
|
||||||
|
base_url.as_deref(),
|
||||||
Some(&progress_callback),
|
Some(&progress_callback),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -6,6 +6,18 @@ use std::io::Read;
|
|||||||
use crate::ProgressCallback;
|
use crate::ProgressCallback;
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
|
|
||||||
|
/// Convert a PPA specification to a base URL
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * user: user for the PPA
|
||||||
|
/// * name: name of the PPA
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * The base URL for the PPA (e.g., "https://ppa.launchpadcontent.net/user/ppa_name/ubuntu/")
|
||||||
|
pub fn ppa_to_base_url(user: &str, name: &str) -> String {
|
||||||
|
format!("https://ppa.launchpadcontent.net/{}/{}/ubuntu", user, name)
|
||||||
|
}
|
||||||
|
|
||||||
async fn check_launchpad_repo(package: &str) -> Result<Option<String>, Box<dyn Error>> {
|
async fn check_launchpad_repo(package: &str) -> Result<Option<String>, Box<dyn Error>> {
|
||||||
let url = format!("https://git.launchpad.net/ubuntu/+source/{}", package);
|
let url = format!("https://git.launchpad.net/ubuntu/+source/{}", package);
|
||||||
let client = reqwest::Client::builder()
|
let client = reqwest::Client::builder()
|
||||||
@@ -178,6 +190,7 @@ async fn get(
|
|||||||
series: &str,
|
series: &str,
|
||||||
pocket: &str,
|
pocket: &str,
|
||||||
version: Option<&str>,
|
version: Option<&str>,
|
||||||
|
base_url: Option<&str>,
|
||||||
) -> Result<PackageInfo, Box<dyn Error>> {
|
) -> Result<PackageInfo, Box<dyn Error>> {
|
||||||
let dist = crate::distro_info::get_dist_from_series(series).await?;
|
let dist = crate::distro_info::get_dist_from_series(series).await?;
|
||||||
|
|
||||||
@@ -191,7 +204,16 @@ async fn get(
|
|||||||
preferred_vcs = Some(lp_url);
|
preferred_vcs = Some(lp_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_url = crate::distro_info::get_base_url(&dist);
|
// Determine the base URL to use (either provided PPA URL or default archive)
|
||||||
|
let distro_base_url = crate::distro_info::get_base_url(&dist);
|
||||||
|
let base_url = if let Some(ppa_url) = base_url {
|
||||||
|
ppa_url.to_string()
|
||||||
|
} else {
|
||||||
|
distro_base_url.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// If using a custom base URL (PPA), disable VCS lookup to force archive download
|
||||||
|
let from_ppa = base_url != distro_base_url;
|
||||||
|
|
||||||
let components = crate::distro_info::get_components(&base_url, series, pocket).await?;
|
let components = crate::distro_info::get_components(&base_url, series, pocket).await?;
|
||||||
debug!("Found components: {:?}", components);
|
debug!("Found components: {:?}", components);
|
||||||
@@ -228,6 +250,11 @@ async fn get(
|
|||||||
preferred_vcs = Some(vcs.clone());
|
preferred_vcs = Some(vcs.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If downloading from PPA, make sure we don't use a VCS
|
||||||
|
if from_ppa {
|
||||||
|
preferred_vcs = None;
|
||||||
|
}
|
||||||
|
|
||||||
let archive_url = format!("{base_url}/{0}", stanza.directory);
|
let archive_url = format!("{base_url}/{0}", stanza.directory);
|
||||||
return Ok(PackageInfo {
|
return Ok(PackageInfo {
|
||||||
dist,
|
dist,
|
||||||
@@ -252,6 +279,7 @@ async fn find_package(
|
|||||||
dist: &str,
|
dist: &str,
|
||||||
pocket: &str,
|
pocket: &str,
|
||||||
version: Option<&str>,
|
version: Option<&str>,
|
||||||
|
base_url: Option<&str>,
|
||||||
progress: ProgressCallback<'_>,
|
progress: ProgressCallback<'_>,
|
||||||
) -> Result<PackageInfo, Box<dyn Error>> {
|
) -> Result<PackageInfo, Box<dyn Error>> {
|
||||||
let series_list = crate::distro_info::get_ordered_series_name(dist).await?;
|
let series_list = crate::distro_info::get_ordered_series_name(dist).await?;
|
||||||
@@ -268,7 +296,7 @@ async fn find_package(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for p in pockets {
|
for p in pockets {
|
||||||
match get(package_name, series, &p, version).await {
|
match get(package_name, series, &p, version, base_url).await {
|
||||||
Ok(info) => {
|
Ok(info) => {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
warn!(
|
warn!(
|
||||||
@@ -297,12 +325,22 @@ async fn find_package(
|
|||||||
///
|
///
|
||||||
/// This function obtains package information either directly from a specific series
|
/// This function obtains package information either directly from a specific series
|
||||||
/// or by searching across all series in a distribution.
|
/// or by searching across all series in a distribution.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `package` - The name of the package to look up
|
||||||
|
/// * `version` - Optional specific version to look for
|
||||||
|
/// * `series` - Optional distribution series (e.g., "noble", "bookworm")
|
||||||
|
/// * `pocket` - Pocket to search in (e.g., "updates", "security", or "" for main)
|
||||||
|
/// * `dist` - Optional distribution name (e.g., "ubuntu", "debian")
|
||||||
|
/// * `base_url` - Optional base URL for the package archive (e.g., "https://ppa.launchpadcontent.net/user/ppa/ubuntu/")
|
||||||
|
/// * `progress` - Optional progress callback
|
||||||
pub async fn lookup(
|
pub async fn lookup(
|
||||||
package: &str,
|
package: &str,
|
||||||
version: Option<&str>,
|
version: Option<&str>,
|
||||||
series: Option<&str>,
|
series: Option<&str>,
|
||||||
pocket: &str,
|
pocket: &str,
|
||||||
dist: Option<&str>,
|
dist: Option<&str>,
|
||||||
|
base_url: Option<&str>,
|
||||||
progress: ProgressCallback<'_>,
|
progress: ProgressCallback<'_>,
|
||||||
) -> Result<PackageInfo, Box<dyn Error>> {
|
) -> Result<PackageInfo, Box<dyn Error>> {
|
||||||
// Obtain the package information, either directly in a series or with a search in all series
|
// Obtain the package information, either directly in a series or with a search in all series
|
||||||
@@ -317,7 +355,7 @@ pub async fn lookup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the package information from that series and pocket
|
// Get the package information from that series and pocket
|
||||||
get(package, s, pocket, version).await?
|
get(package, s, pocket, version, base_url).await?
|
||||||
} else {
|
} else {
|
||||||
let dist = dist.unwrap_or_else(||
|
let dist = dist.unwrap_or_else(||
|
||||||
// Use auto-detection to see if current distro is ubuntu, or fallback to debian by default
|
// Use auto-detection to see if current distro is ubuntu, or fallback to debian by default
|
||||||
@@ -331,7 +369,11 @@ pub async fn lookup(
|
|||||||
|
|
||||||
if let Some(cb) = progress {
|
if let Some(cb) = progress {
|
||||||
cb(
|
cb(
|
||||||
&format!("Searching for package {} in {}...", package, dist),
|
&format!(
|
||||||
|
"Searching for package {} in {}...",
|
||||||
|
package,
|
||||||
|
if base_url.is_none() { dist } else { "ppa" }
|
||||||
|
),
|
||||||
"",
|
"",
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -339,7 +381,7 @@ pub async fn lookup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to find the package in all series from that dist
|
// Try to find the package in all series from that dist
|
||||||
find_package(package, dist, pocket, version, progress).await?
|
find_package(package, dist, pocket, version, base_url, progress).await?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(package_info)
|
Ok(package_info)
|
||||||
@@ -403,7 +445,7 @@ Version: 1.0
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_find_package_fallback() {
|
async fn test_find_package_fallback() {
|
||||||
// python2.7 is in bullseye but not above
|
// python2.7 is in bullseye but not above
|
||||||
let info = find_package("python2.7", "debian", "", None, None)
|
let info = find_package("python2.7", "debian", "", None, None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(info.stanza.package, "python2.7");
|
assert_eq!(info.stanza.package, "python2.7");
|
||||||
@@ -413,7 +455,7 @@ Version: 1.0
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_find_package_devel() {
|
async fn test_find_package_devel() {
|
||||||
// hello is in sid
|
// hello is in sid
|
||||||
let info = find_package("hello", "debian", "", None, None)
|
let info = find_package("hello", "debian", "", None, None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(info.stanza.package, "hello");
|
assert_eq!(info.stanza.package, "hello");
|
||||||
|
|||||||
@@ -590,7 +590,7 @@ mod tests {
|
|||||||
let cwd = temp_dir.path();
|
let cwd = temp_dir.path();
|
||||||
|
|
||||||
// Main 'pull' command: the one we want to test
|
// Main 'pull' command: the one we want to test
|
||||||
let info = crate::package_info::lookup(package, None, series, "", dist, None)
|
let info = crate::package_info::lookup(package, None, series, "", dist, None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
pull(&info, Some(cwd), None, archive.unwrap_or(false))
|
pull(&info, Some(cwd), None, archive.unwrap_or(false))
|
||||||
|
|||||||
Reference in New Issue
Block a user