mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
mktemp: respect path given in template argument
Fix a bug in `mktemp` where it was not respecting the path given by the positional argument. Previously, it would place the temporary file whose name is induced by a given template in the `/tmp` directory, like this: $ mktemp XXX /tmp/LJr $ mktemp d/XXX /tmp/d/IhS After this commit, it respects the directory given in the template argument: $ mktemp XXX LJr $ mktemp d/XXX d/IhS Fixes #3440.
This commit is contained in:
parent
f869fafd03
commit
aa6aefbd64
2 changed files with 105 additions and 7 deletions
|
@ -79,7 +79,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let template = matches.value_of(ARG_TEMPLATE).unwrap();
|
||||
let tmpdir = matches.value_of(OPT_TMPDIR).unwrap_or_default();
|
||||
|
||||
let (template, mut tmpdir) = if matches.is_present(OPT_TMPDIR)
|
||||
// Treat the template string as a path to get the directory
|
||||
// containing the last component.
|
||||
let path = PathBuf::from(template);
|
||||
|
||||
let (template, tmpdir) = if matches.is_present(OPT_TMPDIR)
|
||||
&& !PathBuf::from(tmpdir).is_dir() // if a temp dir is provided, it must be an actual path
|
||||
&& tmpdir.contains("XXX")
|
||||
// If this is a template, it has to contain at least 3 X
|
||||
|
@ -97,8 +101,24 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let tmp = env::temp_dir();
|
||||
(tmpdir, tmp)
|
||||
} else if !matches.is_present(OPT_TMPDIR) {
|
||||
let tmp = env::temp_dir();
|
||||
(template, tmp)
|
||||
// In this case, the command line was `mktemp -t XXX`, so we
|
||||
// treat the argument `XXX` as though it were a filename
|
||||
// regardless of whether it has path separators in it.
|
||||
if matches.is_present(OPT_T) {
|
||||
let tmp = env::temp_dir();
|
||||
(template, tmp)
|
||||
// In this case, the command line was `mktemp XXX`, so we need
|
||||
// to parse out the parent directory and the filename from the
|
||||
// argument `XXX`, since it may be include path separators.
|
||||
} else {
|
||||
let tmp = match path.parent() {
|
||||
None => PathBuf::from("."),
|
||||
Some(d) => PathBuf::from(d),
|
||||
};
|
||||
let filename = path.file_name();
|
||||
let template = filename.unwrap().to_str().unwrap();
|
||||
(template, tmp)
|
||||
}
|
||||
} else {
|
||||
(template, PathBuf::from(tmpdir))
|
||||
};
|
||||
|
@ -113,10 +133,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
return Err(MkTempError::InvalidTemplate(template.into()).into());
|
||||
}
|
||||
|
||||
if matches.is_present(OPT_T) {
|
||||
tmpdir = env::temp_dir();
|
||||
}
|
||||
|
||||
let res = if dry_run {
|
||||
dry_exec(tmpdir, prefix, rand, suffix)
|
||||
} else {
|
||||
|
@ -272,5 +288,19 @@ fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) ->
|
|||
.map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))?
|
||||
.1
|
||||
};
|
||||
|
||||
// Get just the last component of the path to the created
|
||||
// temporary file or directory.
|
||||
let filename = path.file_name();
|
||||
let filename = filename.unwrap().to_str().unwrap();
|
||||
|
||||
// Join the directory to the path to get the path to print. We
|
||||
// cannot use the path returned by the `Builder` because it gives
|
||||
// the absolute path and we need to return a filename that matches
|
||||
// the template given on the command-line which might be a
|
||||
// relative path.
|
||||
let mut path = dir.to_path_buf();
|
||||
path.push(filename);
|
||||
|
||||
println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
|
||||
}
|
||||
|
|
|
@ -411,3 +411,71 @@ fn test_mktemp_directory_tmpdir() {
|
|||
result.no_stderr().stdout_contains("apt-key-gpghome.");
|
||||
assert!(PathBuf::from(result.stdout_str().trim()).is_dir());
|
||||
}
|
||||
|
||||
/// Decide whether a string matches a given template.
|
||||
///
|
||||
/// In the template, the character `'X'` is treated as a wildcard,
|
||||
/// that is, it matches anything. All other characters in `template`
|
||||
/// and `s` must match exactly.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # These all match.
|
||||
/// assert!(matches_template("abc", "abc"));
|
||||
/// assert!(matches_template("aXc", "abc"));
|
||||
/// assert!(matches_template("XXX", "abc"));
|
||||
///
|
||||
/// # None of these match
|
||||
/// assert!(matches_template("abc", "abcd"));
|
||||
/// assert!(matches_template("abc", "ab"));
|
||||
/// assert!(matches_template("aXc", "abd"));
|
||||
/// assert!(matches_template("XXX", "abcd"));
|
||||
/// ```
|
||||
///
|
||||
fn matches_template(template: &str, s: &str) -> bool {
|
||||
if template.len() != s.len() {
|
||||
return false;
|
||||
}
|
||||
for (a, b) in template.chars().zip(s.chars()) {
|
||||
if !(a == 'X' || a == b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// An assertion that uses [`matches_template`] and adds a helpful error message.
|
||||
macro_rules! assert_matches_template {
|
||||
($template:expr, $s:expr) => {{
|
||||
assert!(
|
||||
matches_template($template, $s),
|
||||
"\"{}\" != \"{}\"",
|
||||
$template,
|
||||
$s
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
/// Test that the file is created in the directory given by the template.
|
||||
#[test]
|
||||
fn test_respect_template() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let template = "XXX";
|
||||
let result = ucmd.arg(template).succeeds();
|
||||
let filename = result.no_stderr().stdout_str().trim_end();
|
||||
assert_matches_template!(template, filename);
|
||||
assert!(at.file_exists(filename));
|
||||
}
|
||||
|
||||
/// Test that the file is created in the directory given by the template.
|
||||
#[test]
|
||||
fn test_respect_template_directory() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir("d");
|
||||
let template = "d/XXX";
|
||||
let result = ucmd.arg(template).succeeds();
|
||||
let filename = result.no_stderr().stdout_str().trim_end();
|
||||
assert_matches_template!(template, filename);
|
||||
assert!(at.file_exists(filename));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue