rust/hg-core/src/dirstate_tree/status.rs
author Simon Sapin <simon.sapin@octobus.net>
Fri, 28 May 2021 11:48:59 +0200
changeset 47349 7138c863d0a1
parent 47347 73ddcedeaadf
child 47350 04d1f17f49e7
permissions -rw-r--r--
dirstate-v2: Skip readdir in status based on directory mtime When calling `read_dir` during `status` and the directory is found to be eligible for caching (see code comments), write the directory’s mtime to the dirstate. The presence of a directory mtime in the dirstate is meaningful and indicates eligibility. When an eligible directory mtime is found in the dirstate and `stat()` shows that the mtime has not changed, `status` can skip calling `read_dir` again and instead rely on the names of child nodes in the dirstate tree. The `tempfile` crate is used to create a temporary file in order to use its modification time as "current time" with the same truncation as other files and directories would have in their own modification time. Differential Revision: https://phab.mercurial-scm.org/D10826
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
     1
use crate::dirstate::status::IgnoreFnType;
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
     2
use crate::dirstate_tree::dirstate_map::BorrowedPath;
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
     3
use crate::dirstate_tree::dirstate_map::ChildNodesRef;
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
     4
use crate::dirstate_tree::dirstate_map::DirstateMap;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
     5
use crate::dirstate_tree::dirstate_map::NodeData;
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
     6
use crate::dirstate_tree::dirstate_map::NodeRef;
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
     7
use crate::dirstate_tree::on_disk::DirstateV2ParseError;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
     8
use crate::dirstate_tree::on_disk::Timestamp;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
     9
use crate::dirstate_tree::path_with_basename::WithBasename;
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    10
use crate::matchers::get_ignore_function;
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    11
use crate::matchers::Matcher;
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    12
use crate::utils::files::get_bytes_from_os_string;
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
    13
use crate::utils::files::get_path_from_bytes;
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    14
use crate::utils::hg_path::HgPath;
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
    15
use crate::BadMatch;
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    16
use crate::DirstateStatus;
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    17
use crate::EntryState;
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    18
use crate::HgPathBuf;
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    19
use crate::PatternFileWarning;
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    20
use crate::StatusError;
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    21
use crate::StatusOptions;
47118
c92e63762573 dirstate-tree: Add #[timed] attribute to `status` and `DirstateMap::read`
Simon Sapin <simon.sapin@octobus.net>
parents: 47117
diff changeset
    22
use micro_timer::timed;
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
    23
use rayon::prelude::*;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    24
use std::borrow::Cow;
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    25
use std::io;
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    26
use std::path::Path;
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    27
use std::path::PathBuf;
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
    28
use std::sync::Mutex;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    29
use std::time::SystemTime;
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    30
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    31
/// Returns the status of the working directory compared to its parent
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    32
/// changeset.
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    33
///
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    34
/// This algorithm is based on traversing the filesystem tree (`fs` in function
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    35
/// and variable names) and dirstate tree at the same time. The core of this
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    36
/// traversal is the recursive `traverse_fs_directory_and_dirstate` function
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    37
/// and its use of `itertools::merge_join_by`. When reaching a path that only
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    38
/// exists in one of the two trees, depending on information requested by
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    39
/// `options` we may need to traverse the remaining subtree.
47118
c92e63762573 dirstate-tree: Add #[timed] attribute to `status` and `DirstateMap::read`
Simon Sapin <simon.sapin@octobus.net>
parents: 47117
diff changeset
    40
#[timed]
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
    41
