##// END OF EJS Templates
rust: remove unused `StatusError::IO` enum variant...
Simon Sapin -
r49590:6e930bc4 default
parent child Browse files
Show More
@@ -1,154 +1,151 b''
1 // status.rs
1 // status.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Rust implementation of dirstate.status (dirstate.py).
8 //! Rust implementation of dirstate.status (dirstate.py).
9 //! It is currently missing a lot of functionality compared to the Python one
9 //! It is currently missing a lot of functionality compared to the Python one
10 //! and will only be triggered in narrow cases.
10 //! and will only be triggered in narrow cases.
11
11
12 use crate::dirstate::entry::TruncatedTimestamp;
12 use crate::dirstate::entry::TruncatedTimestamp;
13 use crate::dirstate_tree::on_disk::DirstateV2ParseError;
13 use crate::dirstate_tree::on_disk::DirstateV2ParseError;
14 use crate::{
14 use crate::{
15 utils::hg_path::{HgPath, HgPathError},
15 utils::hg_path::{HgPath, HgPathError},
16 PatternError,
16 PatternError,
17 };
17 };
18
18
19 use std::{borrow::Cow, fmt};
19 use std::{borrow::Cow, fmt};
20
20
21 /// Wrong type of file from a `BadMatch`
21 /// Wrong type of file from a `BadMatch`
22 /// Note: a lot of those don't exist on all platforms.
22 /// Note: a lot of those don't exist on all platforms.
23 #[derive(Debug, Copy, Clone)]
23 #[derive(Debug, Copy, Clone)]
24 pub enum BadType {
24 pub enum BadType {
25 CharacterDevice,
25 CharacterDevice,
26 BlockDevice,
26 BlockDevice,
27 FIFO,
27 FIFO,
28 Socket,
28 Socket,
29 Directory,
29 Directory,
30 Unknown,
30 Unknown,
31 }
31 }
32
32
33 impl fmt::Display for BadType {
33 impl fmt::Display for BadType {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 f.write_str(match self {
35 f.write_str(match self {
36 BadType::CharacterDevice => "character device",
36 BadType::CharacterDevice => "character device",
37 BadType::BlockDevice => "block device",
37 BadType::BlockDevice => "block device",
38 BadType::FIFO => "fifo",
38 BadType::FIFO => "fifo",
39 BadType::Socket => "socket",
39 BadType::Socket => "socket",
40 BadType::Directory => "directory",
40 BadType::Directory => "directory",
41 BadType::Unknown => "unknown",
41 BadType::Unknown => "unknown",
42 })
42 })
43 }
43 }
44 }
44 }
45
45
46 /// Was explicitly matched but cannot be found/accessed
46 /// Was explicitly matched but cannot be found/accessed
47 #[derive(Debug, Copy, Clone)]
47 #[derive(Debug, Copy, Clone)]
48 pub enum BadMatch {
48 pub enum BadMatch {
49 OsError(i32),
49 OsError(i32),
50 BadType(BadType),
50 BadType(BadType),
51 }
51 }
52
52
53 /// `Box<dyn Trait>` is syntactic sugar for `Box<dyn Trait + 'static>`, so add
53 /// `Box<dyn Trait>` is syntactic sugar for `Box<dyn Trait + 'static>`, so add
54 /// an explicit lifetime here to not fight `'static` bounds "out of nowhere".
54 /// an explicit lifetime here to not fight `'static` bounds "out of nowhere".
55 pub type IgnoreFnType<'a> =
55 pub type IgnoreFnType<'a> =
56 Box<dyn for<'r> Fn(&'r HgPath) -> bool + Sync + 'a>;
56 Box<dyn for<'r> Fn(&'r HgPath) -> bool + Sync + 'a>;
57
57
58 /// We have a good mix of owned (from directory traversal) and borrowed (from
58 /// We have a good mix of owned (from directory traversal) and borrowed (from
59 /// the dirstate/explicit) paths, this comes up a lot.
59 /// the dirstate/explicit) paths, this comes up a lot.
60 pub type HgPathCow<'a> = Cow<'a, HgPath>;
60 pub type HgPathCow<'a> = Cow<'a, HgPath>;
61
61
62 #[derive(Debug, Copy, Clone)]
62 #[derive(Debug, Copy, Clone)]
63 pub struct StatusOptions {
63 pub struct StatusOptions {
64 /// Whether we are on a filesystem with UNIX-like exec flags
64 /// Whether we are on a filesystem with UNIX-like exec flags
65 pub check_exec: bool,
65 pub check_exec: bool,
66 pub list_clean: bool,
66 pub list_clean: bool,
67 pub list_unknown: bool,
67 pub list_unknown: bool,
68 pub list_ignored: bool,
68 pub list_ignored: bool,
69 /// Whether to populate `StatusPath::copy_source`
69 /// Whether to populate `StatusPath::copy_source`
70 pub list_copies: bool,
70 pub list_copies: bool,
71 /// Whether to collect traversed dirs for applying a callback later.
71 /// Whether to collect traversed dirs for applying a callback later.
72 /// Used by `hg purge` for example.
72 /// Used by `hg purge` for example.
73 pub collect_traversed_dirs: bool,
73 pub collect_traversed_dirs: bool,
74 }
74 }
75
75
76 #[derive(Default)]
76 #[derive(Default)]
77 pub struct DirstateStatus<'a> {
77 pub struct DirstateStatus<'a> {
78 /// The current time at the start of the `status()` algorithm, as measured
78 /// The current time at the start of the `status()` algorithm, as measured
79 /// and possibly truncated by the filesystem.
79 /// and possibly truncated by the filesystem.
80 pub filesystem_time_at_status_start: Option<TruncatedTimestamp>,
80 pub filesystem_time_at_status_start: Option<TruncatedTimestamp>,
81
81
82 /// Tracked files whose contents have changed since the parent revision
82 /// Tracked files whose contents have changed since the parent revision
83 pub modified: Vec<StatusPath<'a>>,
83 pub modified: Vec<StatusPath<'a>>,
84
84
85 /// Newly-tracked files that were not present in the parent
85 /// Newly-tracked files that were not present in the parent
86 pub added: Vec<StatusPath<'a>>,
86 pub added: Vec<StatusPath<'a>>,
87
87
88 /// Previously-tracked files that have been (re)moved with an hg command
88 /// Previously-tracked files that have been (re)moved with an hg command
89 pub removed: Vec<StatusPath<'a>>,
89 pub removed: Vec<StatusPath<'a>>,
90
90
91 /// (Still) tracked files that are missing, (re)moved with an non-hg
91 /// (Still) tracked files that are missing, (re)moved with an non-hg
92 /// command
92 /// command
93 pub deleted: Vec<StatusPath<'a>>,
93 pub deleted: Vec<StatusPath<'a>>,
94
94
95 /// Tracked files that are up to date with the parent.
95 /// Tracked files that are up to date with the parent.
96 /// Only pupulated if `StatusOptions::list_clean` is true.
96 /// Only pupulated if `StatusOptions::list_clean` is true.
97 pub clean: Vec<StatusPath<'a>>,
97 pub clean: Vec<StatusPath<'a>>,
98
98
99 /// Files in the working directory that are ignored with `.hgignore`.
99 /// Files in the working directory that are ignored with `.hgignore`.
100 /// Only pupulated if `StatusOptions::list_ignored` is true.
100 /// Only pupulated if `StatusOptions::list_ignored` is true.
101 pub ignored: Vec<StatusPath<'a>>,
101 pub ignored: Vec<StatusPath<'a>>,
102
102
103 /// Files in the working directory that are neither tracked nor ignored.
103 /// Files in the working directory that are neither tracked nor ignored.
104 /// Only pupulated if `StatusOptions::list_unknown` is true.
104 /// Only pupulated if `StatusOptions::list_unknown` is true.
105 pub unknown: Vec<StatusPath<'a>>,
105 pub unknown: Vec<StatusPath<'a>>,
106
106
107 /// Was explicitly matched but cannot be found/accessed
107 /// Was explicitly matched but cannot be found/accessed
108 pub bad: Vec<(HgPathCow<'a>, BadMatch)>,
108 pub bad: Vec<(HgPathCow<'a>, BadMatch)>,
109
109
110 /// Either clean or modified, but we can’t tell from filesystem metadata
110 /// Either clean or modified, but we can’t tell from filesystem metadata
111 /// alone. The file contents need to be read and compared with that in
111 /// alone. The file contents need to be read and compared with that in
112 /// the parent.
112 /// the parent.
113 pub unsure: Vec<StatusPath<'a>>,
113 pub unsure: Vec<StatusPath<'a>>,
114
114
115 /// Only filled if `collect_traversed_dirs` is `true`
115 /// Only filled if `collect_traversed_dirs` is `true`
116 pub traversed: Vec<HgPathCow<'a>>,
116 pub traversed: Vec<HgPathCow<'a>>,
117
117
118 /// Whether `status()` made changed to the `DirstateMap` that should be
118 /// Whether `status()` made changed to the `DirstateMap` that should be
119 /// written back to disk
119 /// written back to disk
120 pub dirty: bool,
120 pub dirty: bool,
121 }
121 }
122
122
123 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
123 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
124 pub struct StatusPath<'a> {
124 pub struct StatusPath<'a> {
125 pub path: HgPathCow<'a>,
125 pub path: HgPathCow<'a>,
126 pub copy_source: Option<HgPathCow<'a>>,
126 pub copy_source: Option<HgPathCow<'a>>,
127 }
127 }
128
128
129 #[derive(Debug, derive_more::From)]
129 #[derive(Debug, derive_more::From)]
130 pub enum StatusError {
130 pub enum StatusError {
131 /// Generic IO error
132 IO(std::io::Error),
133 /// An invalid path that cannot be represented in Mercurial was found
131 /// An invalid path that cannot be represented in Mercurial was found
134 Path(HgPathError),
132 Path(HgPathError),
135 /// An invalid "ignore" pattern was found
133 /// An invalid "ignore" pattern was found
136 Pattern(PatternError),
134 Pattern(PatternError),
137 /// Corrupted dirstate
135 /// Corrupted dirstate
138 DirstateV2ParseError(DirstateV2ParseError),
136 DirstateV2ParseError(DirstateV2ParseError),
139 }
137 }
140
138
141 pub type StatusResult<T> = Result<T, StatusError>;
139 pub type StatusResult<T> = Result<T, StatusError>;
142
140
143 impl fmt::Display for StatusError {
141 impl fmt::Display for StatusError {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 match self {
143 match self {
146 StatusError::IO(error) => error.fmt(f),
147 StatusError::Path(error) => error.fmt(f),
144 StatusError::Path(error) => error.fmt(f),
148 StatusError::Pattern(error) => error.fmt(f),
145 StatusError::Pattern(error) => error.fmt(f),
149 StatusError::DirstateV2ParseError(_) => {
146 StatusError::DirstateV2ParseError(_) => {
150 f.write_str("dirstate-v2 parse error")
147 f.write_str("dirstate-v2 parse error")
151 }
148 }
152 }
149 }
153 }
150 }
154 }
151 }
@@ -1,305 +1,303 b''
1 // status.rs
1 // status.rs
2 //
2 //
3 // Copyright 2019, Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019, Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Bindings for the `hg::status` module provided by the
8 //! Bindings for the `hg::status` module provided by the
9 //! `hg-core` crate. From Python, this will be seen as
9 //! `hg-core` crate. From Python, this will be seen as
10 //! `rustext.dirstate.status`.
10 //! `rustext.dirstate.status`.
11
11
12 use crate::{dirstate::DirstateMap, exceptions::FallbackError};
12 use crate::{dirstate::DirstateMap, exceptions::FallbackError};
13 use cpython::exc::OSError;
14 use cpython::{
13 use cpython::{
15 exc::ValueError, ObjectProtocol, PyBytes, PyErr, PyList, PyObject,
14 exc::ValueError, ObjectProtocol, PyBytes, PyErr, PyList, PyObject,
16 PyResult, PyTuple, Python, PythonObject, ToPyObject,
15 PyResult, PyTuple, Python, PythonObject, ToPyObject,
17 };
16 };
18 use hg::dirstate::status::StatusPath;
17 use hg::dirstate::status::StatusPath;
19 use hg::{
18 use hg::{
20 matchers::{AlwaysMatcher, FileMatcher, IncludeMatcher},
19 matchers::{AlwaysMatcher, FileMatcher, IncludeMatcher},
21 parse_pattern_syntax,
20 parse_pattern_syntax,
22 utils::{
21 utils::{
23 files::{get_bytes_from_path, get_path_from_bytes},
22 files::{get_bytes_from_path, get_path_from_bytes},
24 hg_path::{HgPath, HgPathBuf},
23 hg_path::{HgPath, HgPathBuf},
25 },
24 },
26 BadMatch, DirstateStatus, IgnorePattern, PatternFileWarning, StatusError,
25 BadMatch, DirstateStatus, IgnorePattern, PatternFileWarning, StatusError,
27 StatusOptions,
26 StatusOptions,
28 };
27 };
29 use std::borrow::Borrow;
28 use std::borrow::Borrow;
30
29
31 fn collect_status_path_list(py: Python, paths: &[StatusPath<'_>]) -> PyList {
30 fn collect_status_path_list(py: Python, paths: &[StatusPath<'_>]) -> PyList {
32 collect_pybytes_list(py, paths.iter().map(|item| &*item.path))
31 collect_pybytes_list(py, paths.iter().map(|item| &*item.path))
33 }
32 }
34
33
35 /// This will be useless once trait impls for collection are added to `PyBytes`
34 /// This will be useless once trait impls for collection are added to `PyBytes`
36 /// upstream.
35 /// upstream.
37 fn collect_pybytes_list(
36 fn collect_pybytes_list(
38 py: Python,
37 py: Python,
39 iter: impl Iterator<Item = impl AsRef<HgPath>>,
38 iter: impl Iterator<Item = impl AsRef<HgPath>>,
40 ) -> PyList {
39 ) -> PyList {
41 let list = PyList::new(py, &[]);
40 let list = PyList::new(py, &[]);
42
41
43 for path in iter {
42 for path in iter {
44 list.append(
43 list.append(
45 py,
44 py,
46 PyBytes::new(py, path.as_ref().as_bytes()).into_object(),
45 PyBytes::new(py, path.as_ref().as_bytes()).into_object(),
47 )
46 )
48 }
47 }
49
48
50 list
49 list
51 }
50 }
52
51
53 fn collect_bad_matches(
52 fn collect_bad_matches(
54 py: Python,
53 py: Python,
55 collection: &[(impl AsRef<HgPath>, BadMatch)],
54 collection: &[(impl AsRef<HgPath>, BadMatch)],
56 ) -> PyResult<PyList> {
55 ) -> PyResult<PyList> {
57 let list = PyList::new(py, &[]);
56 let list = PyList::new(py, &[]);
58
57
59 let os = py.import("os")?;
58 let os = py.import("os")?;
60 let get_error_message = |code: i32| -> PyResult<_> {
59 let get_error_message = |code: i32| -> PyResult<_> {
61 os.call(
60 os.call(
62 py,
61 py,
63 "strerror",
62 "strerror",
64 PyTuple::new(py, &[code.to_py_object(py).into_object()]),
63 PyTuple::new(py, &[code.to_py_object(py).into_object()]),
65 None,
64 None,
66 )
65 )
67 };
66 };
68
67
69 for (path, bad_match) in collection.iter() {
68 for (path, bad_match) in collection.iter() {
70 let message = match bad_match {
69 let message = match bad_match {
71 BadMatch::OsError(code) => get_error_message(*code)?,
70 BadMatch::OsError(code) => get_error_message(*code)?,
72 BadMatch::BadType(bad_type) => format!(
71 BadMatch::BadType(bad_type) => format!(
73 "unsupported file type (type is {})",
72 "unsupported file type (type is {})",
74 bad_type.to_string()
73 bad_type.to_string()
75 )
74 )
76 .to_py_object(py)
75 .to_py_object(py)
77 .into_object(),
76 .into_object(),
78 };
77 };
79 list.append(
78 list.append(
80 py,
79 py,
81 (PyBytes::new(py, path.as_ref().as_bytes()), message)
80 (PyBytes::new(py, path.as_ref().as_bytes()), message)
82 .to_py_object(py)
81 .to_py_object(py)
83 .into_object(),
82 .into_object(),
84 )
83 )
85 }
84 }
86
85
87 Ok(list)
86 Ok(list)
88 }
87 }
89
88
90 fn handle_fallback(py: Python, err: StatusError) -> PyErr {
89 fn handle_fallback(py: Python, err: StatusError) -> PyErr {
91 match err {
90 match err {
92 StatusError::Pattern(e) => {
91 StatusError::Pattern(e) => {
93 let as_string = e.to_string();
92 let as_string = e.to_string();
94 log::trace!("Rust status fallback: `{}`", &as_string);
93 log::trace!("Rust status fallback: `{}`", &as_string);
95
94
96 PyErr::new::<FallbackError, _>(py, &as_string)
95 PyErr::new::<FallbackError, _>(py, &as_string)
97 }
96 }
98 StatusError::IO(e) => PyErr::new::<OSError, _>(py, e.to_string()),
99 e => PyErr::new::<ValueError, _>(py, e.to_string()),
97 e => PyErr::new::<ValueError, _>(py, e.to_string()),
100 }
98 }
101 }
99 }
102
100
103 pub fn status_wrapper(
101 pub fn status_wrapper(
104 py: Python,
102 py: Python,
105 dmap: DirstateMap,
103 dmap: DirstateMap,
106 matcher: PyObject,
104 matcher: PyObject,
107 root_dir: PyObject,
105 root_dir: PyObject,
108 ignore_files: PyList,
106 ignore_files: PyList,
109 check_exec: bool,
107 check_exec: bool,
110 list_clean: bool,
108 list_clean: bool,
111 list_ignored: bool,
109 list_ignored: bool,
112 list_unknown: bool,
110 list_unknown: bool,
113 collect_traversed_dirs: bool,
111 collect_traversed_dirs: bool,
114 ) -> PyResult<PyTuple> {
112 ) -> PyResult<PyTuple> {
115 let bytes = root_dir.extract::<PyBytes>(py)?;
113 let bytes = root_dir.extract::<PyBytes>(py)?;
116 let root_dir = get_path_from_bytes(bytes.data(py));
114 let root_dir = get_path_from_bytes(bytes.data(py));
117
115
118 let dmap: DirstateMap = dmap.to_py_object(py);
116 let dmap: DirstateMap = dmap.to_py_object(py);
119 let mut dmap = dmap.get_inner_mut(py);
117 let mut dmap = dmap.get_inner_mut(py);
120
118
121 let ignore_files: PyResult<Vec<_>> = ignore_files
119 let ignore_files: PyResult<Vec<_>> = ignore_files
122 .iter(py)
120 .iter(py)
123 .map(|b| {
121 .map(|b| {
124 let file = b.extract::<PyBytes>(py)?;
122 let file = b.extract::<PyBytes>(py)?;
125 Ok(get_path_from_bytes(file.data(py)).to_owned())
123 Ok(get_path_from_bytes(file.data(py)).to_owned())
126 })
124 })
127 .collect();
125 .collect();
128 let ignore_files = ignore_files?;
126 let ignore_files = ignore_files?;
129 // The caller may call `copymap.items()` separately
127 // The caller may call `copymap.items()` separately
130 let list_copies = false;
128 let list_copies = false;
131
129
132 match matcher.get_type(py).name(py).borrow() {
130 match matcher.get_type(py).name(py).borrow() {
133 "alwaysmatcher" => {
131 "alwaysmatcher" => {
134 let matcher = AlwaysMatcher;
132 let matcher = AlwaysMatcher;
135 let (status_res, warnings) = dmap
133 let (status_res, warnings) = dmap
136 .status(
134 .status(
137 &matcher,
135 &matcher,
138 root_dir.to_path_buf(),
136 root_dir.to_path_buf(),
139 ignore_files,
137 ignore_files,
140 StatusOptions {
138 StatusOptions {
141 check_exec,
139 check_exec,
142 list_clean,
140 list_clean,
143 list_ignored,
141 list_ignored,
144 list_unknown,
142 list_unknown,
145 list_copies,
143 list_copies,
146 collect_traversed_dirs,
144 collect_traversed_dirs,
147 },
145 },
148 )
146 )
149 .map_err(|e| handle_fallback(py, e))?;
147 .map_err(|e| handle_fallback(py, e))?;
150 build_response(py, status_res, warnings)
148 build_response(py, status_res, warnings)
151 }
149 }
152 "exactmatcher" => {
150 "exactmatcher" => {
153 let files = matcher.call_method(
151 let files = matcher.call_method(
154 py,
152 py,
155 "files",
153 "files",
156 PyTuple::new(py, &[]),
154 PyTuple::new(py, &[]),
157 None,
155 None,
158 )?;
156 )?;
159 let files: PyList = files.cast_into(py)?;
157 let files: PyList = files.cast_into(py)?;
160 let files: PyResult<Vec<HgPathBuf>> = files
158 let files: PyResult<Vec<HgPathBuf>> = files
161 .iter(py)
159 .iter(py)
162 .map(|f| {
160 .map(|f| {
163 Ok(HgPathBuf::from_bytes(
161 Ok(HgPathBuf::from_bytes(
164 f.extract::<PyBytes>(py)?.data(py),
162 f.extract::<PyBytes>(py)?.data(py),
165 ))
163 ))
166 })
164 })
167 .collect();
165 .collect();
168
166
169 let files = files?;
167 let files = files?;
170 let matcher = FileMatcher::new(files.as_ref())
168 let matcher = FileMatcher::new(files.as_ref())
171 .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?;
169 .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?;
172 let (status_res, warnings) = dmap
170 let (status_res, warnings) = dmap
173 .status(
171 .status(
174 &matcher,
172 &matcher,
175 root_dir.to_path_buf(),
173 root_dir.to_path_buf(),
176 ignore_files,
174 ignore_files,
177 StatusOptions {
175 StatusOptions {
178 check_exec,
176 check_exec,
179 list_clean,
177 list_clean,
180 list_ignored,
178 list_ignored,
181 list_unknown,
179 list_unknown,
182 list_copies,
180 list_copies,
183 collect_traversed_dirs,
181 collect_traversed_dirs,
184 },
182 },
185 )
183 )
186 .map_err(|e| handle_fallback(py, e))?;
184 .map_err(|e| handle_fallback(py, e))?;
187 build_response(py, status_res, warnings)
185 build_response(py, status_res, warnings)
188 }
186 }
189 "includematcher" => {
187 "includematcher" => {
190 // Get the patterns from Python even though most of them are
188 // Get the patterns from Python even though most of them are
191 // redundant with those we will parse later on, as they include
189 // redundant with those we will parse later on, as they include
192 // those passed from the command line.
190 // those passed from the command line.
193 let ignore_patterns: PyResult<Vec<_>> = matcher
191 let ignore_patterns: PyResult<Vec<_>> = matcher
194 .getattr(py, "_kindpats")?
192 .getattr(py, "_kindpats")?
195 .iter(py)?
193 .iter(py)?
196 .map(|k| {
194 .map(|k| {
197 let k = k?;
195 let k = k?;
198 let syntax = parse_pattern_syntax(
196 let syntax = parse_pattern_syntax(
199 &[
197 &[
200 k.get_item(py, 0)?
198 k.get_item(py, 0)?
201 .extract::<PyBytes>(py)?
199 .extract::<PyBytes>(py)?
202 .data(py),
200 .data(py),
203 &b":"[..],
201 &b":"[..],
204 ]
202 ]
205 .concat(),
203 .concat(),
206 )
204 )
207 .map_err(|e| {
205 .map_err(|e| {
208 handle_fallback(py, StatusError::Pattern(e))
206 handle_fallback(py, StatusError::Pattern(e))
209 })?;
207 })?;
210 let pattern = k.get_item(py, 1)?.extract::<PyBytes>(py)?;
208 let pattern = k.get_item(py, 1)?.extract::<PyBytes>(py)?;
211 let pattern = pattern.data(py);
209 let pattern = pattern.data(py);
212 let source = k.get_item(py, 2)?.extract::<PyBytes>(py)?;
210 let source = k.get_item(py, 2)?.extract::<PyBytes>(py)?;
213 let source = get_path_from_bytes(source.data(py));
211 let source = get_path_from_bytes(source.data(py));
214 let new = IgnorePattern::new(syntax, pattern, source);
212 let new = IgnorePattern::new(syntax, pattern, source);
215 Ok(new)
213 Ok(new)
216 })
214 })
217 .collect();
215 .collect();
218
216
219 let ignore_patterns = ignore_patterns?;
217 let ignore_patterns = ignore_patterns?;
220
218
221 let matcher = IncludeMatcher::new(ignore_patterns)
219 let matcher = IncludeMatcher::new(ignore_patterns)
222 .map_err(|e| handle_fallback(py, e.into()))?;
220 .map_err(|e| handle_fallback(py, e.into()))?;
223
221
224 let (status_res, warnings) = dmap
222 let (status_res, warnings) = dmap
225 .status(
223 .status(
226 &matcher,
224 &matcher,
227 root_dir.to_path_buf(),
225 root_dir.to_path_buf(),
228 ignore_files,
226 ignore_files,
229 StatusOptions {
227 StatusOptions {
230 check_exec,
228 check_exec,
231 list_clean,
229 list_clean,
232 list_ignored,
230 list_ignored,
233 list_unknown,
231 list_unknown,
234 list_copies,
232 list_copies,
235 collect_traversed_dirs,
233 collect_traversed_dirs,
236 },
234 },
237 )
235 )
238 .map_err(|e| handle_fallback(py, e))?;
236 .map_err(|e| handle_fallback(py, e))?;
239
237
240 build_response(py, status_res, warnings)
238 build_response(py, status_res, warnings)
241 }
239 }
242 e => Err(PyErr::new::<ValueError, _>(
240 e => Err(PyErr::new::<ValueError, _>(
243 py,
241 py,
244 format!("Unsupported matcher {}", e),
242 format!("Unsupported matcher {}", e),
245 )),
243 )),
246 }
244 }
247 }
245 }
248
246
249 fn build_response(
247 fn build_response(
250 py: Python,
248 py: Python,
251 status_res: DirstateStatus,
249 status_res: DirstateStatus,
252 warnings: Vec<PatternFileWarning>,
250 warnings: Vec<PatternFileWarning>,
253 ) -> PyResult<PyTuple> {
251 ) -> PyResult<PyTuple> {
254 let modified = collect_status_path_list(py, &status_res.modified);
252 let modified = collect_status_path_list(py, &status_res.modified);
255 let added = collect_status_path_list(py, &status_res.added);
253 let added = collect_status_path_list(py, &status_res.added);
256 let removed = collect_status_path_list(py, &status_res.removed);
254 let removed = collect_status_path_list(py, &status_res.removed);
257 let deleted = collect_status_path_list(py, &status_res.deleted);
255 let deleted = collect_status_path_list(py, &status_res.deleted);
258 let clean = collect_status_path_list(py, &status_res.clean);
256 let clean = collect_status_path_list(py, &status_res.clean);
259 let ignored = collect_status_path_list(py, &status_res.ignored);
257 let ignored = collect_status_path_list(py, &status_res.ignored);
260 let unknown = collect_status_path_list(py, &status_res.unknown);
258 let unknown = collect_status_path_list(py, &status_res.unknown);
261 let unsure = collect_status_path_list(py, &status_res.unsure);
259 let unsure = collect_status_path_list(py, &status_res.unsure);
262 let bad = collect_bad_matches(py, &status_res.bad)?;
260 let bad = collect_bad_matches(py, &status_res.bad)?;
263 let traversed = collect_pybytes_list(py, status_res.traversed.iter());
261 let traversed = collect_pybytes_list(py, status_res.traversed.iter());
264 let dirty = status_res.dirty.to_py_object(py);
262 let dirty = status_res.dirty.to_py_object(py);
265 let py_warnings = PyList::new(py, &[]);
263 let py_warnings = PyList::new(py, &[]);
266 for warning in warnings.iter() {
264 for warning in warnings.iter() {
267 // We use duck-typing on the Python side for dispatch, good enough for
265 // We use duck-typing on the Python side for dispatch, good enough for
268 // now.
266 // now.
269 match warning {
267 match warning {
270 PatternFileWarning::InvalidSyntax(file, syn) => {
268 PatternFileWarning::InvalidSyntax(file, syn) => {
271 py_warnings.append(
269 py_warnings.append(
272 py,
270 py,
273 (
271 (
274 PyBytes::new(py, &get_bytes_from_path(&file)),
272 PyBytes::new(py, &get_bytes_from_path(&file)),
275 PyBytes::new(py, syn),
273 PyBytes::new(py, syn),
276 )
274 )
277 .to_py_object(py)
275 .to_py_object(py)
278 .into_object(),
276 .into_object(),
279 );
277 );
280 }
278 }
281 PatternFileWarning::NoSuchFile(file) => py_warnings.append(
279 PatternFileWarning::NoSuchFile(file) => py_warnings.append(
282 py,
280 py,
283 PyBytes::new(py, &get_bytes_from_path(&file)).into_object(),
281 PyBytes::new(py, &get_bytes_from_path(&file)).into_object(),
284 ),
282 ),
285 }
283 }
286 }
284 }
287
285
288 Ok(PyTuple::new(
286 Ok(PyTuple::new(
289 py,
287 py,
290 &[
288 &[
291 unsure.into_object(),
289 unsure.into_object(),
292 modified.into_object(),
290 modified.into_object(),
293 added.into_object(),
291 added.into_object(),
294 removed.into_object(),
292 removed.into_object(),
295 deleted.into_object(),
293 deleted.into_object(),
296 clean.into_object(),
294 clean.into_object(),
297 ignored.into_object(),
295 ignored.into_object(),
298 unknown.into_object(),
296 unknown.into_object(),
299 py_warnings.into_object(),
297 py_warnings.into_object(),
300 bad.into_object(),
298 bad.into_object(),
301 traversed.into_object(),
299 traversed.into_object(),
302 dirty.into_object(),
300 dirty.into_object(),
303 ][..],
301 ][..],
304 ))
302 ))
305 }
303 }
General Comments 0
You need to be logged in to leave comments. Login now