Merge pull request #290 from YunoHost/enh-prompt-multiline

[enh] Add prefill and multiline in prompt
This commit is contained in:
Alexandre Aubin 2021-09-03 15:53:26 +02:00 committed by GitHub
commit f417c84cb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 10 deletions

View file

@ -5,6 +5,7 @@
"confirm": "Confirm {prompt}", "confirm": "Confirm {prompt}",
"deprecated_command": "'{prog} {command}' is deprecated and will be removed in the future", "deprecated_command": "'{prog} {command}' is deprecated and will be removed in the future",
"deprecated_command_alias": "'{prog} {old}' is deprecated and will be removed in the future, use '{prog} {new}' instead", "deprecated_command_alias": "'{prog} {old}' is deprecated and will be removed in the future, use '{prog} {new}' instead",
"edit_text_question": "{}. Edit this text ? [yN]: ",
"error": "Error:", "error": "Error:",
"file_not_exist": "File does not exist: '{path}'", "file_not_exist": "File does not exist: '{path}'",
"folder_exists": "Folder already exists: '{path}'", "folder_exists": "Folder already exists: '{path}'",

View file

@ -6,8 +6,11 @@ import getpass
import locale import locale
import logging import logging
import argparse import argparse
import tempfile
from readline import insert_text, set_startup_hook
from collections import OrderedDict from collections import OrderedDict
from datetime import date, datetime from datetime import date, datetime
from subprocess import call
from moulinette import m18n, Moulinette from moulinette import m18n, Moulinette
from moulinette.actionsmap import ActionsMap from moulinette.actionsmap import ActionsMap
@ -522,7 +525,7 @@ class Interface:
credentials = self.prompt(msg, True, False, color="yellow") credentials = self.prompt(msg, True, False, color="yellow")
return authenticator.authenticate_credentials(credentials=credentials) return authenticator.authenticate_credentials(credentials=credentials)
def prompt(self, message, is_password=False, confirm=False, color="blue"): def prompt(self, message, is_password=False, confirm=False, color="blue", prefill="", is_multiline=False):
"""Prompt for a value """Prompt for a value
Keyword arguments: Keyword arguments:
@ -534,15 +537,41 @@ class Interface:
"Not a tty, can't do interactive prompts", raw_msg=True "Not a tty, can't do interactive prompts", raw_msg=True
) )
if is_password: def _prompt(message):
prompt = lambda m: getpass.getpass(colorize(m18n.g("colon", m), color))
else: if is_password:
prompt = lambda m: input(colorize(m18n.g("colon", m), color)) return getpass.getpass(colorize(m18n.g("colon", message), color))
value = prompt(message) elif not is_multiline:
set_startup_hook(lambda: insert_text(prefill))
try:
value = input(colorize(m18n.g("colon", message), color))
finally:
set_startup_hook()
return value
else:
while True:
value = input(colorize(m18n.g("edit_text_question", message), color))
value = value.lower().strip()
if value in ["", "n", "no"]:
return prefill
elif value in ['y', 'yes']:
break
initial_message = prefill.encode('utf-8')
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
tf.write(initial_message)
tf.flush()
call(["editor", tf.name])
tf.seek(0)
edited_message = tf.read()
return edited_message.decode("utf-8")
value = _prompt(message)
if confirm: if confirm:
m = message[0].lower() + message[1:] m = message[0].lower() + message[1:]
if prompt(m18n.g("confirm", prompt=m)) != value: if _prompt(m18n.g("confirm", prompt=m)) != value:
raise MoulinetteValidationError("values_mismatch") raise MoulinetteValidationError("values_mismatch")
return value return value

View file

@ -67,16 +67,17 @@ def read_json(file_path):
return loaded_json return loaded_json
def read_yaml(file_path): def read_yaml(file_):
""" """
Safely read a yaml file Safely read a yaml file
Keyword argument: Keyword argument:
file_path -- Path to the yaml file file -- Path or stream to the yaml file
""" """
# Read file # Read file
file_content = read_file(file_path) file_path = file_ if isinstance(file_, str) else file_.name
file_content = read_file(file_) if isinstance(file_, str) else file_
# Try to load yaml to check if it's syntaxically correct # Try to load yaml to check if it's syntaxically correct
try: try: