rust/hg-core/src/repo.rs
author Rapha?l Gom?s <rgomes@octobus.net>
Mon, 06 Nov 2023 11:06:08 +0100
changeset 51117 532e74ad3ff6
parent 50974 1928b770e3e7
child 51188 13f58ce70299
permissions -rw-r--r--
rust: run a clippy pass with the latest stable version Our current version of clippy is older than the latest stable. The newest version has new lints that are moslty good advice, so let's apply them ahead of time. This has the added benefit of reducing the noise for developpers like myself that use clippy as an IDE helper, as well as being more prepared for a future clippy upgrade.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
     1
use crate::changelog::Changelog;
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
     2
use crate::config::{Config, ConfigError, ConfigParseError};
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
     3
use crate::dirstate::DirstateParents;
50221
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
     4
use crate::dirstate_tree::dirstate_map::DirstateMapWriteMode;
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
     5
use crate::dirstate_tree::on_disk::Docket as DirstateDocket;
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
     6
use crate::dirstate_tree::owning::OwningDirstateMap;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
     7
use crate::errors::HgResultExt;
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
     8
use crate::errors::{HgError, IoResultExt};
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
     9
use crate::lock::{try_with_lock_no_wait, LockError};
47960
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47959
diff changeset
    10
use crate::manifest::{Manifest, Manifestlog};
47961
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47960
diff changeset
    11
use crate::revlog::filelog::Filelog;
49937
750409505286 rust-clippy: merge "revlog" module definition and struct implementation
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
    12
use crate::revlog::RevlogError;
50228
fc8e37c380d3 dirstate: add a synchronisation point before doing a full dirstate read
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50227
diff changeset
    13
use crate::utils::debug::debug_wait_for_file_or_print;
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
    14
use crate::utils::files::get_path_from_bytes;
47961
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47960
diff changeset
    15
use crate::utils::hg_path::HgPath;
46740
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46735
diff changeset
    16
use crate::utils::SliceExt;
47952
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
    17
use crate::vfs::{is_dir, is_file, Vfs};
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50657
diff changeset
    18
use crate::DirstateError;
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50657
diff changeset
    19
use crate::{requirements, NodePrefix, UncheckedRevision};
48419
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
    20
use std::cell::{Ref, RefCell, RefMut};
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
    21
use std::collections::HashSet;
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
    22
use std::io::Seek;
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
    23
use std::io::SeekFrom;
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
    24
use std::io::Write as IoWrite;
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    25
use std::path::{Path, PathBuf};
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    26
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
    27
const V2_MAX_READ_ATTEMPTS: usize = 5;
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
    28
50252
a6b8b1ab9116 branching: merge stable into default
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 49937 50245
diff changeset
    29
type DirstateMapIdentity = (Option<u64>, Option<Vec<u8>>, usize);
a6b8b1ab9116 branching: merge stable into default
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 49937 50245
diff changeset
    30
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    31
/// A repository on disk
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    32
pub struct Repo {
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    33
    working_directory: PathBuf,
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    34
    dot_hg: PathBuf,
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    35
    store: PathBuf,
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
    36
    requirements: HashSet<String>,
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    37
    config: Config,
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
    38
    dirstate_parents: LazyCell<DirstateParents>,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
    39
    dirstate_map: LazyCell<OwningDirstateMap>,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
    40
    changelog: LazyCell<Changelog>,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
    41
    manifestlog: LazyCell<Manifestlog>,
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    42
}
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    43
46446
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
    44
#[derive(Debug, derive_more::From)]
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    45
pub enum RepoError {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    46
    NotFound {
46503
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    47
        at: PathBuf,
46446
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
    48
    },
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
    49
    #[from]
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    50
    ConfigParseError(ConfigParseError),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    51
    #[from]
46446
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
    52
    Other(HgError),
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
    53
}
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
    54
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    55
impl From<ConfigError> for RepoError {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    56
    fn from(error: ConfigError) -> Self {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    57
        match error {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    58
            ConfigError::Parse(error) => error.into(),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    59
            ConfigError::Other(error) => error.into(),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    60
        }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    61
    }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    62
}
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
    63
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
    64
