launchpad: drive the endpoints from data/launchpad.yml
This commit is contained in:
+84
-8
@@ -23,13 +23,69 @@ use std::path::Path;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::data::embed_data;
|
||||
use crate::put::target::UploadTarget;
|
||||
|
||||
/// Git configuration key holding the Launchpad account name
|
||||
const LP_USER_KEY: &str = "lp.user";
|
||||
|
||||
/// Launchpad service endpoints, loaded from the bundled `launchpad.yml`
|
||||
/// data file (same pattern as `distro_info.yml`): static endpoints that
|
||||
/// change with Launchpad, not with the code, are data — several of them
|
||||
/// were previously duplicated across three modules.
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct LaunchpadData {
|
||||
/// Base URL of the Launchpad REST API
|
||||
api_base: String,
|
||||
/// Host of the PPA SFTP upload server
|
||||
ssh_host: String,
|
||||
/// Port of the PPA SFTP upload server
|
||||
ssh_port: u16,
|
||||
/// Upload queue incoming directory template (`{owner}`/`{ppa}`)
|
||||
incoming_template: String,
|
||||
/// PPA package-content (apt repository) URL template
|
||||
content_host_template: String,
|
||||
/// Ubuntu source-package git web URL template (`{package}`)
|
||||
git_web_template: String,
|
||||
}
|
||||
|
||||
embed_data! {
|
||||
static ref LAUNCHPAD_DATA: LaunchpadData = "../data/launchpad.yml"
|
||||
}
|
||||
|
||||
/// Base URL of the Launchpad REST API
|
||||
const API_BASE: &str = "https://api.launchpad.net/1.0";
|
||||
fn api_base() -> &'static str {
|
||||
&LAUNCHPAD_DATA.api_base
|
||||
}
|
||||
|
||||
/// Host serving PPA package content, derived from the content-host
|
||||
/// template so the URL builders and the URL parsers of PPA addresses
|
||||
/// cannot drift apart
|
||||
pub(crate) fn ppa_content_host() -> &'static str {
|
||||
let template = LAUNCHPAD_DATA.content_host_template.as_str();
|
||||
let after_scheme = template
|
||||
.split_once("://")
|
||||
.map_or(template, |(_, rest)| rest);
|
||||
after_scheme.split('/').next().unwrap_or(after_scheme)
|
||||
}
|
||||
|
||||
/// Base URL of the apt repository serving a PPA's packages
|
||||
/// (e.g. `https://ppa.launchpadcontent.net/user/ppa/ubuntu`)
|
||||
pub(crate) fn ppa_content_url(owner: &str, ppa: &str) -> String {
|
||||
LAUNCHPAD_DATA
|
||||
.content_host_template
|
||||
.replace("{owner}", owner)
|
||||
.replace("{ppa}", ppa)
|
||||
}
|
||||
|
||||
/// URL of the Launchpad git repository of an Ubuntu source package
|
||||
/// (`git.launchpad.net/ubuntu/+source/<package>`), the preferred VCS of
|
||||
/// Ubuntu packages
|
||||
pub(crate) fn ubuntu_source_git_url(package: &str) -> String {
|
||||
LAUNCHPAD_DATA
|
||||
.git_web_template
|
||||
.replace("{package}", package)
|
||||
}
|
||||
|
||||
/// Page size (`ws.size`) asked from Launchpad collections. Launchpad
|
||||
/// truncates collection answers at 75 entries by default and rejects
|
||||
@@ -88,27 +144,30 @@ fn split_ppa(ppa: &str) -> Result<(String, String), String> {
|
||||
|
||||
/// URL of the Launchpad API resource of a Launchpad account
|
||||
fn person_url(user: &str) -> String {
|
||||
format!("{API_BASE}/~{user}")
|
||||
format!("{}/~{user}", api_base())
|
||||
}
|
||||
|
||||
/// URL of the Launchpad API resource of a PPA (`~user/+archive/ubuntu/name`
|
||||
/// covers the default `ppa` archive and named archives alike); shared by the
|
||||
/// put-side pre-flight checks and the apt keyring's fingerprint lookup
|
||||
pub(crate) fn archive_url(user: &str, ppa: &str) -> String {
|
||||
format!("{API_BASE}/~{user}/+archive/ubuntu/{ppa}")
|
||||
format!("{}/~{user}/+archive/ubuntu/{ppa}", api_base())
|
||||
}
|
||||
|
||||
/// Resolve a `user/ppa_name` PPA argument into its upload target
|
||||
/// (`ppa.launchpad.net`, incoming `~user/ppa_name`), like dput-ng's
|
||||
/// Resolve a `user/ppa_name` PPA argument into its upload target (the
|
||||
/// SFTP host and incoming template of `launchpad.yml`), like dput-ng's
|
||||
/// `ppa:user/ppa` profile expansion.
|
||||
pub fn ppa_target(ppa: &str) -> Result<UploadTarget, String> {
|
||||
let (user, name) = split_ppa(ppa)?;
|
||||
|
||||
Ok(UploadTarget {
|
||||
fqdn: "ppa.launchpad.net".to_string(),
|
||||
port: 22,
|
||||
fqdn: LAUNCHPAD_DATA.ssh_host.clone(),
|
||||
port: LAUNCHPAD_DATA.ssh_port,
|
||||
login: None,
|
||||
incoming: format!("~{user}/{name}"),
|
||||
incoming: LAUNCHPAD_DATA
|
||||
.incoming_template
|
||||
.replace("{owner}", &user)
|
||||
.replace("{ppa}", &name),
|
||||
label: format!("ppa:{ppa}"),
|
||||
})
|
||||
}
|
||||
@@ -425,6 +484,23 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// The data-driven endpoint accessors build the same addresses the
|
||||
/// former hardcoded constants carried (each verified against the live
|
||||
/// service), and the content host is derived from the same template
|
||||
/// the content URLs are built from
|
||||
#[test]
|
||||
fn data_driven_endpoints_match_the_service() {
|
||||
assert_eq!(
|
||||
ppa_content_url("vhaudiquet", "noctalia"),
|
||||
"https://ppa.launchpadcontent.net/vhaudiquet/noctalia/ubuntu"
|
||||
);
|
||||
assert_eq!(ppa_content_host(), "ppa.launchpadcontent.net");
|
||||
assert_eq!(
|
||||
ubuntu_source_git_url("hello"),
|
||||
"https://git.launchpad.net/ubuntu/+source/hello"
|
||||
);
|
||||
}
|
||||
|
||||
/// The API answer carries many unrelated fields; deserialization must
|
||||
/// pick the relevant ones and tolerate a null `enabled`
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user