Show More
@@ -35,6 +35,9 b' pub enum IoErrorContext {' | |||
|
35 | 35 | |
|
36 | 36 | impl HgError { |
|
37 | 37 | pub fn corrupted(explanation: impl Into<String>) -> Self { |
|
38 | // TODO: capture a backtrace here and keep it in the error value | |
|
39 | // to aid debugging? | |
|
40 | // https://doc.rust-lang.org/std/backtrace/struct.Backtrace.html | |
|
38 | 41 | HgError::CorruptedRepository(explanation.into()) |
|
39 | 42 | } |
|
40 | 43 | } |
@@ -3,6 +3,7 b'' | |||
|
3 | 3 | // |
|
4 | 4 | // This software may be used and distributed according to the terms of the |
|
5 | 5 | // GNU General Public License version 2 or any later version. |
|
6 | ||
|
6 | 7 | mod ancestors; |
|
7 | 8 | pub mod dagops; |
|
8 | 9 | pub mod errors; |
@@ -33,8 +33,8 b' pub fn cat(' | |||
|
33 | 33 | let changelog = Changelog::open(repo)?; |
|
34 | 34 | let manifest = Manifest::open(repo)?; |
|
35 | 35 | let changelog_entry = changelog.get_rev(rev)?; |
|
36 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) | |
|
37 | .map_err(|_| RevlogError::Corrupted)?; | |
|
36 | let manifest_node = | |
|
37 | Node::from_hex_for_repo(&changelog_entry.manifest_node()?)?; | |
|
38 | 38 | let manifest_entry = manifest.get_node(manifest_node.into())?; |
|
39 | 39 | let mut bytes = vec![]; |
|
40 | 40 | |
@@ -46,8 +46,7 b' pub fn cat(' | |||
|
46 | 46 | |
|
47 | 47 | let file_log = |
|
48 | 48 | Revlog::open(repo, &index_path, Some(&data_path))?; |
|
49 | let file_node = Node::from_hex(node_bytes) | |
|
50 | .map_err(|_| RevlogError::Corrupted)?; | |
|
49 | let file_node = Node::from_hex_for_repo(node_bytes)?; | |
|
51 | 50 | let file_rev = file_log.get_node_rev(file_node.into())?; |
|
52 | 51 | let data = file_log.get_rev_data(file_rev)?; |
|
53 | 52 | if data.starts_with(&METADATA_DELIMITER) { |
@@ -6,7 +6,7 b'' | |||
|
6 | 6 | // GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | use crate::dirstate::parsers::parse_dirstate; |
|
9 |
use crate::errors:: |
|
|
9 | use crate::errors::HgError; | |
|
10 | 10 | use crate::repo::Repo; |
|
11 | 11 | use crate::revlog::changelog::Changelog; |
|
12 | 12 | use crate::revlog::manifest::{Manifest, ManifestEntry}; |
@@ -25,12 +25,7 b' pub struct Dirstate {' | |||
|
25 | 25 | |
|
26 | 26 | impl Dirstate { |
|
27 | 27 | pub fn new(repo: &Repo) -> Result<Self, HgError> { |
|
28 | let content = repo | |
|
29 | .hg_vfs() | |
|
30 | .read("dirstate") | |
|
31 | // TODO: this will be more accurate when we use `HgError` in | |
|
32 | // `Vfs::read`. | |
|
33 | .for_file("dirstate".as_ref())?; | |
|
28 | let content = repo.hg_vfs().read("dirstate")?; | |
|
34 | 29 | Ok(Self { content }) |
|
35 | 30 | } |
|
36 | 31 | |
@@ -57,8 +52,8 b' pub fn list_rev_tracked_files(' | |||
|
57 | 52 | let changelog = Changelog::open(repo)?; |
|
58 | 53 | let manifest = Manifest::open(repo)?; |
|
59 | 54 | let changelog_entry = changelog.get_rev(rev)?; |
|
60 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) | |
|
61 | .map_err(|_| RevlogError::Corrupted)?; | |
|
55 | let manifest_node = | |
|
56 | Node::from_hex_for_repo(&changelog_entry.manifest_node()?)?; | |
|
62 | 57 | let manifest_entry = manifest.get_node(manifest_node.into())?; |
|
63 | 58 | Ok(FilesForRev(manifest_entry)) |
|
64 | 59 | } |
@@ -1,4 +1,4 b'' | |||
|
1 | use crate::errors::HgError; | |
|
1 | use crate::errors::{HgError, IoResultExt}; | |
|
2 | 2 | use crate::operations::{find_root, FindRootError}; |
|
3 | 3 | use crate::requirements; |
|
4 | 4 | use memmap::{Mmap, MmapOptions}; |
@@ -68,24 +68,19 b" impl Vfs<'_> {" | |||
|
68 | 68 | pub(crate) fn read( |
|
69 | 69 | &self, |
|
70 | 70 | relative_path: impl AsRef<Path>, |
|
71 |
) -> |
|
|
72 |
|
|
|
73 | } | |
|
74 | ||
|
75 | pub(crate) fn open( | |
|
76 | &self, | |
|
77 | relative_path: impl AsRef<Path>, | |
|
78 | ) -> std::io::Result<std::fs::File> { | |
|
79 | std::fs::File::open(self.base.join(relative_path)) | |
|
71 | ) -> Result<Vec<u8>, HgError> { | |
|
72 | let path = self.base.join(relative_path); | |
|
73 | std::fs::read(&path).for_file(&path) | |
|
80 | 74 | } |
|
81 | 75 | |
|
82 | 76 | pub(crate) fn mmap_open( |
|
83 | 77 | &self, |
|
84 | 78 | relative_path: impl AsRef<Path>, |
|
85 |
) -> |
|
|
86 |
let |
|
|
79 | ) -> Result<Mmap, HgError> { | |
|
80 | let path = self.base.join(relative_path); | |
|
81 | let file = std::fs::File::open(&path).for_file(&path)?; | |
|
87 | 82 | // TODO: what are the safety requirements here? |
|
88 | let mmap = unsafe { MmapOptions::new().map(&file) }?; | |
|
83 | let mmap = unsafe { MmapOptions::new().map(&file) }.for_file(&path)?; | |
|
89 | 84 | Ok(mmap) |
|
90 | 85 | } |
|
91 | 86 | } |
@@ -1,4 +1,4 b'' | |||
|
1 |
use crate::errors::{HgError, HgResultExt |
|
|
1 | use crate::errors::{HgError, HgResultExt}; | |
|
2 | 2 | use crate::repo::Repo; |
|
3 | 3 | |
|
4 | 4 | fn parse(bytes: &[u8]) -> Result<Vec<String>, HgError> { |
@@ -22,11 +22,8 b' fn parse(bytes: &[u8]) -> Result<Vec<Str' | |||
|
22 | 22 | } |
|
23 | 23 | |
|
24 | 24 | pub fn load(repo: &Repo) -> Result<Vec<String>, HgError> { |
|
25 |
if let Some(bytes) = |
|
|
26 | .hg_vfs() | |
|
27 | .read("requires") | |
|
28 | .for_file("requires".as_ref()) | |
|
29 | .io_not_found_as_none()? | |
|
25 | if let Some(bytes) = | |
|
26 | repo.hg_vfs().read("requires").io_not_found_as_none()? | |
|
30 | 27 | { |
|
31 | 28 | parse(&bytes) |
|
32 | 29 | } else { |
@@ -1,3 +1,4 b'' | |||
|
1 | use crate::errors::HgError; | |
|
1 | 2 | use crate::repo::Repo; |
|
2 | 3 | use crate::revlog::revlog::{Revlog, RevlogError}; |
|
3 | 4 | use crate::revlog::NodePrefix; |
@@ -53,6 +54,8 b' impl ChangelogEntry {' | |||
|
53 | 54 | /// Return the node id of the `manifest` referenced by this `changelog` |
|
54 | 55 | /// entry. |
|
55 | 56 | pub fn manifest_node(&self) -> Result<&[u8], RevlogError> { |
|
56 | self.lines().next().ok_or(RevlogError::Corrupted) | |
|
57 | self.lines() | |
|
58 | .next() | |
|
59 | .ok_or_else(|| HgError::corrupted("empty changelog entry").into()) | |
|
57 | 60 | } |
|
58 | 61 | } |
@@ -3,6 +3,7 b' use std::ops::Deref;' | |||
|
3 | 3 | |
|
4 | 4 | use byteorder::{BigEndian, ByteOrder}; |
|
5 | 5 | |
|
6 | use crate::errors::HgError; | |
|
6 | 7 | use crate::revlog::node::Node; |
|
7 | 8 | use crate::revlog::revlog::RevlogError; |
|
8 | 9 | use crate::revlog::{Revision, NULL_REVISION}; |
@@ -44,7 +45,8 b' impl Index {' | |||
|
44 | 45 | offsets: Some(offsets), |
|
45 | 46 | }) |
|
46 | 47 | } else { |
|
47 |
Err( |
|
|
48 | Err(HgError::corrupted("unexpected inline revlog length") | |
|
49 | .into()) | |
|
48 | 50 | } |
|
49 | 51 | } else { |
|
50 | 52 | Ok(Self { |
@@ -8,6 +8,7 b'' | |||
|
8 | 8 | //! In Mercurial code base, it is customary to call "a node" the binary SHA |
|
9 | 9 | //! of a revision. |
|
10 | 10 | |
|
11 | use crate::errors::HgError; | |
|
11 | 12 | use bytes_cast::BytesCast; |
|
12 | 13 | use std::convert::{TryFrom, TryInto}; |
|
13 | 14 | use std::fmt; |
@@ -136,6 +137,19 b' impl Node {' | |||
|
136 | 137 | } |
|
137 | 138 | } |
|
138 | 139 | |
|
140 | /// `from_hex`, but for input from an internal file of the repository such | |
|
141 | /// as a changelog or manifest entry. | |
|
142 | /// | |
|
143 | /// An error is treated as repository corruption. | |
|
144 | pub fn from_hex_for_repo(hex: impl AsRef<[u8]>) -> Result<Node, HgError> { | |
|
145 | Self::from_hex(hex.as_ref()).map_err(|FromHexError| { | |
|
146 | HgError::CorruptedRepository(format!( | |
|
147 | "Expected a full hexadecimal node ID, found {}", | |
|
148 | String::from_utf8_lossy(hex.as_ref()) | |
|
149 | )) | |
|
150 | }) | |
|
151 | } | |
|
152 | ||
|
139 | 153 | /// Provide access to binary data |
|
140 | 154 | /// |
|
141 | 155 | /// This is needed by FFI layers, for instance to return expected |
@@ -1,3 +1,4 b'' | |||
|
1 | use crate::errors::{HgError, HgResultExt}; | |
|
1 | 2 | use bytes_cast::{unaligned, BytesCast}; |
|
2 | 3 | use memmap::Mmap; |
|
3 | 4 | use std::path::{Path, PathBuf}; |
@@ -38,12 +39,12 b' impl NodeMapDocket {' | |||
|
38 | 39 | index_path: &Path, |
|
39 | 40 | ) -> Result<Option<(Self, Mmap)>, RevlogError> { |
|
40 | 41 | let docket_path = index_path.with_extension("n"); |
|
41 | let docket_bytes = match repo.store_vfs().read(&docket_path) { | |
|
42 | Err(e) if e.kind() == std::io::ErrorKind::NotFound => { | |
|
43 | return Ok(None) | |
|
44 |
|
|
|
45 | Err(e) => return Err(RevlogError::IoError(e)), | |
|
46 | Ok(bytes) => bytes, | |
|
42 | let docket_bytes = if let Some(bytes) = | |
|
43 | repo.store_vfs().read(&docket_path).io_not_found_as_none()? | |
|
44 | { | |
|
45 | bytes | |
|
46 | } else { | |
|
47 | return Ok(None); | |
|
47 | 48 | }; |
|
48 | 49 | |
|
49 | 50 | let input = if let Some((&ONDISK_VERSION, rest)) = |
@@ -54,36 +55,40 b' impl NodeMapDocket {' | |||
|
54 | 55 | return Ok(None); |
|
55 | 56 | }; |
|
56 | 57 | |
|
57 | let (header, rest) = DocketHeader::from_bytes(input)?; | |
|
58 | /// Treat any error as a parse error | |
|
59 | fn parse<T, E>(result: Result<T, E>) -> Result<T, RevlogError> { | |
|
60 | result.map_err(|_| { | |
|
61 | HgError::corrupted("nodemap docket parse error").into() | |
|
62 | }) | |
|
63 | } | |
|
64 | ||
|
65 | let (header, rest) = parse(DocketHeader::from_bytes(input))?; | |
|
58 | 66 | let uid_size = header.uid_size as usize; |
|
59 | 67 | // TODO: do we care about overflow for 4 GB+ nodemap files on 32-bit |
|
60 | 68 | // systems? |
|
61 | 69 | let tip_node_size = header.tip_node_size.get() as usize; |
|
62 | 70 | let data_length = header.data_length.get() as usize; |
|
63 | let (uid, rest) = u8::slice_from_bytes(rest, uid_size)?; | |
|
64 | let (_tip_node, _rest) = u8::slice_from_bytes(rest, tip_node_size)?; | |
|
65 | let uid = | |
|
66 |
|
|
|
71 | let (uid, rest) = parse(u8::slice_from_bytes(rest, uid_size))?; | |
|
72 | let (_tip_node, _rest) = | |
|
73 | parse(u8::slice_from_bytes(rest, tip_node_size))?; | |
|
74 | let uid = parse(std::str::from_utf8(uid))?; | |
|
67 | 75 | let docket = NodeMapDocket { data_length }; |
|
68 | 76 | |
|
69 | 77 | let data_path = rawdata_path(&docket_path, uid); |
|
70 |
// TODO: use ` |
|
|
78 | // TODO: use `vfs.read()` here when the `persistent-nodemap.mmap` | |
|
71 | 79 | // config is false? |
|
72 | match repo.store_vfs().mmap_open(&data_path) { | |
|
73 | Ok(mmap) => { | |
|
74 |
|
|
|
75 | Ok(Some((docket, mmap))) | |
|
76 | } else { | |
|
77 | Err(RevlogError::Corrupted) | |
|
78 | } | |
|
80 | if let Some(mmap) = repo | |
|
81 | .store_vfs() | |
|
82 | .mmap_open(&data_path) | |
|
83 | .io_not_found_as_none()? | |
|
84 | { | |
|
85 | if mmap.len() >= data_length { | |
|
86 | Ok(Some((docket, mmap))) | |
|
87 | } else { | |
|
88 | Err(HgError::corrupted("persistent nodemap too short").into()) | |
|
79 | 89 | } |
|
80 | Err(error) => { | |
|
81 | if error.kind() == std::io::ErrorKind::NotFound { | |
|
82 | Ok(None) | |
|
83 | } else { | |
|
84 | Err(RevlogError::IoError(error)) | |
|
85 | } | |
|
86 | } | |
|
90 | } else { | |
|
91 | Ok(None) | |
|
87 | 92 | } |
|
88 | 93 | } |
|
89 | 94 | } |
@@ -13,25 +13,34 b' use zstd;' | |||
|
13 | 13 | use super::index::Index; |
|
14 | 14 | use super::node::{NodePrefix, NODE_BYTES_LENGTH, NULL_NODE}; |
|
15 | 15 | use super::nodemap; |
|
16 | use super::nodemap::NodeMap; | |
|
16 | use super::nodemap::{NodeMap, NodeMapError}; | |
|
17 | 17 | use super::nodemap_docket::NodeMapDocket; |
|
18 | 18 | use super::patch; |
|
19 | use crate::errors::HgError; | |
|
19 | 20 | use crate::repo::Repo; |
|
20 | 21 | use crate::revlog::Revision; |
|
21 | 22 | |
|
23 | #[derive(derive_more::From)] | |
|
22 | 24 | pub enum RevlogError { |
|
23 | IoError(std::io::Error), | |
|
24 | UnsuportedVersion(u16), | |
|
25 | 25 | InvalidRevision, |
|
26 | 26 | /// Found more than one entry whose ID match the requested prefix |
|
27 | 27 | AmbiguousPrefix, |
|
28 | Corrupted, | |
|
29 | UnknowDataFormat(u8), | |
|
28 | #[from] | |
|
29 | Other(HgError), | |
|
30 | 30 | } |
|
31 | 31 | |
|
32 |
impl From< |
|
|
33 |
fn from( |
|
|
34 | RevlogError::Corrupted | |
|
32 | impl From<NodeMapError> for RevlogError { | |
|
33 | fn from(error: NodeMapError) -> Self { | |
|
34 | match error { | |
|
35 | NodeMapError::MultipleResults => RevlogError::AmbiguousPrefix, | |
|
36 | NodeMapError::RevisionNotInIndex(_) => RevlogError::corrupted(), | |
|
37 | } | |
|
38 | } | |
|
39 | } | |
|
40 | ||
|
41 | impl RevlogError { | |
|
42 | fn corrupted() -> Self { | |
|
43 | RevlogError::Other(HgError::corrupted("corrupted revlog")) | |
|
35 | 44 | } |
|
36 | 45 | } |
|
37 | 46 | |
@@ -59,14 +68,12 b' impl Revlog {' | |||
|
59 | 68 | data_path: Option<&Path>, |
|
60 | 69 | ) -> Result<Self, RevlogError> { |
|
61 | 70 | let index_path = index_path.as_ref(); |
|
62 | let index_mmap = repo | |
|
63 | .store_vfs() | |
|
64 | .mmap_open(&index_path) | |
|
65 | .map_err(RevlogError::IoError)?; | |
|
71 | let index_mmap = repo.store_vfs().mmap_open(&index_path)?; | |
|
66 | 72 | |
|
67 | 73 | let version = get_version(&index_mmap); |
|
68 | 74 | if version != 1 { |
|
69 | return Err(RevlogError::UnsuportedVersion(version)); | |
|
75 | // A proper new version should have had a repo/store requirement. | |
|
76 | return Err(RevlogError::corrupted()); | |
|
70 | 77 | } |
|
71 | 78 | |
|
72 | 79 | let index = Index::new(Box::new(index_mmap))?; |
@@ -80,10 +87,7 b' impl Revlog {' | |||
|
80 | 87 | None |
|
81 | 88 | } else { |
|
82 | 89 | let data_path = data_path.unwrap_or(&default_data_path); |
|
83 | let data_mmap = repo | |
|
84 | .store_vfs() | |
|
85 | .mmap_open(data_path) | |
|
86 | .map_err(RevlogError::IoError)?; | |
|
90 | let data_mmap = repo.store_vfs().mmap_open(data_path)?; | |
|
87 | 91 | Some(Box::new(data_mmap)) |
|
88 | 92 | }; |
|
89 | 93 | |
@@ -121,9 +125,7 b' impl Revlog {' | |||
|
121 | 125 | ) -> Result<Revision, RevlogError> { |
|
122 | 126 | if let Some(nodemap) = &self.nodemap { |
|
123 | 127 | return nodemap |
|
124 | .find_bin(&self.index, node) | |
|
125 | // TODO: propagate details of this error: | |
|
126 | .map_err(|_| RevlogError::Corrupted)? | |
|
128 | .find_bin(&self.index, node)? | |
|
127 | 129 | .ok_or(RevlogError::InvalidRevision); |
|
128 | 130 | } |
|
129 | 131 | |
@@ -136,7 +138,9 b' impl Revlog {' | |||
|
136 | 138 | let mut found_by_prefix = None; |
|
137 | 139 | for rev in (0..self.len() as Revision).rev() { |
|
138 | 140 | let index_entry = |
|
139 |
self.index.get_entry(rev).ok_or( |
|
|
141 | self.index.get_entry(rev).ok_or(HgError::corrupted( | |
|
142 | "revlog references a revision not in the index", | |
|
143 | ))?; | |
|
140 | 144 | if node == *index_entry.hash() { |
|
141 | 145 | return Ok(rev); |
|
142 | 146 | } |
@@ -167,8 +171,9 b' impl Revlog {' | |||
|
167 | 171 | let mut delta_chain = vec![]; |
|
168 | 172 | while let Some(base_rev) = entry.base_rev { |
|
169 | 173 | delta_chain.push(entry); |
|
170 | entry = | |
|
171 |
|
|
|
174 | entry = self | |
|
175 | .get_entry(base_rev) | |
|
176 | .map_err(|_| RevlogError::corrupted())?; | |
|
172 | 177 | } |
|
173 | 178 | |
|
174 | 179 | // TODO do not look twice in the index |
@@ -191,7 +196,7 b' impl Revlog {' | |||
|
191 | 196 | ) { |
|
192 | 197 | Ok(data) |
|
193 | 198 | } else { |
|
194 |
Err(RevlogError:: |
|
|
199 | Err(RevlogError::corrupted()) | |
|
195 | 200 | } |
|
196 | 201 | } |
|
197 | 202 | |
@@ -301,7 +306,8 b" impl<'a> RevlogEntry<'a> {" | |||
|
301 | 306 | b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data()?)), |
|
302 | 307 | // zstd data. |
|
303 | 308 | b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)), |
|
304 | format_type => Err(RevlogError::UnknowDataFormat(format_type)), | |
|
309 | // A proper new format should have had a repo/store requirement. | |
|
310 | _format_type => Err(RevlogError::corrupted()), | |
|
305 | 311 | } |
|
306 | 312 | } |
|
307 | 313 | |
@@ -311,13 +317,13 b" impl<'a> RevlogEntry<'a> {" | |||
|
311 | 317 | let mut buf = Vec::with_capacity(self.compressed_len); |
|
312 | 318 | decoder |
|
313 | 319 | .read_to_end(&mut buf) |
|
314 |
. |
|
|
320 | .map_err(|_| RevlogError::corrupted())?; | |
|
315 | 321 | Ok(buf) |
|
316 | 322 | } else { |
|
317 | 323 | let mut buf = vec![0; self.uncompressed_len]; |
|
318 | 324 | decoder |
|
319 | 325 | .read_exact(&mut buf) |
|
320 |
. |
|
|
326 | .map_err(|_| RevlogError::corrupted())?; | |
|
321 | 327 | Ok(buf) |
|
322 | 328 | } |
|
323 | 329 | } |
@@ -326,14 +332,14 b" impl<'a> RevlogEntry<'a> {" | |||
|
326 | 332 | if self.is_delta() { |
|
327 | 333 | let mut buf = Vec::with_capacity(self.compressed_len); |
|
328 | 334 | zstd::stream::copy_decode(self.bytes, &mut buf) |
|
329 |
. |
|
|
335 | .map_err(|_| RevlogError::corrupted())?; | |
|
330 | 336 | Ok(buf) |
|
331 | 337 | } else { |
|
332 | 338 | let mut buf = vec![0; self.uncompressed_len]; |
|
333 | 339 | let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf) |
|
334 |
. |
|
|
340 | .map_err(|_| RevlogError::corrupted())?; | |
|
335 | 341 | if len != self.uncompressed_len { |
|
336 |
Err(RevlogError:: |
|
|
342 | Err(RevlogError::corrupted()) | |
|
337 | 343 | } else { |
|
338 | 344 | Ok(buf) |
|
339 | 345 | } |
@@ -103,9 +103,6 b' impl From<FindRootError> for CommandErro' | |||
|
103 | 103 | impl From<(RevlogError, &str)> for CommandError { |
|
104 | 104 | fn from((err, rev): (RevlogError, &str)) -> CommandError { |
|
105 | 105 | match err { |
|
106 | RevlogError::IoError(err) => CommandError::Abort(Some( | |
|
107 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
108 | )), | |
|
109 | 106 | RevlogError::InvalidRevision => CommandError::Abort(Some( |
|
110 | 107 | utf8_to_local(&format!( |
|
111 | 108 | "abort: invalid revision identifier {}\n", |
@@ -120,27 +117,7 b' impl From<(RevlogError, &str)> for Comma' | |||
|
120 | 117 | )) |
|
121 | 118 | .into(), |
|
122 | 119 | )), |
|
123 |
RevlogError:: |
|
|
124 | CommandError::Abort(Some( | |
|
125 | utf8_to_local(&format!( | |
|
126 | "abort: unsupported revlog version {}\n", | |
|
127 | version | |
|
128 | )) | |
|
129 | .into(), | |
|
130 | )) | |
|
131 | } | |
|
132 | RevlogError::Corrupted => { | |
|
133 | CommandError::Abort(Some("abort: corrupted revlog\n".into())) | |
|
134 | } | |
|
135 | RevlogError::UnknowDataFormat(format) => { | |
|
136 | CommandError::Abort(Some( | |
|
137 | utf8_to_local(&format!( | |
|
138 | "abort: unknow revlog dataformat {:?}\n", | |
|
139 | format | |
|
140 | )) | |
|
141 | .into(), | |
|
142 | )) | |
|
143 | } | |
|
120 | RevlogError::Other(err) => CommandError::Other(err), | |
|
144 | 121 | } |
|
145 | 122 | } |
|
146 | 123 | } |
General Comments 0
You need to be logged in to leave comments.
Login now