##// END OF EJS Templates
rhg: Add support for ui.ignore and ui.ignore.* config...
Simon Sapin -
r49282:4a983b69 default
parent child Browse files
Show More
@@ -419,6 +419,59 b' impl Config {'
419 .any(|layer| layer.has_non_empty_section(section))
419 .any(|layer| layer.has_non_empty_section(section))
420 }
420 }
421
421
422 /// Yields (key, value) pairs for everything in the given section
423 pub fn iter_section<'a>(
424 &'a self,
425 section: &'a [u8],
426 ) -> impl Iterator<Item = (&[u8], &[u8])> + 'a {
427 // TODO: Use `Iterator`’s `.peekable()` when its `peek_mut` is
428 // available:
429 // https://doc.rust-lang.org/nightly/std/iter/struct.Peekable.html#method.peek_mut
430 struct Peekable<I: Iterator> {
431 iter: I,
432 /// Remember a peeked value, even if it was None.
433 peeked: Option<Option<I::Item>>,
434 }
435
436 impl<I: Iterator> Peekable<I> {
437 fn new(iter: I) -> Self {
438 Self { iter, peeked: None }
439 }
440
441 fn next(&mut self) {
442 self.peeked = None
443 }
444
445 fn peek_mut(&mut self) -> Option<&mut I::Item> {
446 let iter = &mut self.iter;
447 self.peeked.get_or_insert_with(|| iter.next()).as_mut()
448 }
449 }
450
451 // Deduplicate keys redefined in multiple layers
452 let mut keys_already_seen = HashSet::new();
453 let mut key_is_new =
454 move |&(key, _value): &(&'a [u8], &'a [u8])| -> bool {
455 keys_already_seen.insert(key)
456 };
457 // This is similar to `flat_map` + `filter_map`, except with a single
458 // closure that owns `key_is_new` (and therefore the
459 // `keys_already_seen` set):
460 let mut layer_iters = Peekable::new(
461 self.layers
462 .iter()
463 .rev()
464 .map(move |layer| layer.iter_section(section)),
465 );
466 std::iter::from_fn(move || loop {
467 if let Some(pair) = layer_iters.peek_mut()?.find(&mut key_is_new) {
468 return Some(pair);
469 } else {
470 layer_iters.next();
471 }
472 })
473 }
474
422 /// Get raw values bytes from all layers (even untrusted ones) in order
475 /// Get raw values bytes from all layers (even untrusted ones) in order
423 /// of precedence.
476 /// of precedence.
424 #[cfg(test)]
477 #[cfg(test)]
@@ -127,6 +127,17 b' impl ConfigLayer {'
127 .flat_map(|section| section.keys().map(|vec| &**vec))
127 .flat_map(|section| section.keys().map(|vec| &**vec))
128 }
128 }
129
129
130 /// Returns the (key, value) pairs defined in the given section
131 pub fn iter_section<'layer>(
132 &'layer self,
133 section: &[u8],
134 ) -> impl Iterator<Item = (&'layer [u8], &'layer [u8])> {
135 self.sections
136 .get(section)
137 .into_iter()
138 .flat_map(|section| section.iter().map(|(k, v)| (&**k, &*v.bytes)))
139 }
140
130 /// Returns whether any key is defined in the given section
141 /// Returns whether any key is defined in the given section
131 pub fn has_non_empty_section(&self, section: &[u8]) -> bool {
142 pub fn has_non_empty_section(&self, section: &[u8]) -> bool {
132 self.sections
143 self.sections
@@ -21,10 +21,12 b' use hg::manifest::Manifest;'
21 use hg::matchers::AlwaysMatcher;
21 use hg::matchers::AlwaysMatcher;
22 use hg::repo::Repo;
22 use hg::repo::Repo;
23 use hg::utils::files::get_bytes_from_os_string;
23 use hg::utils::files::get_bytes_from_os_string;
24 use hg::utils::files::get_path_from_bytes;
24 use hg::utils::hg_path::{hg_path_to_path_buf, HgPath};
25 use hg::utils::hg_path::{hg_path_to_path_buf, HgPath};
25 use hg::{HgPathCow, StatusOptions};
26 use hg::{HgPathCow, StatusOptions};
26 use log::{info, warn};
27 use log::{info, warn};
27 use std::io;
28 use std::io;
29 use std::path::PathBuf;
28
30
29 pub const HELP_TEXT: &str = "
31 pub const HELP_TEXT: &str = "
30 Show changed files in the working directory
32 Show changed files in the working directory
@@ -213,11 +215,10 b' pub fn run(invocation: &crate::CliInvoca'
213 list_ignored: display_states.ignored,
215 list_ignored: display_states.ignored,
214 collect_traversed_dirs: false,
216 collect_traversed_dirs: false,
215 };
217 };
216 let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded
217 let (mut ds_status, pattern_warnings) = dmap.status(
218 let (mut ds_status, pattern_warnings) = dmap.status(
218 &AlwaysMatcher,
219 &AlwaysMatcher,
219 repo.working_directory_path().to_owned(),
220 repo.working_directory_path().to_owned(),
220 vec![ignore_file],
221 ignore_files(repo, config),
221 options,
222 options,
222 )?;
223 )?;
223 if !pattern_warnings.is_empty() {
224 if !pattern_warnings.is_empty() {
@@ -396,6 +397,25 b' pub fn run(invocation: &crate::CliInvoca'
396 Ok(())
397 Ok(())
397 }
398 }
398
399
400 fn ignore_files(repo: &Repo, config: &Config) -> Vec<PathBuf> {
401 let mut ignore_files = Vec::new();
402 let repo_ignore = repo.working_directory_vfs().join(".hgignore");
403 if repo_ignore.exists() {
404 ignore_files.push(repo_ignore)
405 }
406 for (key, value) in config.iter_section(b"ui") {
407 if key == b"ignore" || key.starts_with(b"ignore.") {
408 let path = get_path_from_bytes(value);
409 // TODO: expand "~/" and environment variable here, like Python
410 // does with `os.path.expanduser` and `os.path.expandvars`
411
412 let joined = repo.working_directory_path().join(path);
413 ignore_files.push(joined);
414 }
415 }
416 ignore_files
417 }
418
399 // Probably more elegant to use a Deref or Borrow trait rather than
419 // Probably more elegant to use a Deref or Borrow trait rather than
400 // harcode HgPathBuf, but probably not really useful at this point
420 // harcode HgPathBuf, but probably not really useful at this point
401 fn display_status_paths(
421 fn display_status_paths(
General Comments 0
You need to be logged in to leave comments. Login now