manifest.rs
119 lines
| 3.6 KiB
| application/rls-services+xml
|
RustLexer
Simon Sapin
|
r48777 | use crate::errors::HgError; | ||
Simon Sapin
|
r46782 | use crate::repo::Repo; | ||
Antoine Cezar
|
r46104 | use crate::revlog::revlog::{Revlog, RevlogError}; | ||
use crate::revlog::Revision; | ||||
Simon Sapin
|
r48778 | use crate::revlog::{Node, NodePrefix}; | ||
Antoine Cezar
|
r46104 | use crate::utils::hg_path::HgPath; | ||
Simon Sapin
|
r49166 | use crate::utils::SliceExt; | ||
Antoine Cezar
|
r46104 | |||
/// A specialized `Revlog` to work with `manifest` data format. | ||||
Simon Sapin
|
r48771 | pub struct Manifestlog { | ||
Antoine Cezar
|
r46104 | /// The generic `revlog` format. | ||
revlog: Revlog, | ||||
} | ||||
Simon Sapin
|
r48771 | impl Manifestlog { | ||
Antoine Cezar
|
r46104 | /// Open the `manifest` of a repository given by its root. | ||
Simon Sapin
|
r48777 | pub fn open(repo: &Repo) -> Result<Self, HgError> { | ||
Simon Sapin
|
r46782 | let revlog = Revlog::open(repo, "00manifest.i", None)?; | ||
Antoine Cezar
|
r46104 | Ok(Self { revlog }) | ||
} | ||||
Simon Sapin
|
r48783 | /// Return the `Manifest` for the given node ID. | ||
/// | ||||
/// Note: this is a node ID in the manifestlog, typically found through | ||||
/// `ChangelogEntry::manifest_node`. It is *not* the node ID of any | ||||
/// changeset. | ||||
/// | ||||
/// See also `Repo::manifest_for_node` | ||||
pub fn data_for_node( | ||||
&self, | ||||
node: NodePrefix, | ||||
) -> Result<Manifest, RevlogError> { | ||||
Simon Sapin
|
r48782 | let rev = self.revlog.rev_from_node(node)?; | ||
Simon Sapin
|
r48783 | self.data_for_rev(rev) | ||
Antoine Cezar
|
r46104 | } | ||
Simon Sapin
|
r48783 | /// Return the `Manifest` of a given revision number. | ||
/// | ||||
/// Note: this is a revision number in the manifestlog, *not* of any | ||||
/// changeset. | ||||
/// | ||||
/// See also `Repo::manifest_for_rev` | ||||
pub fn data_for_rev( | ||||
&self, | ||||
rev: Revision, | ||||
) -> Result<Manifest, RevlogError> { | ||||
Antoine Cezar
|
r46104 | let bytes = self.revlog.get_rev_data(rev)?; | ||
Simon Sapin
|
r48771 | Ok(Manifest { bytes }) | ||
Antoine Cezar
|
r46104 | } | ||
} | ||||
Simon Sapin
|
r48771 | /// `Manifestlog` entry which knows how to interpret the `manifest` data bytes. | ||
Antoine Cezar
|
r46104 | #[derive(Debug)] | ||
Simon Sapin
|
r48771 | pub struct Manifest { | ||
Antoine Cezar
|
r46104 | bytes: Vec<u8>, | ||
} | ||||
Simon Sapin
|
r48771 | impl Manifest { | ||
Simon Sapin
|
r49166 | pub fn iter( | ||
&self, | ||||
) -> impl Iterator<Item = Result<ManifestEntry, HgError>> { | ||||
Antoine Cezar
|
r46104 | self.bytes | ||
.split(|b| b == &b'\n') | ||||
.filter(|line| !line.is_empty()) | ||||
Simon Sapin
|
r49166 | .map(|line| { | ||
let (path, rest) = line.split_2(b'\0').ok_or_else(|| { | ||||
Simon Sapin
|
r49165 | HgError::corrupted("manifest line should contain \\0") | ||
})?; | ||||
Simon Sapin
|
r49166 | let path = HgPath::new(path); | ||
let (hex_node_id, flags) = match rest.split_last() { | ||||
Some((&b'x', rest)) => (rest, Some(b'x')), | ||||
Some((&b'l', rest)) => (rest, Some(b'l')), | ||||
Some((&b't', rest)) => (rest, Some(b't')), | ||||
_ => (rest, None), | ||||
}; | ||||
Ok(ManifestEntry { | ||||
path, | ||||
hex_node_id, | ||||
flags, | ||||
}) | ||||
}) | ||||
Antoine Cezar
|
r46111 | } | ||
Simon Sapin
|
r48778 | |||
/// If the given path is in this manifest, return its filelog node ID | ||||
Simon Sapin
|
r49166 | pub fn find_file( | ||
&self, | ||||
path: &HgPath, | ||||
) -> Result<Option<ManifestEntry>, HgError> { | ||||
Simon Sapin
|
r48778 | // TODO: use binary search instead of linear scan. This may involve | ||
// building (and caching) an index of the byte indicex of each manifest | ||||
// line. | ||||
Simon Sapin
|
r49166 | |||
// TODO: use try_find when available (if still using linear scan) | ||||
// https://github.com/rust-lang/rust/issues/63178 | ||||
for entry in self.iter() { | ||||
let entry = entry?; | ||||
if entry.path == path { | ||||
return Ok(Some(entry)); | ||||
Simon Sapin
|
r48778 | } | ||
} | ||||
Ok(None) | ||||
} | ||||
Antoine Cezar
|
r46104 | } | ||
Simon Sapin
|
r49166 | |||
/// `Manifestlog` entry which knows how to interpret the `manifest` data bytes. | ||||
#[derive(Debug)] | ||||
pub struct ManifestEntry<'manifest> { | ||||
pub path: &'manifest HgPath, | ||||
pub hex_node_id: &'manifest [u8], | ||||
/// `Some` values are b'x', b'l', or 't' | ||||
pub flags: Option<u8>, | ||||
} | ||||
impl ManifestEntry<'_> { | ||||
pub fn node_id(&self) -> Result<Node, HgError> { | ||||
Node::from_hex_for_repo(self.hex_node_id) | ||||
} | ||||
} | ||||