impl Repo {
47405
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    65
    /// tries to find nearest repository root in current working directory or
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    66
    /// its ancestors
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    67
    pub fn find_repo_root() -> Result<PathBuf, RepoError> {
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    68
        let current_directory = crate::utils::current_dir()?;
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    69
        // ancestors() is inclusive: it first yields `current_directory`
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    70
        // as-is.
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    71
        for ancestor in current_directory.ancestors() {
47780
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
    72
            if is_dir(ancestor.join(".hg"))? {
47405
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    73
                return Ok(ancestor.to_path_buf());
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    74
            }
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    75
        }
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
    76
        Err(RepoError::NotFound {
47405
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    77
            at: current_directory,
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
    78
        })
47405
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    79
    }
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
    80
46505
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    81
    /// Find a repository, either at the given path (which must contain a `.hg`
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    82
    /// sub-directory) or by searching the current directory and its
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    83
    /// ancestors.
46503
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    84
    ///
46505
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    85
    /// A method with two very different "modes" like this usually a code smell
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    86
    /// to make two methods instead, but in this case an `Option` is what rhg
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    87
    /// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46503
diff changeset
    88
    /// Having two methods would just move that `if` to almost all callers.
46503
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    89
    pub fn find(
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    90
        config: &Config,
47404
ebdef6283798 rhg: read [paths] for `--repository` value
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47374
diff changeset
    91
        explicit_path: Option<PathBuf>,
46503
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    92
    ) -> Result<Self, RepoError> {
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    93
        if let Some(root) = explicit_path {
47780
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
    94
            if is_dir(root.join(".hg"))? {
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
    95
                Self::new_at_path(root, config)
47780
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
    96
            } else if is_file(&root)? {
46730
dfd35823635b rhg: Fall back to Python for bundle repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46728
diff changeset
    97
                Err(HgError::unsupported("bundle repository").into())
46503
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
    98
            } else {
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
    99
                Err(RepoError::NotFound { at: root })
46446
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
   100
            }
46503
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46486
diff changeset
   101
        } else {
47405
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
   102
            let root = Self::find_repo_root()?;
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47404
diff changeset
   103
            Self::new_at_path(root, config)
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   104
        }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   105
    }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   106
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   107
    /// To be called after checking that `.hg` is a sub-directory
46485
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
   108
    fn new_at_path(
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
   109
        working_directory: PathBuf,
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46484
diff changeset
   110
        config: &Config,
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   111
    ) -> Result<Self, RepoError> {
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   112
        let dot_hg = working_directory.join(".hg");
46463
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   113
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
   114
        let mut repo_config_files =
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
   115
            vec![dot_hg.join("hgrc"), dot_hg.join("hgrc-not-shared")];
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   116
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   117
        let hg_vfs = Vfs { base: &dot_hg };
46463
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   118
        let mut reqs = requirements::load_if_exists(hg_vfs)?;
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   119
        let relative =
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   120
            reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   121
        let shared =
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   122
            reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
46463
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   123
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   124
        // From `mercurial/localrepo.py`:
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   125
        //
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   126
        // if .hg/requires contains the sharesafe requirement, it means
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   127
        // there exists a `.hg/store/requires` too and we should read it
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   128
        // NOTE: presence of SHARESAFE_REQUIREMENT imply that store requirement
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   129
        // is present. We never write SHARESAFE_REQUIREMENT for a repo if store
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   130
        // is not present, refer checkrequirementscompat() for that
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   131
        //
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   132
        // However, if SHARESAFE_REQUIREMENT is not present, it means that the
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   133
        // repository was shared the old way. We check the share source
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   134
        // .hg/requires for SHARESAFE_REQUIREMENT to detect whether the
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   135
        // current repository needs to be reshared
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   136
        let share_safe = reqs.contains(requirements::SHARESAFE_REQUIREMENT);
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   137
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   138
        let store_path;
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   139
        if !shared {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   140
            store_path = dot_hg.join("store");
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   141
        } else {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   142
            let bytes = hg_vfs.read("sharedpath")?;
46669
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46613
diff changeset
   143
            let mut shared_path =
47949
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 47780
diff changeset
   144
                get_path_from_bytes(bytes.trim_end_matches(|b| b == b'\n'))
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 47780
diff changeset
   145
                    .to_owned();
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   146
            if relative {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   147
                shared_path = dot_hg.join(shared_path)
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   148
            }
47780
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
   149
            if !is_dir(&shared_path)? {
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   150
                return Err(HgError::corrupted(format!(
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   151
                    ".hg/sharedpath points to nonexistent directory {}",
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   152
                    shared_path.display()
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   153
                ))
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   154
                .into());
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   155
            }
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   156
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   157
            store_path = shared_path.join("store");
46463
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   158
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   159
            let source_is_share_safe =
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   160
                requirements::load(Vfs { base: &shared_path })?
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   161
                    .contains(requirements::SHARESAFE_REQUIREMENT);
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   162
48809
1d5fd9def5ac rhg: simplify the handling of share-safe config mismatch
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48510
diff changeset
   163
            if share_safe != source_is_share_safe {
1d5fd9def5ac rhg: simplify the handling of share-safe config mismatch
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48510
diff changeset
   164
                return Err(HgError::unsupported("share-safe mismatch").into());
46463
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
   165
            }
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   166
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   167
            if share_safe {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   168
                repo_config_files.insert(0, shared_path.join("hgrc"))
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   169
            }
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   170
        }
46613
f64b6953db70 rhg: Bug fix: with share-safe, always read store requirements
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   171
        if share_safe {
f64b6953db70 rhg: Bug fix: with share-safe, always read store requirements
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   172
            reqs.extend(requirements::load(Vfs { base: &store_path })?);
f64b6953db70 rhg: Bug fix: with share-safe, always read store requirements
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   173
        }
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   174
46741
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46740
diff changeset
   175
        let repo_config = if std::env::var_os("HGRCSKIPREPO").is_none() {
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46740
diff changeset
   176
            config.combine_with_repo(&repo_config_files)?
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46740
diff changeset
   177
        } else {
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46740
diff changeset
   178
            config.clone()
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46740
diff changeset
   179
        };
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   180
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   181
        let repo = Self {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   182
            requirements: reqs,
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   183
            working_directory,
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   184
            store: store_path,
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   185
            dot_hg,
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   186
            config: repo_config,
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   187
            dirstate_parents: LazyCell::new(),
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   188
            dirstate_map: LazyCell::new(),
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   189
            changelog: LazyCell::new(),
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   190
            manifestlog: LazyCell::new(),
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   191
        };
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   192
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   193
        requirements::check(&repo)?;
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   194
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   195
        Ok(repo)
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   196
    }
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   197
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   198
    pub fn working_directory_path(&self) -> &Path {
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   199
        &self.working_directory
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   200
    }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   201
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   202
    pub fn requirements(&self) -> &HashSet<String> {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   203
        &self.requirements
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   204
    }
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46446
diff changeset
   205
46486
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   206
    pub fn config(&self) -> &Config {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   207
        &self.config
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   208
    }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46485
diff changeset
   209
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   210
    /// For accessing repository files (in `.hg`), except for the store
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   211
    /// (`.hg/store`).
46599
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents: 46593
diff changeset
   212
    pub fn hg_vfs(&self) -> Vfs<'_> {
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   213
        Vfs { base: &self.dot_hg }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   214
    }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   215
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   216
    /// For accessing repository store files (in `.hg/store`)
