mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
touch: use an ArgGroup for sources and turn macros into functions (#1813)
* touch: use arggroup for sources * tests/touch: add tests for multiple sources * touch: turn macros into functions * test/touch: fmt * touch: constant for the sources ArgGroup
This commit is contained in:
parent
cd4003007f
commit
fd5ec099d0
2 changed files with 67 additions and 37 deletions
|
@ -13,7 +13,7 @@ pub extern crate filetime;
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use clap::{App, Arg, ArgGroup};
|
||||
use filetime::*;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Error;
|
||||
|
@ -22,6 +22,8 @@ use std::path::Path;
|
|||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
|
||||
pub mod options {
|
||||
// Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
|
||||
pub static SOURCES: &str = "sources";
|
||||
pub mod sources {
|
||||
pub static DATE: &str = "date";
|
||||
pub static REFERENCE: &str = "reference";
|
||||
|
@ -36,23 +38,15 @@ pub mod options {
|
|||
|
||||
static ARG_FILES: &str = "files";
|
||||
|
||||
// Since touch's date/timestamp parsing doesn't account for timezone, the
|
||||
// returned value from time::strptime() is UTC. We get system's timezone to
|
||||
// localize the time.
|
||||
macro_rules! to_local(
|
||||
($exp:expr) => ({
|
||||
let mut tm = $exp;
|
||||
tm.tm_utcoff = time::now().tm_utcoff;
|
||||
tm
|
||||
})
|
||||
);
|
||||
fn to_local(mut tm: time::Tm) -> time::Tm {
|
||||
tm.tm_utcoff = time::now().tm_utcoff;
|
||||
tm
|
||||
}
|
||||
|
||||
macro_rules! local_tm_to_filetime(
|
||||
($exp:expr) => ({
|
||||
let ts = $exp.to_timespec();
|
||||
FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
|
||||
})
|
||||
);
|
||||
fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
|
||||
let ts = tm.to_timespec();
|
||||
FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
|
||||
}
|
||||
|
||||
fn get_usage() -> String {
|
||||
format!("{0} [OPTION]... [USER]", executable!())
|
||||
|
@ -129,6 +123,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.takes_value(true)
|
||||
.min_values(1),
|
||||
)
|
||||
.group(ArgGroup::with_name(options::SOURCES).args(&[
|
||||
options::sources::CURRENT,
|
||||
options::sources::DATE,
|
||||
options::sources::REFERENCE,
|
||||
]))
|
||||
.get_matches_from(args);
|
||||
|
||||
let files: Vec<String> = matches
|
||||
|
@ -136,19 +135,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.map(|v| v.map(ToString::to_string).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
if matches.is_present(options::sources::DATE)
|
||||
&& (matches.is_present(options::sources::REFERENCE)
|
||||
|| matches.is_present(options::sources::CURRENT))
|
||||
|| matches.is_present(options::sources::REFERENCE)
|
||||
&& (matches.is_present(options::sources::DATE)
|
||||
|| matches.is_present(options::sources::CURRENT))
|
||||
|| matches.is_present(options::sources::CURRENT)
|
||||
&& (matches.is_present(options::sources::DATE)
|
||||
|| matches.is_present(options::sources::REFERENCE))
|
||||
{
|
||||
panic!("Invalid options: cannot specify reference time from more than one source");
|
||||
}
|
||||
|
||||
let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
|
||||
stat(
|
||||
&matches.value_of(options::sources::REFERENCE).unwrap()[..],
|
||||
|
@ -169,7 +155,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
};
|
||||
(timestamp, timestamp)
|
||||
} else {
|
||||
let now = local_tm_to_filetime!(time::now());
|
||||
let now = local_tm_to_filetime(time::now());
|
||||
(now, now)
|
||||
};
|
||||
|
||||
|
@ -188,10 +174,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
};
|
||||
|
||||
// Minor optimization: if no reference time was specified, we're done.
|
||||
if !(matches.is_present(options::sources::DATE)
|
||||
|| matches.is_present(options::sources::REFERENCE)
|
||||
|| matches.is_present(options::sources::CURRENT))
|
||||
{
|
||||
if !matches.is_present(options::SOURCES) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +243,7 @@ fn parse_date(str: &str) -> FileTime {
|
|||
// not about to implement GNU parse_datetime.
|
||||
// http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
|
||||
match time::strptime(str, "%c") {
|
||||
Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
|
||||
Ok(tm) => local_tm_to_filetime(to_local(tm)),
|
||||
Err(e) => panic!("Unable to parse date\n{}", e),
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +261,7 @@ fn parse_timestamp(s: &str) -> FileTime {
|
|||
};
|
||||
|
||||
match time::strptime(&ts, format) {
|
||||
Ok(tm) => local_tm_to_filetime!(to_local!(tm)),
|
||||
Ok(tm) => local_tm_to_filetime(to_local(tm)),
|
||||
Err(e) => panic!("Unable to parse timestamp\n{}", e),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,6 +203,53 @@ fn test_touch_set_only_mtime_failed() {
|
|||
ucmd.args(&["-t", "2015010112342", "-m", file]).fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_set_both_time_and_reference() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let ref_file = "test_touch_reference";
|
||||
let file = "test_touch_set_both_time_and_reference";
|
||||
|
||||
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
||||
|
||||
at.touch(ref_file);
|
||||
set_file_times(&at, ref_file, start_of_year, start_of_year);
|
||||
assert!(at.file_exists(ref_file));
|
||||
|
||||
ucmd.args(&["-t", "2015010112342", "-r", ref_file, file])
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_set_both_date_and_reference() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let ref_file = "test_touch_reference";
|
||||
let file = "test_touch_set_both_date_and_reference";
|
||||
|
||||
let start_of_year = str_to_filetime("%Y%m%d%H%M", "201501010000");
|
||||
|
||||
at.touch(ref_file);
|
||||
set_file_times(&at, ref_file, start_of_year, start_of_year);
|
||||
assert!(at.file_exists(ref_file));
|
||||
|
||||
ucmd.args(&["-d", "Thu Jan 01 12:34:00 2015", "-r", ref_file, file])
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_set_both_time_and_date() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "test_touch_set_both_time_and_date";
|
||||
|
||||
ucmd.args(&[
|
||||
"-t",
|
||||
"2015010112342",
|
||||
"-d",
|
||||
"Thu Jan 01 12:34:00 2015",
|
||||
file,
|
||||
])
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_touch_set_only_mtime() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue