-
Notifications
You must be signed in to change notification settings - Fork 92
fix(anolisa): fallback to v1 components.toml when v2 index is unavailable #2566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
e5c50ed
aa01ae4
8e0a6d6
b043005
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,7 @@ use anolisa_platform::pkg_query::{PackageQuery, PackageQueryError}; | |
| use serde::{Deserialize, Serialize}; | ||
| use thiserror::Error; | ||
|
|
||
| use crate::repo_config::{BackendConfig, HostVars, RepoConfig, component_index_v2_url}; | ||
| use crate::repo_config::{BackendConfig, HostVars, RepoConfig, component_index_url, component_index_v2_url}; | ||
|
|
||
| /// On-disk schema version for repo-side `components-v2.toml`. | ||
| pub(crate) const COMPONENT_INDEX_SCHEMA_VERSION: u32 = 2; | ||
|
|
@@ -54,6 +54,7 @@ pub(crate) struct ComponentIndexEntry { | |
| #[serde(default)] | ||
| pub(crate) summary: Option<String>, | ||
| /// Supported host OS/architecture combinations. | ||
| #[serde(default)] | ||
| pub(crate) targets: Vec<ComponentTarget>, | ||
| /// Backend-native package names for this component. | ||
| /// | ||
|
|
@@ -473,7 +474,11 @@ impl ComponentIndex { | |
| } | ||
|
|
||
| fn validate(&self) -> Result<(), ComponentIndexError> { | ||
| if self.schema_version != COMPONENT_INDEX_SCHEMA_VERSION { | ||
| // Accept schema v1 and v2: v1 rows simply lack `targets`, which | ||
| // defaults to an empty vec via `#[serde(default)]`. This lets the | ||
| // v2 parser gracefully load v1 `components.toml` when the v2 file | ||
| // has not been published to the mirror yet. | ||
| if !matches!(self.schema_version, 1 | 2) { | ||
| return Err(ComponentIndexError::UnsupportedSchema { | ||
| actual: self.schema_version, | ||
| expected: COMPONENT_INDEX_SCHEMA_VERSION, | ||
|
|
@@ -492,7 +497,9 @@ impl ComponentIndex { | |
| reason: format!("duplicate component '{name}'"), | ||
| }); | ||
| } | ||
| if entry.targets.is_empty() { | ||
| // v1 indexes predate the `targets` field; skip the non-empty | ||
| // check for schema v1 (targets defaults to empty via serde). | ||
| if self.schema_version >= 2 && entry.targets.is_empty() { | ||
| return Err(ComponentIndexError::Invalid { | ||
| reason: format!("component '{name}' must declare at least one target"), | ||
| }); | ||
|
|
@@ -741,18 +748,43 @@ pub(crate) fn load_component_index( | |
| let url = component_index_v2_url(&base_url); | ||
|
|
||
| let cache = DownloadCache::new(layout.cache_dir.clone()); | ||
| let downloaded = match fetch_index_url(&cache, &url) { | ||
| Ok(art) => art, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] v1 回退逻辑依赖错误文案匹配,易受服务端文案变动影响 当前 v2→v1 回退通过 🤖 Generated by Qoder • Fix in Qoder |
||
| Err(ComponentIndexError::Fetch { ref reason }) | ||
| if reason.contains("http status 404") => | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For local Useful? React with 👍 / 👎. |
||
| { | ||
| // v2 not published yet — fall back to v1 components.toml. | ||
| // The v2 parser accepts v1 rows because `targets` has | ||
| // `#[serde(default)]`, so legacy indexes without targets | ||
| // still load (components simply appear as "no target info"). | ||
| let v1_url = component_index_url(&base_url); | ||
| fetch_index_url(&cache, &v1_url).map_err(|err| ComponentIndexError::Fetch { | ||
| reason: format!( | ||
| "failed to fetch component index (tried v2 then v1): {err}" | ||
| ), | ||
| })? | ||
| } | ||
| Err(err) => return Err(err), | ||
| }; | ||
| ComponentIndex::load(&downloaded.cached_path) | ||
| } | ||
|
|
||
| /// Fetch a component index TOML from `url` into `cache`. | ||
| fn fetch_index_url( | ||
| cache: &DownloadCache, | ||
| url: &str, | ||
| ) -> Result<anolisa_core::download::DownloadedArtifact, ComponentIndexError> { | ||
| #[cfg(test)] | ||
| if !url.starts_with("file://") { | ||
| return Err(ComponentIndexError::Fetch { | ||
| reason: format!("test mode: refusing non-file URL {url}"), | ||
| }); | ||
| } | ||
| let downloaded = cache | ||
| .fetch(&url, None) | ||
| cache | ||
| .fetch(url, None) | ||
| .map_err(|err| ComponentIndexError::Fetch { | ||
| reason: format!("failed to fetch {url}: {err}"), | ||
| })?; | ||
| ComponentIndex::load(&downloaded.cached_path) | ||
| }) | ||
| } | ||
|
|
||
| /// Best-effort load of repo-side `components-v2.toml`. | ||
|
|
@@ -1325,7 +1357,10 @@ cosh = "site-copilot" | |
|
|
||
| #[test] | ||
| fn unsupported_schema_is_rejected() { | ||
| for actual in [1, 99] { | ||
| // Schema v1 and v2 are accepted; anything else is rejected. | ||
| // v1 is accepted because `targets` defaults to an empty vec and | ||
| // the non-empty-target check is skipped for schema v1. | ||
| for actual in [99] { | ||
| let source = format!("schema_version = {actual}"); | ||
| let err = ComponentIndex::from_toml_str(&source, "components.toml") | ||
| .expect_err("unsupported schema"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the fallback loads a schema v1
components.toml, existing v1 rows useplatforms = [...]rather thantargets, so defaultingtargetsto an empty list makessupports_target()false for every component. In particular,install --allfilters throughcomponent_names_for_target()and will report nothing to install even though the fallback index was loaded; translate v1 platform data into target availability or avoid target filtering for schema v1.Useful? React with 👍 / 👎.