Resolve connected library branch fallbacks
This commit is contained in:
@@ -9,3 +9,4 @@ All notable Modrinth Plus changes are documented here.
|
||||
- Added Windows installer publishing to the Gitea generic package registry.
|
||||
- Added Codex repository context and release/security documentation.
|
||||
- Fixed startup compatibility with existing official Modrinth App databases that recorded different checksums for historical SQLite migrations.
|
||||
- Fixed Connected Library Git repository URL resolution for repositories that use `master` instead of `main`.
|
||||
|
||||
@@ -157,9 +157,7 @@ pub async fn list() -> crate::Result<Vec<ConnectedPack>> {
|
||||
|
||||
pub async fn connect(source_url: String) -> crate::Result<ConnectedPack> {
|
||||
let state = State::get().await?;
|
||||
let manifest_url = normalize_manifest_url(&source_url)?;
|
||||
let manifest = fetch_manifest(&manifest_url).await?;
|
||||
validate_manifest(&manifest)?;
|
||||
let (manifest_url, manifest) = resolve_manifest(&source_url).await?;
|
||||
upsert_manifest(&state.pool, None, &source_url, &manifest_url, &manifest)
|
||||
.await?;
|
||||
get_by_source(&state.pool, &source_url).await
|
||||
@@ -197,14 +195,17 @@ pub async fn set_auto_update(
|
||||
pub async fn check(id: String) -> crate::Result<ConnectedCheckResult> {
|
||||
let state = State::get().await?;
|
||||
let pack = get_by_id(&state.pool, &id).await?;
|
||||
let manifest = fetch_manifest(&pack.manifest_url).await?;
|
||||
validate_manifest(&manifest)?;
|
||||
let (manifest_url, manifest) = match fetch_manifest(&pack.manifest_url).await
|
||||
{
|
||||
Ok(manifest) => (pack.manifest_url.clone(), manifest),
|
||||
Err(_) => resolve_manifest(&pack.source_url).await?,
|
||||
};
|
||||
|
||||
upsert_manifest(
|
||||
&state.pool,
|
||||
Some(&pack.id),
|
||||
&pack.source_url,
|
||||
&pack.manifest_url,
|
||||
&manifest_url,
|
||||
&manifest,
|
||||
)
|
||||
.await?;
|
||||
@@ -306,7 +307,7 @@ pub async fn install(id: String) -> crate::Result<ConnectedPack> {
|
||||
get_by_id(&state.pool, &id).await
|
||||
}
|
||||
|
||||
fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
|
||||
fn manifest_url_candidates(source_url: &str) -> crate::Result<Vec<String>> {
|
||||
let source = source_url.trim();
|
||||
let parsed = Url::parse(source)?;
|
||||
|
||||
@@ -318,7 +319,7 @@ fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
|
||||
}
|
||||
|
||||
if source.ends_with(MANIFEST_FILE_NAME) || source.contains("/raw/") {
|
||||
return Ok(source.to_string());
|
||||
return Ok(vec![source.to_string()]);
|
||||
}
|
||||
|
||||
let host = parsed.host_str().unwrap_or_default();
|
||||
@@ -329,30 +330,52 @@ fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
|
||||
|
||||
if host == "github.com" && segments.len() >= 2 {
|
||||
let repo = segments[1].trim_end_matches(".git");
|
||||
return Ok(format!(
|
||||
return Ok(vec![
|
||||
format!(
|
||||
"https://raw.githubusercontent.com/{}/{}/main/{}",
|
||||
segments[0], repo, MANIFEST_FILE_NAME
|
||||
));
|
||||
),
|
||||
format!(
|
||||
"https://raw.githubusercontent.com/{}/{}/master/{}",
|
||||
segments[0], repo, MANIFEST_FILE_NAME
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
if host == "gitlab.com" && segments.len() >= 2 {
|
||||
let repo = segments[1].trim_end_matches(".git");
|
||||
return Ok(format!(
|
||||
return Ok(vec![
|
||||
format!(
|
||||
"https://gitlab.com/{}/{}/-/raw/main/{}",
|
||||
segments[0], repo, MANIFEST_FILE_NAME
|
||||
));
|
||||
),
|
||||
format!(
|
||||
"https://gitlab.com/{}/{}/-/raw/master/{}",
|
||||
segments[0], repo, MANIFEST_FILE_NAME
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
if segments.len() >= 2 {
|
||||
let repo = segments[1].trim_end_matches(".git");
|
||||
return Ok(format!(
|
||||
return Ok(vec![
|
||||
format!(
|
||||
"{}://{}/{}/{}/raw/branch/main/{}",
|
||||
parsed.scheme(),
|
||||
host,
|
||||
segments[0],
|
||||
repo,
|
||||
MANIFEST_FILE_NAME
|
||||
));
|
||||
),
|
||||
format!(
|
||||
"{}://{}/{}/{}/raw/branch/master/{}",
|
||||
parsed.scheme(),
|
||||
host,
|
||||
segments[0],
|
||||
repo,
|
||||
MANIFEST_FILE_NAME
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
Err(ErrorKind::InputError(
|
||||
@@ -362,6 +385,26 @@ fn normalize_manifest_url(source_url: &str) -> crate::Result<String> {
|
||||
.into())
|
||||
}
|
||||
|
||||
async fn resolve_manifest(
|
||||
source_url: &str,
|
||||
) -> crate::Result<(String, ConnectedManifest)> {
|
||||
let candidates = manifest_url_candidates(source_url)?;
|
||||
let mut errors = Vec::new();
|
||||
|
||||
for manifest_url in candidates {
|
||||
match fetch_manifest(&manifest_url).await {
|
||||
Ok(manifest) => return Ok((manifest_url, manifest)),
|
||||
Err(err) => errors.push(format!("{manifest_url}: {err}")),
|
||||
}
|
||||
}
|
||||
|
||||
Err(ErrorKind::InputError(format!(
|
||||
"Could not fetch {MANIFEST_FILE_NAME}. Tried: {}",
|
||||
errors.join("; ")
|
||||
))
|
||||
.into())
|
||||
}
|
||||
|
||||
async fn fetch_manifest(url: &str) -> crate::Result<ConnectedManifest> {
|
||||
let manifest = reqwest::get(url)
|
||||
.await?
|
||||
|
||||
Reference in New Issue
Block a user