Added prompt command.

development
Shawn Davis 4 years ago
parent 155f849a70
commit 761e0ede1a
  1. 2
      VERSION.txt
  2. 146
      scripttease/library/overlays/posix.py
  3. 6
      scripttease/version.py
  4. 52
      tests/test_library_overlays_posix.py

@ -1 +1 @@
6.5.0-d 6.6.0-d

@ -1,6 +1,6 @@
# Imports # Imports
from commonkit import indent from commonkit import indent, split_csv
import os import os
from ..commands import Command from ..commands import Command
@ -19,6 +19,7 @@ __all__ = (
"mkdir", "mkdir",
"move", "move",
"perms", "perms",
"prompt",
"remove", "remove",
"rename", "rename",
"rsync", "rsync",
@ -27,6 +28,7 @@ __all__ = (
"symlink", "symlink",
"touch", "touch",
"Function", "Function",
"Prompt",
) )
# Functions # Functions
@ -313,6 +315,19 @@ def perms(path, group=None, mode=None, owner=None, recursive=False, **kwargs):
return Command("\n".join(a), **kwargs) return Command("\n".join(a), **kwargs)
def prompt(name, back_title="Input", choices=None, default=None, fancy=False, help_text=None, label=None, **kwargs):
return Prompt(
name,
back_title=back_title,
choices=choices,
default=default,
fancy=fancy,
help_text=help_text,
label=label,
**kwargs
)
def remove(path, force=False, recursive=False, **kwargs): def remove(path, force=False, recursive=False, **kwargs):
"""Remove a file or directory. """Remove a file or directory.
@ -560,6 +575,135 @@ class Function(object):
return "\n".join(a) return "\n".join(a)
class Prompt(Command):
"""Prompt the user for input."""
def __init__(self, name, back_title="Input", choices=None, default=None, fancy=False, help_text=None, label=None,
**kwargs):
"""Initialize a prompt for user input.
:param name: The variable name.
:type name: str
:param back_title: The back title of the input. Used only when ``dialog`` is enabled.
:type back_title: str
:param choices: Valid choices for the variable. May be given as a list of strings or a comma separated string.
:type choices: list[str] | str
:param default: The default value of the variable.
:param fancy: Indicates the dialog command should be used.
:type fancy: bool
:param help_text: Additional text to display. Only use when ``fancy`` is ``True``.
:type help_text: str
:param label: The label of the prompt.
"""
self.back_title = back_title
self.default = default
self.dialog_enabled = fancy
self.help_text = help_text
self.label = label or name.replace("_", " ").title()
self.variable_name = name
if type(choices) in (list, tuple):
self.choices = choices
elif type(choices) is str:
self.choices = split_csv(choices, smart=False)
# for i in choices.split(","):
# self.choices.append(i.strip())
else:
self.choices = None
kwargs.setdefault("comment", "prompt user for %s input" % name)
super().__init__(name, **kwargs)
def get_statement(self, cd=False, suppress_comment=False):
"""Get the statement using dialog or read."""
if self.dialog_enabled:
return self._get_dialog_statement()
return self._get_read_statement()
def _get_dialog_statement(self):
"""Get the dialog statement."""
a = list()
a.append('dialog --clear --backtitle "%s" --title "%s"' % (self.back_title, self.label))
if self.choices is not None:
a.append('--menu "%s" 15 40 %s' % (self.help_text or "Select", len(self.choices)))
count = 1
for choice in self.choices:
a.append('"%s" %s' % (choice, count))
count += 1
a.append('2>/tmp/input.txt')
else:
if self.help_text is not None:
a.append('--inputbox "%s"' % self.help_text)
else:
a.append('--inputbox ""')
a.append('8 60 2>/tmp/input.txt')
b = list()
b.append('touch /tmp/input.txt')
b.append(" ".join(a))
b.append('%s=$(</tmp/input.txt)' % self.variable_name)
b.append('clear')
b.append('rm /tmp/input.txt')
if self.default is not None:
b.append('if [[ -z "$%s" ]]; then %s="%s"; fi;' % (self.variable_name, self.variable_name, self.default))
# b.append('echo "$%s"' % self.name)
return "\n".join(b)
def _get_read_statement(self):
"""Get the standard read statement."""
a = list()
if self.choices is not None:
a.append('echo "%s "' % self.label)
options = list()
for choice in self.choices:
options.append('"%s"' % choice)
a.append('options=(%s)' % " ".join(options))
a.append('select opt in "${options[@]}"')
a.append('do')
a.append(' case $opt in')
for choice in self.choices:
a.append(' "%s") %s=$opt; break;;' % (choice, self.variable_name))
# a.append(' %s) %s=$opt;;' % ("|".join(self.choices), self.name))
a.append(' *) echo "invalid choice";;')
a.append(' esac')
a.append('done')
# a.append("read %s" % self.name)
else:
a.append('echo -n "%s "' % self.label)
a.append("read %s" % self.variable_name)
if self.default is not None:
a.append('if [[ -z "$%s" ]]; then %s="%s"; fi;' % (self.variable_name, self.variable_name, self.default))
# a.append('echo "$%s"' % self.name)
return "\n".join(a)
# Mappings # Mappings

