dir_action.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //! Parsing the options for `DirAction`.
  2. use crate::options::parser::MatchedFlags;
  3. use crate::options::{flags, OptionsError, NumberSource};
  4. use crate::fs::dir_action::{DirAction, RecurseOptions};
  5. impl DirAction {
  6. /// Determine which action to perform when trying to list a directory.
  7. /// There are three possible actions, and they overlap somewhat: the
  8. /// `--tree` flag is another form of recursion, so those two are allowed
  9. /// to both be present, but the `--list-dirs` flag is used separately.
  10. pub fn deduce(matches: &MatchedFlags<'_>, can_tree: bool) -> Result<Self, OptionsError> {
  11. let recurse = matches.has(&flags::RECURSE)?;
  12. let as_file = matches.has(&flags::LIST_DIRS)?;
  13. let tree = matches.has(&flags::TREE)?;
  14. if matches.is_strict() {
  15. // Early check for --level when it wouldn’t do anything
  16. if ! recurse && ! tree && matches.count(&flags::LEVEL) > 0 {
  17. return Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE));
  18. }
  19. else if recurse && as_file {
  20. return Err(OptionsError::Conflict(&flags::RECURSE, &flags::LIST_DIRS));
  21. }
  22. else if tree && as_file {
  23. return Err(OptionsError::Conflict(&flags::TREE, &flags::LIST_DIRS));
  24. }
  25. }
  26. if tree && can_tree {
  27. // Tree is only appropriate in details mode, so this has to
  28. // examine the View, which should have already been deduced by now
  29. Ok(Self::Recurse(RecurseOptions::deduce(matches, true)?))
  30. }
  31. else if recurse {
  32. Ok(Self::Recurse(RecurseOptions::deduce(matches, false)?))
  33. }
  34. else if as_file {
  35. Ok(Self::AsFile)
  36. }
  37. else {
  38. Ok(Self::List)
  39. }
  40. }
  41. }
  42. impl RecurseOptions {
  43. /// Determine which files should be recursed into, based on the `--level`
  44. /// flag’s value, and whether the `--tree` flag was passed, which was
  45. /// determined earlier. The maximum level should be a number, and this
  46. /// will fail with an `Err` if it isn’t.
  47. pub fn deduce(matches: &MatchedFlags<'_>, tree: bool) -> Result<Self, OptionsError> {
  48. if let Some(level) = matches.get(&flags::LEVEL)? {
  49. let arg_str = level.to_string_lossy();
  50. match arg_str.parse() {
  51. Ok(l) => {
  52. Ok(Self { tree, max_depth: Some(l) })
  53. }
  54. Err(e) => {
  55. let source = NumberSource::Arg(&flags::LEVEL);
  56. Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
  57. }
  58. }
  59. }
  60. else {
  61. Ok(Self { tree, max_depth: None })
  62. }
  63. }
  64. }
  65. #[cfg(test)]
  66. mod test {
  67. use super::*;
  68. use crate::options::flags;
  69. use crate::options::parser::Flag;
  70. macro_rules! test {
  71. ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
  72. #[test]
  73. fn $name() {
  74. use crate::options::parser::Arg;
  75. use crate::options::test::parse_for_test;
  76. use crate::options::test::Strictnesses::*;
  77. static TEST_ARGS: &[&Arg] = &[&flags::RECURSE, &flags::LIST_DIRS, &flags::TREE, &flags::LEVEL ];
  78. for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, true)) {
  79. assert_eq!(result, $result);
  80. }
  81. }
  82. };
  83. }
  84. // Default behaviour
  85. test!(empty: DirAction <- []; Both => Ok(DirAction::List));
  86. // Listing files as directories
  87. test!(dirs_short: DirAction <- ["-d"]; Both => Ok(DirAction::AsFile));
  88. test!(dirs_long: DirAction <- ["--list-dirs"]; Both => Ok(DirAction::AsFile));
  89. // Recursing
  90. use self::DirAction::Recurse;
  91. test!(rec_short: DirAction <- ["-R"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
  92. test!(rec_long: DirAction <- ["--recurse"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
  93. test!(rec_lim_short: DirAction <- ["-RL4"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(4) })));
  94. test!(rec_lim_short_2: DirAction <- ["-RL=5"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(5) })));
  95. test!(rec_lim_long: DirAction <- ["--recurse", "--level", "666"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(666) })));
  96. test!(rec_lim_long_2: DirAction <- ["--recurse", "--level=0118"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(118) })));
  97. test!(tree: DirAction <- ["--tree"]; Both => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
  98. test!(rec_tree: DirAction <- ["--recurse", "--tree"]; Both => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
  99. test!(rec_short_tree: DirAction <- ["-TR"]; Both => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
  100. // Overriding --list-dirs, --recurse, and --tree
  101. test!(dirs_recurse: DirAction <- ["--list-dirs", "--recurse"]; Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
  102. test!(dirs_tree: DirAction <- ["--list-dirs", "--tree"]; Last => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
  103. test!(just_level: DirAction <- ["--level=4"]; Last => Ok(DirAction::List));
  104. test!(dirs_recurse_2: DirAction <- ["--list-dirs", "--recurse"]; Complain => Err(OptionsError::Conflict(&flags::RECURSE, &flags::LIST_DIRS)));
  105. test!(dirs_tree_2: DirAction <- ["--list-dirs", "--tree"]; Complain => Err(OptionsError::Conflict(&flags::TREE, &flags::LIST_DIRS)));
  106. test!(just_level_2: DirAction <- ["--level=4"]; Complain => Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)));
  107. // Overriding levels
  108. test!(overriding_1: DirAction <- ["-RL=6", "-L=7"]; Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(7) })));
  109. test!(overriding_2: DirAction <- ["-RL=6", "-L=7"]; Complain => Err(OptionsError::Duplicate(Flag::Short(b'L'), Flag::Short(b'L'))));
  110. }