46599
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents: 46593
diff changeset
   217
    pub fn store_vfs(&self) -> Vfs<'_> {
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   218
        Vfs { base: &self.store }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   219
    }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   220
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   221
    /// For accessing the working copy
46822
c71e8d9e7f2a rhg: Initial support for the 'status' command
Georges Racinet <georges.racinet@octobus.net>
parents: 46741
diff changeset
   222
    pub fn working_directory_vfs(&self) -> Vfs<'_> {
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   223
        Vfs {
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   224
            base: &self.working_directory,
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   225
        }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   226
    }
46601
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46599
diff changeset
   227
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   228
    pub fn try_with_wlock_no_wait<R>(
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   229
        &self,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   230
        f: impl FnOnce() -> R,
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   231
    ) -> Result<R, LockError> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   232
        try_with_lock_no_wait(self.hg_vfs(), "wlock", f)
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   233
    }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 48409
diff changeset
   234
50655
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   235
    /// Whether this repo should use dirstate-v2.
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   236
    /// The presence of `dirstate-v2` in the requirements does not mean that
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   237
    /// the on-disk dirstate is necessarily in version 2. In most cases,
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   238
    /// a dirstate-v2 file will indeed be found, but in rare cases (like the
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   239
    /// upgrade mechanism being cut short), the on-disk version will be a
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   240
    /// v1 file.
50657
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   241
    /// Semantically, having a requirement only means that a client cannot
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   242
    /// properly understand or properly update the repo if it lacks the support
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   243
    /// for the required feature, but not that that feature is actually used
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   244
    /// in all occasions.
50655
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   245
    pub fn use_dirstate_v2(&self) -> bool {
47374
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
   246
        self.requirements
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
   247
            .contains(requirements::DIRSTATE_V2_REQUIREMENT)
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
   248
    }
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
   249
48409
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   250
    pub fn has_sparse(&self) -> bool {
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   251
        self.requirements.contains(requirements::SPARSE_REQUIREMENT)
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   252
    }
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   253
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   254
    pub fn has_narrow(&self) -> bool {
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   255
        self.requirements.contains(requirements::NARROW_REQUIREMENT)
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   256
    }
005ae1a343f8 rhg: add support for narrow clones and sparse checkouts
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 48069
diff changeset
   257
49091
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   258
    pub fn has_nodemap(&self) -> bool {
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   259
        self.requirements
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   260
            .contains(requirements::NODEMAP_REQUIREMENT)
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   261
    }
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   262
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   263
    fn dirstate_file_contents(&self) -> Result<Vec<u8>, HgError> {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   264
        Ok(self
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   265
            .hg_vfs()
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   266
            .read("dirstate")
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   267
            .io_not_found_as_none()?
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
   268
            .unwrap_or_default())
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   269
    }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   270
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   271
    fn dirstate_identity(&self) -> Result<Option<u64>, HgError> {
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   272
        use std::os::unix::fs::MetadataExt;
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   273
        Ok(self
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   274
            .hg_vfs()
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   275
            .symlink_metadata("dirstate")
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   276
            .io_not_found_as_none()?
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   277
            .map(|meta| meta.ino()))
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   278
    }
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   279
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   280
    pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   281
        Ok(*self
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   282
            .dirstate_parents
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   283
            .get_or_init(|| self.read_dirstate_parents())?)
