Fetch the requested view's manifest and walk its parent chain up to the root, returning the manifests in root→leaf apply order. Returns `Ok(None)` when the requested view does not exist on the remote. A declared parent that is missing remotely, or a parent chain that loops, means the remote's view metadata is corrupted and is a hard error.
(
&self,
remote: &HttpRemote,
)
| 363 | /// that loops, means the remote's view metadata is corrupted and is a |
| 364 | /// hard error. |
| 365 | async fn fetch_manifest_chain( |
| 366 | &self, |
| 367 | remote: &HttpRemote, |
| 368 | ) -> CliResult<Option<Vec<ViewManifest>>> { |
| 369 | let Some(leaf) = self.fetch_view_manifest(remote, &self.view).await? else { |
| 370 | return Ok(None); |
| 371 | }; |
| 372 | |
| 373 | let mut visited: HashSet<String> = HashSet::new(); |
| 374 | visited.insert(leaf.name.clone()); |
| 375 | let mut next_parent = leaf.parent.clone(); |
| 376 | let mut chain = vec![leaf]; |
| 377 | |
| 378 | while let Some(parent) = next_parent { |
| 379 | if !visited.insert(parent.clone()) { |
| 380 | return Err(CliError::RemoteError { |
| 381 | message: format!( |
| 382 | "View parent chain loops at '{}' — the remote's view metadata is corrupted", |
| 383 | parent |
| 384 | ), |
| 385 | url: Some(self.url.clone()), |
| 386 | }); |
| 387 | } |
| 388 | let child_name = chain |
| 389 | .last() |
| 390 | .map(|m| m.name.clone()) |
| 391 | .unwrap_or_else(|| self.view.clone()); |
| 392 | let manifest = self |
| 393 | .fetch_view_manifest(remote, &parent) |
| 394 | .await? |
| 395 | .ok_or_else(|| CliError::RemoteError { |
| 396 | message: format!( |
| 397 | "View '{}' declares parent '{}', but the remote has no such view", |
| 398 | child_name, parent |
| 399 | ), |
| 400 | url: Some(self.url.clone()), |
| 401 | })?; |
| 402 | next_parent = manifest.parent.clone(); |
| 403 | chain.push(manifest); |
| 404 | } |
| 405 | |
| 406 | // Collected leaf→root; parents must be applied first. |
| 407 | chain.reverse(); |
| 408 | Ok(Some(chain)) |
| 409 | } |
| 410 | |
| 411 | /// Download every change in `missing` and save it to the change store. |
| 412 | /// |