annotate rust/hg-core/src/repo.rs @ 47986:fc208d6faed3

rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct More components of `Repo` will be added following the same pattern. Differential Revision: https://phab.mercurial-scm.org/D11405
author Simon Sapin <simon.sapin@octobus.net>
date Mon, 13 Sep 2021 13:16:10 +0200
parents 81aedf1fc897
children 21d25e9ee58e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
1 use crate::config::{Config, ConfigError, ConfigParseError};
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
2 use crate::dirstate::DirstateParents;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
3 use crate::dirstate_tree::dirstate_map::DirstateMap;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
4 use crate::dirstate_tree::owning::OwningDirstateMap;
47980
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents: 47977
diff changeset
5 use crate::errors::HgError;
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
6 use crate::errors::HgResultExt;
47413
6e49769b7f97 rhg: add exit code to HgError::Abort()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47411
diff changeset
7 use crate::exit_codes;
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 use crate::requirements;
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
9 use crate::utils::files::get_path_from_bytes;
46753
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46748
diff changeset
10 use crate::utils::SliceExt;
47980
9cd35c8c6044 rust: Move VFS code to its own module
Simon Sapin <simon.sapin@octobus.net>
parents: 47977
diff changeset
11 use crate::vfs::{is_dir, is_file, Vfs};
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
12 use crate::DirstateError;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
13 use std::cell::{Cell, Ref, RefCell, RefMut};
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
14 use std::collections::HashSet;
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15 use std::path::{Path, PathBuf};
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17 /// A repository on disk
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18 pub struct Repo {
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 working_directory: PathBuf,
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
20 dot_hg: PathBuf,
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 store: PathBuf,
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
22 requirements: HashSet<String>,
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
23 config: Config,
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
24 // None means not known/initialized yet
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
25 dirstate_parents: Cell<Option<DirstateParents>>,
47986
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
26 dirstate_map: LazyCell<OwningDirstateMap, DirstateError>,
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
27 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
28
46514
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
29 #[derive(Debug, derive_more::From)]
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
30 pub enum RepoError {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
31 NotFound {
46555
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
32 at: PathBuf,
46514
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
33 },
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
34 #[from]
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
35 ConfigParseError(ConfigParseError),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
36 #[from]
46514
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
37 Other(HgError),
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
38 }
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
39
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
40 impl From<ConfigError> for RepoError {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
41 fn from(error: ConfigError) -> Self {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
42 match error {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
43 ConfigError::Parse(error) => error.into(),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
44 ConfigError::Other(error) => error.into(),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
45 }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
46 }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
47 }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
48
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
49 impl Repo {
47411
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
50 /// 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: 47410
diff changeset
51 /// its ancestors
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
52 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: 47410
diff changeset
53 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: 47410
diff changeset
54 // 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: 47410
diff changeset
55 // as-is.
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
56 for ancestor in current_directory.ancestors() {
47779
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
57 if is_dir(ancestor.join(".hg"))? {
47411
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
58 return Ok(ancestor.to_path_buf());
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
59 }
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
60 }
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
61 return Err(RepoError::NotFound {
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
62 at: current_directory,
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
63 });
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
64 }
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
65
46557
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46555
diff changeset
66 /// 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: 46555
diff changeset
67 /// 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: 46555
diff changeset
68 /// ancestors.
46555
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
69 ///
46557
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46555
diff changeset
70 /// 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: 46555
diff changeset
71 /// 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: 46555
diff changeset
72 /// 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: 46555
diff changeset
73 /// Having two methods would just move that `if` to almost all callers.
46555
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
74 pub fn find(
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
75 config: &Config,
47410
ebdef6283798 rhg: read [paths] for `--repository` value
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47380
diff changeset
76 explicit_path: Option<PathBuf>,
46555
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
77 ) -> Result<Self, RepoError> {
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
78 if let Some(root) = explicit_path {
47779
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
79 if is_dir(root.join(".hg"))? {
46753
97ac588b6d9e rhg: Don?t make repository path absolute too early
Simon Sapin <simon.sapin@octobus.net>
parents: 46748
diff changeset
80 Self::new_at_path(root.to_owned(), config)
47779
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
81 } else if is_file(&root)? {
46743
dfd35823635b rhg: Fall back to Python for bundle repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46741
diff changeset
82 Err(HgError::unsupported("bundle repository").into())
46555
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
83 } else {
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
84 Err(RepoError::NotFound {
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
85 at: root.to_owned(),
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
86 })
46514
1dcd9c9975ed rust: Fold find_root and check_requirements into Repo::find
Simon Sapin <simon.sapin@octobus.net>
parents: 46511
diff changeset
87 }
46555
d8730ff51d5a rhg: Add support for -R and --repository command-line arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46545
diff changeset
88 } else {
47411
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
89 let root = Self::find_repo_root()?;
88119fffecc8 rhg: look for repository in ancestors also instead of cwd only
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47410
diff changeset
90 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
91 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
92 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
93
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
94 /// To be called after checking that `.hg` is a sub-directory
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
95 fn new_at_path(
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
96 working_directory: PathBuf,
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
97 config: &Config,
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
98 ) -> Result<Self, RepoError> {
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
99 let dot_hg = working_directory.join(".hg");
46525
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
100
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
101 let mut repo_config_files = Vec::new();
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
102 repo_config_files.push(dot_hg.join("hgrc"));
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
103 repo_config_files.push(dot_hg.join("hgrc-not-shared"));
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
104
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
105 let hg_vfs = Vfs { base: &dot_hg };
46525
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
106 let mut reqs = requirements::load_if_exists(hg_vfs)?;
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
107 let relative =
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
108 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
109 let shared =
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
110 reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
46525
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
111
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
112 // From `mercurial/localrepo.py`:
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
113 //
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
114 // if .hg/requires contains the sharesafe requirement, it means
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
115 // 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: 46524
diff changeset
116 // NOTE: presence of SHARESAFE_REQUIREMENT imply that store requirement
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
117 // 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: 46524
diff changeset
118 // is not present, refer checkrequirementscompat() for that
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
119 //
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
120 // 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: 46524
diff changeset
121 // 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: 46524
diff changeset
122 // .hg/requires for SHARESAFE_REQUIREMENT to detect whether the
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
123 // current repository needs to be reshared
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
124 let share_safe = reqs.contains(requirements::SHARESAFE_REQUIREMENT);
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
125
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
126 let store_path;
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
127 if !shared {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
128 store_path = dot_hg.join("store");
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
129 } else {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
130 let bytes = hg_vfs.read("sharedpath")?;
46708
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46652
diff changeset
131 let mut shared_path =
47977
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 47779
diff changeset
132 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: 47779
diff changeset
133 .to_owned();
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
134 if relative {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
135 shared_path = dot_hg.join(shared_path)
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
136 }
47779
cf5f8da2244c rhg: Propagate permission errors when finding a repository
Simon Sapin <simon.sapin@octobus.net>
parents: 47674
diff changeset
137 if !is_dir(&shared_path)? {
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
138 return Err(HgError::corrupted(format!(
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
139 ".hg/sharedpath points to nonexistent directory {}",
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
140 shared_path.display()
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
141 ))
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
142 .into());
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
143 }
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
144
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
145 store_path = shared_path.join("store");
46525
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
146
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
147 let source_is_share_safe =
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
148 requirements::load(Vfs { base: &shared_path })?
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
149 .contains(requirements::SHARESAFE_REQUIREMENT);
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
150
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
151 if share_safe && !source_is_share_safe {
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
152 return Err(match config
46748
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
153 .get(b"share", b"safe-mismatch.source-not-safe")
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
154 {
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
155 Some(b"abort") | None => HgError::abort(
46748
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
156 "abort: share source does not support share-safe requirement\n\
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
157 (see `hg help config.format.use-share-safe` for more information)",
47413
6e49769b7f97 rhg: add exit code to HgError::Abort()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47411
diff changeset
158 exit_codes::ABORT,
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
159 ),
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
160 _ => HgError::unsupported("share-safe downgrade"),
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
161 }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
162 .into());
46525
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
163 } else if source_is_share_safe && !share_safe {
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
164 return Err(
46748
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
165 match config.get(b"share", b"safe-mismatch.source-safe") {
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
166 Some(b"abort") | None => HgError::abort(
46748
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
167 "abort: version mismatch: source uses share-safe \
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
168 functionality while the current share does not\n\
12d59eec7f1d rhg: Align with Python on some more error messages
Simon Sapin <simon.sapin@octobus.net>
parents: 46743
diff changeset
169 (see `hg help config.format.use-share-safe` for more information)",
47413
6e49769b7f97 rhg: add exit code to HgError::Abort()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 47411
diff changeset
170 exit_codes::ABORT,
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
171 ),
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
172 _ => HgError::unsupported("share-safe upgrade"),
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
173 }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
174 .into(),
46544
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46543
diff changeset
175 );
46525
95b276283b67 rhg: add support for share-safe
Simon Sapin <simon.sapin@octobus.net>
parents: 46524
diff changeset
176 }
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
177
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
178 if share_safe {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
179 repo_config_files.insert(0, shared_path.join("hgrc"))
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
180 }
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
181 }
46652
f64b6953db70 rhg: Bug fix: with share-safe, always read store requirements
Simon Sapin <simon.sapin@octobus.net>
parents: 46640
diff changeset
182 if share_safe {
f64b6953db70 rhg: Bug fix: with share-safe, always read store requirements
Simon Sapin <simon.sapin@octobus.net>
parents: 46640
diff changeset
183 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: 46640
diff changeset
184 }
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
185
46754
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46753
diff changeset
186 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: 46753
diff changeset
187 config.combine_with_repo(&repo_config_files)?
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46753
diff changeset
188 } else {
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46753
diff changeset
189 config.clone()
25e3dac511f0 rhg: Add support for the HGRCSKIPREPO environment variable
Simon Sapin <simon.sapin@octobus.net>
parents: 46753
diff changeset
190 };
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
191
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
192 let repo = Self {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
193 requirements: reqs,
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
194 working_directory,
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
195 store: store_path,
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
196 dot_hg,
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
197 config: repo_config,
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
198 dirstate_parents: Cell::new(None),
47986
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
199 dirstate_map: LazyCell::new(Self::new_dirstate_map),
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
200 };
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
201
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
202 requirements::check(&repo)?;
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
203
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
204 Ok(repo)
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
205 }
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
206
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
207 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
208 &self.working_directory
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
209 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
210
46524
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
211 pub fn requirements(&self) -> &HashSet<String> {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
212 &self.requirements
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
213 }
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46514
diff changeset
214
46545
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
215 pub fn config(&self) -> &Config {
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
216 &self.config
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
217 }
d7685105e504 rhg: Parse per-repository configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46544
diff changeset
218
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
219 /// 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
220 /// (`.hg/store`).
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents: 46632
diff changeset
221 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
222 Vfs { base: &self.dot_hg }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
223 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
224
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
225 /// For accessing repository store files (in `.hg/store`)
46638
1f55cd5b292f rust: Add a log file rotation utility
Simon Sapin <simon.sapin@octobus.net>
parents: 46632
diff changeset
226 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
227 Vfs { base: &self.store }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
228 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
229
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
230 /// For accessing the working copy
46822
c71e8d9e7f2a rhg: Initial support for the 'status' command
Georges Racinet <georges.racinet@octobus.net>
parents: 46754
diff changeset
231 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
232 Vfs {
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
233 base: &self.working_directory,
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
234 }
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
235 }
46640
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46638
diff changeset
236
47380
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
237 pub fn has_dirstate_v2(&self) -> bool {
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
238 self.requirements
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
239 .contains(requirements::DIRSTATE_V2_REQUIREMENT)
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
240 }
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
241
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
242 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: 47980
diff changeset
243 Ok(self
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
244 .hg_vfs()
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
245 .read("dirstate")
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
246 .io_not_found_as_none()?
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
247 .unwrap_or(Vec::new()))
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
248 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
249
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
250 pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
251 if let Some(parents) = self.dirstate_parents.get() {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
252 return Ok(parents);
47380
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
253 }
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
254 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: 47980
diff changeset
255 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: 47980
diff changeset
256 DirstateParents::NULL
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
257 } else if self.has_dirstate_v2() {
47674
ff97e793ed36 dirstate-v2: Introduce a docket file
Simon Sapin <simon.sapin@octobus.net>
parents: 47413
diff changeset
258 crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents()
47380
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
259 } else {
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
260 crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?
47674
ff97e793ed36 dirstate-v2: Introduce a docket file
Simon Sapin <simon.sapin@octobus.net>
parents: 47413
diff changeset
261 .clone()
47380
bd88b6bfd8da rhg: Add support for dirstate-v2
Simon Sapin <simon.sapin@octobus.net>
parents: 46822
diff changeset
262 };
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
263 self.dirstate_parents.set(Some(parents));
47674
ff97e793ed36 dirstate-v2: Introduce a docket file
Simon Sapin <simon.sapin@octobus.net>
parents: 47413
diff changeset
264 Ok(parents)
46640
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46638
diff changeset
265 }
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
266
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
267 fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
268 let dirstate_file_contents = self.dirstate_file_contents()?;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
269 if dirstate_file_contents.is_empty() {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
270 self.dirstate_parents.set(Some(DirstateParents::NULL));
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
271 Ok(OwningDirstateMap::new_empty(Vec::new()))
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
272 } else if self.has_dirstate_v2() {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
273 let docket = crate::dirstate_tree::on_disk::read_docket(
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
274 &dirstate_file_contents,
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
275 )?;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
276 self.dirstate_parents.set(Some(docket.parents()));
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
277 let data_size = docket.data_size();
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
278 let metadata = docket.tree_metadata();
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
279 let mut map = if let Some(data_mmap) = self
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
280 .hg_vfs()
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
281 .mmap_open(docket.data_filename())
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
282 .io_not_found_as_none()?
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
283 {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
284 OwningDirstateMap::new_empty(MmapWrapper(data_mmap))
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
285 } else {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
286 OwningDirstateMap::new_empty(Vec::new())
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
287 };
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
288 let (on_disk, placeholder) = map.get_mut_pair();
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
289 *placeholder = DirstateMap::new_v2(on_disk, data_size, metadata)?;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
290 Ok(map)
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
291 } else {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
292 let mut map = OwningDirstateMap::new_empty(dirstate_file_contents);
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
293 let (on_disk, placeholder) = map.get_mut_pair();
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
294 let (inner, parents) = DirstateMap::new_v1(on_disk)?;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
295 self.dirstate_parents
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
296 .set(Some(parents.unwrap_or(DirstateParents::NULL)));
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
297 *placeholder = inner;
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
298 Ok(map)
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
299 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
300 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
301
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
302 pub fn dirstate_map(
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
303 &self,
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
304 ) -> Result<Ref<OwningDirstateMap>, DirstateError> {
47986
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
305 self.dirstate_map.get_or_init(self)
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
306 }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
307
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
308 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: 47984
diff changeset
309 &self,
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
310 ) -> Result<RefMut<OwningDirstateMap>, DirstateError> {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
311 self.dirstate_map.get_mut_or_init(self)
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
312 }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
313 }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
314
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
315 /// 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: 47984
diff changeset
316 ///
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
317 /// This differs from `OnceCell` in that the value can still be "deinitialized"
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
318 /// later by setting its inner `Option` to `None`.
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
319 struct LazyCell<T, E> {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
320 value: RefCell<Option<T>>,
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
321 // `Fn`s that don’t capture environment are zero-size, so this box does
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
322 // not allocate:
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
323 init: Box<dyn Fn(&Repo) -> Result<T, E>>,
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
324 }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
325
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
326 impl<T, E> LazyCell<T, E> {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
327 fn new(init: impl Fn(&Repo) -> Result<T, E> + 'static) -> Self {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
328 Self {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
329 value: RefCell::new(None),
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
330 init: Box::new(init),
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
331 }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
332 }
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
333
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
334 fn get_or_init(&self, repo: &Repo) -> Result<Ref<T>, E> {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
335 let mut borrowed = self.value.borrow();
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
336 if borrowed.is_none() {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
337 drop(borrowed);
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
338 // 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: 47980
diff changeset
339 // 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: 47980
diff changeset
340 // needed.
47986
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
341 *self.value.borrow_mut() = Some((self.init)(repo)?);
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
342 borrowed = self.value.borrow()
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
343 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
344 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: 47980
diff changeset
345 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
346
47986
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
347 pub fn get_mut_or_init(&self, repo: &Repo) -> Result<RefMut<T>, E> {
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
348 let mut borrowed = self.value.borrow_mut();
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
349 if borrowed.is_none() {
47986
fc208d6faed3 rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47984
diff changeset
350 *borrowed = Some((self.init)(repo)?);
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
351 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
352 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: 47980
diff changeset
353 }
46167
8a4914397d02 rust: introduce Repo and Vfs types for filesystem abstraction
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
354 }
47984
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
355
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
356 // TODO: remove this when https://github.com/RazrFalcon/memmap2-rs/pull/22 is on crates.io
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
357 struct MmapWrapper(memmap2::Mmap);
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
358
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
359 impl std::ops::Deref for MmapWrapper {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
360 type Target = [u8];
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
361
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
362 fn deref(&self) -> &[u8] {
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
363 self.0.deref()
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
364 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
365 }
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
366
81aedf1fc897 rust: Add Repo::dirstate_map and use it in `rhg status`
Simon Sapin <simon.sapin@octobus.net>
parents: 47980
diff changeset
367 unsafe impl stable_deref_trait::StableDeref for MmapWrapper {}