cat.rs
115 lines
| 3.3 KiB
| application/rls-services+xml
|
RustLexer
Antoine Cezar
|
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
|
r46782 | use crate::repo::Repo; | ||
Simon Sapin
|
r46647 | use crate::revlog::Node; | ||
Raphaël Gomès
|
r50832 | use crate::revlog::RevlogError; | ||
Simon Sapin
|
r48775 | |||
Arseniy Alekseyev
|
r49039 | use crate::utils::hg_path::HgPath; | ||
Antoine Cezar
|
r46112 | |||
Simon Sapin
|
r49165 | use crate::errors::HgError; | ||
Simon Sapin
|
r49166 | use crate::manifest::Manifest; | ||
use crate::manifest::ManifestEntry; | ||||
Arseniy Alekseyev
|
r49039 | use itertools::put_back; | ||
use itertools::PutBack; | ||||
use std::cmp::Ordering; | ||||
Arseniy Alekseyev
|
r49038 | |||
Arseniy Alekseyev
|
r49051 | pub struct CatOutput<'a> { | ||
Simon Sapin
|
r47478 | /// 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 | ||||
Arseniy Alekseyev
|
r49051 | pub results: Vec<(&'a HgPath, Vec<u8>)>, | ||
Simon Sapin
|
r47478 | /// Which of the CLI arguments did not match any manifest file | ||
Arseniy Alekseyev
|
r49051 | pub missing: Vec<&'a HgPath>, | ||
Simon Sapin
|
r47478 | /// The node ID that the given revset was resolved to | ||
pub node: Node, | ||||
} | ||||
Arseniy Alekseyev
|
r49039 | // Find an item in an iterator over a sorted collection. | ||
Simon Sapin
|
r49166 | fn find_item<'a>( | ||
i: &mut PutBack<impl Iterator<Item = Result<ManifestEntry<'a>, HgError>>>, | ||||
Simon Sapin
|
r49165 | needle: &HgPath, | ||
Simon Sapin
|
r49166 | ) -> Result<Option<Node>, HgError> { | ||
Arseniy Alekseyev
|
r49039 | loop { | ||
match i.next() { | ||||
Simon Sapin
|
r49165 | None => return Ok(None), | ||
Some(result) => { | ||||
Simon Sapin
|
r49166 | let entry = result?; | ||
match needle.as_bytes().cmp(entry.path.as_bytes()) { | ||||
Simon Sapin
|
r49165 | Ordering::Less => { | ||
Simon Sapin
|
r49166 | i.put_back(Ok(entry)); | ||
Simon Sapin
|
r49165 | return Ok(None); | ||
} | ||||
Ordering::Greater => continue, | ||||
Simon Sapin
|
r49166 | Ordering::Equal => return Ok(Some(entry.node_id()?)), | ||
Arseniy Alekseyev
|
r49039 | } | ||
Simon Sapin
|
r49165 | } | ||
Arseniy Alekseyev
|
r49039 | } | ||
} | ||||
} | ||||
Raphaël Gomès
|
r50820 | // Tuple of (missing, found) paths in the manifest | ||
type ManifestQueryResponse<'a> = (Vec<(&'a HgPath, Node)>, Vec<&'a HgPath>); | ||||
Simon Sapin
|
r49166 | fn find_files_in_manifest<'query>( | ||
manifest: &Manifest, | ||||
query: impl Iterator<Item = &'query HgPath>, | ||||
Raphaël Gomès
|
r50820 | ) -> Result<ManifestQueryResponse<'query>, HgError> { | ||
Simon Sapin
|
r49166 | let mut manifest = put_back(manifest.iter()); | ||
Arseniy Alekseyev
|
r49039 | let mut res = vec![]; | ||
let mut missing = vec![]; | ||||
Arseniy Alekseyev
|
r49051 | for file in query { | ||
Simon Sapin
|
r49165 | match find_item(&mut manifest, file)? { | ||
Arseniy Alekseyev
|
r49039 | None => missing.push(file), | ||
Arseniy Alekseyev
|
r49051 | Some(item) => res.push((file, item)), | ||
Arseniy Alekseyev
|
r49039 | } | ||
} | ||||
Raphaël Gomès
|
r50825 | Ok((res, missing)) | ||
Arseniy Alekseyev
|
r49039 | } | ||
Simon Sapin
|
r47478 | /// Output the given revision of files | ||
Simon Sapin
|
r46751 | /// | ||
/// * `root`: Repository root | ||||
/// * `rev`: The revision to cat the files from. | ||||
/// * `files`: The files to output. | ||||
Simon Sapin
|
r47478 | pub fn cat<'a>( | ||
Simon Sapin
|
r46782 | repo: &Repo, | ||
Simon Sapin
|
r47162 | revset: &str, | ||
Arseniy Alekseyev
|
r49051 | mut files: Vec<&'a HgPath>, | ||
) -> Result<CatOutput<'a>, RevlogError> { | ||||
Simon Sapin
|
r47162 | let rev = crate::revset::resolve_single(revset, repo)?; | ||
Simon Sapin
|
r48778 | let manifest = repo.manifest_for_rev(rev)?; | ||
Simon Sapin
|
r48774 | let node = *repo | ||
.changelog()? | ||||
Simon Sapin
|
r47478 | .node_from_rev(rev) | ||
Simon Sapin
|
r48774 | .expect("should succeed when repo.manifest did"); | ||
Arseniy Alekseyev
|
r49051 | let mut results: Vec<(&'a HgPath, Vec<u8>)> = vec![]; | ||
Simon Sapin
|
r47478 | let mut found_any = false; | ||
Arseniy Alekseyev
|
r49039 | |||
Arseniy Alekseyev
|
r49038 | files.sort_unstable(); | ||
Raphaël Gomès
|
r50825 | let (found, missing) = | ||
find_files_in_manifest(&manifest, files.into_iter())?; | ||||
Antoine Cezar
|
r46112 | |||
Simon Sapin
|
r49166 | for (file_path, file_node) in found { | ||
Arseniy Alekseyev
|
r49039 | found_any = true; | ||
Arseniy Alekseyev
|
r49051 | let file_log = repo.filelog(file_path)?; | ||
results.push(( | ||||
file_path, | ||||
Simon Sapin
|
r49372 | file_log.data_for_node(file_node)?.into_file_data()?, | ||
Arseniy Alekseyev
|
r49051 | )); | ||
Antoine Cezar
|
r46112 | } | ||
Simon Sapin
|
r47478 | Ok(CatOutput { | ||
found_any, | ||||
Arseniy Alekseyev
|
r49051 | results, | ||
Simon Sapin
|
r47478 | missing, | ||
node, | ||||
}) | ||||
Antoine Cezar
|
r46112 | } | ||