Skip to content

Commit

Permalink
allow prompt and getpass to dispatch on the input-stream type (#28038)
Browse files Browse the repository at this point in the history
* allow prompt and getpass to dispatch on the input-stream type

* dispatch on both stdin and stdout

* tests

* test default arg of Base.prompt
  • Loading branch information
stevengj authored Jul 13, 2018
1 parent 98061ab commit 0e07246
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
23 changes: 16 additions & 7 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,10 @@ graphical interface.
function getpass end

if Sys.iswindows()
function getpass(prompt::AbstractString)
print(prompt, ": ")
flush(stdout)
function getpass(input::TTY, output::IO, prompt::AbstractString)
input === stdin || throw(ArgumentError("getpass only works for stdin"))
print(output, prompt, ": ")
flush(output)
s = SecretBuffer()
plen = 0
while true
Expand All @@ -478,12 +479,17 @@ function getpass(prompt::AbstractString)
return s
end
else
function getpass(prompt::AbstractString)
function getpass(input::TTY, output::IO, prompt::AbstractString)
(input === stdin && output === stdout) || throw(ArgumentError("getpass only works for stdin"))
msg = string(prompt, ": ")
unsafe_SecretBuffer!(ccall(:getpass, Cstring, (Cstring,), msg))
end
end

# allow new getpass methods to be defined if stdin has been
# redirected to some custom stream, e.g. in IJulia.
getpass(prompt::AbstractString) = getpass(stdin, stdout, prompt)

"""
prompt(message; default="") -> Union{String, Nothing}
Expand All @@ -493,15 +499,18 @@ then the user can enter just a newline character to select the `default`.
See also `Base.getpass` and `Base.winprompt` for secure entry of passwords.
"""
function prompt(message::AbstractString; default::AbstractString="")
function prompt(input::IO, output::IO, message::AbstractString; default::AbstractString="")
msg = !isempty(default) ? "$message [$default]: " : "$message: "
print(msg)
uinput = readline(keep=true)
print(output, msg)
uinput = readline(input, keep=true)
isempty(uinput) && return nothing # Encountered an EOF
uinput = chomp(uinput)
isempty(uinput) ? default : uinput
end

# allow new prompt methods to be defined if stdin has been
# redirected to some custom stream, e.g. in IJulia.
prompt(message::AbstractString; default::AbstractString="") = prompt(stdin, stdout, message, default=default)

# Windows authentication prompt
if Sys.iswindows()
Expand Down
10 changes: 10 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,16 @@ let a = [1,2,3]
@test a == [0,0,0]
end

# PR #28038 (prompt/getpass stream args)
@test_throws MethodError Base.getpass(IOBuffer(), stdout, "pass")
let buf = IOBuffer()
@test Base.prompt(IOBuffer("foo\nbar\n"), buf, "baz") == "foo"
@test String(take!(buf)) == "baz: "
@test Base.prompt(IOBuffer("\n"), buf, "baz", default="foobar") == "foobar"
@test String(take!(buf)) == "baz [foobar]: "
@test Base.prompt(IOBuffer("blah\n"), buf, "baz", default="foobar") == "blah"
end

# Test that we can VirtualProtect jitted code to writable
@noinline function WeVirtualProtectThisToRWX(x, y)
return x + y
Expand Down

2 comments on commit 0e07246

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily benchmark build, I will reply here when finished:

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

Please sign in to comment.