Show More
@@ -1,136 +1,132 b'' | |||
|
1 | 1 | // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net> |
|
2 | 2 | // and Mercurial contributors |
|
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 | 7 | mod ancestors; |
|
8 | 8 | pub mod dagops; |
|
9 | 9 | pub mod errors; |
|
10 | 10 | pub mod narrow; |
|
11 | 11 | pub mod sparse; |
|
12 | 12 | pub use ancestors::{AncestorsIterator, MissingAncestors}; |
|
13 | 13 | pub mod dirstate; |
|
14 | 14 | pub mod dirstate_tree; |
|
15 | 15 | pub mod discovery; |
|
16 | 16 | pub mod exit_codes; |
|
17 | 17 | pub mod requirements; |
|
18 | 18 | pub mod testing; // unconditionally built, for use from integration tests |
|
19 | 19 | pub use dirstate::{ |
|
20 | 20 | dirs_multiset::{DirsMultiset, DirsMultisetIter}, |
|
21 | 21 | status::{ |
|
22 | 22 | BadMatch, BadType, DirstateStatus, HgPathCow, StatusError, |
|
23 | 23 | StatusOptions, |
|
24 | 24 | }, |
|
25 | 25 | DirstateEntry, DirstateParents, EntryState, |
|
26 | 26 | }; |
|
27 | 27 | pub mod copy_tracing; |
|
28 | 28 | mod filepatterns; |
|
29 | 29 | pub mod matchers; |
|
30 | 30 | pub mod repo; |
|
31 | 31 | pub mod revlog; |
|
32 | 32 | pub use revlog::*; |
|
33 | 33 | pub mod checkexec; |
|
34 | 34 | pub mod config; |
|
35 | 35 | pub mod lock; |
|
36 | 36 | pub mod logging; |
|
37 | 37 | pub mod operations; |
|
38 | 38 | pub mod revset; |
|
39 | 39 | pub mod utils; |
|
40 | 40 | pub mod vfs; |
|
41 | 41 | |
|
42 | 42 | use crate::utils::hg_path::{HgPathBuf, HgPathError}; |
|
43 | 43 | pub use filepatterns::{ |
|
44 | 44 | parse_pattern_syntax, read_pattern_file, IgnorePattern, |
|
45 | 45 | PatternFileWarning, PatternSyntax, |
|
46 | 46 | }; |
|
47 | 47 | use std::collections::HashMap; |
|
48 | 48 | use std::fmt; |
|
49 | 49 | use twox_hash::RandomXxHashBuilder64; |
|
50 | 50 | |
|
51 | 51 | pub type LineNumber = usize; |
|
52 | 52 | |
|
53 | 53 | /// Rust's default hasher is too slow because it tries to prevent collision |
|
54 | 54 | /// attacks. We are not concerned about those: if an ill-minded person has |
|
55 | 55 | /// write access to your repository, you have other issues. |
|
56 | 56 | pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>; |
|
57 | 57 | |
|
58 | 58 | // TODO: should this be the default `FastHashMap` for all of hg-core, not just |
|
59 | 59 | // dirstate_tree? How does XxHash compare with AHash, hashbrownβs default? |
|
60 | 60 | pub type FastHashbrownMap<K, V> = |
|
61 | 61 | hashbrown::HashMap<K, V, RandomXxHashBuilder64>; |
|
62 | 62 | |
|
63 | 63 | #[derive(Debug, PartialEq)] |
|
64 | 64 | pub enum DirstateMapError { |
|
65 | 65 | PathNotFound(HgPathBuf), |
|
66 | EmptyPath, | |
|
67 | 66 | InvalidPath(HgPathError), |
|
68 | 67 | } |
|
69 | 68 | |
|
70 | 69 | impl fmt::Display for DirstateMapError { |
|
71 | 70 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
72 | 71 | match self { |
|
73 | 72 | DirstateMapError::PathNotFound(_) => { |
|
74 | 73 | f.write_str("expected a value, found none") |
|
75 | 74 | } |
|
76 | DirstateMapError::EmptyPath => { | |
|
77 | f.write_str("Overflow in dirstate.") | |
|
78 | } | |
|
79 | 75 | DirstateMapError::InvalidPath(path_error) => path_error.fmt(f), |
|
80 | 76 | } |
|
81 | 77 | } |
|
82 | 78 | } |
|
83 | 79 | |
|
84 | 80 | #[derive(Debug, derive_more::From)] |
|
85 | 81 | pub enum DirstateError { |
|
86 | 82 | Map(DirstateMapError), |
|
87 | 83 | Common(errors::HgError), |
|
88 | 84 | } |
|
89 | 85 | |
|
90 | 86 | impl fmt::Display for DirstateError { |
|
91 | 87 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
92 | 88 | match self { |
|
93 | 89 | DirstateError::Map(error) => error.fmt(f), |
|
94 | 90 | DirstateError::Common(error) => error.fmt(f), |
|
95 | 91 | } |
|
96 | 92 | } |
|
97 | 93 | } |
|
98 | 94 | |
|
99 | 95 | #[derive(Debug, derive_more::From)] |
|
100 | 96 | pub enum PatternError { |
|
101 | 97 | #[from] |
|
102 | 98 | Path(HgPathError), |
|
103 | 99 | UnsupportedSyntax(String), |
|
104 | 100 | UnsupportedSyntaxInFile(String, String, usize), |
|
105 | 101 | TooLong(usize), |
|
106 | 102 | #[from] |
|
107 | 103 | IO(std::io::Error), |
|
108 | 104 | /// Needed a pattern that can be turned into a regex but got one that |
|
109 | 105 | /// can't. This should only happen through programmer error. |
|
110 | 106 | NonRegexPattern(IgnorePattern), |
|
111 | 107 | } |
|
112 | 108 | |
|
113 | 109 | impl fmt::Display for PatternError { |
|
114 | 110 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
115 | 111 | match self { |
|
116 | 112 | PatternError::UnsupportedSyntax(syntax) => { |
|
117 | 113 | write!(f, "Unsupported syntax {}", syntax) |
|
118 | 114 | } |
|
119 | 115 | PatternError::UnsupportedSyntaxInFile(syntax, file_path, line) => { |
|
120 | 116 | write!( |
|
121 | 117 | f, |
|
122 | 118 | "{}:{}: unsupported syntax {}", |
|
123 | 119 | file_path, line, syntax |
|
124 | 120 | ) |
|
125 | 121 | } |
|
126 | 122 | PatternError::TooLong(size) => { |
|
127 | 123 | write!(f, "matcher pattern is too long ({} bytes)", size) |
|
128 | 124 | } |
|
129 | 125 | PatternError::IO(error) => error.fmt(f), |
|
130 | 126 | PatternError::Path(error) => error.fmt(f), |
|
131 | 127 | PatternError::NonRegexPattern(pattern) => { |
|
132 | 128 | write!(f, "'{:?}' cannot be turned into a regex", pattern) |
|
133 | 129 | } |
|
134 | 130 | } |
|
135 | 131 | } |
|
136 | 132 | } |
@@ -1,124 +1,118 b'' | |||
|
1 | 1 | // dirs_multiset.rs |
|
2 | 2 | // |
|
3 | 3 | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> |
|
4 | 4 | // |
|
5 | 5 | // This software may be used and distributed according to the terms of the |
|
6 | 6 | // GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | //! Bindings for the `hg::dirstate::dirs_multiset` file provided by the |
|
9 | 9 | //! `hg-core` package. |
|
10 | 10 | |
|
11 | 11 | use std::cell::RefCell; |
|
12 | 12 | |
|
13 | 13 | use cpython::{ |
|
14 | 14 | exc, ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyObject, PyResult, |
|
15 | 15 | Python, UnsafePyLeaked, |
|
16 | 16 | }; |
|
17 | 17 | |
|
18 | 18 | use hg::{ |
|
19 | 19 | utils::hg_path::{HgPath, HgPathBuf}, |
|
20 |
DirsMultiset, DirsMultisetIter, |
|
|
20 | DirsMultiset, DirsMultisetIter, | |
|
21 | 21 | }; |
|
22 | 22 | |
|
23 | 23 | py_class!(pub class Dirs |py| { |
|
24 | 24 | @shared data inner: DirsMultiset; |
|
25 | 25 | |
|
26 | 26 | // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes |
|
27 | 27 | // a `list`) |
|
28 | 28 | def __new__( |
|
29 | 29 | _cls, |
|
30 | 30 | map: PyObject, |
|
31 | 31 | ) -> PyResult<Self> { |
|
32 | 32 | let inner = if map.cast_as::<PyDict>(py).is_ok() { |
|
33 | 33 | let err = "pathutil.dirs() with a dict should only be used by the Python dirstatemap \ |
|
34 | 34 | and should not be used when Rust is enabled"; |
|
35 | 35 | return Err(PyErr::new::<exc::TypeError, _>(py, err.to_string())) |
|
36 | 36 | } else { |
|
37 | 37 | let map: Result<Vec<HgPathBuf>, PyErr> = map |
|
38 | 38 | .iter(py)? |
|
39 | 39 | .map(|o| { |
|
40 | 40 | Ok(HgPathBuf::from_bytes( |
|
41 | 41 | o?.extract::<PyBytes>(py)?.data(py), |
|
42 | 42 | )) |
|
43 | 43 | }) |
|
44 | 44 | .collect(); |
|
45 | 45 | DirsMultiset::from_manifest(&map?) |
|
46 | 46 | .map_err(|e| { |
|
47 | 47 | PyErr::new::<exc::ValueError, _>(py, e.to_string()) |
|
48 | 48 | })? |
|
49 | 49 | }; |
|
50 | 50 | |
|
51 | 51 | Self::create_instance(py, inner) |
|
52 | 52 | } |
|
53 | 53 | |
|
54 | 54 | def addpath(&self, path: PyObject) -> PyResult<PyObject> { |
|
55 | 55 | self.inner(py).borrow_mut().add_path( |
|
56 | 56 | HgPath::new(path.extract::<PyBytes>(py)?.data(py)), |
|
57 | 57 | ).and(Ok(py.None())).or_else(|e| { |
|
58 | 58 | match e { |
|
59 | DirstateMapError::EmptyPath => { | |
|
60 | Ok(py.None()) | |
|
61 | }, | |
|
62 | 59 | e => { |
|
63 | 60 | Err(PyErr::new::<exc::ValueError, _>( |
|
64 | 61 | py, |
|
65 | 62 | e.to_string(), |
|
66 | 63 | )) |
|
67 | 64 | } |
|
68 | 65 | } |
|
69 | 66 | }) |
|
70 | 67 | } |
|
71 | 68 | |
|
72 | 69 | def delpath(&self, path: PyObject) -> PyResult<PyObject> { |
|
73 | 70 | self.inner(py).borrow_mut().delete_path( |
|
74 | 71 | HgPath::new(path.extract::<PyBytes>(py)?.data(py)), |
|
75 | 72 | ) |
|
76 | 73 | .and(Ok(py.None())) |
|
77 | 74 | .or_else(|e| { |
|
78 | 75 | match e { |
|
79 | DirstateMapError::EmptyPath => { | |
|
80 | Ok(py.None()) | |
|
81 | }, | |
|
82 | 76 | e => { |
|
83 | 77 | Err(PyErr::new::<exc::ValueError, _>( |
|
84 | 78 | py, |
|
85 | 79 | e.to_string(), |
|
86 | 80 | )) |
|
87 | 81 | } |
|
88 | 82 | } |
|
89 | 83 | }) |
|
90 | 84 | } |
|
91 | 85 | def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> { |
|
92 | 86 | let leaked_ref = self.inner(py).leak_immutable(); |
|
93 | 87 | DirsMultisetKeysIterator::from_inner( |
|
94 | 88 | py, |
|
95 | 89 | unsafe { leaked_ref.map(py, |o| o.iter()) }, |
|
96 | 90 | ) |
|
97 | 91 | } |
|
98 | 92 | |
|
99 | 93 | def __contains__(&self, item: PyObject) -> PyResult<bool> { |
|
100 | 94 | Ok(self.inner(py).borrow().contains(HgPath::new( |
|
101 | 95 | item.extract::<PyBytes>(py)?.data(py), |
|
102 | 96 | ))) |
|
103 | 97 | } |
|
104 | 98 | }); |
|
105 | 99 | |
|
106 | 100 | impl Dirs { |
|
107 | 101 | pub fn from_inner(py: Python, d: DirsMultiset) -> PyResult<Self> { |
|
108 | 102 | Self::create_instance(py, d) |
|
109 | 103 | } |
|
110 | 104 | |
|
111 | 105 | fn translate_key( |
|
112 | 106 | py: Python, |
|
113 | 107 | res: &HgPathBuf, |
|
114 | 108 | ) -> PyResult<Option<PyBytes>> { |
|
115 | 109 | Ok(Some(PyBytes::new(py, res.as_bytes()))) |
|
116 | 110 | } |
|
117 | 111 | } |
|
118 | 112 | |
|
119 | 113 | py_shared_iterator!( |
|
120 | 114 | DirsMultisetKeysIterator, |
|
121 | 115 | UnsafePyLeaked<DirsMultisetIter<'static>>, |
|
122 | 116 | Dirs::translate_key, |
|
123 | 117 | Option<PyBytes> |
|
124 | 118 | ); |
General Comments 0
You need to be logged in to leave comments.
Login now