##// END OF EJS Templates
dirstate-tree: Add tree traversal/iteration...
dirstate-tree: Add tree traversal/iteration Like Python’s, Rust’s iterators are "external" in that they are driven by a caller who calls a `next` method. This is as opposed to "internal" iterators who drive themselves and call a callback for each item. Writing an internal iterator traversing a tree is easy with recursion, but internal iterators cannot rely on the call stack in that way, they must save in an explicit object all state that they need to be preserved across two `next` calls. This algorithm uses a `Vec` as a stack that contains what would be local variables on the call stack if we could use recursion. Differential Revision: https://phab.mercurial-scm.org/D10370

File last commit:

r47478:b1f2c2b3 default
r47870:caa3031c default
Show More
cat.rs
105 lines | 3.7 KiB | application/rls-services+xml | RustLexer
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112 // 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.
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use std::path::PathBuf;
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use crate::repo::Repo;
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112 use crate::revlog::changelog::Changelog;
Simon Sapin
rust: replace most "operation" structs with functions...
r46751 use crate::revlog::manifest::Manifest;
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112 use crate::revlog::path_encode::path_encode;
use crate::revlog::revlog::Revlog;
use crate::revlog::revlog::RevlogError;
Simon Sapin
rust: use NodePrefix::from_hex instead of hex::decode directly...
r46647 use crate::revlog::Node;
Antoine cezar
hg-core: fix path encoding usage...
r46408 use crate::utils::files::get_path_from_bytes;
use crate::utils::hg_path::{HgPath, HgPathBuf};
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 pub struct CatOutput {
/// Whether any file in the manifest matched the paths given as CLI
/// arguments
pub found_any: bool,
/// The contents of matching files, in manifest order
pub concatenated: Vec<u8>,
/// Which of the CLI arguments did not match any manifest file
pub missing: Vec<HgPathBuf>,
/// The node ID that the given revset was resolved to
pub node: Node,
}
Antoine cezar
rhg: strip copied files metadata from `cat` output...
r46406 const METADATA_DELIMITER: [u8; 2] = [b'\x01', b'\n'];
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 /// Output the given revision of files
Simon Sapin
rust: replace most "operation" structs with functions...
r46751 ///
/// * `root`: Repository root
/// * `rev`: The revision to cat the files from.
/// * `files`: The files to output.
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 pub fn cat<'a>(
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 repo: &Repo,
Simon Sapin
rhg: centralize parsing of `--rev` CLI arguments...
r47162 revset: &str,
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 files: &'a [HgPathBuf],
) -> Result<CatOutput, RevlogError> {
Simon Sapin
rhg: centralize parsing of `--rev` CLI arguments...
r47162 let rev = crate::revset::resolve_single(revset, repo)?;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 let changelog = Changelog::open(repo)?;
let manifest = Manifest::open(repo)?;
Simon Sapin
rhg: centralize parsing of `--rev` CLI arguments...
r47162 let changelog_entry = changelog.get_rev(rev)?;
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 let node = *changelog
.node_from_rev(rev)
.expect("should succeed when changelog.get_rev did");
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 let manifest_node =
Node::from_hex_for_repo(&changelog_entry.manifest_node()?)?;
Simon Sapin
rust: Make NodePrefix allocation-free and Copy, remove NodePrefixRef...
r47160 let manifest_entry = manifest.get_node(manifest_node.into())?;
Simon Sapin
rust: replace most "operation" structs with functions...
r46751 let mut bytes = vec![];
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 let mut matched = vec![false; files.len()];
let mut found_any = false;
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112
Simon Sapin
rust: replace most "operation" structs with functions...
r46751 for (manifest_file, node_bytes) in manifest_entry.files_with_nodes() {
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 for (cat_file, is_matched) in files.iter().zip(&mut matched) {
Simon Sapin
rust: replace most "operation" structs with functions...
r46751 if cat_file.as_bytes() == manifest_file.as_bytes() {
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 *is_matched = true;
found_any = true;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 let index_path = store_path(manifest_file, b".i");
let data_path = store_path(manifest_file, b".d");
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 let file_log =
Revlog::open(repo, &index_path, Some(&data_path))?;
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 let file_node = Node::from_hex_for_repo(node_bytes)?;
Simon Sapin
rust: Make NodePrefix allocation-free and Copy, remove NodePrefixRef...
r47160 let file_rev = file_log.get_node_rev(file_node.into())?;
Simon Sapin
rust: replace most "operation" structs with functions...
r46751 let data = file_log.get_rev_data(file_rev)?;
if data.starts_with(&METADATA_DELIMITER) {
let end_delimiter_position = data
[METADATA_DELIMITER.len()..]
.windows(METADATA_DELIMITER.len())
.position(|bytes| bytes == METADATA_DELIMITER);
if let Some(position) = end_delimiter_position {
let offset = METADATA_DELIMITER.len() * 2;
bytes.extend(data[position + offset..].iter());
}
} else {
bytes.extend(data);
}
}
}
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112 }
Simon Sapin
rhg: `cat` command: print error messages for missing files...
r47478 let missing: Vec<_> = files
.iter()
.zip(&matched)
.filter(|pair| !*pair.1)
.map(|pair| pair.0.clone())
.collect();
Ok(CatOutput {
found_any,
concatenated: bytes,
missing,
node,
})
Antoine Cezar
hg-core: add a `CatRev` operation...
r46112 }
Antoine cezar
hg-core: fix path encoding usage...
r46408
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 fn store_path(hg_path: &HgPath, suffix: &[u8]) -> PathBuf {
Antoine cezar
hg-core: fix path encoding usage...
r46408 let encoded_bytes =
path_encode(&[b"data/", hg_path.as_bytes(), suffix].concat());
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 get_path_from_bytes(&encoded_bytes).into()
Antoine cezar
hg-core: fix path encoding usage...
r46408 }