rust/hg-core/src/operations/cat.rs
author Matt Harbison <matt_harbison@yahoo.com>
Mon, 18 Apr 2022 16:18:33 -0400
changeset 49136 a7fe96abcf56
parent 48569 20d0d896183e
child 49998 49131579db62
permissions -rw-r--r--
packaging: fix the type hint on the download_entry function Flagged by PyCharm. Differential Revision: https://phab.mercurial-scm.org/D12571
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
45547
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     1
// list_tracked_files.rs
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     2
//
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     3
// Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net>
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     4
//
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     5
// This software may be used and distributed according to the terms of the
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     6
// GNU General Public License version 2 or any later version.
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     7
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents: 46136
diff changeset
     8
use crate::repo::Repo;
45547
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
     9
use crate::revlog::revlog::RevlogError;
46037
88e741bf2d93 rust: use NodePrefix::from_hex instead of hex::decode directly
Simon Sapin <simon-commits@exyr.org>
parents: 46036
diff changeset
    10
use crate::revlog::Node;
47989
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47988
diff changeset
    11
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    12
use crate::utils::hg_path::HgPath;
45547
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
    13
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    14
use crate::errors::HgError;
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    15
use crate::manifest::Manifest;
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    16
use crate::manifest::ManifestEntry;
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    17
use itertools::put_back;
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    18
use itertools::PutBack;
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    19
use std::cmp::Ordering;
48236
6b5773f89183 rhg: faster hg cat when many files are requested
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47997
diff changeset
    20
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    21
pub struct CatOutput<'a> {
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    22
    /// Whether any file in the manifest matched the paths given as CLI
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    23
    /// arguments
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    24
    pub found_any: bool,
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    25
    /// The contents of matching files, in manifest order
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    26
    pub results: Vec<(&'a HgPath, Vec<u8>)>,
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    27
    /// Which of the CLI arguments did not match any manifest file
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    28
    pub missing: Vec<&'a HgPath>,
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    29
    /// The node ID that the given revset was resolved to
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    30
    pub node: Node,
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    31
}
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    32
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    33
// Find an item in an iterator over a sorted collection.
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    34
fn find_item<'a>(
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    35
    i: &mut PutBack<impl Iterator<Item = Result<ManifestEntry<'a>, HgError>>>,
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    36
    needle: &HgPath,
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    37
) -> Result<Option<Node>, HgError> {
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    38
    loop {
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    39
        match i.next() {
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    40
            None => return Ok(None),
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    41
            Some(result) => {
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    42
                let entry = result?;
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    43
                match needle.as_bytes().cmp(entry.path.as_bytes()) {
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    44
                    Ordering::Less => {
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    45
                        i.put_back(Ok(entry));
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    46
                        return Ok(None);
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    47
                    }
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    48
                    Ordering::Greater => continue,
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    49
                    Ordering::Equal => return Ok(Some(entry.node_id()?)),
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    50
                }
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    51
            }
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    52
        }
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    53
    }
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    54
}
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    55
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    56
fn find_files_in_manifest<'query>(
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    57
    manifest: &Manifest,
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    58
    query: impl Iterator<Item = &'query HgPath>,
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    59
) -> Result<(Vec<(&'query HgPath, Node)>, Vec<&'query HgPath>), HgError> {
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    60
    let mut manifest = put_back(manifest.iter());
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    61
    let mut res = vec![];
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    62
    let mut missing = vec![];
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    63
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    64
    for file in query {
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    65
        match find_item(&mut manifest, file)? {
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    66
            None => missing.push(file),
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    67
            Some(item) => res.push((file, item)),
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    68
        }
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    69
    }
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    70
    return Ok((res, missing));
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    71
}
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    72
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    73
/// Output the given revision of files
46136
dca9cb99971c rust: replace most "operation" structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46135
diff changeset
    74
///
dca9cb99971c rust: replace most "operation" structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46135
diff changeset
    75
/// * `root`: Repository root
dca9cb99971c rust: replace most "operation" structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46135
diff changeset
    76
/// * `rev`: The revision to cat the files from.
dca9cb99971c rust: replace most "operation" structs with functions
Simon Sapin <simon.sapin@octobus.net>
parents: 46135
diff changeset
    77
/// * `files`: The files to output.
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    78
pub fn cat<'a>(
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents: 46136
diff changeset
    79
    repo: &Repo,
46501
4b381dbbf8b7 rhg: centralize parsing of `--rev` CLI arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
    80
    revset: &str,
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    81
    mut files: Vec<&'a HgPath>,
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    82
) -> Result<CatOutput<'a>, RevlogError> {
46501
4b381dbbf8b7 rhg: centralize parsing of `--rev` CLI arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46499
diff changeset
    83
    let rev = crate::revset::resolve_single(revset, repo)?;
47992
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47989
diff changeset
    84
    let manifest = repo.manifest_for_rev(rev)?;
47988
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47987
diff changeset
    85
    let node = *repo
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47987
diff changeset
    86
        .changelog()?
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    87
        .node_from_rev(rev)
47988
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47987
diff changeset
    88
        .expect("should succeed when repo.manifest did");
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    89
    let mut results: Vec<(&'a HgPath, Vec<u8>)> = vec![];
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
    90
    let mut found_any = false;
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    91
48236
6b5773f89183 rhg: faster hg cat when many files are requested
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47997
diff changeset
    92
    files.sort_unstable();
6b5773f89183 rhg: faster hg cat when many files are requested
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 47997
diff changeset
    93
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
    94
    let (found, missing) = find_files_in_manifest(
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    95
        &manifest,
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
    96
        files.into_iter().map(|f| f.as_ref()),
48391
10c32e1b892a rhg: Propogate manifest parse errors instead of panicking
Simon Sapin <simon.sapin@octobus.net>
parents: 48249
diff changeset
    97
    )?;
45547
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
    98
48392
eb428010aad2 rhg: Also parse flags in the manifest parser
Simon Sapin <simon.sapin@octobus.net>
parents: 48391
diff changeset
    99
    for (file_path, file_node) in found {
48237
0cc69017d47f rhg: stop manifest traversal when no more files are needed
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48236
diff changeset
   100
        found_any = true;
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
   101
        let file_log = repo.filelog(file_path)?;
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
   102
        results.push((
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
   103
            file_path,
48569
20d0d896183e rhg: Rename some revlog-related types and methods
Simon Sapin <simon.sapin@octobus.net>
parents: 48392
diff changeset
   104
            file_log.data_for_node(file_node)?.into_file_data()?,
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
   105
        ));
45547
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
   106
    }
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
   107
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
   108
    Ok(CatOutput {
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
   109
        found_any,
48249
027ebad952ac rhg: internally, return a structured representation from hg cat
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48246
diff changeset
   110
        results,
46757
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
   111
        missing,
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
   112
        node,
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
   113
    })
45547
522ec3dc44b9 hg-core: add a `CatRev` operation
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
   114
}