48419
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   284
    }
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   285
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   286
    fn read_dirstate_parents(&self) -> Result<DirstateParents, HgError> {
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   287
        let dirstate = self.dirstate_file_contents()?;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   288
        let parents = if dirstate.is_empty() {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   289
            DirstateParents::NULL
50655
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   290
        } else if self.use_dirstate_v2() {
50657
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   291
            let docket_res =
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   292
                crate::dirstate_tree::on_disk::read_docket(&dirstate);
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   293
            match docket_res {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   294
                Ok(docket) => docket.parents(),
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   295
                Err(_) => {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   296
                    log::info!(
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   297
                        "Parsing dirstate docket failed, \
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   298
                        falling back to dirstate-v1"
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   299
                    );
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   300
                    *crate::dirstate::parsers::parse_dirstate_parents(
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   301
                        &dirstate,
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   302
                    )?
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   303
                }
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   304
            }
47374
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
   305
        } else {
49930
e98fd81bb151 rust-clippy: fix most warnings in `hg-core`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49217
diff changeset
   306
            *crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?
47374
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
   307
        };
48419
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   308
        self.dirstate_parents.set(parents);
47674
ff97e793ed36 dirstate-v2: Introduce a docket file
Simon Sapin <simon.sapin@octobus.net>
parents: 47407
diff changeset
   309
        Ok(parents)
46601
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46599
diff changeset
   310
    }
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   311
50244
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   312
    /// Returns the information read from the dirstate docket necessary to
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   313
    /// check if the data file has been updated/deleted by another process
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   314
    /// since we last read the dirstate.
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   315
    /// Namely, the inode, data file uuid and the data size.
50244
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   316
    fn get_dirstate_data_file_integrity(
48420
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   317
        &self,
50252
a6b8b1ab9116 branching: merge stable into default
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 49937 50245
diff changeset
   318
    ) -> Result<DirstateMapIdentity, HgError> {
48420
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   319
        assert!(
50655
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   320
            self.use_dirstate_v2(),
48420
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   321
            "accessing dirstate data file ID without dirstate-v2"
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   322
        );
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   323
        // Get the identity before the contents since we could have a race
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   324
        // between the two. Having an identity that is too old is fine, but
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   325
        // one that is younger than the content change is bad.
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   326
        let identity = self.dirstate_identity()?;
48420
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   327
        let dirstate = self.dirstate_file_contents()?;
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   328
        if dirstate.is_empty() {
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   329
            self.dirstate_parents.set(DirstateParents::NULL);
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   330
            Ok((identity, None, 0))
48420
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   331
        } else {
50657
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   332
            let docket_res =
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   333
                crate::dirstate_tree::on_disk::read_docket(&dirstate);
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   334
            match docket_res {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   335
                Ok(docket) => {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   336
                    self.dirstate_parents.set(docket.parents());
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   337
                    Ok((
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   338
                        identity,
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   339
                        Some(docket.uuid.to_owned()),
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   340
                        docket.data_size(),
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   341
                    ))
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   342
                }
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   343
                Err(_) => {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   344
                    log::info!(
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   345
                        "Parsing dirstate docket failed, \
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   346
                        falling back to dirstate-v1"
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   347
                    );
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   348
                    let parents =
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   349
                        *crate::dirstate::parsers::parse_dirstate_parents(
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   350
                            &dirstate,
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   351
                        )?;
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   352
                    self.dirstate_parents.set(parents);
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   353
                    Ok((identity, None, 0))
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   354
                }
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   355
            }
48420
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   356
        }
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   357
    }
