Skip to content

Commit 9b49f36

Browse files
committed
tail: parse default before obsolete
1 parent f6edea2 commit 9b49f36

File tree

2 files changed

+84
-51
lines changed

2 files changed

+84
-51
lines changed

src/uu/tail/src/args.rs

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub enum VerificationResult {
130130
NoOutput,
131131
}
132132

133-
#[derive(Debug, Default)]
133+
#[derive(Debug)]
134134
pub struct Settings {
135135
pub follow: Option<FollowMode>,
136136
pub max_unchanged_stats: u32,
@@ -144,13 +144,26 @@ pub struct Settings {
144144
pub inputs: VecDeque<Input>,
145145
}
146146

147-
impl Settings {
148-
pub fn from_obsolete_args(args: &parse::ObsoleteArgs, name: Option<OsString>) -> Self {
149-
let mut settings: Self = Self {
150-
sleep_sec: Duration::from_secs_f32(1.0),
147+
impl Default for Settings {
148+
fn default() -> Self {
149+
Self {
151150
max_unchanged_stats: 5,
152-
..Default::default()
153-
};
151+
sleep_sec: Duration::from_secs_f32(1.0),
152+
follow: Default::default(),
153+
mode: Default::default(),
154+
pid: Default::default(),
155+
retry: Default::default(),
156+
use_polling: Default::default(),
157+
verbose: Default::default(),
158+
presume_input_pipe: Default::default(),
159+
inputs: Default::default(),
160+
}
161+
}
162+
}
163+
164+
impl Settings {
165+
pub fn from_obsolete_args(args: &parse::ObsoleteArgs, name: Option<&OsString>) -> Self {
166+
let mut settings: Self = Default::default();
154167
if args.follow {
155168
settings.follow = if name.is_some() {
156169
Some(FollowMode::Name)
@@ -170,25 +183,25 @@ impl Settings {
170183

171184
pub fn from(matches: &clap::ArgMatches) -> UResult<Self> {
172185
let mut settings: Self = Self {
173-
sleep_sec: Duration::from_secs_f32(1.0),
174-
max_unchanged_stats: 5,
186+
follow: if matches.get_flag(options::FOLLOW_RETRY) {
187+
Some(FollowMode::Name)
188+
} else if matches.value_source(options::FOLLOW) != Some(ValueSource::CommandLine) {
189+
None
190+
} else if matches.get_one::<String>(options::FOLLOW)
191+
== Some(String::from("name")).as_ref()
192+
{
193+
Some(FollowMode::Name)
194+
} else {
195+
Some(FollowMode::Descriptor)
196+
},
197+
retry: matches.get_flag(options::RETRY) || matches.get_flag(options::FOLLOW_RETRY),
198+
use_polling: matches.get_flag(options::USE_POLLING),
199+
mode: FilterMode::from(matches)?,
200+
verbose: matches.get_flag(options::verbosity::VERBOSE),
201+
presume_input_pipe: matches.get_flag(options::PRESUME_INPUT_PIPE),
175202
..Default::default()
176203
};
177204

178-
settings.follow = if matches.get_flag(options::FOLLOW_RETRY) {
179-
Some(FollowMode::Name)
180-
} else if matches.value_source(options::FOLLOW) != Some(ValueSource::CommandLine) {
181-
None
182-
} else if matches.get_one::<String>(options::FOLLOW) == Some(String::from("name")).as_ref()
183-
{
184-
Some(FollowMode::Name)
185-
} else {
186-
Some(FollowMode::Descriptor)
187-
};
188-
189-
settings.retry =
190-
matches.get_flag(options::RETRY) || matches.get_flag(options::FOLLOW_RETRY);
191-
192205
if let Some(source) = matches.get_one::<String>(options::SLEEP_INT) {
193206
// Advantage of `fundu` over `Duration::(try_)from_secs_f64(source.parse().unwrap())`:
194207
// * doesn't panic on errors like `Duration::from_secs_f64` would.
@@ -205,8 +218,6 @@ impl Settings {
205218
})?;
206219
}
207220

208-
settings.use_polling = matches.get_flag(options::USE_POLLING);
209-
210221
if let Some(s) = matches.get_one::<String>(options::MAX_UNCHANGED_STATS) {
211222
settings.max_unchanged_stats = match s.parse::<u32>() {
212223
Ok(s) => s,
@@ -246,8 +257,6 @@ impl Settings {
246257
}
247258
}
248259

249-
settings.mode = FilterMode::from(matches)?;
250-
251260
let mut inputs: VecDeque<Input> = matches
252261
.get_many::<String>(options::ARG_FILES)
253262
.map(|v| v.map(|string| Input::from(&string)).collect())
@@ -258,13 +267,10 @@ impl Settings {
258267
inputs.push_front(Input::default());
259268
}
260269

261-
settings.verbose = (matches.get_flag(options::verbosity::VERBOSE) || inputs.len() > 1)
262-
&& !matches.get_flag(options::verbosity::QUIET);
270+
settings.verbose = inputs.len() > 1 && !matches.get_flag(options::verbosity::QUIET);
263271

264272
settings.inputs = inputs;
265273

266-
settings.presume_input_pipe = matches.get_flag(options::PRESUME_INPUT_PIPE);
267-
268274
Ok(settings)
269275
}
270276

@@ -342,6 +348,19 @@ impl Settings {
342348

343349
VerificationResult::Ok
344350
}
351+
352+
pub fn is_default(&self) -> bool {
353+
let default = Self::default();
354+
self.max_unchanged_stats == default.max_unchanged_stats
355+
&& self.sleep_sec == default.sleep_sec
356+
&& self.follow == default.follow
357+
&& self.mode == default.mode
358+
&& self.pid == default.pid
359+
&& self.retry == default.retry
360+
&& self.use_polling == default.use_polling
361+
&& (self.verbose == default.verbose || self.inputs.len() > 1)
362+
&& self.presume_input_pipe == default.presume_input_pipe
363+
}
345364
}
346365

347366
pub fn parse_obsolete(args: &str) -> UResult<Option<parse::ObsoleteArgs>> {
@@ -389,28 +408,42 @@ fn parse_num(src: &str) -> Result<Signum, ParseSizeError> {
389408
})
390409
}
391410

392-
pub fn parse_args(mut args: impl uucore::Args) -> UResult<Settings> {
393-
let first = args.next().unwrap();
394-
let second = match args.next() {
411+
pub fn parse_args(args: impl uucore::Args) -> UResult<Settings> {
412+
let args_vec: Vec<OsString> = args.collect();
413+
let clap_result = match uu_app().try_get_matches_from(args_vec.clone()) {
414+
Ok(matches) => {
415+
let settings = Settings::from(&matches)?;
416+
if !settings.is_default() {
417+
// non-default settings can't have obsolete arguments
418+
return Ok(settings);
419+
}
420+
Ok(settings)
421+
}
422+
Err(err) => Err(err.into()),
423+
};
424+
425+
// clap parsing failed or resulted to default -> check for obsolete/deprecated args
426+
// argv[0] is always present
427+
let second = match args_vec.get(1) {
395428
Some(second) => second,
396-
None => return Settings::from(&uu_app().try_get_matches_from(vec![first])?),
429+
None => return clap_result,
397430
};
398431
let second_str = match second.to_str() {
399432
Some(second_str) => second_str,
400433
None => {
401-
let second_string = second.to_string_lossy();
434+
let invalid_string = second.to_string_lossy();
402435
return Err(USimpleError::new(
403436
1,
404-
format!("bad argument encoding: '{second_string}'"),
437+
format!("bad argument encoding: '{invalid_string}'"),
405438
));
406439
}
407440
};
408441
match parse_obsolete(second_str)? {
409-
Some(obsolete_args) => Ok(Settings::from_obsolete_args(&obsolete_args, args.next())),
410-
None => {
411-
let args = vec![first, second].into_iter().chain(args);
412-
Settings::from(&uu_app().try_get_matches_from(args)?)
413-
}
442+
Some(obsolete_args) => Ok(Settings::from_obsolete_args(
443+
&obsolete_args,
444+
args_vec.get(2),
445+
)),
446+
None => clap_result,
414447
}
415448
}
416449

@@ -583,7 +616,7 @@ mod tests {
583616
let result = Settings::from_obsolete_args(&args, None);
584617
assert_eq!(result.follow, Some(FollowMode::Descriptor));
585618

586-
let result = Settings::from_obsolete_args(&args, Some("test".into()));
619+
let result = Settings::from_obsolete_args(&args, Some(&"file".into()));
587620
assert_eq!(result.follow, Some(FollowMode::Name));
588621
}
589622
}

tests/by-util/test_tail.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4737,21 +4737,21 @@ fn test_gnu_args_f() {
47374737
let scene = TestScenario::new(util_name!());
47384738
let at = &scene.fixtures;
47394739

4740-
let mut p = scene
4741-
.ucmd()
4742-
.set_stdin(Stdio::piped())
4743-
.arg("+f")
4744-
.run_no_wait();
4740+
let source = "file";
4741+
at.touch(source);
4742+
let mut p = scene.ucmd().args(&["+f", source]).run_no_wait();
47454743
p.make_assertion_with_delay(500).is_alive();
47464744
p.kill()
47474745
.make_assertion()
47484746
.with_all_output()
47494747
.no_stderr()
47504748
.no_stdout();
47514749

4752-
let source = "file";
4753-
at.touch(source);
4754-
let mut p = scene.ucmd().args(&["+f", source]).run_no_wait();
4750+
let mut p = scene
4751+
.ucmd()
4752+
.set_stdin(Stdio::piped())
4753+
.arg("+f")
4754+
.run_no_wait();
47554755
p.make_assertion_with_delay(500).is_alive();
47564756
p.kill()
47574757
.make_assertion()

0 commit comments

Comments
 (0)