Skip to content

Commit

Permalink
adding support for backspace and up/down arrows
Browse files Browse the repository at this point in the history
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
  • Loading branch information
vsoch committed Feb 10, 2022
1 parent 6780052 commit 456fbb5
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 4 deletions.
47 changes: 45 additions & 2 deletions docs/getting_started/user-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,28 @@ Or the container backend:
$ paks run --container-tech podman busybox
This will take you into a shell where you can interact! For example, here is a save:
This will take you into a shell where you can interact, and issue Paks commands,
discussed next.

Paks Commands
=============

The most useful thing (I think) as a developer that I sometimes want to do is
save my container. This obviously doesn't include mounted volumes, but it does
include changes I've made the filesystem. A save comes down to:

1. Committing the current state
2. Squashing layers to not be in danger of going over the limit.
3. Saving the container with a suffix (e.g., ``-saved``).

So let's say that we do a paks run, and then attempt a save. That might
look like this:

.. code-block:: console
/ # #save
$ paks run ubuntu
# touch PANCAKES
# #save
Saving container...
sha256:d82aaa268feb59344cf31a757ce7f5c0caa6a6bbd10b8d0af1d55cdbc50b609b
[+] Building 0.2s (5/5) FINISHED
Expand All @@ -80,6 +97,32 @@ This will take you into a shell where you can interact! For example, here is a s
#save
And then you can see that there is an ubuntu-saved container!

.. code-block:: console
$ docker images | grep ubuntu
ubuntu-saved latest 93e336d994de 2 minutes ago 72.8MB
ubuntu latest 54c9d81cbb44 7 days ago 72.8MB
We could change the suffix of the thing saved too, because paks commands accept different kinds of arguments
and key word arguments (kwargs). In this case, the suffix is a keyword:

.. code-block:: console
$ paks run ubuntu
# touch PANCAKES
# #save suffix=-pancakes
...
#5 writing image sha256:6d3b5b27d0b15054eada3159a14c8c1a7fb251e6553adeddc37f54f0cfc9cc33 done
#5 naming to docker.io/library/ubuntu-pancakes done
#5 DONE 0.0s
Untagged: dockerio-ubuntu-rugged-leg-4547-whispering-nunchucks-1604:latest
Deleted: sha256:e6609a04affa74dd17fc931f1217503207f1b5030d82edaf657d30627511d53c
Successfully saved container! ⭐️
More commands coming soon!

- docker inspect of different metadata
Expand Down
59 changes: 57 additions & 2 deletions paks/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import subprocess
import select
import string
import pty
import termios
import tty
Expand Down Expand Up @@ -74,12 +75,36 @@ class ContainerTechnology:

def __init__(self):

# Save history for the length of one interactive command (shell)
self.clear_history()

# If we weren't created with settings, add empty
if not hasattr(self, "settings"):
from paks.settings import EmptySettings

self.settings = EmptySettings()

def clear_history(self):
self.history = []

def get_history(self, line):
"""
Given an input with some number of up/down and newline, derive command.
"""
up = line.count("[A")
down = line.count("[B")
change = up - down

# 0 change - we are on same line
# here we are looking back up into history (negative index)
if change > 0 and len(self.history) >= change:
newline = self.history[-1 * change]
newline += line.replace("[A", "").replace("[B", "")
return newline

# If we get here, either down error or no change
return ""

def encode(self, msg):
return bytes((msg).encode("utf-8"))

Expand All @@ -105,6 +130,9 @@ def _interactive_command(self, cmd):
# open pseudo-terminal to interact with subprocess
openpty, opentty = pty.openpty()

# The user will likely press up / down, we can store a limited history back
self.clear_history()

# use os.setsid() make it run in a new process group, or bash job control will not be enabled
p = subprocess.Popen(
cmd,
Expand All @@ -122,18 +150,45 @@ def _interactive_command(self, cmd):
r, w, e = select.select([sys.stdin, openpty], [], [])
if sys.stdin in r:
terminal_input = os.read(sys.stdin.fileno(), 10240)
string_input += terminal_input.decode("utf-8")
new_char = terminal_input.decode("utf-8")

# if we have a backspace (ord 127)
if (
len(new_char) == 1
and ord(new_char) == 127
and len(string_input) > 0
):
string_input = string_input[:-1]
else:
string_input = string_input + new_char

# Replace weird characters
string_input = re.sub(
r"[^a-zA-Z0-9%s\n\r\w ]" % string.punctuation, "", string_input
)

# If we don't have a newline, continue adding on to new input
if "\n" not in string_input and "\r" not in string_input:
os.write(openpty, terminal_input)
continue

# If we are looking for history with up [A or down [B arrows
# Note there is a preceding escape we are ignoring (ord 27)
if "[A" in string_input or "[B" in string_input:
string_input = self.get_history(string_input.strip())

# Universal exit command
if "exit" in string_input:
print("\n\rContainer exited. ")
print("\n\rContainer exited.\n\r")
return self.uri.extended_name

# If no change, do not continue
if not string_input:
continue

# Add derived line to the history
self.history.append(string_input)

# Parse the command and determine if it's a match!
executor = self.commands.get_executor(string_input)
if executor is not None:
Expand Down

0 comments on commit 456fbb5

Please sign in to comment.