c7c23bb036c9 rhg: Add lazy/cached dirstate data file ID parsing on Repo
Simon Sapin <simon.sapin@octobus.net>
parents: 48419
diff changeset
   358
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   359
    fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> {
50655
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   360
        if self.use_dirstate_v2() {
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   361
            // The v2 dirstate is split into a docket and a data file.
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   362
            // Since we don't always take the `wlock` to read it
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   363
            // (like in `hg status`), it is susceptible to races.
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   364
            // A simple retry method should be enough since full rewrites
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   365
            // only happen when too much garbage data is present and
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   366
            // this race is unlikely.
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   367
            let mut tries = 0;
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   368
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   369
            while tries < V2_MAX_READ_ATTEMPTS {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   370
                tries += 1;
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   371
                match self.read_docket_and_data_file() {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   372
                    Ok(m) => {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   373
                        return Ok(m);
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   374
                    }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   375
                    Err(e) => match e {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   376
                        DirstateError::Common(HgError::RaceDetected(
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   377
                            context,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   378
                        )) => {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   379
                            log::info!(
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   380
                                "dirstate read race detected {} (retry {}/{})",
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   381
                                context,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   382
                                tries,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   383
                                V2_MAX_READ_ATTEMPTS,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   384
                            );
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   385
                            continue;
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   386
                        }
50657
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   387
                        _ => {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   388
                            log::info!(
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   389
                                "Reading dirstate v2 failed, \
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   390
                                falling back to v1"
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   391
                            );
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   392
                            return self.new_dirstate_map_v1();
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   393
                        }
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   394
                    },
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   395
                }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   396
            }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   397
            let error = HgError::abort(
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   398
                format!("dirstate read race happened {tries} times in a row"),
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   399
                255,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   400
                None,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   401
            );
50252
a6b8b1ab9116 branching: merge stable into default
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 49937 50245
diff changeset
   402
            Err(DirstateError::Common(error))
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   403
        } else {
50657
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   404
            self.new_dirstate_map_v1()
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   405
        }
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   406
    }
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   407
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   408
    fn new_dirstate_map_v1(&self) -> Result<OwningDirstateMap, DirstateError> {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   409
        debug_wait_for_file_or_print(self.config(), "dirstate.pre-read-file");
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   410
        let identity = self.dirstate_identity()?;
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   411
        let dirstate_file_contents = self.dirstate_file_contents()?;
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   412
        if dirstate_file_contents.is_empty() {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   413
            self.dirstate_parents.set(DirstateParents::NULL);
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   414
            Ok(OwningDirstateMap::new_empty(Vec::new()))
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   415
        } else {
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   416
            let (map, parents) =
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   417
                OwningDirstateMap::new_v1(dirstate_file_contents, identity)?;
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   418
            self.dirstate_parents.set(parents);
bf16ef96defe rust-dirstate: fall back to v1 if reading v2 failed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50655
diff changeset
   419
            Ok(map)
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   420
        }
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   421
    }
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   422
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   423
    fn read_docket_and_data_file(
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   424
        &self,
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   425
    ) -> Result<OwningDirstateMap, DirstateError> {
50228
fc8e37c380d3 dirstate: add a synchronisation point before doing a full dirstate read
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50227
diff changeset
   426
        debug_wait_for_file_or_print(self.config(), "dirstate.pre-read-file");
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   427
        let dirstate_file_contents = self.dirstate_file_contents()?;
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   428
        let identity = self.dirstate_identity()?;
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   429
        if dirstate_file_contents.is_empty() {
48419
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   430
            self.dirstate_parents.set(DirstateParents::NULL);
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   431
            return Ok(OwningDirstateMap::new_empty(Vec::new()));
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   432
        }
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   433
        let docket = crate::dirstate_tree::on_disk::read_docket(
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   434
            &dirstate_file_contents,
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   435
        )?;
50234
2be6d5782728 dirstate: add a synchronisation point in the middle of the read
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50228
diff changeset
   436
        debug_wait_for_file_or_print(
2be6d5782728 dirstate: add a synchronisation point in the middle of the read
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50228
diff changeset
   437
            self.config(),
2be6d5782728 dirstate: add a synchronisation point in the middle of the read
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50228
diff changeset
   438
            "dirstate.post-docket-read-file",
2be6d5782728 dirstate: add a synchronisation point in the middle of the read
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50228
diff changeset
   439
        );
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   440
        self.dirstate_parents.set(docket.parents());
50243
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50239
diff changeset
   441
        let uuid = docket.uuid.to_owned();
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   442
        let data_size = docket.data_size();
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   443
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   444
        let context = "between reading dirstate docket and data file";
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   445
        let race_error = HgError::RaceDetected(context.into());
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   446
        let metadata = docket.tree_metadata();
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   447
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   448
        let mut map = if crate::vfs::is_on_nfs_mount(docket.data_filename()) {
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   449
            // Don't mmap on NFS to prevent `SIGBUS` error on deletion
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   450
            let contents = self.hg_vfs().read(docket.data_filename());
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   451
            let contents = match contents {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   452
                Ok(c) => c,
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   453
                Err(HgError::IoError { error, context }) => {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   454
                    match error.raw_os_error().expect("real os error") {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   455
                        // 2 = ENOENT, No such file or directory
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   456
                        // 116 = ESTALE, Stale NFS file handle
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   457
                        //
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   458
                        // TODO match on `error.kind()` when
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   459
                        // `ErrorKind::StaleNetworkFileHandle` is stable.
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   460
                        2 | 116 => {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   461
                            // Race where the data file was deleted right after
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   462
                            // we read the docket, try again
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   463
                            return Err(race_error.into());
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   464
                        }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   465
                        _ => {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   466
                            return Err(
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   467
                                HgError::IoError { error, context }.into()
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   468
                            )
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   469
                        }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   470
                    }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   471
                }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   472
                Err(e) => return Err(e.into()),
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   473
            };
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   474
            OwningDirstateMap::new_v2(
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   475
                contents, data_size, metadata, uuid, identity,
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   476
            )
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   477
        } else {
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   478
            match self
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   479
                .hg_vfs()
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   480
                .mmap_open(docket.data_filename())
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   481
                .io_not_found_as_none()
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   482
            {
50243
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50239
diff changeset
   483
                Ok(Some(data_mmap)) => OwningDirstateMap::new_v2(
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   484
                    data_mmap, data_size, metadata, uuid, identity,
50243
6cce0afc1454 rust-dirstate: remember the data file uuid dirstate was loaded with
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50239
diff changeset
   485
                ),
50239
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   486
                Ok(None) => {
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   487
                    // Race where the data file was deleted right after we
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   488
                    // read the docket, try again
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   489
                    return Err(race_error.into());
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   490
                }
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   491
                Err(e) => return Err(e.into()),
491f3dd080eb dirstate: deal with read-race for pure rust code path (rhg)
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50234
diff changeset
   492
            }
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   493
        }?;
50222
ecd28d89c29e dirstate-v2: add devel config option to control write behavior
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50221
diff changeset
   494
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   495
        let write_mode_config = self
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   496
            .config()
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   497
            .get_str(b"devel", b"dirstate.v2.data_update_mode")
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   498
            .unwrap_or(Some("auto"))
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   499
            .unwrap_or("auto"); // don't bother for devel options
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   500
        let write_mode = match write_mode_config {
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   501
            "auto" => DirstateMapWriteMode::Auto,
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   502
            "force-new" => DirstateMapWriteMode::ForceNewDataFile,
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   503
            "force-append" => DirstateMapWriteMode::ForceAppend,
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   504
            _ => DirstateMapWriteMode::Auto,
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   505
        };
50222
ecd28d89c29e dirstate-v2: add devel config option to control write behavior
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50221
diff changeset
   506
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   507
        map.with_dmap_mut(|m| m.set_write_mode(write_mode));
50222
ecd28d89c29e dirstate-v2: add devel config option to control write behavior
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50221
diff changeset
   508
50227
cbd4c9234e25 rust-repo: move dirstate-v2 opening to a separate method
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50222
diff changeset
   509
        Ok(map)
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   510
    }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   511
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   512
    pub fn dirstate_map(
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   513
        &self,
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   514
    ) -> Result<Ref<OwningDirstateMap>, DirstateError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   515
        self.dirstate_map.get_or_init(|| self.new_dirstate_map())
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   516
    }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   517
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   518
    pub fn dirstate_map_mut(
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   519
        &self,
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   520
    ) -> Result<RefMut<OwningDirstateMap>, DirstateError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   521
        self.dirstate_map
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   522
            .get_mut_or_init(|| self.new_dirstate_map())
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   523
    }
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   524
49090
a5ef50becea8 rust-revlog: make `Changelog` and `ManifestLog` unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49005
diff changeset
   525
    fn new_changelog(&self) -> Result<Changelog, HgError> {
49091
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   526
        Changelog::open(&self.store_vfs(), self.has_nodemap())
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   527
    }
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   528
47963
001d747c2baf rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   529
    pub fn changelog(&self) -> Result<Ref<Changelog>, HgError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   530
        self.changelog.get_or_init(|| self.new_changelog())
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   531
    }
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   532
47963
001d747c2baf rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   533
    pub fn changelog_mut(&self) -> Result<RefMut<Changelog>, HgError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   534
        self.changelog.get_mut_or_init(|| self.new_changelog())
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   535
    }
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   536
49090
a5ef50becea8 rust-revlog: make `Changelog` and `ManifestLog` unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49005
diff changeset
   537
    fn new_manifestlog(&self) -> Result<Manifestlog, HgError> {
49091
9b5334c1e499 rust-repo: extract a function for checking nodemap requirement
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
   538
        Manifestlog::open(&self.store_vfs(), self.has_nodemap())
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   539
    }
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   540
47963
001d747c2baf rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   541
    pub fn manifestlog(&self) -> Result<Ref<Manifestlog>, HgError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   542
        self.manifestlog.get_or_init(|| self.new_manifestlog())
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   543
    }
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   544
47963
001d747c2baf rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   545
    pub fn manifestlog_mut(&self) -> Result<RefMut<Manifestlog>, HgError> {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   546
        self.manifestlog.get_mut_or_init(|| self.new_manifestlog())
47959
21d25e9ee58e rust: Keep lazily-initialized Changelog and Manifest log on the Repo object
Simon Sapin <simon.sapin@octobus.net>
parents: 47958
diff changeset
   547
    }
