Reconstruct the requested view's metadata chain from a sync pack in root-to-leaf order. The server includes the requested ref and every ancestor snapshot. Views are metadata closures over the common graph, so pull applies this whole chain after saving the missing graph objects.
(
pack: &SyncPack,
leaf: &str,
url: &str,
)
| 111 | /// snapshot. Views are metadata closures over the common graph, so pull applies |
| 112 | /// this whole chain after saving the missing graph objects. |
| 113 | fn manifest_chain_from_pack( |
| 114 | pack: &SyncPack, |
| 115 | leaf: &str, |
| 116 | url: &str, |
| 117 | ) -> CliResult<Vec<ViewManifest>> { |
| 118 | let mut by_name = HashMap::new(); |
| 119 | for r in &pack.refs { |
| 120 | if let Some(m) = manifest_from_pack(pack, &r.name, url)? { |
| 121 | by_name.insert(r.name.clone(), m); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | let mut chain = Vec::new(); |
| 126 | let mut seen = std::collections::HashSet::new(); |
| 127 | let mut cursor = Some(leaf.to_string()); |
| 128 | while let Some(name) = cursor { |
| 129 | if !seen.insert(name.clone()) { |
| 130 | return Err(CliError::RemoteError { |
| 131 | message: format!("Remote view parent chain contains a cycle at '{name}'"), |
| 132 | url: Some(url.to_string()), |
| 133 | }); |
| 134 | } |
| 135 | let manifest = by_name.remove(&name).ok_or_else(|| CliError::RemoteError { |
| 136 | message: format!("Remote view metadata is missing '{name}'"), |
| 137 | url: Some(url.to_string()), |
| 138 | })?; |
| 139 | cursor = manifest.parent.clone(); |
| 140 | chain.push(manifest); |
| 141 | } |
| 142 | chain.reverse(); |
| 143 | Ok(chain) |
| 144 | } |
| 145 | |
| 146 | // Constants |
| 147 |