Improve UX of selecting configuration file - additional table column with filename, echo message when defaulting to the lone configuration file.

pull/2617/head
derekpierre 2021-04-08 11:22:23 -04:00
parent 4b1a7fd07c
commit 0c660fc233
3 changed files with 36 additions and 28 deletions

View File

@ -14,14 +14,12 @@
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import glob
import json
from json.decoder import JSONDecodeError
from typing import Optional, Type, List
import click
from json.decoder import JSONDecodeError
from nucypher.config.base import CharacterConfiguration
from typing import Optional, Type
from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.characters.lawful import Ursula
@ -38,7 +36,9 @@ from nucypher.cli.literature import (
CONFIRM_URSULA_IPV4_ADDRESS
)
from nucypher.cli.types import WORKER_IP
from nucypher.config.base import CharacterConfiguration
from nucypher.config.characters import StakeHolderConfiguration
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
from nucypher.utilities.networking import InvalidWorkerIP, validate_worker_ip
from nucypher.utilities.networking import determine_external_ip_address, UnknownIPAddress
@ -50,6 +50,23 @@ def forget(emitter: StdoutEmitter, configuration: CharacterConfiguration) -> Non
emitter.message(SUCCESSFUL_FORGET_NODES, color='red')
def get_config_filepaths(config_class: Type[CharacterConfiguration], config_root: str = None) -> List:
#
# Scrape disk for configuration files
#
config_root = config_root or DEFAULT_CONFIG_ROOT
default_config_file = glob.glob(config_class.default_filepath(config_root=config_root))
# updated glob pattern for secondary configuration files accommodates for:
# 1. configuration files with "0x..." checksum address as suffix - including older ursula config files
# 2. newer (ursula) configuration files which use signing_pub_key[:8] as hex as the suffix
glob_pattern = f'{config_root}/{config_class.NAME}-[0-9a-fA-f]*.{config_class._CONFIG_FILE_EXTENSION}'
secondary_config_files = sorted(glob.glob(glob_pattern)) # sort list to make order deterministic
config_files = [*default_config_file, *secondary_config_files]
return config_files
def get_or_update_configuration(emitter: StdoutEmitter,
filepath: str,
config_class: Type[CharacterConfiguration],

View File

@ -15,9 +15,8 @@
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import glob
import os
from pathlib import Path
from typing import Callable
from typing import Optional, Tuple, Type
@ -33,6 +32,7 @@ from nucypher.blockchain.eth.registry import InMemoryContractRegistry, BaseContr
from nucypher.blockchain.eth.signers.base import Signer
from nucypher.blockchain.eth.token import NU, Stake
from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.cli.actions.configure import get_config_filepaths
from nucypher.cli.literature import (
GENERIC_SELECT_ACCOUNT,
NO_CONFIGURATIONS_ON_DISK,
@ -48,7 +48,7 @@ from nucypher.cli.literature import (
from nucypher.cli.painting.policies import paint_cards
from nucypher.cli.painting.staking import paint_stakes
from nucypher.config.base import CharacterConfiguration
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, NUCYPHER_ENVVAR_WORKER_ADDRESS
from nucypher.config.constants import NUCYPHER_ENVVAR_WORKER_ADDRESS, DEFAULT_CONFIG_ROOT
from nucypher.policy.identity import Card
@ -228,20 +228,8 @@ def select_config_file(emitter: StdoutEmitter,
"""
#
# Scrape Disk Configurations
#
config_root = config_root or DEFAULT_CONFIG_ROOT
default_config_file = glob.glob(config_class.default_filepath(config_root=config_root))
# updated glob pattern for secondary configuration files accommodates for:
# 1. configuration files with "0x..." checksum address as suffix - including older ursula config files
# 2. newer (ursula) configuration files which use signing_pub_key[:8] as hex as the suffix
glob_pattern = f'{config_root}/{config_class.NAME}-[0-9a-fA-f]*.{config_class._CONFIG_FILE_EXTENSION}'
secondary_config_files = glob.glob(glob_pattern)
config_files = [*default_config_file, *secondary_config_files]
config_files = get_config_filepaths(config_class=config_class, config_root=config_root)
if not config_files:
emitter.message(NO_CONFIGURATIONS_ON_DISK.format(name=config_class.NAME.capitalize(),
command=config_class.NAME), color='red')
@ -249,8 +237,8 @@ def select_config_file(emitter: StdoutEmitter,
checksum_address = checksum_address or os.environ.get(NUCYPHER_ENVVAR_WORKER_ADDRESS, None) # TODO: Deprecate worker_address in favor of checksum_address
parsed_addresses = list()
parsed_config_files = list()
parsed_addresses_and_filenames = list()
# parse configuration files for checksum address values
for fp in config_files:
try:
@ -259,8 +247,8 @@ def select_config_file(emitter: StdoutEmitter,
# matching configuration file found, no need to continue - return filepath
return fp
parsed_addresses.append([config_checksum_address])
parsed_config_files.append(fp)
parsed_addresses_and_filenames.append([config_checksum_address, Path(fp).name]) # store checksum & filename
except config_class.OldVersion:
# no use causing entire usage to crash if file can't be used anyway - inform the user; they can
# decide for themself
@ -280,11 +268,13 @@ def select_config_file(emitter: StdoutEmitter,
#
# Interactive
#
parsed_addresses = tuple(parsed_addresses) # must be tuple-of-iterables for tabulation
emitter.echo(f"\nConfiguration Directory: {config_root}\n")
parsed_addresses_and_filenames = tuple(parsed_addresses_and_filenames) # must be tuple-of-iterables for tabulation
# Display account info
headers = ['Account']
emitter.echo(tabulate(parsed_addresses, headers=headers, showindex='always'))
headers = ['Account', 'Configuration File']
emitter.echo(tabulate(parsed_addresses_and_filenames, headers=headers, showindex='always'))
# Prompt the user for selection, and return
prompt = f"Select {config_class.NAME} configuration"
@ -295,6 +285,7 @@ def select_config_file(emitter: StdoutEmitter,
else:
# Default: Only one config file, use it.
config_file = parsed_config_files[0]
emitter.echo(f"Defaulting to {config_class.NAME} configuration file: {config_file}")
return config_file

View File

@ -317,7 +317,7 @@ NO_FEE_TO_WITHDRAW = "No policy fee can be withdrawn."
MISSING_CONFIGURATION_FILE = """
No {name} configuration file found. To create a new {name} configuration run:
No {name} configuration file found. To create a new {name} configuration run:
nucypher {init_command}
"""
@ -325,7 +325,7 @@ nucypher {init_command}
SELECT_NETWORK = "Select Network"
NO_CONFIGURATIONS_ON_DISK = "No {name} configurations found. run 'nucypher {command} init' then try again."
NO_CONFIGURATIONS_ON_DISK = "No {name} configurations found. Run 'nucypher {command} init' then try again."
SUCCESSFUL_UPDATE_CONFIGURATION_VALUES = "Updated configuration values: {fields}"