cat.rs
115 lines
| 3.1 KiB
| application/rls-services+xml
|
RustLexer
|
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. | ||||
|
r46782 | use crate::repo::Repo; | ||
|
r46112 | use crate::revlog::revlog::RevlogError; | ||
|
r46647 | use crate::revlog::Node; | ||
|
r48775 | |||
|
r49039 | use crate::utils::hg_path::HgPath; | ||
|
r46112 | |||
|
r49039 | use itertools::put_back; | ||
use itertools::PutBack; | ||||
use std::cmp::Ordering; | ||||
|
r49038 | |||
|
r49051 | pub struct CatOutput<'a> { | ||
|
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 | ||||
|
r49051 | pub results: Vec<(&'a HgPath, Vec<u8>)>, | ||
|
r47478 | /// Which of the CLI arguments did not match any manifest file | ||
|
r49051 | pub missing: Vec<&'a HgPath>, | ||
|
r47478 | /// The node ID that the given revset was resolved to | ||
pub node: Node, | ||||
} | ||||
|
r49039 | // Find an item in an iterator over a sorted collection. | ||
fn find_item<'a, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>( | ||||
i: &mut PutBack<I>, | ||||
needle: &'b HgPath, | ||||
|
r49051 | ) -> Option<D> { | ||
|
r49039 | loop { | ||
match i.next() { | ||||
None => return None, | ||||
Some(val) => match needle.as_bytes().cmp(val.0.as_bytes()) { | ||||
Ordering::Less => { | ||||
i.put_back(val); | ||||
return None; | ||||
} | ||||
Ordering::Greater => continue, | ||||
|
r49051 | Ordering::Equal => return Some(val.1), | ||
|
r49039 | }, | ||
} | ||||
} | ||||
} | ||||
fn find_files_in_manifest< | ||||
|
r49051 | 'manifest, | ||
'query, | ||||
Data, | ||||
Manifest: Iterator<Item = (&'manifest HgPath, Data)>, | ||||
Query: Iterator<Item = &'query HgPath>, | ||||
|
r49039 | >( | ||
|
r49051 | manifest: Manifest, | ||
query: Query, | ||||
) -> (Vec<(&'query HgPath, Data)>, Vec<&'query HgPath>) { | ||||
|
r49039 | let mut manifest = put_back(manifest); | ||
let mut res = vec![]; | ||||
let mut missing = vec![]; | ||||
|
r49051 | for file in query { | ||
|
r49039 | match find_item(&mut manifest, file) { | ||
None => missing.push(file), | ||||
|
r49051 | Some(item) => res.push((file, item)), | ||
|
r49039 | } | ||
} | ||||
return (res, missing); | ||||
} | ||||
|
r47478 | /// Output the given revision of files | ||
|
r46751 | /// | ||
/// * `root`: Repository root | ||||
/// * `rev`: The revision to cat the files from. | ||||
/// * `files`: The files to output. | ||||
|
r47478 | pub fn cat<'a>( | ||
|
r46782 | repo: &Repo, | ||
|
r47162 | revset: &str, | ||
|
r49051 | mut files: Vec<&'a HgPath>, | ||
) -> Result<CatOutput<'a>, RevlogError> { | ||||
|
r47162 | let rev = crate::revset::resolve_single(revset, repo)?; | ||
|
r48778 | let manifest = repo.manifest_for_rev(rev)?; | ||
|
r48774 | let node = *repo | ||
.changelog()? | ||||
|
r47478 | .node_from_rev(rev) | ||
|
r48774 | .expect("should succeed when repo.manifest did"); | ||
|
r49051 | let mut results: Vec<(&'a HgPath, Vec<u8>)> = vec![]; | ||
|
r47478 | let mut found_any = false; | ||
|
r49039 | |||
|
r49038 | files.sort_unstable(); | ||
|
r49039 | let (found, missing) = find_files_in_manifest( | ||
manifest.files_with_nodes(), | ||||
|
r49051 | files.into_iter().map(|f| f.as_ref()), | ||
|
r49039 | ); | ||
|
r46112 | |||
|
r49051 | for (file_path, node_bytes) in found { | ||
|
r49039 | found_any = true; | ||
|
r49051 | let file_log = repo.filelog(file_path)?; | ||
|
r49039 | let file_node = Node::from_hex_for_repo(node_bytes)?; | ||
|
r49051 | results.push(( | ||
file_path, | ||||
file_log.data_for_node(file_node)?.into_data()?, | ||||
)); | ||||
|
r46112 | } | ||
|
r47478 | Ok(CatOutput { | ||
found_any, | ||||
|
r49051 | results, | ||
|
r47478 | missing, | ||
node, | ||||
}) | ||||
|
r46112 | } | ||