Instead of having status() returning a tuple of those paths and
DirstateStatus.
Details
Details
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
Instead of having status() returning a tuple of those paths and
DirstateStatus.
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
M | rust/hg-core/src/dirstate/status.rs (41 lines) | |||
M | rust/hg-core/src/dirstate_tree/dirstate_map.rs (10 lines) | |||
M | rust/hg-core/src/dirstate_tree/dispatch.rs (18 lines) | |||
M | rust/hg-core/src/operations/dirstate_status.rs (9 lines) | |||
M | rust/hg-cpython/src/dirstate/status.rs (19 lines) | |||
M | rust/rhg/src/commands/status.rs (10 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
1d841e12af21 | 540454a939eb | Simon Sapin | Apr 6 2021, 9:14 AM |
Status | Author | Revision | |
---|---|---|---|
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Abandoned | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin |
pub modified: Vec<HgPathCow<'a>>, | pub modified: Vec<HgPathCow<'a>>, | ||||
pub added: Vec<HgPathCow<'a>>, | pub added: Vec<HgPathCow<'a>>, | ||||
pub removed: Vec<HgPathCow<'a>>, | pub removed: Vec<HgPathCow<'a>>, | ||||
pub deleted: Vec<HgPathCow<'a>>, | pub deleted: Vec<HgPathCow<'a>>, | ||||
pub clean: Vec<HgPathCow<'a>>, | pub clean: Vec<HgPathCow<'a>>, | ||||
pub ignored: Vec<HgPathCow<'a>>, | pub ignored: Vec<HgPathCow<'a>>, | ||||
pub unknown: Vec<HgPathCow<'a>>, | pub unknown: Vec<HgPathCow<'a>>, | ||||
pub bad: Vec<(HgPathCow<'a>, BadMatch)>, | pub bad: Vec<(HgPathCow<'a>, BadMatch)>, | ||||
/// Either clean or modified, but we can’t tell from filesystem metadata | |||||
/// alone. The file contents need to be read and compared with that in | |||||
/// the parent. | |||||
pub unsure: Vec<HgPathCow<'a>>, | |||||
/// Only filled if `collect_traversed_dirs` is `true` | /// Only filled if `collect_traversed_dirs` is `true` | ||||
pub traversed: Vec<HgPathBuf>, | pub traversed: Vec<HgPathBuf>, | ||||
} | } | ||||
#[derive(Debug, derive_more::From)] | #[derive(Debug, derive_more::From)] | ||||
pub enum StatusError { | pub enum StatusError { | ||||
/// Generic IO error | /// Generic IO error | ||||
IO(std::io::Error), | IO(std::io::Error), | ||||
results.par_extend(new_results); | results.par_extend(new_results); | ||||
} | } | ||||
} | } | ||||
#[timed] | #[timed] | ||||
pub fn build_response<'a>( | pub fn build_response<'a>( | ||||
results: impl IntoIterator<Item = DispatchedPath<'a>>, | results: impl IntoIterator<Item = DispatchedPath<'a>>, | ||||
traversed: Vec<HgPathBuf>, | traversed: Vec<HgPathBuf>, | ||||
) -> (Vec<HgPathCow<'a>>, DirstateStatus<'a>) { | ) -> DirstateStatus<'a> { | ||||
let mut lookup = vec![]; | let mut unsure = vec![]; | ||||
let mut modified = vec![]; | let mut modified = vec![]; | ||||
let mut added = vec![]; | let mut added = vec![]; | ||||
let mut removed = vec![]; | let mut removed = vec![]; | ||||
let mut deleted = vec![]; | let mut deleted = vec![]; | ||||
let mut clean = vec![]; | let mut clean = vec![]; | ||||
let mut ignored = vec![]; | let mut ignored = vec![]; | ||||
let mut unknown = vec![]; | let mut unknown = vec![]; | ||||
let mut bad = vec![]; | let mut bad = vec![]; | ||||
for (filename, dispatch) in results.into_iter() { | for (filename, dispatch) in results.into_iter() { | ||||
match dispatch { | match dispatch { | ||||
Dispatch::Unknown => unknown.push(filename), | Dispatch::Unknown => unknown.push(filename), | ||||
Dispatch::Unsure => lookup.push(filename), | Dispatch::Unsure => unsure.push(filename), | ||||
Dispatch::Modified => modified.push(filename), | Dispatch::Modified => modified.push(filename), | ||||
Dispatch::Added => added.push(filename), | Dispatch::Added => added.push(filename), | ||||
Dispatch::Removed => removed.push(filename), | Dispatch::Removed => removed.push(filename), | ||||
Dispatch::Deleted => deleted.push(filename), | Dispatch::Deleted => deleted.push(filename), | ||||
Dispatch::Clean => clean.push(filename), | Dispatch::Clean => clean.push(filename), | ||||
Dispatch::Ignored => ignored.push(filename), | Dispatch::Ignored => ignored.push(filename), | ||||
Dispatch::None => {} | Dispatch::None => {} | ||||
Dispatch::Bad(reason) => bad.push((filename, reason)), | Dispatch::Bad(reason) => bad.push((filename, reason)), | ||||
Dispatch::Directory { .. } => {} | Dispatch::Directory { .. } => {} | ||||
} | } | ||||
} | } | ||||
( | |||||
lookup, | |||||
DirstateStatus { | DirstateStatus { | ||||
modified, | modified, | ||||
added, | added, | ||||
removed, | removed, | ||||
deleted, | deleted, | ||||
clean, | clean, | ||||
ignored, | ignored, | ||||
unknown, | unknown, | ||||
bad, | bad, | ||||
unsure, | |||||
traversed, | traversed, | ||||
}, | } | ||||
) | |||||
} | } | ||||
/// Get the status of files in the working directory. | /// Get the status of files in the working directory. | ||||
/// | /// | ||||
/// This is the current entry-point for `hg-core` and is realistically unusable | /// This is the current entry-point for `hg-core` and is realistically unusable | ||||
/// outside of a Python context because its arguments need to provide a lot of | /// outside of a Python context because its arguments need to provide a lot of | ||||
/// information that will not be necessary in the future. | /// information that will not be necessary in the future. | ||||
#[timed] | #[timed] | ||||
pub fn status<'a>( | pub fn status<'a>( | ||||
dmap: &'a DirstateMap, | dmap: &'a DirstateMap, | ||||
matcher: &'a (dyn Matcher + Sync), | matcher: &'a (dyn Matcher + Sync), | ||||
root_dir: PathBuf, | root_dir: PathBuf, | ||||
ignore_files: Vec<PathBuf>, | ignore_files: Vec<PathBuf>, | ||||
options: StatusOptions, | options: StatusOptions, | ||||
) -> StatusResult<( | ) -> StatusResult<(DirstateStatus<'a>, Vec<PatternFileWarning>)> { | ||||
(Vec<HgPathCow<'a>>, DirstateStatus<'a>), | |||||
Vec<PatternFileWarning>, | |||||
)> { | |||||
let (status, warnings) = | let (status, warnings) = | ||||
Status::new(dmap, matcher, root_dir, ignore_files, options)?; | Status::new(dmap, matcher, root_dir, ignore_files, options)?; | ||||
Ok((status.run()?, warnings)) | Ok((status.run()?, warnings)) | ||||
} | } |
use crate::utils::hg_path::{HgPath, HgPathBuf}; | use crate::utils::hg_path::{HgPath, HgPathBuf}; | ||||
use crate::CopyMapIter; | use crate::CopyMapIter; | ||||
use crate::DirstateEntry; | use crate::DirstateEntry; | ||||
use crate::DirstateError; | use crate::DirstateError; | ||||
use crate::DirstateMapError; | use crate::DirstateMapError; | ||||
use crate::DirstateParents; | use crate::DirstateParents; | ||||
use crate::DirstateStatus; | use crate::DirstateStatus; | ||||
use crate::EntryState; | use crate::EntryState; | ||||
use crate::HgPathCow; | |||||
use crate::PatternFileWarning; | use crate::PatternFileWarning; | ||||
use crate::StateMapIter; | use crate::StateMapIter; | ||||
use crate::StatusError; | use crate::StatusError; | ||||
use crate::StatusOptions; | use crate::StatusOptions; | ||||
pub struct DirstateMap { | pub struct DirstateMap { | ||||
parents: Option<DirstateParents>, | parents: Option<DirstateParents>, | ||||
dirty_parents: bool, | dirty_parents: bool, | ||||
} | } | ||||
fn status<'a>( | fn status<'a>( | ||||
&'a self, | &'a self, | ||||
_matcher: &'a (dyn Matcher + Sync), | _matcher: &'a (dyn Matcher + Sync), | ||||
_root_dir: PathBuf, | _root_dir: PathBuf, | ||||
_ignore_files: Vec<PathBuf>, | _ignore_files: Vec<PathBuf>, | ||||
_options: StatusOptions, | _options: StatusOptions, | ||||
) -> Result< | ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError> | ||||
( | { | ||||
(Vec<HgPathCow<'a>>, DirstateStatus<'a>), | |||||
Vec<PatternFileWarning>, | |||||
), | |||||
StatusError, | |||||
> { | |||||
todo!() | todo!() | ||||
} | } | ||||
fn copy_map_len(&self) -> usize { | fn copy_map_len(&self) -> usize { | ||||
self.nodes_with_copy_source_count | self.nodes_with_copy_source_count | ||||
} | } | ||||
fn copy_map_iter(&self) -> CopyMapIter<'_> { | fn copy_map_iter(&self) -> CopyMapIter<'_> { |
use std::path::PathBuf; | use std::path::PathBuf; | ||||
use crate::dirstate::parsers::Timestamp; | use crate::dirstate::parsers::Timestamp; | ||||
use crate::matchers::Matcher; | use crate::matchers::Matcher; | ||||
use crate::utils::hg_path::{HgPath, HgPathBuf}; | use crate::utils::hg_path::{HgPath, HgPathBuf}; | ||||
use crate::CopyMapIter; | use crate::CopyMapIter; | ||||
use crate::DirstateEntry; | use crate::DirstateEntry; | ||||
use crate::DirstateError; | use crate::DirstateError; | ||||
use crate::DirstateMap; | use crate::DirstateMap; | ||||
use crate::DirstateMapError; | use crate::DirstateMapError; | ||||
use crate::DirstateParents; | use crate::DirstateParents; | ||||
use crate::DirstateStatus; | use crate::DirstateStatus; | ||||
use crate::EntryState; | use crate::EntryState; | ||||
use crate::HgPathCow; | |||||
use crate::PatternFileWarning; | use crate::PatternFileWarning; | ||||
use crate::StateMapIter; | use crate::StateMapIter; | ||||
use crate::StatusError; | use crate::StatusError; | ||||
use crate::StatusOptions; | use crate::StatusOptions; | ||||
pub trait DirstateMapMethods { | pub trait DirstateMapMethods { | ||||
fn clear(&mut self); | fn clear(&mut self); | ||||
fn set_dirs(&mut self) -> Result<(), DirstateMapError>; | fn set_dirs(&mut self) -> Result<(), DirstateMapError>; | ||||
fn status<'a>( | fn status<'a>( | ||||
&'a self, | &'a self, | ||||
matcher: &'a (dyn Matcher + Sync), | matcher: &'a (dyn Matcher + Sync), | ||||
root_dir: PathBuf, | root_dir: PathBuf, | ||||
ignore_files: Vec<PathBuf>, | ignore_files: Vec<PathBuf>, | ||||
options: StatusOptions, | options: StatusOptions, | ||||
) -> Result< | ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>; | ||||
( | |||||
(Vec<HgPathCow<'a>>, DirstateStatus<'a>), | |||||
Vec<PatternFileWarning>, | |||||
), | |||||
StatusError, | |||||
>; | |||||
fn copy_map_len(&self) -> usize; | fn copy_map_len(&self) -> usize; | ||||
fn copy_map_iter(&self) -> CopyMapIter<'_>; | fn copy_map_iter(&self) -> CopyMapIter<'_>; | ||||
fn copy_map_contains_key(&self, key: &HgPath) -> bool; | fn copy_map_contains_key(&self, key: &HgPath) -> bool; | ||||
fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf>; | fn copy_map_get(&self, key: &HgPath) -> Option<&HgPathBuf>; | ||||
} | } | ||||
fn status<'a>( | fn status<'a>( | ||||
&'a self, | &'a self, | ||||
matcher: &'a (dyn Matcher + Sync), | matcher: &'a (dyn Matcher + Sync), | ||||
root_dir: PathBuf, | root_dir: PathBuf, | ||||
ignore_files: Vec<PathBuf>, | ignore_files: Vec<PathBuf>, | ||||
options: StatusOptions, | options: StatusOptions, | ||||
) -> Result< | ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError> | ||||
( | { | ||||
(Vec<HgPathCow<'a>>, DirstateStatus<'a>), | |||||
Vec<PatternFileWarning>, | |||||
), | |||||
StatusError, | |||||
> { | |||||
crate::status(self, matcher, root_dir, ignore_files, options) | crate::status(self, matcher, root_dir, ignore_files, options) | ||||
} | } | ||||
fn copy_map_len(&self) -> usize { | fn copy_map_len(&self) -> usize { | ||||
self.copy_map.len() | self.copy_map.len() | ||||
} | } | ||||
fn copy_map_iter(&self) -> CopyMapIter<'_> { | fn copy_map_iter(&self) -> CopyMapIter<'_> { |
// dirstate_status.rs | // dirstate_status.rs | ||||
// | // | ||||
// Copyright 2019, Raphaël Gomès <rgomes@octobus.net> | // Copyright 2019, Raphaël Gomès <rgomes@octobus.net> | ||||
// | // | ||||
// This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
use crate::dirstate::status::{build_response, Dispatch, HgPathCow, Status}; | use crate::dirstate::status::{build_response, Dispatch, Status}; | ||||
use crate::matchers::Matcher; | use crate::matchers::Matcher; | ||||
use crate::{DirstateStatus, StatusError}; | use crate::{DirstateStatus, StatusError}; | ||||
/// A tuple of the paths that need to be checked in the filelog because it's | |||||
/// ambiguous whether they've changed, and the rest of the already dispatched | |||||
/// files. | |||||
pub type LookupAndStatus<'a> = (Vec<HgPathCow<'a>>, DirstateStatus<'a>); | |||||
impl<'a, M: ?Sized + Matcher + Sync> Status<'a, M> { | impl<'a, M: ?Sized + Matcher + Sync> Status<'a, M> { | ||||
pub(crate) fn run(&self) -> Result<LookupAndStatus<'a>, StatusError> { | pub(crate) fn run(&self) -> Result<DirstateStatus<'a>, StatusError> { | ||||
let (traversed_sender, traversed_receiver) = | let (traversed_sender, traversed_receiver) = | ||||
crossbeam_channel::unbounded(); | crossbeam_channel::unbounded(); | ||||
// Step 1: check the files explicitly mentioned by the user | // Step 1: check the files explicitly mentioned by the user | ||||
let (work, mut results) = self.walk_explicit(traversed_sender.clone()); | let (work, mut results) = self.walk_explicit(traversed_sender.clone()); | ||||
if !work.is_empty() { | if !work.is_empty() { | ||||
// Hashmaps are quite a bit slower to build than vecs, so only | // Hashmaps are quite a bit slower to build than vecs, so only |
parse_pattern_syntax, | parse_pattern_syntax, | ||||
utils::{ | utils::{ | ||||
files::{get_bytes_from_path, get_path_from_bytes}, | files::{get_bytes_from_path, get_path_from_bytes}, | ||||
hg_path::{HgPath, HgPathBuf}, | hg_path::{HgPath, HgPathBuf}, | ||||
}, | }, | ||||
BadMatch, DirstateStatus, IgnorePattern, PatternFileWarning, StatusError, | BadMatch, DirstateStatus, IgnorePattern, PatternFileWarning, StatusError, | ||||
StatusOptions, | StatusOptions, | ||||
}; | }; | ||||
use std::borrow::{Borrow, Cow}; | use std::borrow::Borrow; | ||||
/// This will be useless once trait impls for collection are added to `PyBytes` | /// This will be useless once trait impls for collection are added to `PyBytes` | ||||
/// upstream. | /// upstream. | ||||
fn collect_pybytes_list( | fn collect_pybytes_list( | ||||
py: Python, | py: Python, | ||||
collection: &[impl AsRef<HgPath>], | collection: &[impl AsRef<HgPath>], | ||||
) -> PyList { | ) -> PyList { | ||||
let list = PyList::new(py, &[]); | let list = PyList::new(py, &[]); | ||||
Ok(get_path_from_bytes(file.data(py)).to_owned()) | Ok(get_path_from_bytes(file.data(py)).to_owned()) | ||||
}) | }) | ||||
.collect(); | .collect(); | ||||
let ignore_files = ignore_files?; | let ignore_files = ignore_files?; | ||||
match matcher.get_type(py).name(py).borrow() { | match matcher.get_type(py).name(py).borrow() { | ||||
"alwaysmatcher" => { | "alwaysmatcher" => { | ||||
let matcher = AlwaysMatcher; | let matcher = AlwaysMatcher; | ||||
let ((lookup, status_res), warnings) = dmap | let (status_res, warnings) = dmap | ||||
.status( | .status( | ||||
&matcher, | &matcher, | ||||
root_dir.to_path_buf(), | root_dir.to_path_buf(), | ||||
ignore_files, | ignore_files, | ||||
StatusOptions { | StatusOptions { | ||||
check_exec, | check_exec, | ||||
last_normal_time, | last_normal_time, | ||||
list_clean, | list_clean, | ||||
list_ignored, | list_ignored, | ||||
list_unknown, | list_unknown, | ||||
collect_traversed_dirs, | collect_traversed_dirs, | ||||
}, | }, | ||||
) | ) | ||||
.map_err(|e| handle_fallback(py, e))?; | .map_err(|e| handle_fallback(py, e))?; | ||||
build_response(py, lookup, status_res, warnings) | build_response(py, status_res, warnings) | ||||
} | } | ||||
"exactmatcher" => { | "exactmatcher" => { | ||||
let files = matcher.call_method( | let files = matcher.call_method( | ||||
py, | py, | ||||
"files", | "files", | ||||
PyTuple::new(py, &[]), | PyTuple::new(py, &[]), | ||||
None, | None, | ||||
)?; | )?; | ||||
let files: PyList = files.cast_into(py)?; | let files: PyList = files.cast_into(py)?; | ||||
let files: PyResult<Vec<HgPathBuf>> = files | let files: PyResult<Vec<HgPathBuf>> = files | ||||
.iter(py) | .iter(py) | ||||
.map(|f| { | .map(|f| { | ||||
Ok(HgPathBuf::from_bytes( | Ok(HgPathBuf::from_bytes( | ||||
f.extract::<PyBytes>(py)?.data(py), | f.extract::<PyBytes>(py)?.data(py), | ||||
)) | )) | ||||
}) | }) | ||||
.collect(); | .collect(); | ||||
let files = files?; | let files = files?; | ||||
let matcher = FileMatcher::new(files.as_ref()) | let matcher = FileMatcher::new(files.as_ref()) | ||||
.map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?; | .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?; | ||||
let ((lookup, status_res), warnings) = dmap | let (status_res, warnings) = dmap | ||||
.status( | .status( | ||||
&matcher, | &matcher, | ||||
root_dir.to_path_buf(), | root_dir.to_path_buf(), | ||||
ignore_files, | ignore_files, | ||||
StatusOptions { | StatusOptions { | ||||
check_exec, | check_exec, | ||||
last_normal_time, | last_normal_time, | ||||
list_clean, | list_clean, | ||||
list_ignored, | list_ignored, | ||||
list_unknown, | list_unknown, | ||||
collect_traversed_dirs, | collect_traversed_dirs, | ||||
}, | }, | ||||
) | ) | ||||
.map_err(|e| handle_fallback(py, e))?; | .map_err(|e| handle_fallback(py, e))?; | ||||
build_response(py, lookup, status_res, warnings) | build_response(py, status_res, warnings) | ||||
} | } | ||||
"includematcher" => { | "includematcher" => { | ||||
// Get the patterns from Python even though most of them are | // Get the patterns from Python even though most of them are | ||||
// redundant with those we will parse later on, as they include | // redundant with those we will parse later on, as they include | ||||
// those passed from the command line. | // those passed from the command line. | ||||
let ignore_patterns: PyResult<Vec<_>> = matcher | let ignore_patterns: PyResult<Vec<_>> = matcher | ||||
.getattr(py, "_kindpats")? | .getattr(py, "_kindpats")? | ||||
.iter(py)? | .iter(py)? | ||||
let ignore_patterns = ignore_patterns?; | let ignore_patterns = ignore_patterns?; | ||||
let mut all_warnings = vec![]; | let mut all_warnings = vec![]; | ||||
let (matcher, warnings) = | let (matcher, warnings) = | ||||
IncludeMatcher::new(ignore_patterns, &root_dir) | IncludeMatcher::new(ignore_patterns, &root_dir) | ||||
.map_err(|e| handle_fallback(py, e.into()))?; | .map_err(|e| handle_fallback(py, e.into()))?; | ||||
all_warnings.extend(warnings); | all_warnings.extend(warnings); | ||||
let ((lookup, status_res), warnings) = dmap | let (status_res, warnings) = dmap | ||||
.status( | .status( | ||||
&matcher, | &matcher, | ||||
root_dir.to_path_buf(), | root_dir.to_path_buf(), | ||||
ignore_files, | ignore_files, | ||||
StatusOptions { | StatusOptions { | ||||
check_exec, | check_exec, | ||||
last_normal_time, | last_normal_time, | ||||
list_clean, | list_clean, | ||||
list_ignored, | list_ignored, | ||||
list_unknown, | list_unknown, | ||||
collect_traversed_dirs, | collect_traversed_dirs, | ||||
}, | }, | ||||
) | ) | ||||
.map_err(|e| handle_fallback(py, e))?; | .map_err(|e| handle_fallback(py, e))?; | ||||
all_warnings.extend(warnings); | all_warnings.extend(warnings); | ||||
build_response(py, lookup, status_res, all_warnings) | build_response(py, status_res, all_warnings) | ||||
} | } | ||||
e => Err(PyErr::new::<ValueError, _>( | e => Err(PyErr::new::<ValueError, _>( | ||||
py, | py, | ||||
format!("Unsupported matcher {}", e), | format!("Unsupported matcher {}", e), | ||||
)), | )), | ||||
} | } | ||||
} | } | ||||
fn build_response( | fn build_response( | ||||
py: Python, | py: Python, | ||||
lookup: Vec<Cow<HgPath>>, | |||||
status_res: DirstateStatus, | status_res: DirstateStatus, | ||||
warnings: Vec<PatternFileWarning>, | warnings: Vec<PatternFileWarning>, | ||||
) -> PyResult<PyTuple> { | ) -> PyResult<PyTuple> { | ||||
let modified = collect_pybytes_list(py, status_res.modified.as_ref()); | let modified = collect_pybytes_list(py, status_res.modified.as_ref()); | ||||
let added = collect_pybytes_list(py, status_res.added.as_ref()); | let added = collect_pybytes_list(py, status_res.added.as_ref()); | ||||
let removed = collect_pybytes_list(py, status_res.removed.as_ref()); | let removed = collect_pybytes_list(py, status_res.removed.as_ref()); | ||||
let deleted = collect_pybytes_list(py, status_res.deleted.as_ref()); | let deleted = collect_pybytes_list(py, status_res.deleted.as_ref()); | ||||
let clean = collect_pybytes_list(py, status_res.clean.as_ref()); | let clean = collect_pybytes_list(py, status_res.clean.as_ref()); | ||||
let ignored = collect_pybytes_list(py, status_res.ignored.as_ref()); | let ignored = collect_pybytes_list(py, status_res.ignored.as_ref()); | ||||
let unknown = collect_pybytes_list(py, status_res.unknown.as_ref()); | let unknown = collect_pybytes_list(py, status_res.unknown.as_ref()); | ||||
let lookup = collect_pybytes_list(py, lookup.as_ref()); | let unsure = collect_pybytes_list(py, status_res.unsure.as_ref()); | ||||
let bad = collect_bad_matches(py, status_res.bad.as_ref())?; | let bad = collect_bad_matches(py, status_res.bad.as_ref())?; | ||||
let traversed = collect_pybytes_list(py, status_res.traversed.as_ref()); | let traversed = collect_pybytes_list(py, status_res.traversed.as_ref()); | ||||
let py_warnings = PyList::new(py, &[]); | let py_warnings = PyList::new(py, &[]); | ||||
for warning in warnings.iter() { | for warning in warnings.iter() { | ||||
// We use duck-typing on the Python side for dispatch, good enough for | // We use duck-typing on the Python side for dispatch, good enough for | ||||
// now. | // now. | ||||
match warning { | match warning { | ||||
PatternFileWarning::InvalidSyntax(file, syn) => { | PatternFileWarning::InvalidSyntax(file, syn) => { | ||||
PyBytes::new(py, &get_bytes_from_path(&file)).into_object(), | PyBytes::new(py, &get_bytes_from_path(&file)).into_object(), | ||||
), | ), | ||||
} | } | ||||
} | } | ||||
Ok(PyTuple::new( | Ok(PyTuple::new( | ||||
py, | py, | ||||
&[ | &[ | ||||
lookup.into_object(), | unsure.into_object(), | ||||
modified.into_object(), | modified.into_object(), | ||||
added.into_object(), | added.into_object(), | ||||
removed.into_object(), | removed.into_object(), | ||||
deleted.into_object(), | deleted.into_object(), | ||||
clean.into_object(), | clean.into_object(), | ||||
ignored.into_object(), | ignored.into_object(), | ||||
unknown.into_object(), | unknown.into_object(), | ||||
py_warnings.into_object(), | py_warnings.into_object(), | ||||
bad.into_object(), | bad.into_object(), | ||||
traversed.into_object(), | traversed.into_object(), | ||||
][..], | ][..], | ||||
)) | )) | ||||
} | } |
// anyway | // anyway | ||||
check_exec: true, | check_exec: true, | ||||
list_clean: display_states.clean, | list_clean: display_states.clean, | ||||
list_unknown: display_states.unknown, | list_unknown: display_states.unknown, | ||||
list_ignored: display_states.ignored, | list_ignored: display_states.ignored, | ||||
collect_traversed_dirs: false, | collect_traversed_dirs: false, | ||||
}; | }; | ||||
let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded | ||||
let ((lookup, ds_status), pattern_warnings) = hg::status( | let (ds_status, pattern_warnings) = hg::status( | ||||
&dmap, | &dmap, | ||||
&AlwaysMatcher, | &AlwaysMatcher, | ||||
repo.working_directory_path().to_owned(), | repo.working_directory_path().to_owned(), | ||||
vec![ignore_file], | vec![ignore_file], | ||||
options, | options, | ||||
)?; | )?; | ||||
if !pattern_warnings.is_empty() { | if !pattern_warnings.is_empty() { | ||||
warn!("Pattern warnings: {:?}", &pattern_warnings); | warn!("Pattern warnings: {:?}", &pattern_warnings); | ||||
} | } | ||||
if !ds_status.bad.is_empty() { | if !ds_status.bad.is_empty() { | ||||
warn!("Bad matches {:?}", &(ds_status.bad)) | warn!("Bad matches {:?}", &(ds_status.bad)) | ||||
} | } | ||||
if !lookup.is_empty() { | if !ds_status.unsure.is_empty() { | ||||
info!( | info!( | ||||
"Files to be rechecked by retrieval from filelog: {:?}", | "Files to be rechecked by retrieval from filelog: {:?}", | ||||
&lookup | &ds_status.unsure | ||||
); | ); | ||||
} | } | ||||
// TODO check ordering to match `hg status` output. | // TODO check ordering to match `hg status` output. | ||||
// (this is as in `hg help status`) | // (this is as in `hg help status`) | ||||
if display_states.modified { | if display_states.modified { | ||||
display_status_paths(ui, &(ds_status.modified), b"M")?; | display_status_paths(ui, &(ds_status.modified), b"M")?; | ||||
} | } | ||||
if !lookup.is_empty() { | if !ds_status.unsure.is_empty() { | ||||
let p1: Node = parents | let p1: Node = parents | ||||
.expect( | .expect( | ||||
"Dirstate with no parents should not list any file to | "Dirstate with no parents should not list any file to | ||||
be rechecked for modifications", | be rechecked for modifications", | ||||
) | ) | ||||
.p1 | .p1 | ||||
.into(); | .into(); | ||||
let p1_hex = format!("{:x}", p1); | let p1_hex = format!("{:x}", p1); | ||||
let mut rechecked_modified: Vec<HgPathCow> = Vec::new(); | let mut rechecked_modified: Vec<HgPathCow> = Vec::new(); | ||||
let mut rechecked_clean: Vec<HgPathCow> = Vec::new(); | let mut rechecked_clean: Vec<HgPathCow> = Vec::new(); | ||||
for to_check in lookup { | for to_check in ds_status.unsure { | ||||
if cat_file_is_modified(repo, &to_check, &p1_hex)? { | if cat_file_is_modified(repo, &to_check, &p1_hex)? { | ||||
rechecked_modified.push(to_check); | rechecked_modified.push(to_check); | ||||
} else { | } else { | ||||
rechecked_clean.push(to_check); | rechecked_clean.push(to_check); | ||||
} | } | ||||
} | } | ||||
if display_states.modified { | if display_states.modified { | ||||
display_status_paths(ui, &rechecked_modified, b"M")?; | display_status_paths(ui, &rechecked_modified, b"M")?; |