list_tracked_files.rs
167 lines
| 5.2 KiB
| application/rls-services+xml
|
RustLexer
Antoine Cezar
|
r45918 | // list_tracked_files.rs | ||
// | ||||
// Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> | ||||
// | ||||
// This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | ||||
use crate::dirstate::parsers::parse_dirstate; | ||||
Antoine Cezar
|
r46107 | use crate::revlog::changelog::Changelog; | ||
use crate::revlog::manifest::{Manifest, ManifestEntry}; | ||||
Simon Sapin
|
r46647 | use crate::revlog::node::{Node, NodePrefix}; | ||
Antoine Cezar
|
r46107 | use crate::revlog::revlog::RevlogError; | ||
use crate::revlog::Revision; | ||||
Antoine Cezar
|
r45918 | use crate::utils::hg_path::HgPath; | ||
use crate::{DirstateParseError, EntryState}; | ||||
use rayon::prelude::*; | ||||
use std::convert::From; | ||||
use std::fs; | ||||
Simon Sapin
|
r46750 | use std::path::Path; | ||
Antoine Cezar
|
r45918 | |||
Antoine Cezar
|
r46106 | /// Kind of error encountered by `ListDirstateTrackedFiles` | ||
Antoine Cezar
|
r45918 | #[derive(Debug)] | ||
Antoine Cezar
|
r46106 | pub enum ListDirstateTrackedFilesErrorKind { | ||
/// Error when reading the `dirstate` file | ||||
IoError(std::io::Error), | ||||
/// Error when parsing the `dirstate` file | ||||
Antoine Cezar
|
r45918 | ParseError(DirstateParseError), | ||
} | ||||
Antoine Cezar
|
r46106 | /// A `ListDirstateTrackedFiles` error | ||
Antoine Cezar
|
r45918 | #[derive(Debug)] | ||
Antoine Cezar
|
r46106 | pub struct ListDirstateTrackedFilesError { | ||
/// Kind of error encountered by `ListDirstateTrackedFiles` | ||||
pub kind: ListDirstateTrackedFilesErrorKind, | ||||
Antoine Cezar
|
r45918 | } | ||
Antoine Cezar
|
r46106 | impl From<ListDirstateTrackedFilesErrorKind> | ||
for ListDirstateTrackedFilesError | ||||
{ | ||||
fn from(kind: ListDirstateTrackedFilesErrorKind) -> Self { | ||||
ListDirstateTrackedFilesError { kind } | ||||
Antoine Cezar
|
r45918 | } | ||
} | ||||
Antoine Cezar
|
r46106 | impl From<std::io::Error> for ListDirstateTrackedFilesError { | ||
fn from(err: std::io::Error) -> Self { | ||||
let kind = ListDirstateTrackedFilesErrorKind::IoError(err); | ||||
ListDirstateTrackedFilesError { kind } | ||||
Raphaël Gomès
|
r46007 | } | ||
Antoine Cezar
|
r45918 | } | ||
/// List files under Mercurial control in the working directory | ||||
/// by reading the dirstate | ||||
Simon Sapin
|
r46751 | pub struct Dirstate { | ||
Antoine Cezar
|
r46106 | /// The `dirstate` content. | ||
Antoine Cezar
|
r45918 | content: Vec<u8>, | ||
} | ||||
Simon Sapin
|
r46751 | impl Dirstate { | ||
Simon Sapin
|
r46750 | pub fn new(root: &Path) -> Result<Self, ListDirstateTrackedFilesError> { | ||
Antoine Cezar
|
r46106 | let dirstate = root.join(".hg/dirstate"); | ||
let content = fs::read(&dirstate)?; | ||||
Ok(Self { content }) | ||||
} | ||||
Simon Sapin
|
r46751 | pub fn tracked_files( | ||
&self, | ||||
Antoine Cezar
|
r46106 | ) -> Result<Vec<&HgPath>, ListDirstateTrackedFilesError> { | ||
Antoine Cezar
|
r45918 | let (_, entries, _) = parse_dirstate(&self.content) | ||
Antoine Cezar
|
r46106 | .map_err(ListDirstateTrackedFilesErrorKind::ParseError)?; | ||
Antoine Cezar
|
r45918 | let mut files: Vec<&HgPath> = entries | ||
.into_iter() | ||||
.filter_map(|(path, entry)| match entry.state { | ||||
EntryState::Removed => None, | ||||
_ => Some(path), | ||||
}) | ||||
.collect(); | ||||
files.par_sort_unstable(); | ||||
Ok(files) | ||||
} | ||||
} | ||||
Antoine Cezar
|
r46107 | |||
/// Kind of error encountered by `ListRevTrackedFiles` | ||||
#[derive(Debug)] | ||||
pub enum ListRevTrackedFilesErrorKind { | ||||
/// Error when reading a `revlog` file. | ||||
IoError(std::io::Error), | ||||
/// The revision has not been found. | ||||
InvalidRevision, | ||||
Simon Sapin
|
r46646 | /// Found more than one revision whose ID match the requested prefix | ||
AmbiguousPrefix, | ||||
Antoine Cezar
|
r46107 | /// A `revlog` file is corrupted. | ||
CorruptedRevlog, | ||||
/// The `revlog` format version is not supported. | ||||
UnsuportedRevlogVersion(u16), | ||||
/// The `revlog` data format is not supported. | ||||
UnknowRevlogDataFormat(u8), | ||||
} | ||||
/// A `ListRevTrackedFiles` error | ||||
#[derive(Debug)] | ||||
pub struct ListRevTrackedFilesError { | ||||
/// Kind of error encountered by `ListRevTrackedFiles` | ||||
pub kind: ListRevTrackedFilesErrorKind, | ||||
} | ||||
impl From<ListRevTrackedFilesErrorKind> for ListRevTrackedFilesError { | ||||
fn from(kind: ListRevTrackedFilesErrorKind) -> Self { | ||||
ListRevTrackedFilesError { kind } | ||||
} | ||||
} | ||||
impl From<RevlogError> for ListRevTrackedFilesError { | ||||
fn from(err: RevlogError) -> Self { | ||||
match err { | ||||
RevlogError::IoError(err) => { | ||||
ListRevTrackedFilesErrorKind::IoError(err) | ||||
} | ||||
RevlogError::UnsuportedVersion(version) => { | ||||
ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) | ||||
} | ||||
RevlogError::InvalidRevision => { | ||||
ListRevTrackedFilesErrorKind::InvalidRevision | ||||
} | ||||
Simon Sapin
|
r46646 | RevlogError::AmbiguousPrefix => { | ||
ListRevTrackedFilesErrorKind::AmbiguousPrefix | ||||
} | ||||
Antoine Cezar
|
r46107 | RevlogError::Corrupted => { | ||
ListRevTrackedFilesErrorKind::CorruptedRevlog | ||||
} | ||||
RevlogError::UnknowDataFormat(format) => { | ||||
ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) | ||||
} | ||||
} | ||||
.into() | ||||
} | ||||
} | ||||
/// List files under Mercurial control at a given revision. | ||||
Simon Sapin
|
r46751 | pub fn list_rev_tracked_files( | ||
root: &Path, | ||||
rev: &str, | ||||
) -> Result<FilesForRev, ListRevTrackedFilesError> { | ||||
let changelog = Changelog::open(root)?; | ||||
let manifest = Manifest::open(root)?; | ||||
let changelog_entry = match rev.parse::<Revision>() { | ||||
Ok(rev) => changelog.get_rev(rev)?, | ||||
_ => { | ||||
let changelog_node = NodePrefix::from_hex(&rev) | ||||
.or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?; | ||||
changelog.get_node(changelog_node.borrow())? | ||||
} | ||||
}; | ||||
let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) | ||||
.or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?; | ||||
let manifest_entry = manifest.get_node((&manifest_node).into())?; | ||||
Ok(FilesForRev(manifest_entry)) | ||||
Antoine Cezar
|
r46107 | } | ||
Simon Sapin
|
r46751 | pub struct FilesForRev(ManifestEntry); | ||
Antoine Cezar
|
r46107 | |||
Simon Sapin
|
r46751 | impl FilesForRev { | ||
pub fn iter(&self) -> impl Iterator<Item = &HgPath> { | ||||
self.0.files() | ||||
Antoine Cezar
|
r46107 | } | ||
} | ||||