pub fn status<'tree, 'on_disk: 'tree>(
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
    42
    dmap: &'tree mut DirstateMap<'on_disk>,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    43
    matcher: &(dyn Matcher + Sync),
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    44
    root_dir: PathBuf,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    45
    ignore_files: Vec<PathBuf>,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    46
    options: StatusOptions,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
    47
) -> Result<(DirstateStatus<'on_disk>, Vec<PatternFileWarning>), StatusError> {
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    48
    let (ignore_fn, warnings): (IgnoreFnType, _) =
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    49
        if options.list_ignored || options.list_unknown {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    50
            get_ignore_function(ignore_files, &root_dir)?
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    51
        } else {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    52
            (Box::new(|&_| true), vec![])
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    53
        };
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    54
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
    55
    let common = StatusCommon {
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
    56
        dmap,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    57
        options,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    58
        matcher,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    59
        ignore_fn,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    60
        outcome: Default::default(),
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    61
        cached_directory_mtimes_to_add: Default::default(),
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    62
        filesystem_time_at_status_start: filesystem_now(&root_dir).ok(),
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    63
    };
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    64
    let is_at_repo_root = true;
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
    65
    let hg_path = &BorrowedPath::OnDisk(HgPath::new(""));
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    66
    let has_ignored_ancestor = false;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    67
    let root_cached_mtime = None;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    68
    let root_dir_metadata = None;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    69
    // If the path we have for the repository root is a symlink, do follow it.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    70
    // (As opposed to symlinks within the working directory which are not
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    71
    // followed, using `std::fs::symlink_metadata`.)
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    72
    common.traverse_fs_directory_and_dirstate(
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    73
        has_ignored_ancestor,
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
    74
        dmap.root.as_ref(),
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    75
        hg_path,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    76
        &root_dir,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    77
        root_dir_metadata,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    78
        root_cached_mtime,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    79
        is_at_repo_root,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
    80
    )?;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    81
    let outcome = common.outcome.into_inner().unwrap();
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    82
    let to_add = common.cached_directory_mtimes_to_add.into_inner().unwrap();
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    83
    for (path, mtime) in &to_add {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    84
        let node = DirstateMap::get_or_insert_node(
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    85
            dmap.on_disk,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    86
            &mut dmap.root,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    87
            path,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    88
            WithBasename::to_cow_owned,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    89
            |_| {},
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    90
        )?;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    91
        match &node.data {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    92
            NodeData::Entry(_) => {} // Don’t overwrite an entry
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    93
            NodeData::CachedDirectory { .. } | NodeData::None => {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    94
                node.data = NodeData::CachedDirectory { mtime: *mtime }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    95
            }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    96
        }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    97
    }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
    98
    Ok((outcome, warnings))
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
    99
}
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   100
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   101
/// Bag of random things needed by various parts of the algorithm. Reduces the
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   102
/// number of parameters passed to functions.
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   103
struct StatusCommon<'a, 'tree, 'on_disk: 'tree> {
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   104
    dmap: &'tree DirstateMap<'on_disk>,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   105
    options: StatusOptions,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   106
    matcher: &'a (dyn Matcher + Sync),
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   107
    ignore_fn: IgnoreFnType<'a>,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   108
    outcome: Mutex<DirstateStatus<'on_disk>>,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   109
    cached_directory_mtimes_to_add:
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   110
        Mutex<Vec<(Cow<'on_disk, HgPath>, Timestamp)>>,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   111
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   112
    /// The current time at the start of the `status()` algorithm, as measured
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   113
    /// and possibly truncated by the filesystem.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   114
    filesystem_time_at_status_start: Option<SystemTime>,
47112
d5956136d19d dirstate-tree: Give to `status()` mutable access to the `DirstateMap`
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   115
}
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   116
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   117
impl<'a, 'tree, 'on_disk> StatusCommon<'a, 'tree, 'on_disk> {
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   118
    fn read_dir(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   119
        &self,
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   120
        hg_path: &HgPath,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   121
        fs_path: &Path,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   122
        is_at_repo_root: bool,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   123
    ) -> Result<Vec<DirEntry>, ()> {
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   124
        DirEntry::read_dir(fs_path, is_at_repo_root)
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   125
            .map_err(|error| self.io_error(error, hg_path))
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   126
    }
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   127
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   128
    fn io_error(&self, error: std::io::Error, hg_path: &HgPath) {
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   129
        let errno = error.raw_os_error().expect("expected real OS error");
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   130
        self.outcome
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   131
            .lock()
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   132
            .unwrap()
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   133
            .bad
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   134
            .push((hg_path.to_owned().into(), BadMatch::OsError(errno)))
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   135
    }
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   136
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   137
    /// If this returns true, we can get accurate results by only using
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   138
    /// `symlink_metadata` for child nodes that exist in the dirstate and don’t
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   139
    /// need to call `read_dir`.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   140
    fn can_skip_fs_readdir(
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   141
        &self,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   142
        directory_metadata: Option<&std::fs::Metadata>,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   143
        cached_directory_mtime: Option<&Timestamp>,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   144
    ) -> bool {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   145
        if !self.options.list_unknown && !self.options.list_ignored {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   146
            // All states that we care about listing have corresponding
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   147
            // dirstate entries.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   148
            // This happens for example with `hg status -mard`.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   149
            return true;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   150
        }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   151
        if let Some(cached_mtime) = cached_directory_mtime {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   152
            // The dirstate contains a cached mtime for this directory, set by
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   153
            // a previous run of the `status` algorithm which found this
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   154
            // directory eligible for `read_dir` caching.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   155
            if let Some(meta) = directory_metadata {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   156
                if let Ok(current_mtime) = meta.modified() {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   157
                    if current_mtime == cached_mtime.into() {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   158
                        // The mtime of that directory has not changed since
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   159
                        // then, which means that the
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   160
                        // results of `read_dir` should also
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   161
                        // be unchanged.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   162
                        return true;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   163
                    }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   164
                }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   165
            }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   166
        }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   167
        false
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   168
    }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   169
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   170
    /// Returns whether the filesystem directory was found to have any entry
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   171
    /// that does not have a corresponding dirstate tree node.
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   172
    fn traverse_fs_directory_and_dirstate(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   173
        &self,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   174
        has_ignored_ancestor: bool,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   175
        dirstate_nodes: ChildNodesRef<'tree, 'on_disk>,
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   176
        directory_hg_path: &BorrowedPath<'tree, 'on_disk>,
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   177
        directory_fs_path: &Path,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   178
        directory_metadata: Option<&std::fs::Metadata>,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   179
        cached_directory_mtime: Option<&Timestamp>,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   180
        is_at_repo_root: bool,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   181
    ) -> Result<bool, DirstateV2ParseError> {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   182
        if self.can_skip_fs_readdir(directory_metadata, cached_directory_mtime)
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   183
        {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   184
            dirstate_nodes
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   185
                .par_iter()
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   186
                .map(|dirstate_node| {
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   187
                    let fs_path = directory_fs_path.join(get_path_from_bytes(
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   188
                        dirstate_node.base_name(self.dmap.on_disk)?.as_bytes(),
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   189
                    ));
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   190
                    match std::fs::symlink_metadata(&fs_path) {
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   191
                        Ok(fs_metadata) => self.traverse_fs_and_dirstate(
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   192
                            &fs_path,
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   193
                            &fs_metadata,
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   194
                            dirstate_node,
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   195
                            has_ignored_ancestor,
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   196
                        ),
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   197
                        Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   198
                            self.traverse_dirstate_only(dirstate_node)
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   199
                        }
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   200
                        Err(error) => {
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   201
                            let hg_path =
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   202
                                dirstate_node.full_path(self.dmap.on_disk)?;
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   203
                            Ok(self.io_error(error, hg_path))
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   204
                        }
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   205
                    }
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   206
                })
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   207
                .collect::<Result<_, _>>()?;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   208
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   209
            // Conservatively don’t let the caller assume that there aren’t
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   210
            // any, since we don’t know.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   211
            let directory_has_any_fs_only_entry = true;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   212
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   213
            return Ok(directory_has_any_fs_only_entry);
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   214
        }
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   215
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   216
        let mut fs_entries = if let Ok(entries) = self.read_dir(
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   217
            directory_hg_path,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   218
            directory_fs_path,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   219
            is_at_repo_root,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   220
        ) {
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   221
            entries
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   222
        } else {
47346
5e12b6bfdd3e dirstate-tree: Fix status algorithm with unreadable directory
Simon Sapin <simon.sapin@octobus.net>
parents: 47338
diff changeset
   223
            // Treat an unreadable directory (typically because of insufficient
5e12b6bfdd3e dirstate-tree: Fix status algorithm with unreadable directory
Simon Sapin <simon.sapin@octobus.net>
parents: 47338
diff changeset
   224
            // permissions) like an empty directory. `self.read_dir` has
5e12b6bfdd3e dirstate-tree: Fix status algorithm with unreadable directory
Simon Sapin <simon.sapin@octobus.net>
parents: 47338
diff changeset
   225
            // already called `self.io_error` so a warning will be emitted.
5e12b6bfdd3e dirstate-tree: Fix status algorithm with unreadable directory
Simon Sapin <simon.sapin@octobus.net>
parents: 47338
diff changeset
   226
            Vec::new()
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   227
        };
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   228
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   229
        // `merge_join_by` requires both its input iterators to be sorted:
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   230
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   231
        let dirstate_nodes = dirstate_nodes.sorted();
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   232
        // `sort_unstable_by_key` doesn’t allow keys borrowing from the value:
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   233
        // https://github.com/rust-lang/rust/issues/34162
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   234
        fs_entries.sort_unstable_by(|e1, e2| e1.base_name.cmp(&e2.base_name));
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   235
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   236
        // Propagate here any error that would happen inside the comparison
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   237
        // callback below
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   238
        for dirstate_node in &dirstate_nodes {
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   239
            dirstate_node.base_name(self.dmap.on_disk)?;
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   240
        }
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   241
        itertools::merge_join_by(
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   242
            dirstate_nodes,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   243
            &fs_entries,
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   244
            |dirstate_node, fs_entry| {
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   245
                // This `unwrap` never panics because we already propagated
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   246
                // those errors above
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   247
                dirstate_node
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   248
                    .base_name(self.dmap.on_disk)
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   249
                    .unwrap()
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   250
                    .cmp(&fs_entry.base_name)
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   251
            },
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   252
        )
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   253
        .par_bridge()
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   254
        .map(|pair| {
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   255
            use itertools::EitherOrBoth::*;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   256
            let is_fs_only = pair.is_right();
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   257
            match pair {
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   258
                Both(dirstate_node, fs_entry) => self
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   259
                    .traverse_fs_and_dirstate(
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   260
                        &fs_entry.full_path,
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   261
                        &fs_entry.metadata,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   262
                        dirstate_node,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   263
                        has_ignored_ancestor,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   264
                    )?,
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   265
                Left(dirstate_node) => {
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   266
                    self.traverse_dirstate_only(dirstate_node)?
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   267
                }
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   268
                Right(fs_entry) => self.traverse_fs_only(
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   269
                    has_ignored_ancestor,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   270
                    directory_hg_path,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   271
                    fs_entry,
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   272
                ),
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   273
            }
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   274
            Ok(is_fs_only)
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   275
        })
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   276
        .try_reduce(|| false, |a, b| Ok(a || b))
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   277
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   278
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   279
    fn traverse_fs_and_dirstate(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   280
        &self,
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   281
        fs_path: &Path,
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   282
        fs_metadata: &std::fs::Metadata,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   283
        dirstate_node: NodeRef<'tree, 'on_disk>,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   284
        has_ignored_ancestor: bool,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   285
    ) -> Result<(), DirstateV2ParseError> {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   286
        let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?;
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   287
        let file_type = fs_metadata.file_type();
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   288
        let file_or_symlink = file_type.is_file() || file_type.is_symlink();
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   289
        if !file_or_symlink {
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   290
            // If we previously had a file here, it was removed (with
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   291
            // `hg rm` or similar) or deleted before it could be
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   292
            // replaced by a directory or something else.
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   293
            self.mark_removed_or_deleted_if_file(
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   294
                &hg_path,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   295
                dirstate_node.state()?,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   296
            );
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   297
        }
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   298
        if file_type.is_dir() {
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   299
            if self.options.collect_traversed_dirs {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   300
                self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   301
                    .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   302
                    .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   303
                    .traversed
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   304
                    .push(hg_path.detach_from_tree())
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   305
            }
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   306
            let is_ignored = has_ignored_ancestor || (self.ignore_fn)(hg_path);
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   307
            let is_at_repo_root = false;
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   308
            let directory_has_any_fs_only_entry = self
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   309
                .traverse_fs_directory_and_dirstate(
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   310
                    is_ignored,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   311
                    dirstate_node.children(self.dmap.on_disk)?,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   312
                    hg_path,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   313
                    fs_path,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   314
                    Some(fs_metadata),
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   315
                    dirstate_node.cached_directory_mtime(),
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   316
                    is_at_repo_root,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   317
                )?;
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   318
            self.maybe_save_directory_mtime(
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   319
                directory_has_any_fs_only_entry,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   320
                fs_metadata,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   321
                dirstate_node,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   322
            )?
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   323
        } else {
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   324
            if file_or_symlink && self.matcher.matches(hg_path) {
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   325
                if let Some(state) = dirstate_node.state()? {
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   326
                    match state {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   327
                        EntryState::Added => self
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   328
                            .outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   329
                            .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   330
                            .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   331
                            .added
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   332
                            .push(hg_path.detach_from_tree()),
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   333
                        EntryState::Removed => self
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   334
                            .outcome
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   335
                            .lock()
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   336
                            .unwrap()
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   337
                            .removed
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   338
                            .push(hg_path.detach_from_tree()),
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   339
                        EntryState::Merged => self
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   340
                            .outcome
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   341
                            .lock()
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   342
                            .unwrap()
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   343
                            .modified
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   344
                            .push(hg_path.detach_from_tree()),
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   345
                        EntryState::Normal => self
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   346
                            .handle_normal_file(&dirstate_node, fs_metadata)?,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   347
                        // This variant is not used in DirstateMap
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   348
                        // nodes
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   349
                        EntryState::Unknown => unreachable!(),
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   350
                    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   351
                } else {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   352
                    // `node.entry.is_none()` indicates a "directory"
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   353
                    // node, but the filesystem has a file
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   354
                    self.mark_unknown_or_ignored(has_ignored_ancestor, hg_path)
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   355
                }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   356
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   357
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   358
            for child_node in dirstate_node.children(self.dmap.on_disk)?.iter()
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   359
            {
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   360
                self.traverse_dirstate_only(child_node)?
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   361
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   362
        }
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   363
        Ok(())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   364
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   365
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   366
    fn maybe_save_directory_mtime(
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   367
        &self,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   368
        directory_has_any_fs_only_entry: bool,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   369
        directory_metadata: &std::fs::Metadata,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   370
        dirstate_node: NodeRef<'tree, 'on_disk>,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   371
    ) -> Result<(), DirstateV2ParseError> {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   372
        if !directory_has_any_fs_only_entry {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   373
            // All filesystem directory entries from `read_dir` have a
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   374
            // corresponding node in the dirstate, so we can reconstitute the
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   375
            // names of those entries without calling `read_dir` again.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   376
            if let (Some(status_start), Ok(directory_mtime)) = (
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   377
                &self.filesystem_time_at_status_start,
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   378
                directory_metadata.modified(),
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   379
            ) {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   380
                // Although the Rust standard library’s `SystemTime` type
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   381
                // has nanosecond precision, the times reported for a
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   382
                // directory’s (or file’s) modified time may have lower
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   383
                // resolution based on the filesystem (for example ext3
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   384
                // only stores integer seconds), kernel (see
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   385
                // https://stackoverflow.com/a/14393315/1162888), etc.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   386
                if &directory_mtime >= status_start {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   387
                    // The directory was modified too recently, don’t cache its
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   388
                    // `read_dir` results.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   389
                    //
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   390
                    // A timeline like this is possible:
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   391
                    //
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   392
                    // 1. A change to this directory (direct child was
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   393
                    //    added or removed) cause its mtime to be set
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   394
                    //    (possibly truncated) to `directory_mtime`
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   395
                    // 2. This `status` algorithm calls `read_dir`
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   396
                    // 3. An other change is made to the same directory is
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   397
                    //    made so that calling `read_dir` agin would give
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   398
                    //    different results, but soon enough after 1. that
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   399
                    //    the mtime stays the same
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   400
                    //
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   401
                    // On a system where the time resolution poor, this
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   402
                    // scenario is not unlikely if all three steps are caused
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   403
                    // by the same script.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   404
                } else {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   405
                    // We’ve observed (through `status_start`) that time has
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   406
                    // “progressed” since `directory_mtime`, so any further
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   407
                    // change to this directory is extremely likely to cause a
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   408
                    // different mtime.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   409
                    //
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   410
                    // Having the same mtime again is not entirely impossible
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   411
                    // since the system clock is not monotonous. It could jump
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   412
                    // backward to some point before `directory_mtime`, then a
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   413
                    // directory change could potentially happen during exactly
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   414
                    // the wrong tick.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   415
                    //
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   416
                    // We deem this scenario (unlike the previous one) to be
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   417
                    // unlikely enough in practice.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   418
                    let timestamp = directory_mtime.into();
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   419
                    let cached = dirstate_node.cached_directory_mtime();
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   420
                    if cached != Some(&timestamp) {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   421
                        let hg_path = dirstate_node
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   422
                            .full_path_borrowed(self.dmap.on_disk)?
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   423
                            .detach_from_tree();
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   424
                        self.cached_directory_mtimes_to_add
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   425
                            .lock()
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   426
                            .unwrap()
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   427
                            .push((hg_path, timestamp))
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   428
                    }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   429
                }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   430
            }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   431
        }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   432
        Ok(())
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   433
    }
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   434
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   435
    /// A file with `EntryState::Normal` in the dirstate was found in the
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   436
    /// filesystem
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   437
    fn handle_normal_file(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   438
        &self,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   439
        dirstate_node: &NodeRef<'tree, 'on_disk>,
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   440
        fs_metadata: &std::fs::Metadata,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   441
    ) -> Result<(), DirstateV2ParseError> {
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   442
        // Keep the low 31 bits
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   443
        fn truncate_u64(value: u64) -> i32 {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   444
            (value & 0x7FFF_FFFF) as i32
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   445
        }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   446
        fn truncate_i64(value: i64) -> i32 {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   447
            (value & 0x7FFF_FFFF) as i32
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   448
        }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   449
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   450
        let entry = dirstate_node
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   451
            .entry()?
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   452
            .expect("handle_normal_file called with entry-less node");
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   453
        let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?;
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   454
        let mode_changed =
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   455
            || self.options.check_exec && entry.mode_changed(fs_metadata);
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   456
        let size_changed = entry.size != truncate_u64(fs_metadata.len());
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   457
        if entry.size >= 0
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   458
            && size_changed
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   459
            && fs_metadata.file_type().is_symlink()
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   460
        {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   461
            // issue6456: Size returned may be longer due to encryption
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   462
            // on EXT-4 fscrypt. TODO maybe only do it on EXT4?
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   463
            self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   464
                .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   465
                .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   466
                .unsure
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   467
                .push(hg_path.detach_from_tree())
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   468
        } else if dirstate_node.has_copy_source()
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   469
            || entry.is_from_other_parent()
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   470
            || (entry.size >= 0 && (size_changed || mode_changed()))
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   471
        {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   472
            self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   473
                .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   474
                .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   475
                .modified
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   476
                .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   477
        } else {
47338
f27f2afb15da dirstate-tree: Skip readdir() in `hg status -mard`
Simon Sapin <simon.sapin@octobus.net>
parents: 47336
diff changeset
   478
            let mtime = mtime_seconds(fs_metadata);
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   479
            if truncate_i64(mtime) != entry.mtime
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   480
                || mtime == self.options.last_normal_time
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   481
            {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   482
                self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   483
                    .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   484
                    .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   485
                    .unsure
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   486
                    .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   487
            } else if self.options.list_clean {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   488
                self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   489
                    .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   490
                    .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   491
                    .clean
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   492
                    .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   493
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   494
        }
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   495
        Ok(())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   496
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   497
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   498
    /// A node in the dirstate tree has no corresponding filesystem entry
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   499
    fn traverse_dirstate_only(
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   500
        &self,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   501
        dirstate_node: NodeRef<'tree, 'on_disk>,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   502
    ) -> Result<(), DirstateV2ParseError> {
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   503
        self.mark_removed_or_deleted_if_file(
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   504
            &dirstate_node.full_path_borrowed(self.dmap.on_disk)?,
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   505
            dirstate_node.state()?,
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   506
        );
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   507
        dirstate_node
47336
8d0260d0dbc9 dirstate-v2: Make the dirstate bytes buffer available in more places
Simon Sapin <simon.sapin@octobus.net>
parents: 47335
diff changeset
   508
            .children(self.dmap.on_disk)?
47333
69530e5d4fe5 dirstate-tree: Add `NodeRef` and `ChildNodesRef` enums
Simon Sapin <simon.sapin@octobus.net>
parents: 47331
diff changeset
   509
            .par_iter()
47335
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   510
            .map(|child_node| self.traverse_dirstate_only(child_node))
ed1583a845d2 dirstate-v2: Make more APIs fallible, returning Result
Simon Sapin <simon.sapin@octobus.net>
parents: 47333
diff changeset
   511
            .collect()
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   512
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   513
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   514
    /// A node in the dirstate tree has no corresponding *file* on the
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   515
    /// filesystem
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   516
    ///
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   517
    /// Does nothing on a "directory" node
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   518
    fn mark_removed_or_deleted_if_file(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   519
        &self,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   520
        hg_path: &BorrowedPath<'tree, 'on_disk>,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   521
        dirstate_node_state: Option<EntryState>,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   522
    ) {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   523
        if let Some(state) = dirstate_node_state {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   524
            if self.matcher.matches(hg_path) {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   525
                if let EntryState::Removed = state {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   526
                    self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   527
                        .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   528
                        .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   529
                        .removed
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   530
                        .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   531
                } else {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   532
                    self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   533
                        .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   534
                        .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   535
                        .deleted
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   536
                        .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   537
                }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   538
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   539
        }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   540
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   541
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   542
    /// Something in the filesystem has no corresponding dirstate node
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   543
    fn traverse_fs_only(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   544
        &self,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   545
        has_ignored_ancestor: bool,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   546
        directory_hg_path: &HgPath,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   547
        fs_entry: &DirEntry,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   548
    ) {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   549
        let hg_path = directory_hg_path.join(&fs_entry.base_name);
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   550
        let file_type = fs_entry.metadata.file_type();
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   551
        let file_or_symlink = file_type.is_file() || file_type.is_symlink();
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   552
        if file_type.is_dir() {
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   553
            let is_ignored =
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   554
                has_ignored_ancestor || (self.ignore_fn)(&hg_path);
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   555
            let traverse_children = if is_ignored {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   556
                // Descendants of an ignored directory are all ignored
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   557
                self.options.list_ignored
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   558
            } else {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   559
                // Descendants of an unknown directory may be either unknown or
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   560
                // ignored
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   561
                self.options.list_unknown || self.options.list_ignored
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   562
            };
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   563
            if traverse_children {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   564
                let is_at_repo_root = false;
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   565
                if let Ok(children_fs_entries) = self.read_dir(
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   566
                    &hg_path,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   567
                    &fs_entry.full_path,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   568
                    is_at_repo_root,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   569
                ) {
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   570
                    children_fs_entries.par_iter().for_each(|child_fs_entry| {
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   571
                        self.traverse_fs_only(
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   572
                            is_ignored,
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   573
                            &hg_path,
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   574
                            child_fs_entry,
47115
1b4f0f819f92 dirstate-tree: Handle I/O errors in status
Simon Sapin <simon.sapin@octobus.net>
parents: 47114
diff changeset
   575
                        )
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   576
                    })
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   577
                }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   578
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   579
            if self.options.collect_traversed_dirs {
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   580
                self.outcome.lock().unwrap().traversed.push(hg_path.into())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   581
            }
47114
aeb03758f37a dirstate-tree: Ignore FIFOs etc. in the status algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47113
diff changeset
   582
        } else if file_or_symlink && self.matcher.matches(&hg_path) {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   583
            self.mark_unknown_or_ignored(
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   584
                has_ignored_ancestor,
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   585
                &BorrowedPath::InMemory(&hg_path),
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   586
            )
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   587
        }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   588
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   589
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   590
    fn mark_unknown_or_ignored(
47117
60d852ae7e7b dirstate-tree: Paralellize the status algorithm with Rayon
Simon Sapin <simon.sapin@octobus.net>
parents: 47115
diff changeset
   591
        &self,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   592
        has_ignored_ancestor: bool,
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   593
        hg_path: &BorrowedPath<'_, 'on_disk>,
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   594
    ) {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   595
        let is_ignored = has_ignored_ancestor || (self.ignore_fn)(&hg_path);
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   596
        if is_ignored {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   597
            if self.options.list_ignored {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   598
                self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   599
                    .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   600
                    .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   601
                    .ignored
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   602
                    .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   603
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   604
        } else {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   605
            if self.options.list_unknown {
47347
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   606
                self.outcome
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   607
                    .lock()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   608
                    .unwrap()
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   609
                    .unknown
73ddcedeaadf dirstate-tree: Change status() results to not borrow DirstateMap
Simon Sapin <simon.sapin@octobus.net>
parents: 47346
diff changeset
   610
                    .push(hg_path.detach_from_tree())
47113
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   611
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   612
        }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   613
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   614
}
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   615
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   616
#[cfg(unix)] // TODO
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   617
fn mtime_seconds(metadata: &std::fs::Metadata) -> i64 {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   618
    // Going through `Metadata::modified()` would be portable, but would take
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   619
    // care to construct a `SystemTime` value with sub-second precision just
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   620
    // for us to throw that away here.
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   621
    use std::os::unix::fs::MetadataExt;
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   622
    metadata.mtime()
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   623
}
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   624
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   625
struct DirEntry {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   626
    base_name: HgPathBuf,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   627
    full_path: PathBuf,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   628
    metadata: std::fs::Metadata,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   629
}
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   630
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   631
impl DirEntry {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   632
    /// Returns **unsorted** entries in the given directory, with name and
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   633
    /// metadata.
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   634
    ///
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   635
    /// If a `.hg` sub-directory is encountered:
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   636
    ///
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   637
    /// * At the repository root, ignore that sub-directory
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   638
    /// * Elsewhere, we’re listing the content of a sub-repo. Return an empty
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   639
    ///   list instead.
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   640
    fn read_dir(path: &Path, is_at_repo_root: bool) -> io::Result<Vec<Self>> {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   641
        let mut results = Vec::new();
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   642
        for entry in path.read_dir()? {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   643
            let entry = entry?;
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   644
            let metadata = entry.metadata()?;
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   645
            let name = get_bytes_from_os_string(entry.file_name());
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   646
            // FIXME don't do this when cached
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   647
            if name == b".hg" {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   648
                if is_at_repo_root {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   649
                    // Skip the repo’s own .hg (might be a symlink)
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   650
                    continue;
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   651
                } else if metadata.is_dir() {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   652
                    // A .hg sub-directory at another location means a subrepo,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   653
                    // skip it entirely.
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   654
                    return Ok(Vec::new());
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   655
                }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   656
            }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   657
            results.push(DirEntry {
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   658
                base_name: name.into(),
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   659
                full_path: entry.path(),
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   660
                metadata,
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   661
            })
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   662
        }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   663
        Ok(results)
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   664
    }
be579775c2d9 dirstate-tree: Add the new `status()` algorithm
Simon Sapin <simon.sapin@octobus.net>
parents: 47112
diff changeset
   665
}
47349
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   666
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   667
/// Return the `mtime` of a temporary file newly-created in the `.hg` directory
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   668
/// of the give repository.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   669
///
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   670
/// This is similar to `SystemTime::now()`, with the result truncated to the
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   671
/// same time resolution as other files’ modification times. Using `.hg`
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   672
/// instead of the system’s default temporary directory (such as `/tmp`) makes
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   673
/// it more likely the temporary file is in the same disk partition as contents
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   674
/// of the working directory, which can matter since different filesystems may
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   675
/// store timestamps with different resolutions.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   676
///
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   677
/// This may fail, typically if we lack write permissions. In that case we
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   678
/// should continue the `status()` algoritm anyway and consider the current
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   679
/// date/time to be unknown.
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   680
fn filesystem_now(repo_root: &Path) -> Result<SystemTime, io::Error> {
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   681
    tempfile::tempfile_in(repo_root.join(".hg"))?
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   682
        .metadata()?
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   683
        .modified()
7138c863d0a1 dirstate-v2: Skip readdir in status based on directory mtime
Simon Sapin <simon.sapin@octobus.net>
parents: 47347
diff changeset
   684
}