47960
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47959
diff changeset
   548
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   549
    /// Returns the manifest of the *changeset* with the given node ID
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   550
    pub fn manifest_for_node(
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   551
        &self,
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   552
        node: impl Into<NodePrefix>,
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   553
    ) -> Result<Manifest, RevlogError> {
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   554
        self.manifestlog()?.data_for_node(
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   555
            self.changelog()?
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   556
                .data_for_node(node.into())?
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   557
                .manifest_node()?
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   558
                .into(),
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   559
        )
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   560
    }
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   561
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   562
    /// Returns the manifest of the *changeset* with the given revision number
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   563
    pub fn manifest_for_rev(
47960
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47959
diff changeset
   564
        &self,
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50657
diff changeset
   565
        revision: UncheckedRevision,
47960
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47959
diff changeset
   566
    ) -> Result<Manifest, RevlogError> {
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   567
        self.manifestlog()?.data_for_node(
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   568
            self.changelog()?
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   569
                .data_for_rev(revision)?
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   570
                .manifest_node()?
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
   571
                .into(),
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
   572
        )
47960
cfb6e6699b25 rust: Add Repo::manifest(revision)
Simon Sapin <simon.sapin@octobus.net>
parents: 47959
diff changeset
   573
    }
47961
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47960
diff changeset
   574
48510
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   575
    pub fn has_subrepos(&self) -> Result<bool, DirstateError> {
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   576
        if let Some(entry) = self.dirstate_map()?.get(HgPath::new(".hgsub"))? {
49136
3f5e207f78be rust: use `entry.tracked()` directly
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49091
diff changeset
   577
            Ok(entry.tracked())
48510
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   578
        } else {
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   579
            Ok(false)
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   580
        }
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   581
    }
7f633432ca92 rhg: Sub-repositories are not supported
Simon Sapin <simon.sapin@octobus.net>
parents: 48421
diff changeset
   582
