Skip to content

Commit 0e00974

Browse files
Merge pull request #33090 from JuliaLang/sk/tempname
tempname: add `parent` and `cleanup` arguments
2 parents 76ec9d6 + 75cb006 commit 0e00974

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ New library functions
2222
---------------------
2323

2424
* The `splitpath` function now accepts any `AbstractString` whereas previously it only accepted paths of type `String` ([#33012]).
25+
* The `tempname` function now takes an optional `parent::AbstractString` argument to give it a directory in which to attempt to produce a temporary path name ([#33090]).
26+
* The `tempname` function now takes a `cleanup::Bool` keyword argument defaulting to `true`, which causes the process to try to ensure that any file or directory at the path returned by `tempname` is deleted upon process exit ([#33090]).
2527

2628

2729
Standard library changes

base/file.jl

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -500,29 +500,32 @@ function mktemp(parent::AbstractString=tempdir(); cleanup::Bool=true)
500500
return (filename, Base.open(filename, "r+"))
501501
end
502502

503-
function tempname()
504-
parent = tempdir()
503+
function tempname(parent::AbstractString=tempdir(); cleanup::Bool=true)
504+
isdir(parent) || throw(ArgumentError("$(repr(parent)) is not a directory"))
505505
seed::UInt32 = rand(UInt32)
506506
while true
507507
if (seed & typemax(UInt16)) == 0
508508
seed += 1
509509
end
510510
filename = _win_tempname(parent, seed)
511511
if !ispath(filename)
512+
cleanup && temp_cleanup_later(filename)
512513
return filename
513514
end
514515
seed += 1
515516
end
516517
end
517518

518519
else # !windows
520+
519521
# Obtain a temporary filename.
520-
function tempname()
521-
d = tempdir() # tempnam ignores TMPDIR on darwin
522-
p = ccall(:tempnam, Cstring, (Cstring, Cstring), d, temp_prefix)
522+
function tempname(parent::AbstractString=tempdir(); cleanup::Bool=true)
523+
isdir(parent) || throw(ArgumentError("$(repr(parent)) is not a directory"))
524+
p = ccall(:tempnam, Cstring, (Cstring, Cstring), parent, temp_prefix)
523525
systemerror(:tempnam, p == C_NULL)
524526
s = unsafe_string(p)
525527
Libc.free(p)
528+
cleanup && temp_cleanup_later(s)
526529
return s
527530
end
528531

@@ -540,16 +543,35 @@ end # os-test
540543

541544

542545
"""
543-
tempname()
546+
tempname(parent=tempdir(); cleanup=true) -> String
544547
545548
Generate a temporary file path. This function only returns a path; no file is
546-
created. The path is likely to be unique, but this cannot be guaranteed.
549+
created. The path is likely to be unique, but this cannot be guaranteed due to
550+
the very remote posibility of two simultaneous calls to `tempname` generating
551+
the same file name. The name is guaranteed to differ from all files already
552+
existing at the time of the call to `tempname`.
553+
554+
When called with no arguments, the temporary name will be an absolute path to a
555+
temporary name in the system temporary directory as given by `tempdir()`. If a
556+
`parent` directory argument is given, the temporary path will be in that
557+
directory instead.
558+
559+
The `cleanup` option controls whether the process attempts to delete the
560+
returned path automatically when the process exits. Note that the `tempname`
561+
function does not create any file or directory at the returned location, so
562+
there is nothing to cleanup unless you create a file or directory there. If
563+
you do and `clean` is `true` it will be deleted upon process termination.
564+
565+
!!! compat "Julia 1.4"
566+
The `parent` and `cleanup` arguments were added in 1.4. Prior to Julia 1.4
567+
the path `tempname` would never be cleaned up at process termination.
547568
548569
!!! warning
549570
550571
This can lead to security holes if another process obtains the same
551572
file name and creates the file before you are able to. Open the file with
552-
`JL_O_EXCL` if this is a concern. Using [`mktemp()`](@ref) is also recommended instead.
573+
`JL_O_EXCL` if this is a concern. Using [`mktemp()`](@ref) is also
574+
recommended instead.
553575
"""
554576
tempname()
555577

test/file.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ if !Sys.iswindows()
4848
cd(pwd_)
4949
end
5050

51+
using Random
52+
53+
@testset "tempname with parent" begin
54+
t = tempname()
55+
@test dirname(t) == tempdir()
56+
mktempdir() do d
57+
t = tempname(d)
58+
@test dirname(t) == d
59+
end
60+
@test_throws ArgumentError tempname(randstring())
61+
end
62+
5163
child_eval(code::String) = eval(Meta.parse(readchomp(`$(Base.julia_cmd()) -E $code`)))
5264

5365
@testset "mktemp/dir basic cleanup" begin
@@ -67,6 +79,14 @@ child_eval(code::String) = eval(Meta.parse(readchomp(`$(Base.julia_cmd()) -E $co
6779
# mktempdir with cleanup
6880
t = child_eval("t = mktempdir(); touch(joinpath(t, \"file.txt\")); t")
6981
@test !ispath(t)
82+
# tempname without cleanup
83+
t = child_eval("t = tempname(cleanup=false); touch(t); t")
84+
@test isfile(t)
85+
rm(t, force=true)
86+
@test !ispath(t)
87+
# tempname with cleanup
88+
t = child_eval("t = tempname(); touch(t); t")
89+
@test !ispath(t)
7090
end
7191

7292
import Base.Filesystem: TEMP_CLEANUP_MIN, TEMP_CLEANUP_MAX, TEMP_CLEANUP

0 commit comments

Comments
 (0)