Parse the text wire format. Parsing validates structure only; call [`Self::verify`] to check that the declared state matches the log. Unknown trailing header fields are ignored so the format can grow without breaking older readers.
(text: &str)
| 169 | /// the declared state matches the log. Unknown trailing header fields are |
| 170 | /// ignored so the format can grow without breaking older readers. |
| 171 | pub fn parse(text: &str) -> Result<Self, ManifestError> { |
| 172 | let mut lines = text.lines(); |
| 173 | |
| 174 | let header = loop { |
| 175 | match lines.next() { |
| 176 | Some(line) if line.trim().is_empty() => continue, |
| 177 | Some(line) => break line, |
| 178 | None => return Err(ManifestError::Empty), |
| 179 | } |
| 180 | }; |
| 181 | |
| 182 | let mut fields = header.split('\t'); |
| 183 | let name = fields |
| 184 | .next() |
| 185 | .map(str::trim) |
| 186 | .filter(|s| !s.is_empty()) |
| 187 | .ok_or_else(|| ManifestError::MalformedHeader(header.to_string()))? |
| 188 | .to_string(); |
| 189 | let scope_text = fields |
| 190 | .next() |
| 191 | .map(str::trim) |
| 192 | .filter(|s| !s.is_empty()) |
| 193 | .ok_or_else(|| ManifestError::MalformedHeader(header.to_string()))?; |
| 194 | let parent_text = fields |
| 195 | .next() |
| 196 | .map(str::trim) |
| 197 | .ok_or_else(|| ManifestError::MalformedHeader(header.to_string()))?; |
| 198 | let state_text = fields |
| 199 | .next() |
| 200 | .map(str::trim) |
| 201 | .ok_or_else(|| ManifestError::MalformedHeader(header.to_string()))?; |
| 202 | |
| 203 | let scope = match scope_text.to_ascii_lowercase().as_str() { |
| 204 | "shared" => ViewScope::Shared, |
| 205 | "draft" => ViewScope::Draft, |
| 206 | other => { |
| 207 | return Err(ManifestError::UnknownScope { |
| 208 | name, |
| 209 | scope: other.to_string(), |
| 210 | }) |
| 211 | } |
| 212 | }; |
| 213 | |
| 214 | let parent = match parent_text { |
| 215 | NONE_FIELD | "" => None, |
| 216 | p => Some(p.to_string()), |
| 217 | }; |
| 218 | |
| 219 | let mut changes = Vec::new(); |
| 220 | for (i, line) in lines.enumerate() { |
| 221 | let line = line.trim(); |
| 222 | if line.is_empty() { |
| 223 | continue; |
| 224 | } |
| 225 | let hash = Hash::from_base32(line.as_bytes()).ok_or(ManifestError::InvalidHash { |
| 226 | // +2: 1-based, plus the header line. |
| 227 | line: i + 2, |
| 228 | text: line.to_string(), |