47963
001d747c2baf rust: Return HgError instead of RevlogError in revlog constructors
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   583
    pub fn filelog(&self, path: &HgPath) -> Result<Filelog, HgError> {
47961
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47960
diff changeset
   584
        Filelog::open(self, path)
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47960
diff changeset
   585
    }
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   586
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   587
    /// Write to disk any updates that were made through `dirstate_map_mut`.
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   588
    ///
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   589
    /// The "wlock" must be held while calling this.
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   590
    /// See for example `try_with_wlock_no_wait`.
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   591
    ///
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   592
    /// TODO: have a `WritableRepo` type only accessible while holding the
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   593
    /// lock?
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   594
    pub fn write_dirstate(&self) -> Result<(), DirstateError> {
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   595
        let map = self.dirstate_map()?;
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   596
        // TODO: Maintain a `DirstateMap::dirty` flag, and return early here if
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   597
        // it’s unset
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   598
        let parents = self.dirstate_parents()?;
50655
1e2c6cda2309 rust-dirstate: rename `has_dirstate_v2` to `use_dirstate_v2`
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50252
diff changeset
   599
        let (packed_dirstate, old_uuid_to_remove) = if self.use_dirstate_v2() {
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   600
            let (identity, uuid, data_size) =
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   601
                self.get_dirstate_data_file_integrity()?;
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   602
            let identity_changed = identity != map.old_identity();
50244
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   603
            let uuid_changed = uuid.as_deref() != map.old_uuid();
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   604
            let data_length_changed = data_size != map.old_data_size();
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   605
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   606
            if identity_changed || uuid_changed || data_length_changed {
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   607
                // If any of identity, uuid or length have changed since
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   608
                // last disk read, don't write.
50244
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   609
                // This is fine because either we're in a command that doesn't
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   610
                // write anything too important (like `hg status`), or we're in
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   611
                // `hg add` and we're supposed to have taken the lock before
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   612
                // reading anyway.
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   613
                //
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   614
                // TODO complain loudly if we've changed anything important
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   615
                // without taking the lock.
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   616
                // (see `hg help config.format.use-dirstate-tracked-hint`)
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   617
                log::debug!(
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   618
                    "dirstate has changed since last read, not updating."
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   619
                );
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   620
                return Ok(());
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   621
            }
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   622
07d030b38097 rust-dirstate-v2: don't write dirstate if data file has changed
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50243
diff changeset
   623
            let uuid_opt = map.old_uuid();
50221
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
   624
            let write_mode = if uuid_opt.is_some() {
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
   625
                DirstateMapWriteMode::Auto
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
   626
            } else {
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
   627
                DirstateMapWriteMode::ForceNewDataFile
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
   628
            };
49145
dd2503a63d33 rust-dirstate-v2: save proper data size if no new data on append
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49000
diff changeset
   629
            let (data, tree_metadata, append, old_data_size) =
50221
1891086f6c7f dirstate: use more than a bool to control append behavior
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 50211
diff changeset
   630
                map.pack_v2(write_mode)?;
49150
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   631
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   632
            // Reuse the uuid, or generate a new one, keeping the old for
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   633
            // deletion.
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   634
            let (uuid, old_uuid) = match uuid_opt {
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   635
                Some(uuid) => {
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   636
                    let as_str = std::str::from_utf8(uuid)
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   637
                        .map_err(|_| {
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   638
                            HgError::corrupted(
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   639
                                "non-UTF-8 dirstate data file ID",
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   640
                            )
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   641
                        })?
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   642
                        .to_owned();
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   643
                    if append {
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   644
                        (as_str, None)
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   645
                    } else {
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   646
                        (DirstateDocket::new_uid(), Some(as_str))
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   647
                    }
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   648
                }
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   649
                None => (DirstateDocket::new_uid(), None),
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   650
            };
49150
f2ef6a4f918f rhg: fix dirstate-v2 data file removal system
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49146
diff changeset
   651
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   652
            let data_filename = format!("dirstate.{}", uuid);
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   653
            let data_filename = self.hg_vfs().join(data_filename);
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   654
            let mut options = std::fs::OpenOptions::new();
49202
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   655
            options.write(true);
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   656
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   657
            // Why are we not using the O_APPEND flag when appending?
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   658
            //
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   659
            // - O_APPEND makes it trickier to deal with garbage at the end of
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   660
            //   the file, left by a previous uncommitted transaction. By
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   661
            //   starting the write at [old_data_size] we make sure we erase
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   662
            //   all such garbage.
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   663
            //
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   664
            // - O_APPEND requires to special-case 0-byte writes, whereas we
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   665
            //   don't need that.
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   666
            //
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   667
            // - Some OSes have bugs in implementation O_APPEND:
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   668
            //   revlog.py talks about a Solaris bug, but we also saw some ZFS
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   669
            //   bug: https://github.com/openzfs/zfs/pull/3124,
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   670
            //   https://github.com/openzfs/zfs/issues/13370
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   671
            //
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   672
            if !append {
50211
f5e4248e5bce dirstate: add some debug output when writing the dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50180
diff changeset
   673
                log::trace!("creating a new dirstate data file");
49202
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   674
                options.create_new(true);
50211
f5e4248e5bce dirstate: add some debug output when writing the dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50180
diff changeset
   675
            } else {
f5e4248e5bce dirstate: add some debug output when writing the dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50180
diff changeset
   676
                log::trace!("appending to the dirstate data file");
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   677
            }
49202
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   678
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   679
            let data_size = (|| {
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   680
                // TODO: loop and try another random ID if !append and this
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   681
                // returns `ErrorKind::AlreadyExists`? Collision chance of two
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   682
                // random IDs is one in 2**32
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   683
                let mut file = options.open(&data_filename)?;
49202
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   684
                if append {
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   685
                    file.seek(SeekFrom::Start(old_data_size as u64))?;
49145
dd2503a63d33 rust-dirstate-v2: save proper data size if no new data on append
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49000
diff changeset
   686
                }
49202
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   687
                file.write_all(&data)?;
2d0e22171ef9 rhg: align the dirstate v2 writing algorithm with python
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 49150
diff changeset
   688
                file.flush()?;
51117
532e74ad3ff6 rust: run a clippy pass with the latest stable version
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
   689
                file.stream_position()
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   690
            })()
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   691
            .when_writing_file(&data_filename)?;
49146
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   692
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   693
            let packed_dirstate = DirstateDocket::serialize(
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   694
                parents,
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   695
                tree_metadata,
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   696
                data_size,
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   697
                uuid.as_bytes(),
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   698
            )
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   699
            .map_err(|_: std::num::TryFromIntError| {
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   700
                HgError::corrupted("overflow in dirstate docket serialization")
49146
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   701
            })?;
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   702
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   703
            (packed_dirstate, old_uuid)
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   704
        } else {
50245
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   705
            let identity = self.dirstate_identity()?;
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   706
            if identity != map.old_identity() {
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   707
                // If identity changed since last disk read, don't write.
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   708
                // This is fine because either we're in a command that doesn't
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   709
                // write anything too important (like `hg status`), or we're in
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   710
                // `hg add` and we're supposed to have taken the lock before
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   711
                // reading anyway.
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   712
                //
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   713
                // TODO complain loudly if we've changed anything important
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   714
                // without taking the lock.
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   715
                // (see `hg help config.format.use-dirstate-tracked-hint`)
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   716
                log::debug!(
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   717
                    "dirstate has changed since last read, not updating."
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   718
                );
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   719
                return Ok(());
dbe09fb038fc rhg: remember the inode of .hg/dirstate
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50244
diff changeset
   720
            }
49146
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   721
            (map.pack_v1(parents)?, None)
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   722
        };
49146
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   723
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   724
        let vfs = self.hg_vfs();
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   725
        vfs.atomic_write("dirstate", &packed_dirstate)?;
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   726
        if let Some(uuid) = old_uuid_to_remove {
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   727
            // Remove the old data file after the new docket pointing to the
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   728
            // new data file was written.
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   729
            vfs.remove_file(format!("dirstate.{}", uuid))?;
802e2c25dab8 rust-dirstate-v2: clean up previous data file after the docket is written
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49145
diff changeset
   730
        }
48421
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   731
        Ok(())
2097f63575a5 rhg: Add Repo::write_dirstate
Simon Sapin <simon.sapin@octobus.net>
parents: 48420
diff changeset
   732
    }
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   733
}
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   734
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   735
/// Lazily-initialized component of `Repo` with interior mutability
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   736
///
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   737
/// This differs from `OnceCell` in that the value can still be "deinitialized"
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   738
/// later by setting its inner `Option` to `None`. It also takes the
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   739
/// initialization function as an argument when the value is requested, not
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   740
/// when the instance is created.
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   741
struct LazyCell<T> {
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   742
    value: RefCell<Option<T>>,
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   743
}
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   744
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   745
impl<T> LazyCell<T> {
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   746
    fn new() -> Self {
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   747
        Self {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   748
            value: RefCell::new(None),
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   749
        }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   750
    }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   751
48419
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   752
    fn set(&self, value: T) {
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   753
        *self.value.borrow_mut() = Some(value)
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   754
    }
c8659e61073d rhg: Make Repo::dirstate_parents a LazyCell
Simon Sapin <simon.sapin@octobus.net>
parents: 48417
diff changeset
   755
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   756
    fn get_or_init<E>(
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   757
        &self,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   758
        init: impl Fn() -> Result<T, E>,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   759
    ) -> Result<Ref<T>, E> {
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   760
        let mut borrowed = self.value.borrow();
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   761
        if borrowed.is_none() {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   762
            drop(borrowed);
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   763
            // Only use `borrow_mut` if it is really needed to avoid panic in
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   764
            // case there is another outstanding borrow but mutation is not
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   765
            // needed.
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   766
            *self.value.borrow_mut() = Some(init()?);
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   767
            borrowed = self.value.borrow()
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   768
        }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   769
        Ok(Ref::map(borrowed, |option| option.as_ref().unwrap()))
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   770
    }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   771
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   772
    fn get_mut_or_init<E>(
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   773
        &self,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   774
        init: impl Fn() -> Result<T, E>,
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   775
    ) -> Result<RefMut<T>, E> {
47958
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47956
diff changeset
   776
        let mut borrowed = self.value.borrow_mut();
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   777
        if borrowed.is_none() {
49177
90a15199cbc6 rust-repo: make `Send` by not storing functions in `LazyCell`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49164
diff changeset
   778
            *borrowed = Some(init()?);
47956
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   779
        }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   780
        Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap()))
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47952
diff changeset
   781
    }
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
   782
}