@ -1,5 +1,5 @@
DATE = "2020-09-22" DATE = "2020-09-24"
VERSION = "6.5.0-d" VERSION = "6.6.0-d"
MAJOR = 6 MAJOR = 6
MINOR = 5 MINOR = 6
PATCH = 0 PATCH = 0

@ -113,6 +113,12 @@ def test_perms():
assert "chmod -R 755 /path/to/dir" in s assert "chmod -R 755 /path/to/dir" in s
def test_prompt():
# This is just a placeholder to test the prompt() interface. See TestPrompt.
c = prompt("testing")
assert isinstance(c, Prompt)
def test_remove(): def test_remove():
c = remove("/path/to/dir", force=True, recursive=True) c = remove("/path/to/dir", force=True, recursive=True)
s = c.get_statement() s = c.get_statement()
@ -222,3 +228,49 @@ class TestFunction(object):
assert "# A test function." in s assert "# A test function." in s
assert "function testing()" in s assert "function testing()" in s
assert "touch /path/to/file.txt" in s assert "touch /path/to/file.txt" in s
class TestPrompt(object):
def test_init(self):
c = Prompt("testing", choices=["yes", "no", "maybe"])
assert type(c.choices) is list
c = Prompt("testing", choices="yes, no, maybe")
assert type(c.choices) is list
c = Prompt("testing")
assert c.choices is None
def test_get_dialog_statement(self):
c = Prompt("testing", choices=["yes", "no", "maybe"], fancy=True)
s = c.get_statement()
assert 'dialog --clear --backtitle "Input" --title "Testing"' in s
assert '--menu "Select" 15 40 3 "yes" 1 "no" 2 "maybe" 3 2>/tmp/input.txt' in s
assert 'testing=$(</tmp/input.txt)' in s
assert 'clear' in s
assert 'rm /tmp/input.txt' in s
c = Prompt("testing", fancy=True, help_text="This is a test.")
s = c.get_statement()
assert 'dialog --clear --backtitle "Input" --title "Testing"' in s
assert '--inputbox "This is a test." 8 60 2>/tmp/input.txt' in s
assert 'testing=$(</tmp/input.txt)' in s
assert 'clear' in s
assert 'rm /tmp/input.txt' in s
c = Prompt("testing", default="it is", fancy=True)
s = c.get_statement()
assert 'if [[ -z "$testing" ]]; then testing="it is"; fi;' in s
def test_get_read_statement(self):
c = Prompt("testing", choices=["yes", "no", "maybe"])
s = c.get_statement()
assert 'options=("yes" "no" "maybe")' in s
assert 'select opt in "${options[@]}"' in s
c = Prompt("testing", default="yes")
s = c.get_statement()
assert 'echo -n "Testing "' in s
assert "read testing" in s
assert 'then testing="yes"' in s

Loading…
Cancel
Save