##// END OF EJS Templates
rust-requirements: allow loading repos with `bookmarksinstore` requirement...
Martin von Zweigbergk -
r49935:81d293eb default
parent child Browse files
Show More
@@ -1,161 +1,168 b''
1 1 use crate::errors::{HgError, HgResultExt};
2 2 use crate::repo::Repo;
3 3 use crate::utils::join_display;
4 4 use crate::vfs::Vfs;
5 5 use std::collections::HashSet;
6 6
7 7 fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> {
8 8 // The Python code reading this file uses `str.splitlines`
9 9 // which looks for a number of line separators (even including a couple of
10 10 // non-ASCII ones), but Python code writing it always uses `\n`.
11 11 let lines = bytes.split(|&byte| byte == b'\n');
12 12
13 13 lines
14 14 .filter(|line| !line.is_empty())
15 15 .map(|line| {
16 16 // Python uses Unicode `str.isalnum` but feature names are all
17 17 // ASCII
18 18 if line[0].is_ascii_alphanumeric() && line.is_ascii() {
19 19 Ok(String::from_utf8(line.into()).unwrap())
20 20 } else {
21 21 Err(HgError::corrupted("parse error in 'requires' file"))
22 22 }
23 23 })
24 24 .collect()
25 25 }
26 26
27 27 pub(crate) fn load(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> {
28 28 parse(&hg_vfs.read("requires")?)
29 29 }
30 30
31 31 pub(crate) fn load_if_exists(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> {
32 32 if let Some(bytes) = hg_vfs.read("requires").io_not_found_as_none()? {
33 33 parse(&bytes)
34 34 } else {
35 35 // Treat a missing file the same as an empty file.
36 36 // From `mercurial/localrepo.py`:
37 37 // > requires file contains a newline-delimited list of
38 38 // > features/capabilities the opener (us) must have in order to use
39 39 // > the repository. This file was introduced in Mercurial 0.9.2,
40 40 // > which means very old repositories may not have one. We assume
41 41 // > a missing file translates to no requirements.
42 42 Ok(HashSet::new())
43 43 }
44 44 }
45 45
46 46 pub(crate) fn check(repo: &Repo) -> Result<(), HgError> {
47 47 let unknown: Vec<_> = repo
48 48 .requirements()
49 49 .iter()
50 50 .map(String::as_str)
51 51 // .filter(|feature| !ALL_SUPPORTED.contains(feature.as_str()))
52 52 .filter(|feature| {
53 53 !REQUIRED.contains(feature) && !SUPPORTED.contains(feature)
54 54 })
55 55 .collect();
56 56 if !unknown.is_empty() {
57 57 return Err(HgError::unsupported(format!(
58 58 "repository requires feature unknown to this Mercurial: {}",
59 59 join_display(&unknown, ", ")
60 60 )));
61 61 }
62 62 let missing: Vec<_> = REQUIRED
63 63 .iter()
64 64 .filter(|&&feature| !repo.requirements().contains(feature))
65 65 .collect();
66 66 if !missing.is_empty() {
67 67 return Err(HgError::unsupported(format!(
68 68 "repository is missing feature required by this Mercurial: {}",
69 69 join_display(&missing, ", ")
70 70 )));
71 71 }
72 72 Ok(())
73 73 }
74 74
75 75 /// rhg does not support repositories that are *missing* any of these features
76 76 const REQUIRED: &[&str] = &["revlogv1", "store", "fncache", "dotencode"];
77 77
78 78 /// rhg supports repository with or without these
79 79 const SUPPORTED: &[&str] = &[
80 80 "generaldelta",
81 81 SHARED_REQUIREMENT,
82 82 SHARESAFE_REQUIREMENT,
83 83 SPARSEREVLOG_REQUIREMENT,
84 84 RELATIVE_SHARED_REQUIREMENT,
85 85 REVLOG_COMPRESSION_ZSTD,
86 86 DIRSTATE_V2_REQUIREMENT,
87 87 // As of this writing everything rhg does is read-only.
88 88 // When it starts writing to the repository, it’ll need to either keep the
89 89 // persistent nodemap up to date or remove this entry:
90 90 NODEMAP_REQUIREMENT,
91 91 // Not all commands support `sparse` and `narrow`. The commands that do
92 92 // not should opt out by checking `has_sparse` and `has_narrow`.
93 93 SPARSE_REQUIREMENT,
94 94 NARROW_REQUIREMENT,
95 // rhg doesn't care about bookmarks at all yet
96 BOOKMARKS_IN_STORE_REQUIREMENT,
95 97 ];
96 98
97 99 // Copied from mercurial/requirements.py:
98 100
99 101 pub(crate) const DIRSTATE_V2_REQUIREMENT: &str = "dirstate-v2";
100 102
101 103 /// When narrowing is finalized and no longer subject to format changes,
102 104 /// we should move this to just "narrow" or similar.
103 105 #[allow(unused)]
104 106 pub(crate) const NARROW_REQUIREMENT: &str = "narrowhg-experimental";
105 107
108 /// Bookmarks must be stored in the `store` part of the repository and will be
109 /// share accross shares
110 #[allow(unused)]
111 pub(crate) const BOOKMARKS_IN_STORE_REQUIREMENT: &str = "bookmarksinstore";
112
106 113 /// Enables sparse working directory usage
107 114 #[allow(unused)]
108 115 pub(crate) const SPARSE_REQUIREMENT: &str = "exp-sparse";
109 116
110 117 /// Enables the internal phase which is used to hide changesets instead
111 118 /// of stripping them
112 119 #[allow(unused)]
113 120 pub(crate) const INTERNAL_PHASE_REQUIREMENT: &str = "internal-phase";
114 121
115 122 /// Stores manifest in Tree structure
116 123 #[allow(unused)]
117 124 pub(crate) const TREEMANIFEST_REQUIREMENT: &str = "treemanifest";
118 125
119 126 /// Increment the sub-version when the revlog v2 format changes to lock out old
120 127 /// clients.
121 128 #[allow(unused)]
122 129 pub(crate) const REVLOGV2_REQUIREMENT: &str = "exp-revlogv2.1";
123 130
124 131 /// A repository with the sparserevlog feature will have delta chains that
125 132 /// can spread over a larger span. Sparse reading cuts these large spans into
126 133 /// pieces, so that each piece isn't too big.
127 134 /// Without the sparserevlog capability, reading from the repository could use
128 135 /// huge amounts of memory, because the whole span would be read at once,
129 136 /// including all the intermediate revisions that aren't pertinent for the
130 137 /// chain. This is why once a repository has enabled sparse-read, it becomes
131 138 /// required.
132 139 #[allow(unused)]
133 140 pub(crate) const SPARSEREVLOG_REQUIREMENT: &str = "sparserevlog";
134 141
135 142 /// A repository with the the copies-sidedata-changeset requirement will store
136 143 /// copies related information in changeset's sidedata.
137 144 #[allow(unused)]
138 145 pub(crate) const COPIESSDC_REQUIREMENT: &str = "exp-copies-sidedata-changeset";
139 146
140 147 /// The repository use persistent nodemap for the changelog and the manifest.
141 148 #[allow(unused)]
142 149 pub(crate) const NODEMAP_REQUIREMENT: &str = "persistent-nodemap";
143 150
144 151 /// Denotes that the current repository is a share
145 152 #[allow(unused)]
146 153 pub(crate) const SHARED_REQUIREMENT: &str = "shared";
147 154
148 155 /// Denotes that current repository is a share and the shared source path is
149 156 /// relative to the current repository root path
150 157 #[allow(unused)]
151 158 pub(crate) const RELATIVE_SHARED_REQUIREMENT: &str = "relshared";
152 159
153 160 /// A repository with share implemented safely. The repository has different
154 161 /// store and working copy requirements i.e. both `.hg/requires` and
155 162 /// `.hg/store/requires` are present.
156 163 #[allow(unused)]
157 164 pub(crate) const SHARESAFE_REQUIREMENT: &str = "share-safe";
158 165
159 166 /// A repository that use zstd compression inside its revlog
160 167 #[allow(unused)]
161 168 pub(crate) const REVLOG_COMPRESSION_ZSTD: &str = "revlog-compression-zstd";
General Comments 0
You need to be logged in to leave comments. Login now