Details
Details
- Reviewers
- None
- Group Reviewers
hg-reviewers - Commits
- rHG522ec3dc44b9: hg-core: add a `CatRev` operation
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
hg-reviewers |
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
A | M | rust/hg-core/src/operations/cat.rs (145 lines) | ||
M | rust/hg-core/src/operations/mod.rs (2 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
0a3d81e6e35c | 704264ff6724 | Antoine Cezar | Sep 11 2020, 11:32 AM |
Status | Author | Revision | |
---|---|---|---|
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | D9049 hg-core: add path_encode | |
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | D8962 rhg: Add debug timing | |
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar | ||
Closed | acezar |
// 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 std::convert::From; | |||||
use std::path::PathBuf; | |||||
use crate::revlog::changelog::Changelog; | |||||
use crate::revlog::manifest::{Manifest, ManifestEntry}; | |||||
use crate::revlog::path_encode::path_encode; | |||||
use crate::revlog::revlog::Revlog; | |||||
use crate::revlog::revlog::RevlogError; | |||||
use crate::revlog::Revision; | |||||
use crate::utils::hg_path::HgPathBuf; | |||||
/// Kind of error encountered by `CatRev` | |||||
#[derive(Debug)] | |||||
pub enum CatRevErrorKind { | |||||
/// Error when reading a `revlog` file. | |||||
IoError(std::io::Error), | |||||
/// The revision has not been found. | |||||
InvalidRevision, | |||||
/// 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 `CatRev` error | |||||
#[derive(Debug)] | |||||
pub struct CatRevError { | |||||
/// Kind of error encountered by `CatRev` | |||||
pub kind: CatRevErrorKind, | |||||
} | |||||
impl From<CatRevErrorKind> for CatRevError { | |||||
fn from(kind: CatRevErrorKind) -> Self { | |||||
CatRevError { kind } | |||||
} | |||||
} | |||||
impl From<RevlogError> for CatRevError { | |||||
fn from(err: RevlogError) -> Self { | |||||
match err { | |||||
RevlogError::IoError(err) => CatRevErrorKind::IoError(err), | |||||
RevlogError::UnsuportedVersion(version) => { | |||||
CatRevErrorKind::UnsuportedRevlogVersion(version) | |||||
} | |||||
RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision, | |||||
RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog, | |||||
RevlogError::UnknowDataFormat(format) => { | |||||
CatRevErrorKind::UnknowRevlogDataFormat(format) | |||||
} | |||||
} | |||||
.into() | |||||
} | |||||
} | |||||
/// List files under Mercurial control at a given revision. | |||||
pub struct CatRev<'a> { | |||||
root: &'a PathBuf, | |||||
/// The revision to cat the files from. | |||||
rev: &'a str, | |||||
/// The files to output. | |||||
files: &'a [HgPathBuf], | |||||
/// The changelog file | |||||
changelog: Changelog, | |||||
/// The manifest file | |||||
manifest: Manifest, | |||||
/// The manifest entry corresponding to the revision. | |||||
/// | |||||
/// Used to hold the owner of the returned references. | |||||
manifest_entry: Option<ManifestEntry>, | |||||
} | |||||
impl<'a> CatRev<'a> { | |||||
pub fn new( | |||||
root: &'a PathBuf, | |||||
rev: &'a str, | |||||
files: &'a [HgPathBuf], | |||||
) -> Result<Self, CatRevError> { | |||||
let changelog = Changelog::open(&root)?; | |||||
let manifest = Manifest::open(&root)?; | |||||
let manifest_entry = None; | |||||
Ok(Self { | |||||
root, | |||||
rev, | |||||
files, | |||||
changelog, | |||||
manifest, | |||||
manifest_entry, | |||||
}) | |||||
} | |||||
pub fn run(&mut self) -> Result<Vec<u8>, CatRevError> { | |||||
let changelog_entry = match self.rev.parse::<Revision>() { | |||||
Ok(rev) => self.changelog.get_rev(rev)?, | |||||
_ => { | |||||
let changelog_node = hex::decode(&self.rev) | |||||
.map_err(|_| CatRevErrorKind::InvalidRevision)?; | |||||
self.changelog.get_node(&changelog_node)? | |||||
} | |||||
}; | |||||
let manifest_node = hex::decode(&changelog_entry.manifest_node()?) | |||||
.map_err(|_| CatRevErrorKind::CorruptedRevlog)?; | |||||
self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?); | |||||
if let Some(ref manifest_entry) = self.manifest_entry { | |||||
let mut bytes = vec![]; | |||||
for (manifest_file, node_bytes) in | |||||
manifest_entry.files_with_nodes() | |||||
{ | |||||
for cat_file in self.files.iter() { | |||||
if cat_file.as_bytes() == manifest_file.as_bytes() { | |||||
let encoded_bytes = | |||||
path_encode(manifest_file.as_bytes()); | |||||
let revlog_index_string = format!( | |||||
".hg/store/data/{}.i", | |||||
String::from_utf8_lossy(&encoded_bytes), | |||||
); | |||||
let revlog_index_path = | |||||
self.root.join(&revlog_index_string); | |||||
let file_log = Revlog::open(&revlog_index_path)?; | |||||
let file_node = hex::decode(&node_bytes) | |||||
.map_err(|_| CatRevErrorKind::CorruptedRevlog)?; | |||||
let file_rev = file_log.get_node_rev(&file_node)?; | |||||
let data = file_log.get_rev_data(file_rev)?; | |||||
bytes.extend(data); | |||||
} | |||||
} | |||||
} | |||||
Ok(bytes) | |||||
} else { | |||||
unreachable!("manifest_entry should have been stored"); | |||||
} | |||||
} | |||||
} |
//! A distinction is made between operations and commands. | //! A distinction is made between operations and commands. | ||||
//! An operation is what can be done whereas a command is what is exposed by | //! An operation is what can be done whereas a command is what is exposed by | ||||
//! the cli. A single command can use several operations to achieve its goal. | //! the cli. A single command can use several operations to achieve its goal. | ||||
mod cat; | |||||
mod debugdata; | mod debugdata; | ||||
mod dirstate_status; | mod dirstate_status; | ||||
mod find_root; | mod find_root; | ||||
mod list_tracked_files; | mod list_tracked_files; | ||||
pub use cat::{CatRev, CatRevError, CatRevErrorKind}; | |||||
pub use debugdata::{ | pub use debugdata::{ | ||||
DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, | DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, | ||||
}; | }; | ||||
pub use find_root::{FindRoot, FindRootError, FindRootErrorKind}; | pub use find_root::{FindRoot, FindRootError, FindRootErrorKind}; | ||||
pub use list_tracked_files::{ | pub use list_tracked_files::{ | ||||
ListDirstateTrackedFiles, ListDirstateTrackedFilesError, | ListDirstateTrackedFiles, ListDirstateTrackedFilesError, | ||||
ListDirstateTrackedFilesErrorKind, | ListDirstateTrackedFilesErrorKind, | ||||
}; | }; |