Packages
nerves_bootstrap
0.6.3
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.5
1.14.4
1.14.3
1.14.2
1.14.0
1.13.1
1.13.0
1.12.2
1.12.1
1.12.0
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
1.11.0
1.10.6
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.1
1.8.0
1.7.1
1.7.0
1.6.3
1.6.2
1.6.1
1.6.0
1.5.3
1.5.2
1.5.1
1.5.0
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.1
1.0.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
Nerves mix integration bootstrap and new project generator
Current section
Files
Jump to
Current section
Files
lib/mix/nerves/shell.ex
defmodule Mix.Nerves.Shell do
def open(command, initial_input \\ []) do
# We need to get raw binary access to the stdout file descriptor
# so we can directly pass through control characters output by the command
stdout_port = Port.open({:fd, 0, 1}, [:binary, :eof, :stream, :out])
# We use the tty_sl driver for input because it handles tty geometry and
# streaming mode.
stdin_port = Port.open({:spawn, "tty_sl -c -e"}, [:binary, :eof, :stream, :in])
# We run the command through the script command to emulate a pty
cmd_port = Port.open({:spawn, "script -q /dev/null #{command}"}, [:binary, :eof, :stream, :stderr_to_stdout])
# Tell the script command about the terminal dimensions
{w, h} = get_tty_geometry(stdin_port)
Port.command(cmd_port,
"""
stty sane rows #{h} cols #{w}; stty -echo
export PS1=""; export PS2=""
start() {
echo -e "\\e[17F\\e[0J\\e[1;7m\n Preparing Nerves Shell \\e[0m"
echo -e "\\e]0;Nerves Shell\\a"
export PS1="\\[\\e[1;7m\\] Nerves \\[\\e[0;1m\\] \\w > \\[\\e[0m\\]"
export PS2="\\[\\e[1;7m\\] Nerves \\[\\e[0;1m\\] \\w ..\\[\\e[0m\\]"
#{Enum.join(initial_input, "\n")}
stty echo
}; start
""")
shell_loop(stdin_port, stdout_port, cmd_port)
end
defp shell_loop(stdin_port, stdout_port, cmd_port) do
receive do
# Route input from stdin to the command port
{^stdin_port, {:data, data}} ->
Port.command(cmd_port, data)
shell_loop(stdin_port, stdout_port, cmd_port)
# Route output from the command port to stdout
{^cmd_port, {:data, data}} ->
Port.command(stdout_port, data)
shell_loop(stdin_port, stdout_port, cmd_port)
# If any of the ports get closed, break out of the loop
{_port, :eof} ->
:ok
# Ignore other messages
_message ->
shell_loop(stdin_port, stdout_port, cmd_port)
end
end
@ctrl_op_get_winsize 100
defp get_tty_geometry(tty_port) do
geometry = :erlang.port_control(tty_port, @ctrl_op_get_winsize, [])
|> :erlang.list_to_binary()
<<w::native-integer-size(32), h::native-integer-size(32)>> = geometry
{w, h}
end
end