mirror of https://github.com/nucypher/nucypher.git
Move modifier flags to main CLI; Session based CLI configuration StdoutEmitter for pre and post character handling
parent
43513cd3b4
commit
0ed8c6c0a4
|
@ -1,15 +1,16 @@
|
|||
import shutil
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
import click
|
||||
from nacl.exceptions import CryptoError
|
||||
from twisted.logger import Logger
|
||||
|
||||
import nucypher
|
||||
from nucypher.blockchain.eth.registry import EthereumContractRegistry
|
||||
from nucypher.characters.control.emitters import StdoutEmitter
|
||||
from nucypher.characters.lawful import Ursula
|
||||
from nucypher.cli.config import NucypherClickConfig
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
from nucypher.network.middleware import RestMiddleware
|
||||
|
||||
DESTRUCTION = '''
|
||||
*Permanently and irreversibly delete all* nucypher files including
|
||||
|
@ -24,36 +25,15 @@ Delete {}?'''
|
|||
|
||||
LOG = Logger('cli.actions')
|
||||
|
||||
|
||||
def handle_control_output(response: dict = None,
|
||||
message: str = None,
|
||||
json: bool = False,
|
||||
quiet: bool = False,
|
||||
color: str = 'white',
|
||||
bold: bool = False,
|
||||
) -> None:
|
||||
|
||||
try:
|
||||
if not quiet and not json:
|
||||
if response:
|
||||
for k, v in response.items():
|
||||
click.secho(message=f'{k} ...... {v}', fg=color, bold=bold)
|
||||
elif message:
|
||||
if json:
|
||||
sys.stdout({'result': message, 'version': nucypher.__version__})
|
||||
click.secho(message=message, fg=color, bold=bold)
|
||||
else:
|
||||
click.secho(message=message, fg=color, bold=bold)
|
||||
else:
|
||||
raise ValueError('Either "response" or "message" is required, but got neither.')
|
||||
elif json:
|
||||
sys.stdout(response)
|
||||
except Exception:
|
||||
LOG.debug("Error while formatting nucypher console output")
|
||||
raise
|
||||
console_emitter = NucypherClickConfig.emit
|
||||
|
||||
|
||||
def load_seednodes(min_stake: int, federated_only: bool, teacher_uris: list = None) -> List[Ursula]:
|
||||
def load_seednodes(min_stake: int,
|
||||
federated_only: bool,
|
||||
network_middleware: RestMiddleware = None,
|
||||
teacher_uris: list = None
|
||||
) -> List[Ursula]:
|
||||
|
||||
teacher_nodes = list()
|
||||
if teacher_uris is None:
|
||||
# Default teacher nodes can be placed here
|
||||
|
@ -61,7 +41,8 @@ def load_seednodes(min_stake: int, federated_only: bool, teacher_uris: list = No
|
|||
for uri in teacher_uris:
|
||||
teacher_node = Ursula.from_teacher_uri(teacher_uri=uri,
|
||||
min_stake=min_stake,
|
||||
federated_only=federated_only)
|
||||
federated_only=federated_only,
|
||||
network_middleware=network_middleware)
|
||||
teacher_nodes.append(teacher_node)
|
||||
return teacher_nodes
|
||||
|
||||
|
@ -96,12 +77,12 @@ def destroy_system_configuration(config_class,
|
|||
character_config.destroy(force=force)
|
||||
except FileNotFoundError:
|
||||
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
|
||||
click.secho(message, fg='red')
|
||||
console_emitter(message=message, color='red')
|
||||
log.debug(message)
|
||||
raise click.Abort()
|
||||
else:
|
||||
message = "Deleted configuration files at {}".format(character_config.config_root)
|
||||
click.secho(message, fg='green')
|
||||
console_emitter(message=message, color='green')
|
||||
log.debug(message)
|
||||
|
||||
return config_root
|
||||
|
@ -109,7 +90,7 @@ def destroy_system_configuration(config_class,
|
|||
|
||||
def unlock_keyring(configuration, password):
|
||||
try:
|
||||
click.secho("Decrypting keyring...", fg='blue')
|
||||
console_emitter(message="Decrypting keyring...", color='blue')
|
||||
configuration.keyring.unlock(password=password)
|
||||
except CryptoError:
|
||||
raise configuration.keyring.AuthenticationFailed
|
||||
|
@ -126,8 +107,9 @@ def connect_to_blockchain(configuration, recompile_contracts: bool = False):
|
|||
|
||||
|
||||
def forget(configuration):
|
||||
"""Forget all known nodes via storages"""
|
||||
"""Forget all known nodes via storage"""
|
||||
click.confirm("Permanently delete all known node data?", abort=True)
|
||||
configuration.forget_nodes()
|
||||
message = "Removed all stored node node metadata and certificates"
|
||||
console_emitter(message=message, color='red')
|
||||
click.secho(message=message, fg='red')
|
||||
|
|
|
@ -19,7 +19,7 @@ import collections
|
|||
import os
|
||||
|
||||
import click
|
||||
from constant_sorrow.constants import NO_PASSWORD
|
||||
from constant_sorrow.constants import NO_PASSWORD, NO_EMITTER
|
||||
from twisted.logger import Logger
|
||||
from twisted.logger import globalLogPublisher
|
||||
|
||||
|
@ -33,6 +33,9 @@ from nucypher.utilities.logging import (
|
|||
|
||||
class NucypherClickConfig:
|
||||
|
||||
# Output Sinks
|
||||
emitters = list()
|
||||
capture_stdout = False
|
||||
__sentry_endpoint = NUCYPHER_SENTRY_ENDPOINT
|
||||
|
||||
# Environment Variables
|
||||
|
@ -65,6 +68,11 @@ class NucypherClickConfig:
|
|||
self.__keyring_password = keyring_password
|
||||
return self.__keyring_password
|
||||
|
||||
@classmethod
|
||||
def emit(cls, *args, **kwargs):
|
||||
for emitter in cls.emitters:
|
||||
emitter(*args, **kwargs)
|
||||
|
||||
|
||||
class NucypherDeployerClickConfig(NucypherClickConfig):
|
||||
|
||||
|
|
|
@ -20,38 +20,101 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
import click
|
||||
|
||||
from nucypher.characters.banners import NUCYPHER_BANNER
|
||||
from nucypher.characters.control.emitters import StdoutEmitter, IPCStdoutEmitter
|
||||
from nucypher.cli import status
|
||||
from nucypher.cli.characters import moe, ursula, alice, bob, enrico
|
||||
from nucypher.cli.config import nucypher_click_config
|
||||
from nucypher.cli.config import nucypher_click_config, NucypherClickConfig
|
||||
from nucypher.cli.painting import echo_version
|
||||
from nucypher.network.middleware import RestMiddleware
|
||||
from nucypher.utilities.logging import GlobalConsoleLogger
|
||||
from nucypher.utilities.sandbox.middleware import MockRestMiddleware
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option('--version', help="Echo the CLI version", is_flag=True, callback=echo_version, expose_value=False, is_eager=True)
|
||||
@click.option('-v', '--verbose', help="Specify verbosity level", count=True)
|
||||
@click.option('-J', '--json', help="Send all output to stdout as JSON", is_flag=True, default=False)
|
||||
@click.option('--no-logs', help="Disable all logging output", is_flag=True, default=False)
|
||||
@click.option('-Z', '--mock-networking', help="Use in-memory transport instead of networking", count=True)
|
||||
@click.option('-J', '--json-ipc', help="Send all output to stdout as JSON", is_flag=True, default=False)
|
||||
@click.option('-Q', '--quiet', help="Disable console printing", is_flag=True, default=False)
|
||||
@click.option('-L', '--no-logs', help="Disable all logging output", is_flag=True, default=False)
|
||||
@click.option('-D', '--debug', help="Enable debugging mode", is_flag=True)
|
||||
@click.option('--no-registry', help="Skip importing the default contract registry", is_flag=True)
|
||||
@nucypher_click_config
|
||||
def nucypher_cli(click_config, verbose, json, no_logs):
|
||||
def nucypher_cli(click_config,
|
||||
verbose,
|
||||
mock_networking,
|
||||
json_ipc,
|
||||
no_logs,
|
||||
quiet,
|
||||
debug,
|
||||
no_registry):
|
||||
|
||||
# Session Emitter for pre and post character control engagement.
|
||||
if json_ipc:
|
||||
emitter = IPCStdoutEmitter(quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout)
|
||||
else:
|
||||
emitter = StdoutEmitter(quiet=quiet, capture_stdout=NucypherClickConfig.capture_stdout)
|
||||
|
||||
NucypherClickConfig.emitter = emitter
|
||||
click_config.emitter(message=NUCYPHER_BANNER)
|
||||
|
||||
# Logging
|
||||
if not no_logs:
|
||||
GlobalConsoleLogger.start_if_not_started()
|
||||
|
||||
if not json:
|
||||
click.echo(NUCYPHER_BANNER)
|
||||
|
||||
# CLI Session Configuration
|
||||
click_config.verbose = verbose
|
||||
click_config.json = json
|
||||
click_config.mock_networking = mock_networking
|
||||
click_config.json_ipc = json_ipc
|
||||
click_config.no_logs = no_logs
|
||||
click_config.quiet = quiet
|
||||
click_config.no_registry = no_registry
|
||||
click_config.debug = debug
|
||||
|
||||
# only used for testing outputs;
|
||||
# Redirects outputs to in-memory python containers.
|
||||
if mock_networking:
|
||||
click_config.emitter(message="WARNING: Mock networking is enabled")
|
||||
click_config.middleware = MockRestMiddleware()
|
||||
else:
|
||||
click_config.middleware = RestMiddleware()
|
||||
|
||||
# Global Warnings
|
||||
if click_config.verbose:
|
||||
click.secho("Verbose mode is enabled", fg='blue')
|
||||
click_config.emitter("Verbose mode is enabled", color='blue')
|
||||
|
||||
|
||||
nucypher_cli.add_command(status.status)
|
||||
nucypher_cli.add_command(alice.alice)
|
||||
nucypher_cli.add_command(bob.bob)
|
||||
nucypher_cli.add_command(enrico.enrico)
|
||||
nucypher_cli.add_command(moe.moe)
|
||||
nucypher_cli.add_command(ursula.ursula)
|
||||
#
|
||||
# Character CLI Entry Points (Fan Out Input)
|
||||
#
|
||||
|
||||
r"""
|
||||
ursula
|
||||
|
|
||||
| moe
|
||||
| /
|
||||
| /
|
||||
stdin --> cli.main --- alice
|
||||
| \
|
||||
| \
|
||||
| bob
|
||||
|
|
||||
enrico
|
||||
|
||||
"""
|
||||
|
||||
# New character CLI modules must be added here
|
||||
# for the entry point to be attached to the nucypher base command.
|
||||
# Inversely, commenting out an entry point will disable it.
|
||||
|
||||
ENTRTY_POINTS = (
|
||||
status.status,
|
||||
alice.alice,
|
||||
bob.bob,
|
||||
enrico.enrico,
|
||||
moe.moe,
|
||||
ursula.ursula
|
||||
)
|
||||
|
||||
for entry_point in ENTRTY_POINTS:
|
||||
nucypher_cli.add_command(entry_point)
|
||||
|
|
|
@ -21,9 +21,11 @@ import maya
|
|||
from constant_sorrow.constants import NO_KNOWN_NODES
|
||||
|
||||
from nucypher.characters.banners import NUCYPHER_BANNER
|
||||
from nucypher.cli import actions
|
||||
from nucypher.characters.control.emitters import StdoutEmitter
|
||||
from nucypher.config.constants import SEEDNODES
|
||||
|
||||
emitter = StdoutEmitter()
|
||||
|
||||
|
||||
def echo_version(ctx, param, value):
|
||||
if not value or ctx.resilient_parsing:
|
||||
|
@ -32,29 +34,23 @@ def echo_version(ctx, param, value):
|
|||
ctx.exit()
|
||||
|
||||
|
||||
def paint_new_installation_help(new_configuration, config_root=None, config_file=None, quiet: bool = False):
|
||||
def paint_new_installation_help(new_configuration, config_root=None, config_file=None):
|
||||
character_config_class = new_configuration.__class__
|
||||
character_name = character_config_class._CHARACTER_CLASS.__name__.lower()
|
||||
character_name = character_config_class._NAME.lower()
|
||||
|
||||
actions.handle_control_output(message="Generated keyring {}".format(new_configuration.keyring_dir),
|
||||
color='green',
|
||||
quiet=quiet)
|
||||
emitter(message="Generated keyring {}".format(new_configuration.keyring_dir), color='green')
|
||||
|
||||
actions.handle_control_output(message="Saved configuration file {}".format(new_configuration.config_file_location),
|
||||
color='green',
|
||||
quiet=quiet)
|
||||
emitter(message="Saved configuration file {}".format(new_configuration.config_file_location), color='green')
|
||||
|
||||
# Give the use a suggestion as to what to do next...
|
||||
suggested_command = f'nucypher {character_name} run'
|
||||
how_to_run_message = f"\nTo run an {character_name.capitalize()} node from the default configuration filepath run: \n\n'{suggested_command}'\n"
|
||||
|
||||
if config_root is not None:
|
||||
config_file_location = os.path.join(config_root, config_file or character_config_class.CONFIG_FILENAME)
|
||||
suggested_command += ' --config-file {}'.format(config_file_location)
|
||||
click.secho(how_to_run_message.format(suggested_command), fg='green')
|
||||
|
||||
return actions.handle_control_output(message=how_to_run_message.format(suggested_command),
|
||||
color='green',
|
||||
quiet=quiet)
|
||||
return emitter(message=how_to_run_message.format(suggested_command), color='green')
|
||||
|
||||
|
||||
def build_fleet_state_status(ursula) -> str:
|
||||
|
|
Loading…
Reference in New Issue