Skip to content

Commit

Permalink
Added tests and review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
filchristou committed Jul 3, 2023
1 parent a32e15f commit d9b8369
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 30 deletions.
1 change: 1 addition & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
- uses: julia-actions/julia-runtest@v1
env:
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
- run: julia -e "import Pkg; Pkg.add(\"TestEnv\")"
docs:
name: Documentation
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion bin/julia-r
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ atreplinit() do repl
# Run one command as part of connection setup to trigger compilation
# This makes the REPL more immediately responsive after it prints the
# welcome message.
RemoteREPL.run_remote_repl_command(RemoteREPL._repl_client_connection,
remotecmd(RemoteREPL._repl_client_connection,
stdout, "\"hi\"")
println("""
Connected to $host
Expand Down
9 changes: 9 additions & 0 deletions docs/src/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ julia> session_id = UUID("f03aec15-3e14-4d58-bcfa-82f8d33c9f9a")
julia> connect_repl(; session_id=session_id)
```

## Pass a command non-interactively
To programmatically pass a command to the remote julia kernel use [`remotecmd`](@ref). For example:

```julia
julia> con2server = connect_remote(Sockets.localhost, 9093) # connect to port 9093 in localhost
julia> remotecmd(con2server, "myvar = 1") # define a new var
```

## Use alternatives to SSH

### AWS Session Manager
Expand Down
2 changes: 1 addition & 1 deletion docs/src/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ serve_repl
connect_remote
RemoteREPL.@remote
RemoteREPL.remote_eval
RemoteREPL.run_remote_repl_command
RemoteREPL.remotecmd
RemoteREPL.remote_module!
```

2 changes: 1 addition & 1 deletion src/RemoteREPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ using Sockets, Serialization
using UUIDs, Logging
using OpenSSH_jll

export connect_repl, serve_repl, @remote, connect_remote, run_remote_repl_command, remote_module!
export connect_repl, serve_repl, @remote, connect_remote, remotecmd, remote_module!

const DEFAULT_PORT = 27754
const PROTOCOL_MAGIC = "RemoteREPL"
Expand Down
30 changes: 14 additions & 16 deletions src/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -307,12 +307,12 @@ function REPL.complete_line(provider::RemoteCompletionProvider,
end

"""
run_remote_repl_command(conn::Connection, out_stream::IO, cmdstr::String)
remotecmd(conn::Connection, out_stream::IO, cmdstr::String)
Evaluate `cmdstr` in the remote session of connection `conn` and write result into `out_stream`.
Also supports the magic `RemoteREPL` commands like `%module` and `%include`.
"""
function run_remote_repl_command(conn::Connection, out_stream::IO, cmdstr::String)
function remotecmd(conn::Connection, out_stream::IO, cmdstr::String)
# Compute command
magic = match_magic_syntax(cmdstr)
if isnothing(magic)
Expand Down Expand Up @@ -382,41 +382,39 @@ function run_remote_repl_command(conn::Connection, out_stream::IO, cmdstr::Strin
end

"""
run_remote_repl_command(cmdstr::String)
remotecmd(cmdstr::String)
Evaluate `cmdstr` in the last opened RemoteREPL connection and print result to `Base.stdout`
"""
run_remote_repl_command(cmd::String) = run_remote_repl_command(_repl_client_connection, Base.stdout, cmd)
remotecmd(cmd::String) = remotecmd(_repl_client_connection, Base.stdout, cmd)

"""
run_remote_repl_command(conn::Connection, cmdstr::String)
remotecmd(conn::Connection, cmdstr::String)
Evaluate `cmdstr` in the connection `conn` and print result to `Base.stdout`.
"""
run_remote_repl_command(conn::Connection, cmd::String) = run_remote_repl_command(conn, Base.stdout, cmd)
remotecmd(conn::Connection, cmd::String) = remotecmd(conn, Base.stdout, cmd)

"""
remote_module!(mod::Module, conn::Connection = _repl_client_connection)
remote_module!(conn::Connection = _repl_client_connection, mod::Module)
Change future remote commands in the session of connection `conn` to be evaluated into module `mod`.
The default connection `_repl_client_connection` is the last established RemoteREPL connection.
If the module cannot be evaluated locally pass the name as a string.
Equivalent to using the `%module` magic.
"""
function remote_module!(mod::Module, conn=_repl_client_connection)
run_remote_repl_command(conn, Base.stdout, "%module $(mod)")
end
remote_module!(conn::Connection, mod::Module) = remotecmd(conn, Base.stdout, "%module $(mod)")
remote_module!(mod::Module) = remotecmd(_repl_client_connection, Base.stdout, "%module $(mod)")

"""
remote_module!(modstr::String, conn::Connection = _repl_client_connection)
remote_module!(conn::Connection = _repl_client_connection, modstr::String)
Change future remote commands in the session of connection `conn` to be evaluated into module identified by `modstr`.
The default connection `_repl_client_connection` is the last established RemoteREPL connection.
Equivalent to using the `%module` magic.
"""
function remote_module!(modstr::String, conn=_repl_client_connection)
run_remote_repl_command(conn, Base.stdout, "%module "*modstr)
end
remote_module!(conn::Connection, modstr::String) = remotecmd(conn, Base.stdout, "%module "*modstr)
remote_module!(modstr::String) = remotecmd(_repl_client_connection, Base.stdout, "%module "*modstr)



Expand Down Expand Up @@ -491,7 +489,7 @@ function connect_repl(host=Sockets.localhost, port::Integer=DEFAULT_PORT;

conn = connect_remote(host, port; tunnel, ssh_opts, region, namespace, session_id)
out_stream = stdout
prompt = ReplMaker.initrepl(c->run_remote_repl_command(conn, out_stream, c),
prompt = ReplMaker.initrepl(c->remotecmd(conn, out_stream, c),
repl = Base.active_repl,
valid_input_checker = valid_input_checker,
prompt_text = ()->repl_prompt_text(conn),
Expand Down Expand Up @@ -606,7 +604,7 @@ function remote_eval(host, port::Integer, cmdstr::AbstractString;
local result
try
setup_connection!(conn)
result = run_remote_repl_command(conn, IOBuffer(), cmdstr)
result = remotecmd(conn, IOBuffer(), cmdstr)
finally
close(conn)
end
Expand Down
9 changes: 4 additions & 5 deletions src/server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -252,16 +252,15 @@ function serve_repl(server::Base.IOServer; on_client_connect=nothing)
while isopen(server)
socket = accept(server)

session, session_id, socketidx = lock(session_lock) do
# expect session id
session_id = deserialize(socket)
session = if haskey(open_sessions, session_id)
# expect session id
session_id = deserialize(socket)
session = lock(session_lock) do
if haskey(open_sessions, session_id)
push!(open_sessions[session_id].sockets, socket)
open_sessions[session_id]
else
open_sessions[session_id] = ServerSideSession([socket], Dict(), Main)
end
session, session_id, length(session.sockets)
end

peer = getpeername(socket)
Expand Down
24 changes: 18 additions & 6 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@ end
@test repl_prompt_text(fake_conn("ABC", DEFAULT_PORT, is_open=false)) == "julia@ABC [disconnected]> "
end

function wait_conn(host, port, use_ssh; max_tries=4)
function wait_conn(host, port, use_ssh; max_tries=4, session_id=nothing)
for i=1:max_tries
try
return RemoteREPL.Connection(host=host, port=port,
tunnel=use_ssh ? :ssh : :none,
ssh_opts=`-o StrictHostKeyChecking=no`)
tunnel=use_ssh ? :ssh : :none,
ssh_opts=`-o StrictHostKeyChecking=no`,
session_id=session_id)
catch exc
if i == max_tries
rethrow()
Expand All @@ -81,7 +82,7 @@ function wait_conn(host, port, use_ssh; max_tries=4)
end

function runcommand_unwrap(conn, cmdstr)
result = RemoteREPL.run_remote_repl_command(conn, IOBuffer(), cmdstr)
result = remotecmd(conn, IOBuffer(), cmdstr)
# Unwrap Text for testing purposes
return result isa Text ? result.content : result
end
Expand Down Expand Up @@ -113,7 +114,7 @@ end

# Use non-default port to avoid clashes with concurrent interactive use or testing.
test_port = RemoteREPL.find_free_port(Sockets.localhost)
server_proc = run(`$(Base.julia_cmd()) -e "using Sockets; using RemoteREPL; serve_repl($test_port)"`, wait=false)
server_proc = run(`$(Base.julia_cmd()) --project -e "using TestEnv; TestEnv.activate(); using RemoteREPL, Sockets, UUIDs ; serve_repl($test_port)"`, wait=false)

try

Expand Down Expand Up @@ -301,7 +302,7 @@ end


test_port = RemoteREPL.find_free_port(Sockets.localhost)
server_proc = run(```$(Base.julia_cmd()) -e "using Sockets; using RemoteREPL; module EvalInMod ; end;
server_proc = run(```$(Base.julia_cmd()) --project -e "using TestEnv; TestEnv.activate(); using RemoteREPL, Sockets, UUIDs ; module EvalInMod ; end;
serve_repl($test_port, on_client_connect=sess->sess.in_module=EvalInMod)"```, wait=false)
try

Expand All @@ -311,6 +312,17 @@ try
runcommand(cmdstr) = runcommand_unwrap(conn, cmdstr)

@test runcommand("@__MODULE__") == "Main.EvalInMod"

# common sessions
sid = uuid4()
conn2 = wait_conn(test_interface, test_port, use_ssh; session_id = sid)
conn3 = wait_conn(test_interface, test_port, use_ssh; session_id = sid)

# change module to Main once
remote_module!(conn2, "Main")

@test runcommand_unwrap(conn2, "@__MODULE__") == "Main"
@test runcommand_unwrap(conn3, "@__MODULE__") == "Main"
end

finally
Expand Down

0 comments on commit d9b8369

Please sign in to comment.