Beispiel #1
0
def main(
    ctx: click.Context,
    line_length: int,
    check: bool,
    diff: bool,
    compact_diff: bool,
    include: str,
    exclude: str,
    src: List[PathLike],
    config: Optional[PathLike],
    verbose: bool,
):
    """The uncompromising Snakemake code formatter.

    SRC specifies directories and files to format. Directories will be searched for
    file names that conform to the include/exclude patterns provided.

    Files are modified in-place by default; use diff, check, or
     `snakefmt - < Snakefile` to avoid this.
    """
    log_level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(format="[%(levelname)s] %(message)s", level=log_level)

    if not src:
        click.echo(
            "No path provided. Nothing to do 😴. Call with -h for help.",
            err=True)
        ctx.exit(0)

    if "-" in src and len(src) > 1:
        raise click.BadArgumentUsage("Cannot mix stdin (-) with other files")

    if diff and compact_diff:
        logging.warning(
            "Both --diff and --compact-diff given. Returning compact diff...")

    try:
        include_regex = construct_regex(include)
    except re.error:
        raise InvalidRegularExpression(
            f"Invalid regular expression for --include given: {include!r}")

    try:
        exclude_regex = construct_regex(exclude)
    except re.error:
        raise InvalidRegularExpression(
            f"Invalid regular expression for --exclude given: {exclude!r}")

    files_to_format: Set[PathLike] = set()
    gitignore = get_gitignore(Path())
    for path in src:
        path = Path(path)
        if path.name == "-" or path.is_file():
            # if a file was explicitly given, we don't care about its extension
            files_to_format.add(path)
        elif path.is_dir():
            files_to_format.update(
                get_snakefiles_in_dir(path, include_regex, exclude_regex,
                                      gitignore))
        else:
            logging.warning(f"ignoring invalid path: {path}")

    differ = Diff(compact=compact_diff)
    files_changed, files_unchanged = 0, 0
    files_with_errors = 0
    for path in files_to_format:
        path_is_stdin = path.name == "-"
        if path_is_stdin:
            logging.debug("Formatting from stdin")
            path = sys.stdin
        else:
            logging.debug(f"Formatting {path}")

        try:
            original_content = path.read_text()
        except AttributeError:
            original_content = path.read()

        try:
            snakefile = Snakefile(StringIO(original_content))
            formatter = Formatter(snakefile,
                                  line_length=line_length,
                                  black_config=config)
            formatted_content = formatter.get_formatted()
        except Exception as error:
            if check:
                logging.error(
                    f"'{error.__class__.__name__}: {error}' in file {path}")
                files_with_errors += 1
                continue
            else:
                raise error

        if check:
            is_changed = differ.is_changed(original_content, formatted_content)
            if is_changed:
                logging.debug("Formatted content is different from original")
                files_changed += 1
            else:
                files_unchanged += 1

        if diff or compact_diff:
            filename = "stdin" if path_is_stdin else str(path)
            click.echo(f"{'=' * 5}> Diff for {filename} <{'=' * 5}\n")
            difference = differ.compare(original_content, formatted_content)
            click.echo(difference)
        elif not any([check, diff, compact_diff]):
            if path_is_stdin:
                sys.stdout.write(formatted_content)
            else:
                write_file_back = differ.is_changed(original_content,
                                                    formatted_content)
                if write_file_back:
                    logging.info(f"Writing formatted content to {path}")
                    with path.open("w") as out_handle:
                        out_handle.write(formatted_content)

    if check:
        if files_unchanged == len(files_to_format):
            logging.info(
                f"All {len(files_to_format)} file(s) would be left unchanged 🎉"
            )
            ctx.exit(ExitCode.NO_CHANGE.value)
        elif files_with_errors > 0:
            exit_value = ExitCode.ERROR.value
        elif files_changed > 0:
            exit_value = ExitCode.WOULD_CHANGE.value

        if files_with_errors > 0:
            logging.info(
                f"{files_with_errors} file(s) raised parsing errors 🤕")
        if files_changed > 0:
            logging.info(f"{files_changed} file(s) would be changed 😬")
        if files_unchanged > 0:
            logging.info(
                f"{files_unchanged} file(s) would be left unchanged 🎉")
        ctx.exit(exit_value)

    logging.info("All done 🎉")
Beispiel #2
0
def bob(click_config, action, quiet, teacher_uri, min_stake, http_port,
        discovery_port, federated_only, network, config_root, config_file,
        provider_uri, registry_filepath, dev, force, dry_run, label,
        policy_encrypting_key, alice_verifying_key, message_kit):
    """
    Start and manage a "Bob" character.
    """

    if not click_config.json_ipc and not click_config.quiet:
        click.secho(BOB_BANNER)

    if action == 'init':
        """Create a brand-new persistent Bob"""

        if dev:
            click_config.emit(message="WARNING: Using temporary storage area",
                              color='yellow')

        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar

        new_bob_config = BobConfiguration.generate(
            password=click_config.get_password(confirm=True),
            config_root=config_root or click_config,
            rest_host="localhost",
            domains={network} if network else None,
            federated_only=federated_only,
            no_registry=click_config.no_registry,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri)

        return painting.paint_new_installation_help(
            new_configuration=new_bob_config, config_file=config_file)

    #
    # Get Bob Configuration
    #

    if dev:
        bob_config = BobConfiguration(
            dev_mode=True,
            domains={network},
            provider_uri=provider_uri,
            federated_only=True,
            network_middleware=click_config.middleware)
    else:

        try:
            bob_config = BobConfiguration.from_configuration_file(
                filepath=config_file,
                domains={network or GLOBAL_DOMAIN},
                rest_port=discovery_port,
                provider_uri=provider_uri,
                network_middleware=click_config.middleware)
        except FileNotFoundError:
            return actions.handle_missing_configuration_file(
                character_config_class=BobConfiguration,
                config_file=config_file)

    # Teacher Ursula
    teacher_uris = [teacher_uri] if teacher_uri else list()
    teacher_nodes = actions.load_seednodes(
        teacher_uris=teacher_uris,
        min_stake=min_stake,
        federated_only=federated_only,
        network_middleware=click_config.middleware)

    if not dev:
        click_config.unlock_keyring(character_configuration=bob_config)

    # Produce
    BOB = bob_config(known_nodes=teacher_nodes,
                     network_middleware=click_config.middleware)

    # Switch to character control emitter
    if click_config.json_ipc:
        BOB.controller.emitter = IPCStdoutEmitter(quiet=click_config.quiet)

    if action == "run":
        click_config.emitter(
            message=f"Bob Verifying Key {bytes(BOB.stamp).hex()}",
            color='green',
            bold=True)
        bob_encrypting_key = bytes(BOB.public_keys(DecryptingPower)).hex()
        click_config.emitter(
            message=f"Bob Encrypting Key {bob_encrypting_key}",
            color="blue",
            bold=True)
        controller = BOB.make_web_controller()
        BOB.log.info('Starting HTTP Character Web Controller')
        return controller.start(http_port=http_port, dry_run=dry_run)

    elif action == "view":
        """Paint an existing configuration to the console"""
        response = BobConfiguration._read_configuration_file(
            filepath=config_file or bob_config.config_file_location)
        return BOB.controller.emitter(response=response)

    elif action == "public-keys":
        response = BOB.controller.public_keys()
        return response

    elif action == "retrieve":

        if not all(
            (label, policy_encrypting_key, alice_verifying_key, message_kit)):
            input_specification, output_specification = BOB.control.get_specifications(
                interface_name='retrieve')
            required_fields = ', '.join(input_specification)
            raise click.BadArgumentUsage(
                f'{required_fields} are required flags to retrieve')

        bob_request_data = {
            'label': label,
            'policy_encrypting_key': policy_encrypting_key,
            'alice_verifying_key': alice_verifying_key,
            'message_kit': message_kit,
        }

        response = BOB.controller.retrieve(request=bob_request_data)
        return response

    elif action == "destroy":
        """Delete Bob's character configuration files from the disk"""
        if dev:
            message = "'nucypher ursula destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)
        return actions.destroy_configuration(character_config=bob_config)

    else:
        raise click.BadArgumentUsage(f"No such argument {action}")
Beispiel #3
0
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig):
    """
    Upgrade NuCypher existing proxy contract deployments.
    """
    # Init
    emitter = general_config.emitter
    ADMINISTRATOR, _, _, registry = actor_options.create_actor(emitter)

    contract_name = actor_options.contract_name
    if not contract_name:
        raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade")

    existing_secret = click.prompt('Enter existing contract upgrade secret', hide_input=True)
    new_secret = click.prompt('Enter new contract upgrade secret', hide_input=True, confirmation_prompt=True)

    if multisig:
        if not target_address:
            raise click.BadArgumentUsage(message="--multisig requires using --target-address.")
        if not actor_options.force:
            click.confirm(f"Confirm building a re-target transaction for {contract_name}'s proxy to {target_address}?",
                          abort=True)
        transaction = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,
                                                   target_address=target_address,
                                                   existing_plaintext_secret=existing_secret,
                                                   new_plaintext_secret=new_secret,
                                                   just_build_transaction=True)

        trustee = Trustee(registry=registry, checksum_address=ADMINISTRATOR.deployer_address)
        data_for_multisig_executives = trustee.produce_data_to_sign(transaction)

        emitter.message(f"Transaction to retarget {contract_name} proxy to {target_address} was built:", color='green')
        paint_multisig_proposed_transaction(emitter, data_for_multisig_executives)

        # TODO: Move this logic to a better place
        nonce = data_for_multisig_executives['parameters']['nonce']
        filepath = f'proposal-{nonce}.json'
        with open(filepath, 'w') as outfile:
            json.dump(data_for_multisig_executives, outfile)
        emitter.echo(f"Saved proposal to {filepath}", color='blue', bold=True)

    elif retarget:
        if not target_address:
            raise click.BadArgumentUsage(message="--target-address is required when using --retarget")
        if not actor_options.force:
            click.confirm(f"Confirm re-target {contract_name}'s proxy to {target_address}?", abort=True)
        receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,
                                               target_address=target_address,
                                               existing_plaintext_secret=existing_secret,
                                               new_plaintext_secret=new_secret)
        emitter.message(f"Successfully re-targeted {contract_name} proxy to {target_address}", color='green')
        paint_receipt_summary(emitter=emitter, receipt=receipt)
    else:
        if not actor_options.force:
            click.confirm(f"Confirm deploy new version of {contract_name} and retarget proxy?", abort=True)
        receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name,
                                                  existing_plaintext_secret=existing_secret,
                                                  new_plaintext_secret=new_secret,
                                                  ignore_deployed=ignore_deployed)
        emitter.message(f"Successfully deployed and upgraded {contract_name}", color='green')
        for name, receipt in receipts.items():
            paint_receipt_summary(emitter=emitter, receipt=receipt)
Beispiel #4
0
def gpu_use_view_command(node, user, lab, dense, only_errors, display_time,
                         display_load):
    r"""Display real-time information about the GPUs on skynet

There are two blocks per GPU, the left block indicates whether or not the GPU is
alloced and the right block indicates whether or not something is running on it.
Red means there is some error (idle reservation or process running out of SLURM)
and pink/magenta means idle reservation but in the debug partition.


Notes:

    - When using gpu-use with `watch`, add `--color` for the output to be displayed
correctly, i.e. use `watch --color gpu-use -d`.
    """
    if dense and only_errors:
        dense = False

    node_re = re.compile(node) if node is not None else None
    user_re = re.compile(user) if user is not None else None

    session = SessionMaker()

    nodes = session.query(Node)
    users = None
    if node_re is not None:
        node_names = [
            name[0] for name in session.query(Node.name).all()
            if node_re.match(name[0]) is not None
        ]
        if len(node_names) == 0:
            raise click.BadArgumentUsage("No nodes matched {}".format(node))

        node_filter = Node.name.in_(node_names)
        nodes = nodes.filter(Node.name.in_(node_names))

    if lab is not None:
        labs = filter_labs(session, lab)

        user_names = list(set(user.name for lab in labs for user in lab.users))
        users = session.query(User).filter(User.name.in_(user_names))
        nodes = nodes.filter(Node.users.any(User.name.in_(user_names)))

    if user_re is not None:
        user_names = [
            name[0] for name in session.query(User.name).all()
            if user_re.match(name[0]) is not None
        ]

        if len(user_names) == 0:
            raise click.BadArgumentUsage("No users matched {}".format(user))

        users = (session.query(User) if users is None else users).filter(
            User.name.in_(user_names))
        nodes = nodes.filter(Node.users.any(User.name.in_(user_names)))

    nodes = (nodes.order_by(Node.name).options(
        sa.orm.joinedload(Node.gpus),
        sa.orm.joinedload(Node.slurm_jobs),
        sa.orm.joinedload(Node.gpus).joinedload("processes"),
        sa.orm.joinedload(Node.slurm_jobs).joinedload("processes"),
    ).all())

    if users is not None:
        users = users.all()

    if not supports_unicode():
        click.echo(
            "Terminal does not support unicode, do `export LANG=en_US.UTF-8` for a better experience (may also need to start tmux with `-u`)"
        )

    nodes = sorted(nodes, key=lambda n: len(n.gpus))

    if not only_errors and dense is None:
        if len(nodes) > 4:
            dense = True

    if only_errors:
        show_errors(nodes, users)
    elif dense:
        show_dense(nodes, users, display_time, display_load)
    else:
        show_regular(nodes, users, display_time, display_load)
Beispiel #5
0
def register_key(key_name: str, experimental_login: bool) -> None:
    """Register a key with the store to sign assertions."""
    if experimental_login:
        raise click.BadArgumentUsage(
            f"Set {storeapi.constants.ENVIRONMENT_STORE_AUTH}=candid instead")
    snapcraft_legacy.register_key(key_name)
Beispiel #6
0
def cmd(
    ctx,
    name: Optional[str],
    version: Optional[str],
    idn: Optional[str],
    *,
    overrides: Optional[str],
    remove: bool,
    yes: bool,
    no_iam: bool,
    no_noop: bool,
):
    """Update the infrastructure."""
    s3_bucket, s3_prefix = ctx.obj["s3_bucket"], ctx.obj["s3_prefix"]
    if remove:
        if name and version and idn or name and version:
            extra = [a for a in [version, idn] if a]
            raise click.BadArgumentUsage(
                f"Got unexpected extra arguments ({', '.join(extra)})")
        idn, name = name, None
        if not idn:
            raise click.MissingParameter(param_hint='"name"',
                                         param_type="argument")
        stk = stack.Stack(idn)
        if not stk.exists:
            raise cli_util.UserError(f"brick does not exist: {idn}")
        tree = _merge(stk.tree)
        state = {"root": stack.State(["DELETE"])}
        for node in tree.all_nodes_itr():
            if "type" in node.data:
                state[node.identifier] = stack.State(["DELETE"])

        def states_itr() -> Iterator[Dict[str, stack.State]]:
            stk.delete(False)
            yield from stk.events(state, False)

        _display(tree, states_itr(), state, yes)
        return
    node, _idn = load.execute(idn, name, version, overrides, s3_bucket,
                              s3_prefix)
    tpl = encode.Template(node)
    body = tpl.dumps()
    tplb = body.encode("utf-8")
    artifacts: List[Tuple[Union[pathlib.Path, IO[bytes]],
                          aws_util.AssetInfo]] = []
    if len(tplb) > 51_000:  # pragma: no cover
        info = aws_util.asset_info(io.BytesIO(tplb))
        body = info.url
        artifacts.append((io.BytesIO(tplb), info))
    # pylint: disable=protected-access
    artifacts += [(a._path, cast(aws_util.AssetInfo, a))
                  for a in config.ASSETS.get()]
    util.upload(artifacts)
    stk = stack.Stack(_idn)
    tree = _merge(stk.tree if stk.exists else {}, tpl.tree)
    with stk.plan(body, tpl.params, not no_iam) as plan:
        states = iter(plan)
        try:
            state = next(states)
        except StopIteration:
            msg = f"{_idn} is already up to date"
            if no_noop:
                raise cli_util.UserError(msg)
            LOGGER.info(msg)
            return
        _display(tree, states, state, yes)
    click.secho("\nInstance value\n", fg="magenta")
    value = json.dumps(stack.Stack(_idn).value,
                       indent=2,
                       separators=(", ", ": "))
    if sys.stdout.isatty():  # pragma: no cover
        # pylint: disable=no-member
        # PyCQA/pylint#491
        value = highlight(value, lexers.JsonLexer(),
                          formatters.TerminalFormatter())
    click.echo(value, nl=not sys.stdout.isatty())
def rpg(pass_length: int, number: int, output: click.File,
        exclude_charsets: str, no_safe: bool, verbose: bool) -> None:
    """
    Generate random, entropic, complex and safe password.
    \f

    :param int pass_length: desire password length
    :param int number: number of password to generate. Default is 1
    :param click.File output: output file
    :param str exclude_charsets: comma-separated charsets to exclude. Default is None
    :param bool no_safe: do not check password in Have I Been Pwned db. Default is False
    :param bool verbose: print verbose output. Default is False
    :return: None
    """
    # Check pass_length validity
    msg.Prints.verbose(f"Checking <pass-length> ({pass_length}) validity",
                       verbose)
    if pass_length > _max_pass_length or pass_length < _min_pass_length:
        raise click.BadArgumentUsage(
            msg.Echoes.error((
                f"Invalid value for \"<pass-length>\": {pass_length} "
                f"is not in the valid range of {_min_pass_length} to {_max_pass_length}."
            )))

    # Check number validity
    msg.Prints.verbose(f"Checking <pass-number> ({number}) validity", verbose)
    if number > _max_pass_number:
        raise click.BadOptionUsage(
            "number",
            msg.Echoes.error(
                "Invalid value for \"<pass-number>\": the maximum value accepted is 50."
            ))

    # Load charsets and check the validity
    msg.Prints.verbose("Loading charsets", verbose)
    chars = _get_char_list(exclude_charsets)
    msg.Prints.verbose("Charsets loaded\nChecking charsets validity", verbose)

    # Check at least one charsets type has been selected
    if not chars:
        raise click.BadOptionUsage(
            "--exclude-charsets",
            msg.Echoes.error(
                "RPG needs at least one charsets type to generate password."))
    else:
        if not len(chars) == len(string.ascii_lowercase +
                                 string.ascii_uppercase + string.digits +
                                 string.punctuation):
            # User chose to not use any charsets, print warning message
            msg.Prints.warning(
                "You are going to generate passwords without one or more of default charsets!"
            )
            msg.Prints.warning(
                "RPG cares a lot for your security, it's recommended to avoid this practice if possible!\n"
            )

    # Check if --no-safe option is in use, if so, print a warning message
    if no_safe:
        msg.Prints.warning(
            "You are going to generate passwords without checking if they have been already leaked!"
        )
        msg.Prints.warning(
            "RPG cares a lot for your security, it's recommended to avoid this practice if possible!\n"
        )

    msg.Prints.verbose("Start to generate passwords", verbose)

    # Print loading
    pw_list = []
    with click.progressbar(length=number,
                           label="Generating passwords",
                           show_pos=True) as pw_bar:
        for _ in pw_bar:
            pw = _generate_random_password(pass_length, chars, no_safe)
            if pw is not None:
                pw_list.append(pw)
            else:
                raise click.ClickException(
                    msg.Echoes.error(
                        "An error occurred while querying Have I Been Pwned API. Please retry or use --no-safe option"
                    ))

    # Print generated passwords
    if output:
        output.write("Passwords:\n")
    else:
        msg.Prints.emphasis("Passwords:")

    for pw in pw_list:
        if output:
            output.write(f"{pw}\n")
        else:
            msg.Prints.info(pw)

    # Calculate entropy and print it
    entropy = _get_entropy(pass_length, chars)
    if output:
        output.write(f"\nEntropy: {entropy}")
    else:
        msg.Prints.emphasis(
            f"\nThe entropy of generated password is: {entropy}")

    # Print summary table, only if --verbose or --output
    if output:
        output.write(f"\n{_password_entropy_table}")
    else:
        msg.Prints.verbose(_password_entropy_table, verbose)
Beispiel #8
0
def felix(click_config, action, teacher_uri, min_stake, network, host, dry_run,
          port, discovery_port, provider_uri, config_root, checksum_address,
          poa, config_file, db_filepath, no_registry, registry_filepath,
          force):

    if not click_config.quiet:
        click.secho(FELIX_BANNER.format(checksum_address or ''))

    if action == "init":
        """Create a brand-new Felix"""

        # Validate "Init" Input
        if not network:
            raise click.BadArgumentUsage(
                '--network is required to initialize a new configuration.')

        # Validate "Init" Input
        if not checksum_address:
            raise click.BadArgumentUsage(
                '--checksum-address is required to initialize a new Felix configuration.'
            )

        # Acquire Keyring Password
        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar
        new_password = click_config.get_password(confirm=True)

        new_felix_config = FelixConfiguration.generate(
            password=new_password,
            config_root=config_root,
            rest_host=host,
            rest_port=discovery_port,
            db_filepath=db_filepath,
            domains={network} if network else None,
            checksum_public_address=checksum_address,
            no_registry=no_registry,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri,
            poa=poa)

        # Paint Help
        painting.paint_new_installation_help(
            new_configuration=new_felix_config,
            config_root=config_root,
            config_file=config_file)

        return  # <-- do not remove (conditional flow control)

    #
    # Authenticated Configurations
    #

    # Domains -> bytes | or default
    domains = [bytes(network, encoding='utf-8')] if network else None

    # Load Felix from Configuration File with overrides
    try:
        felix_config = FelixConfiguration.from_configuration_file(
            filepath=config_file,
            domains=domains,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri,
            rest_host=host,
            rest_port=port,
            db_filepath=db_filepath,
            poa=poa)
    except FileNotFoundError:
        click.secho(
            f"No Felix configuration file found at {config_file}. "
            f"Check the filepath or run 'nucypher felix init' to create a new system configuration."
        )
        raise click.Abort

    else:

        # Produce Teacher Ursulas
        teacher_uris = [teacher_uri] if teacher_uri else list()
        teacher_nodes = actions.load_seednodes(
            teacher_uris=teacher_uris,
            min_stake=min_stake,
            federated_only=False,
            network_middleware=click_config.middleware)

        # Produce Felix
        click_config.unlock_keyring(character_configuration=felix_config)
        FELIX = felix_config.produce(domains=network,
                                     known_nodes=teacher_nodes)
        FELIX.make_web_app()  # attach web application, but dont start service

    if action == "createdb":  # Initialize Database
        if os.path.isfile(FELIX.db_filepath):
            if not force:
                click.confirm("Overwrite existing database?", abort=True)
            os.remove(FELIX.db_filepath)
            click.secho(f"Destroyed existing database {FELIX.db_filepath}")

        FELIX.create_tables()
        click.secho(f"Created new database at {FELIX.db_filepath}")

    elif action == 'view':
        token_balance = FELIX.token_balance
        eth_balance = FELIX.eth_balance
        click.secho(f"""
Address .... {FELIX.checksum_public_address}
NU ......... {str(token_balance)}
ETH ........ {str(eth_balance)}
        """)
        return

    elif action == "accounts":
        accounts = FELIX.blockchain.interface.w3.eth.accounts
        for account in accounts:
            click.secho(account)
        return

    elif action == "destroy":
        """Delete all configuration files from the disk"""
        return actions.destroy_configuration(character_config=felix_config,
                                             force=force)

    elif action == 'run':  # Start web services
        FELIX.start(host=host,
                    port=port,
                    web_services=not dry_run,
                    distribution=True,
                    crash_on_error=click_config.debug)

    else:  # Error
        raise click.BadArgumentUsage("No such argument {}".format(action))
Beispiel #9
0
def upgrade(general_config, actor_options, retarget, target_address,
            ignore_deployed, confirmations):
    """Upgrade NuCypher existing proxy contract deployments."""

    #
    # Setup
    #

    emitter = general_config.emitter
    ADMINISTRATOR, deployer_address, blockchain, local_registry = actor_options.create_actor(
        emitter)

    #
    # Pre-flight
    #

    contract_name = actor_options.contract_name
    if not contract_name:
        raise click.BadArgumentUsage(
            message="--contract-name is required when using --upgrade")

    try:
        # Check contract name exists
        Deployer = ADMINISTRATOR.deployers[contract_name]
    except KeyError:
        message = UNKNOWN_CONTRACT_NAME.format(
            contract_name=contract_name,
            constants=ADMINISTRATOR.deployers.keys())
        emitter.echo(message, color='red', bold=True)
        raise click.Abort()
    deployer = Deployer(registry=local_registry)

    # Check deployer address is owner
    if Deployer._ownable and deployer_address != deployer.owner:  # blockchain read
        emitter.echo(
            DEPLOYER_IS_NOT_OWNER.format(deployer_address=deployer_address,
                                         contract_name=contract_name,
                                         agent=deployer.make_agent()))
        raise click.Abort()
    else:
        emitter.echo('✓ Verified deployer address as contract owner',
                     color='green')

    #
    # Business
    #

    if retarget:
        if not target_address:
            raise click.BadArgumentUsage(
                message="--target-address is required when using --retarget")
        if not actor_options.force:
            click.confirm(CONFIRM_RETARGET.format(
                contract_name=contract_name, target_address=target_address),
                          abort=True)
        receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,
                                               target_address=target_address,
                                               confirmations=confirmations)
        message = SUCCESSFUL_RETARGET.format(contract_name=contract_name,
                                             target_address=target_address)
        emitter.message(message, color='green')
        paint_receipt_summary(emitter=emitter, receipt=receipt)
        return  # Exit

    else:
        github_registry = establish_deployer_registry(
            emitter=emitter,
            download_registry=True,
            network=actor_options.network)
        if not actor_options.force:

            # Check for human verification of versioned upgrade details
            click.confirm(
                CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name),
                abort=True)
            if deployer._ownable:  # Only ownable + upgradeable contracts apply
                verify_upgrade_details(blockchain=blockchain,
                                       registry=github_registry,
                                       deployer=deployer)

        # Success
        receipts = ADMINISTRATOR.upgrade_contract(
            contract_name=contract_name,
            ignore_deployed=ignore_deployed,
            confirmations=confirmations)
        emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name),
                        color='green')

        for name, receipt in receipts.items():
            paint_receipt_summary(emitter=emitter, receipt=receipt)
        emitter.echo(REGISTRY_PUBLICATION_HINT.format(
            contract_name=contract_name,
            local_registry=local_registry,
            network=actor_options.network),
                     color='blue')
        emitter.echo(ETHERSCAN_VERIFY_HINT.format(
            solc_version=SOLIDITY_COMPILER_VERSION),
                     color='blue')
        return  # Exit
Beispiel #10
0
def stake(click_config,
          action,
          checksum_address,
          index,
          value,
          duration):
    """
    Manage token staking.  TODO

    \b
    Actions
    -------------------------------------------------
    \b
    list              List all stakes for this node.
    init              Stage a new stake.
    confirm-activity  Manually confirm-activity for the current period.
    divide            Divide an existing stake.
    collect-reward    Withdraw staking reward.

    """
    ursula_config = click_config.ursula_config

    #
    # Initialize
    #
    if not ursula_config.federated_only:
        ursula_config.connect_to_blockchain(click_config)
        ursula_config.connect_to_contracts(click_config)

    if not checksum_address:

        if click_config.accounts == NO_BLOCKCHAIN_CONNECTION:
            click.echo('No account found.')
            raise click.Abort()

        for index, address in enumerate(click_config.accounts):
            if index == 0:
                row = 'etherbase (0) | {}'.format(address)
            else:
                row = '{} .......... | {}'.format(index, address)
            click.echo(row)

        click.echo("Select ethereum address")
        account_selection = click.prompt("Enter 0-{}".format(len(ur.accounts)), type=click.INT)
        address = click_config.accounts[account_selection]

    if action == 'list':
        live_stakes = ursula_config.miner_agent.get_all_stakes(miner_address=checksum_address)
        for index, stake_info in enumerate(live_stakes):
            row = '{} | {}'.format(index, stake_info)
            click.echo(row)

    elif action == 'init':
        click.confirm("Stage a new stake?", abort=True)

        live_stakes = ursula_config.miner_agent.get_all_stakes(miner_address=checksum_address)
        if len(live_stakes) > 0:
            raise RuntimeError("There is an existing stake for {}".format(checksum_address))

        # Value
        balance = ursula_config.miner_agent.token_agent.get_balance(address=checksum_address)
        click.echo("Current balance: {}".format(balance))
        value = click.prompt("Enter stake value", type=click.INT)

        # Duration
        message = "Minimum duration: {} | Maximum Duration: {}".format(MIN_LOCKED_PERIODS, MAX_MINTING_PERIODS)
        click.echo(message)
        duration = click.prompt("Enter stake duration in periods (1 Period = 24 Hours)", type=click.INT)

        start_period = ursula_config.miner_agent.get_current_period()
        end_period = start_period + duration

        # Review
        click.echo("""

        | Staged Stake |

        Node: {address}
        Value: {value}
        Duration: {duration}
        Start Period: {start_period}
        End Period: {end_period}

        """.format(address=checksum_address,
                   value=value,
                   duration=duration,
                   start_period=start_period,
                   end_period=end_period))

        raise NotImplementedError

    elif action == 'confirm-activity':
        """Manually confirm activity for the active period"""
        stakes = ursula_config.miner_agent.get_all_stakes(miner_address=checksum_address)
        if len(stakes) == 0:
            raise RuntimeError("There are no active stakes for {}".format(checksum_address))
        ursula_config.miner_agent.confirm_activity(node_address=checksum_address)

    elif action == 'divide':
        """Divide an existing stake by specifying the new target value and end period"""

        stakes = ursula_config.miner_agent.get_all_stakes(miner_address=checksum_address)
        if len(stakes) == 0:
            raise RuntimeError("There are no active stakes for {}".format(checksum_address))

        if not index:
            for selection_index, stake_info in enumerate(stakes):
                click.echo("{} ....... {}".format(selection_index, stake_info))
            index = click.prompt("Select a stake to divide", type=click.INT)

        target_value = click.prompt("Enter new target value", type=click.INT)
        extension = click.prompt("Enter number of periods to extend", type=click.INT)

        click.echo("""
        Current Stake: {}

        New target value {}
        New end period: {}

        """.format(stakes[index],
                   target_value,
                   target_value + extension))

        click.confirm("Is this correct?", abort=True)
        ursula_config.miner_agent.divide_stake(miner_address=checksum_address,
                                               stake_index=index,
                                               value=value,
                                               periods=extension)

    elif action == 'collect-reward':          # TODO: Implement
        """Withdraw staking reward to the specified wallet address"""
        # click.confirm("Send {} to {}?".format)
        # ursula_config.miner_agent.collect_staking_reward(collector_address=address)
        raise NotImplementedError

    else:
        raise click.BadArgumentUsage("No such argument {}".format(action))
Beispiel #11
0
def ursula(click_config,
           action,
           debug,
           dev,
           quiet,
           dry_run,
           force,
           lonely,
           network,
           teacher_uri,
           min_stake,
           rest_host,
           rest_port,
           db_filepath,
           checksum_address,
           federated_only,
           poa,
           config_root,
           config_file,
           metadata_dir,  # TODO: Start nodes from an additional existing metadata dir
           provider_uri,
           no_registry,
           registry_filepath
           ) -> None:
    """
    Manage and run an Ursula node.

    \b
    Actions
    -------------------------------------------------
    \b
    run            Run an "Ursula" node.
    init           Create a new Ursula node configuration.
    view           View the Ursula node's configuration.
    forget         Forget all known nodes.
    save-metadata  Manually write node metadata to disk without running
    destroy        Delete Ursula node configuration.

    """

    #
    # Boring Setup Stuff
    #
    if not quiet:
        log = Logger('ursula.cli')

    if debug and quiet:
        raise click.BadOptionUsage(option_name="quiet", message="--debug and --quiet cannot be used at the same time.")

    if debug:
        click_config.log_to_sentry = False
        click_config.log_to_file = True
        globalLogPublisher.removeObserver(logToSentry)                          # Sentry
        globalLogPublisher.addObserver(SimpleObserver(log_level_name='debug'))  # Print

    elif quiet:
        globalLogPublisher.removeObserver(logToSentry)
        globalLogPublisher.removeObserver(SimpleObserver)
        globalLogPublisher.removeObserver(getJsonFileObserver())

    #
    # Pre-Launch Warnings
    #
    if not quiet:
        if dev:
            click.secho("WARNING: Running in development mode", fg='yellow')
        if force:
            click.secho("WARNING: Force is enabled", fg='yellow')

    #
    # Unauthenticated Configurations
    #
    if action == "init":
        """Create a brand-new persistent Ursula"""

        if dev and not quiet:
            click.secho("WARNING: Using temporary storage area", fg='yellow')

        if not config_root:                         # Flag
            config_root = click_config.config_file  # Envvar

        if not rest_host:
            rest_host = click.prompt("Enter Ursula's public-facing IPv4 address")

        ursula_config = UrsulaConfiguration.generate(password=click_config.get_password(confirm=True),
                                                     config_root=config_root,
                                                     rest_host=rest_host,
                                                     rest_port=rest_port,
                                                     db_filepath=db_filepath,
                                                     domains={network} if network else None,
                                                     federated_only=federated_only,
                                                     checksum_public_address=checksum_address,
                                                     no_registry=federated_only or no_registry,
                                                     registry_filepath=registry_filepath,
                                                     provider_uri=provider_uri,
                                                     poa=poa)

        if not quiet:
            click.secho("Generated keyring {}".format(ursula_config.keyring_dir), fg='green')
            click.secho("Saved configuration file {}".format(ursula_config.config_file_location), fg='green')

            # Give the use a suggestion as to what to do next...
            how_to_run_message = "\nTo run an Ursula node from the default configuration filepath run: \n\n'{}'\n"
            suggested_command = 'nucypher ursula run'
            if config_root is not None:
                config_file_location = os.path.join(config_root, config_file or UrsulaConfiguration.CONFIG_FILENAME)
                suggested_command += ' --config-file {}'.format(config_file_location)
            click.secho(how_to_run_message.format(suggested_command), fg='green')
            return  # FIN

        else:
            click.secho("OK")

    elif action == "destroy":
        """Delete all configuration files from the disk"""

        if dev:
            message = "'nucypher ursula destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)

        try:
            ursula_config = UrsulaConfiguration.from_configuration_file(filepath=config_file, domains={network})

        except FileNotFoundError:
            config_root = config_root or DEFAULT_CONFIG_ROOT
            config_file_location = config_file or UrsulaConfiguration.DEFAULT_CONFIG_FILE_LOCATION

            if not force:
                message = "No configuration file found at {}; \n" \
                          "Destroy top-level configuration directory: {}?".format(config_file_location, config_root)
                click.confirm(message, abort=True)  # ABORT

            shutil.rmtree(config_root, ignore_errors=False)

        else:
            if not force:
                click.confirm('''
*Permanently and irreversibly delete all* nucypher files including
    - Private and Public Keys
    - Known Nodes
    - TLS certificates
    - Node Configurations
    - Log Files

Delete {}?'''.format(ursula_config.config_root), abort=True)

            try:
                ursula_config.destroy(force=force)
            except FileNotFoundError:
                message = 'Failed: No nucypher files found at {}'.format(ursula_config.config_root)
                click.secho(message, fg='red')
                log.debug(message)
                raise click.Abort()
            else:
                message = "Deleted configuration files at {}".format(ursula_config.config_root)
                click.secho(message, fg='green')
                log.debug(message)

        if not quiet:
            click.secho("Destroyed {}".format(config_root))

        return

    # Development Configuration
    if dev:
        ursula_config = UrsulaConfiguration(dev_mode=True,
                                            domains={TEMPORARY_DOMAIN},
                                            poa=poa,
                                            registry_filepath=registry_filepath,
                                            provider_uri=provider_uri,
                                            checksum_public_address=checksum_address,
                                            federated_only=federated_only,
                                            rest_host=rest_host,
                                            rest_port=rest_port,
                                            db_filepath=db_filepath)
    # Authenticated Configurations
    else:

        # Deserialize network domain name if override passed
        if network:
            domain_constant = getattr(constants, network.upper())
            domains = {domain_constant}
        else:
            domains = None

        ursula_config = UrsulaConfiguration.from_configuration_file(filepath=config_file,
                                                                    domains=domains,
                                                                    registry_filepath=registry_filepath,
                                                                    provider_uri=provider_uri,
                                                                    rest_host=rest_host,
                                                                    rest_port=rest_port,
                                                                    db_filepath=db_filepath,

                                                                    # TODO: Handle Boolean overrides
                                                                    # poa=poa,
                                                                    # federated_only=federated_only,
                                                                    )

        try:  # Unlock Keyring
            if not quiet:
                click.secho('Decrypting keyring...', fg='blue')
            ursula_config.keyring.unlock(password=click_config.get_password())  # Takes ~3 seconds, ~1GB Ram
        except CryptoError:
            raise ursula_config.keyring.AuthenticationFailed

    if not ursula_config.federated_only:
        try:
            ursula_config.connect_to_blockchain(recompile_contracts=False)
            ursula_config.connect_to_contracts()
        except EthereumContractRegistry.NoRegistry:
            message = "Cannot configure blockchain character: No contract registry found; " \
                      "Did you mean to pass --federated-only?"
            raise EthereumContractRegistry.NoRegistry(message)

    click_config.ursula_config = ursula_config  # Pass Ursula's config onto staking sub-command


    #
    # Launch Warnings
    #
    if not quiet:
        if ursula_config.federated_only:
            click.secho("WARNING: Running in Federated mode", fg='yellow')

    #
    # Action Switch
    #
    if action == 'run':
        """Seed, Produce, Run!"""

        #
        # Seed - Step 1
        #
        teacher_nodes = list()
        if teacher_uri:
            node = Ursula.from_teacher_uri(teacher_uri=teacher_uri,
                                           min_stake=min_stake,
                                           federated_only=ursula_config.federated_only)
            teacher_nodes.append(node)

        #
        # Produce - Step 2
        #
        ursula = ursula_config(known_nodes=teacher_nodes, lonely=lonely)

        # GO!
        try:

            #
            # Run - Step 3
            #
            click.secho("Connecting to {}".format(','.join(str(d) for d in ursula_config.domains)), fg='blue', bold=True)
            click.secho("Running Ursula {} on {}".format(ursula, ursula.rest_interface), fg='green', bold=True)
            if not debug:
                stdio.StandardIO(UrsulaCommandProtocol(ursula=ursula))

            if dry_run:
                # That's all folks!
                return

            ursula.get_deployer().run()  # <--- Blocking Call (Reactor)

        except Exception as e:
            ursula_config.log.critical(str(e))
            click.secho("{} {}".format(e.__class__.__name__, str(e)), fg='red')
            raise  # Crash :-(

        finally:
            if not quiet:
                click.secho("Stopping Ursula")
            ursula_config.cleanup()
            if not quiet:
                click.secho("Ursula Stopped", fg='red')

        return

    elif action == "save-metadata":
        """Manually save a node self-metadata file"""

        ursula = ursula_config.produce(ursula_config=ursula_config)
        metadata_path = ursula.write_node_metadata(node=ursula)
        if not quiet:
            click.secho("Successfully saved node metadata to {}.".format(metadata_path), fg='green')
        return

    elif action == "view":
        """Paint an existing configuration to the console"""
        paint_configuration(config_filepath=config_file or ursula_config.config_file_location)
        return

    elif action == "forget":
        """Forget all known nodes via storages"""
        click.confirm("Permanently delete all known node data?", abort=True)
        ursula_config.forget_nodes()
        message = "Removed all stored node node metadata and certificates"
        click.secho(message=message, fg='red')
        return

    else:
        raise click.BadArgumentUsage("No such argument {}".format(action))
Beispiel #12
0
def _get_indicator(indname):
    try:
        return xc.core.indicator.registry[indname.upper()].get_instance()
    except KeyError:
        raise click.BadArgumentUsage(
            f"Indicator '{indname}' not found in xclim.")
Beispiel #13
0
def alice(
    click_config,
    action,

    # Mode
    dev,
    force,
    dry_run,

    # Network
    teacher_uri,
    min_stake,
    federated_only,
    network,
    discovery_port,
    controller_port,

    # Filesystem
    config_root,
    config_file,

    # Blockchain
    pay_with,
    provider_uri,
    geth,
    sync,
    poa,
    no_registry,
    registry_filepath,
    device,

    # Alice
    bob_encrypting_key,
    bob_verifying_key,
    label,
    m,
    n,
    value,
    rate,
    duration,
    expiration,
    message_kit,
):

    #
    # Validate
    #

    if federated_only and geth:
        raise click.BadOptionUsage(
            option_name="--geth",
            message="Federated only cannot be used with the --geth flag")

    # Banner
    click.clear()
    if not click_config.json_ipc and not click_config.quiet:
        click.secho(ALICE_BANNER)

    #
    # Managed Ethereum Client
    #

    ETH_NODE = NO_BLOCKCHAIN_CONNECTION
    if geth:
        ETH_NODE = actions.get_provider_process()
        provider_uri = ETH_NODE.provider_uri(scheme='file')

    #
    # Eager Actions (No Authentication Required)
    #

    if action == 'init':
        """Create a brand-new persistent Alice"""

        if dev:
            raise click.BadArgumentUsage(
                "Cannot create a persistent development character")

        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar

        new_alice_config = AliceConfiguration.generate(
            password=get_password(confirm=True),
            config_root=config_root,
            checksum_address=pay_with,
            domains={network} if network else None,
            federated_only=federated_only,
            download_registry=no_registry,
            registry_filepath=registry_filepath,
            provider_process=ETH_NODE,
            poa=poa,
            provider_uri=provider_uri,
            m=m,
            n=n,
            duration=duration,
            rate=rate)

        painting.paint_new_installation_help(
            new_configuration=new_alice_config)
        return  # Exit

    elif action == "view":
        """Paint an existing configuration to the console"""
        configuration_file_location = config_file or AliceConfiguration.default_filepath(
        )
        response = AliceConfiguration._read_configuration_file(
            filepath=configuration_file_location)
        click_config.emit(response)
        return  # Exit

    #
    # Make Alice
    #

    if dev:
        alice_config = AliceConfiguration(
            dev_mode=True,
            network_middleware=click_config.middleware,
            domains={network},
            provider_process=ETH_NODE,
            provider_uri=provider_uri,
            federated_only=True)

    else:
        try:
            alice_config = AliceConfiguration.from_configuration_file(
                dev_mode=False,
                filepath=config_file,
                domains={network} if network else None,
                network_middleware=click_config.middleware,
                rest_port=discovery_port,
                checksum_address=pay_with,
                provider_process=ETH_NODE,
                provider_uri=provider_uri)
        except FileNotFoundError:
            return actions.handle_missing_configuration_file(
                character_config_class=AliceConfiguration,
                config_file=config_file)

    ALICE = actions.make_cli_character(character_config=alice_config,
                                       click_config=click_config,
                                       dev=dev,
                                       teacher_uri=teacher_uri,
                                       min_stake=min_stake)

    #
    # Admin Actions
    #

    if action == "run":
        """Start Alice Controller"""

        # RPC
        if click_config.json_ipc:
            rpc_controller = ALICE.make_rpc_controller()
            _transport = rpc_controller.make_control_transport()
            rpc_controller.start()
            return

        # HTTP
        else:
            ALICE.controller.emitter(
                message=f"Alice Verifying Key {bytes(ALICE.stamp).hex()}",
                color="green",
                bold=True)
            controller = ALICE.make_web_controller(
                crash_on_error=click_config.debug)
            ALICE.log.info('Starting HTTP Character Web Controller')
            return controller.start(http_port=controller_port, dry_run=dry_run)

    elif action == "destroy":
        """Delete all configuration files from the disk"""
        if dev:
            message = "'nucypher alice destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)
        return actions.destroy_configuration(character_config=alice_config,
                                             force=force)

    #
    # Alice API
    #

    elif action == "public-keys":
        response = ALICE.controller.public_keys()
        return response

    elif action == "derive-policy-pubkey":

        # Validate
        if not label:
            raise click.BadOptionUsage(
                option_name='label',
                message=
                "--label is required for deriving a policy encrypting key.")

        # Request
        return ALICE.controller.derive_policy_encrypting_key(label=label)

    elif action == "grant":

        # Validate
        if not all((bob_verifying_key, bob_encrypting_key, label)):
            raise click.BadArgumentUsage(
                message=
                "--bob-verifying-key, --bob-encrypting-key, and --label are "
                "required options to grant (optionally --m, --n, and --expiration)."
            )

        # Request
        grant_request = {
            'bob_encrypting_key': bob_encrypting_key,
            'bob_verifying_key': bob_verifying_key,
            'label': label,
            'm': m,
            'n': n,
            'expiration': expiration,
        }

        if not ALICE.federated_only:
            grant_request.update({'value': value})

        return ALICE.controller.grant(request=grant_request)

    elif action == "revoke":

        # Validate
        if not label and bob_verifying_key:
            raise click.BadArgumentUsage(
                message=
                f"--label and --bob-verifying-key are required options for revoke."
            )

        # Request
        revoke_request = {
            'label': label,
            'bob_verifying_key': bob_verifying_key
        }
        return ALICE.controller.revoke(request=revoke_request)

    elif action == "decrypt":

        # Validate
        if not all((label, message_kit)):
            input_specification, output_specification = ALICE.controller.get_specifications(
                interface_name=action)
            required_fields = ', '.join(input_specification)
            raise click.BadArgumentUsage(
                f'{required_fields} are required flags to decrypt')

        # Request
        request_data = {'label': label, 'message_kit': message_kit}
        response = ALICE.controller.decrypt(request=request_data)
        return response

    else:
        raise click.BadArgumentUsage(f"No such argument {action}")
Beispiel #14
0
def _bkt_info(
    repo: Repo,
    task: Task,
    geometry: Polygon,
    bucket_name: str,
    sort: tuple,
    limit: int,
    column: tuple,
    where: str,
    check=False,
) -> (GeoDataFrame, list):
    if geometry.area == 0:
        raise click.BadArgumentUsage('ROI has zero area')
    cache_file_name = _cache_pairs_file_name(repo)
    # TODO check ROI exists

    _df = pairs.load_from_cache(cache_file_name=cache_file_name,
                                geometry=geometry)

    _bk = bucket.create_list(_df, buckets_dir='')

    if _bk is None or _bk.empty:
        raise AssertionError(f'No products could be found for ROI ')
    if bucket_name.isnumeric():
        _t = _bk.groupby('bucket', as_index=False).ngroup()
        _df = _bk[_t == int(bucket_name)]
    else:
        _df = _bk[_bk['bucket'] == bucket_name]
    _f = list(column)
    _ds = _list_products(_df, where=where, sort=list(sort), limit=limit)
    _m, _s = _task_ms(task)
    # log.error(f"{_m} {_s}")
    if task.loaded:
        if _m or _s:

            def _ms(b):
                _x = 'm' if _m == b else ' '
                _x += 's' if _s == b else ' '
                return _x

            _ds['task'] = _ds['title'].apply(_ms)
            _f += ['task']
        _e, eodata = task.get_valid_key('eodata')

        # TODO other formats parsers: Sentinel-1.ZIP ,TOPSAR
        def _ch_fs(b):
            _p = _local_eodata_relative_path(eodata, b)
            if os.path.isfile(os.path.join(_p, 'manifest.safe')):
                _m = os.path.join(_p, 'measurement')
                if os.path.isdir(_m):
                    return '+' if any(os.scandir(_m)) else '~'
            return ''

        if check and not _e:
            _ds['exists'] = _ds['productIdentifier'].apply(_ch_fs)
            _f += ['exists']
            pass

        # _ds = _ds.reindex(['task', *_f], axis=1, copy=False)
        # output.comment(f"Task '{_tname}' applied\n\n")
        headers = ['#', 'task', *_f]
    if _df.empty:
        raise OCLIException(f"bucket {bucket_name} not found")
    bname = _df.iloc[0]['bucket']
    _ds = _ds[_f]
    # remove injected title if not in columns
    return bname, _ds, _ds.columns.to_list()
Beispiel #15
0
def do_update(
        project: Project,
        dev: bool = False,
        sections: Sequence[str] = (),
        default: bool = True,
        strategy: str = "reuse",
        save: str = "compatible",
        unconstrained: bool = False,
        packages: Sequence[str] = (),
) -> None:
    """Update specified packages or all packages

    :param project: The project instance
    :param dev: whether to update dev dependencies
    :param sections: update speicified sections
    :param default: update default
    :param strategy: update strategy (reuse/eager)
    :param save: save strategy (compatible/exact/wildcard)
    :param unconstrained: ignore version constraint
    :param packages: specified packages to update
    :return: None
    """
    check_project_file(project)
    if len(packages) > 0 and (len(sections) > 1 or not default):
        raise click.BadParameter(
            "packages argument can't be used together with multple -s or --no-default."
        )
    if not packages:
        if unconstrained:
            raise click.BadArgumentUsage(
                "--unconstrained must be used with package names given.")
        # pdm update with no packages given, same as 'lock' + 'sync'
        do_lock(project)
        do_sync(project, sections, dev, default, clean=False)
        return
    section = sections[0] if sections else ("dev" if dev else "default")
    all_dependencies = project.all_dependencies
    dependencies = all_dependencies[section]
    updated_deps = {}
    tracked_names = set()
    for name in packages:
        matched_name = next(
            filter(
                lambda k: safe_name(strip_extras(k)[0]).lower() == safe_name(
                    name).lower(),
                dependencies.keys(),
            ),
            None,
        )
        if not matched_name:
            raise ProjectError("{} does not exist in {} dependencies.".format(
                context.io.green(name, bold=True), section))
        if unconstrained:
            dependencies[matched_name].specifier = get_specifier("")
        tracked_names.add(matched_name)
        updated_deps[matched_name] = dependencies[matched_name]
    context.io.echo("Updating packages: {}.".format(", ".join(
        context.io.green(v, bold=True) for v in tracked_names)))
    resolved = do_lock(project, strategy, tracked_names, all_dependencies)
    do_sync(project, sections=(section, ), default=False, clean=False)
    if unconstrained:
        # Need to update version constraints
        save_version_specifiers(updated_deps, resolved, save)
        project.add_dependencies(updated_deps)
        lockfile = project.lockfile
        lockfile["root"]["content_hash"] = "md5:" + project.get_content_hash(
            "md5")
        project.write_lockfile(lockfile, False)
Beispiel #16
0
def ursula(click_config, action, dev, quiet, dry_run, force, lonely, network,
           teacher_uri, min_stake, rest_host, rest_port, db_filepath,
           checksum_address, withdraw_address, federated_only, poa,
           config_root, config_file, provider_uri, recompile_solidity,
           no_registry, registry_filepath, value, duration, index, list_,
           divide) -> None:
    """
    Manage and run an "Ursula" PRE node.

    \b
    Actions
    -------------------------------------------------
    \b
    init              Create a new Ursula node configuration.
    view              View the Ursula node's configuration.
    run               Run an "Ursula" node.
    save-metadata     Manually write node metadata to disk without running
    forget            Forget all known nodes.
    destroy           Delete Ursula node configuration.
    stake             Manage stakes for this node.
    confirm-activity  Manually confirm-activity for the current period.
    collect-reward    Withdraw staking reward.

    """

    #
    # Boring Setup Stuff
    #
    if not quiet:
        log = Logger('ursula.cli')

    if click_config.debug and quiet:
        raise click.BadOptionUsage(
            option_name="quiet",
            message="--debug and --quiet cannot be used at the same time.")

    if not click_config.json_ipc and not click_config.quiet:
        click.secho(URSULA_BANNER.format(checksum_address or ''))

    #
    # Pre-Launch Warnings
    #
    if not click_config.quiet:
        if dev:
            click.secho("WARNING: Running in Development mode", fg='yellow')
        if force:
            click.secho("WARNING: Force is enabled", fg='yellow')

    #
    # Unauthenticated Configurations & Un-configured Ursula Control
    #
    if action == "init":
        """Create a brand-new persistent Ursula"""

        if not network:
            raise click.BadArgumentUsage(
                '--network is required to initialize a new configuration.')

        if dev:
            click_config.emitter(
                message="WARNING: Using temporary storage area",
                color='yellow')

        if not config_root:  # Flag
            config_root = click_config.config_file  # Envvar

        if not rest_host:
            rest_host = click.prompt(
                "Enter Ursula's public-facing IPv4 address"
            )  # TODO: Remove this step

        ursula_config = UrsulaConfiguration.generate(
            password=click_config.get_password(confirm=True),
            config_root=config_root,
            rest_host=rest_host,
            rest_port=rest_port,
            db_filepath=db_filepath,
            domains={network} if network else None,
            federated_only=federated_only,
            checksum_public_address=checksum_address,
            no_registry=federated_only or no_registry,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri,
            poa=poa)

        painting.paint_new_installation_help(new_configuration=ursula_config,
                                             config_root=config_root,
                                             config_file=config_file,
                                             federated_only=federated_only)
        return

    #
    # Configured Ursulas
    #

    # Development Configuration
    if dev:
        ursula_config = UrsulaConfiguration(
            dev_mode=True,
            domains={TEMPORARY_DOMAIN},
            poa=poa,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri,
            checksum_public_address=checksum_address,
            federated_only=federated_only,
            rest_host=rest_host,
            rest_port=rest_port,
            db_filepath=db_filepath)
    # Authenticated Configurations
    else:

        # Domains -> bytes | or default
        domains = [bytes(network, encoding='utf-8')] if network else None

        # Load Ursula from Configuration File
        ursula_config = UrsulaConfiguration.from_configuration_file(
            filepath=config_file,
            domains=domains,
            registry_filepath=registry_filepath,
            provider_uri=provider_uri,
            rest_host=rest_host,
            rest_port=rest_port,
            db_filepath=db_filepath,
            poa=poa)

        click_config.unlock_keyring(character_configuration=ursula_config)

    #
    # Connect to Blockchain (Non-Federated)
    #

    if not ursula_config.federated_only:
        click_config.connect_to_blockchain(
            character_configuration=ursula_config,
            recompile_contracts=recompile_solidity)

    click_config.ursula_config = ursula_config  # Pass Ursula's config onto staking sub-command

    #
    # Launch Warnings
    #

    if ursula_config.federated_only:
        click_config.emitter(message="WARNING: Running in Federated mode",
                             color='yellow')

    # Seed - Step 1
    teacher_uris = [teacher_uri] if teacher_uri else list()
    teacher_nodes = actions.load_seednodes(
        teacher_uris=teacher_uris,
        min_stake=min_stake,
        federated_only=federated_only,
        network_middleware=click_config.middleware)

    # Produce - Step 2
    URSULA = ursula_config(known_nodes=teacher_nodes, lonely=lonely)

    #
    # Action Switch
    #

    if action == 'run':
        """Seed, Produce, Run!"""

        # GO!
        try:

            click_config.emitter(message="Starting Ursula on {}".format(
                URSULA.rest_interface),
                                 color='green',
                                 bold=True)

            # Ursula Deploy Warnings
            click_config.emitter(message="Connecting to {}".format(','.join(
                str(d, encoding='utf-8') for d in ursula_config.domains)),
                                 color='green',
                                 bold=True)

            if not URSULA.federated_only and URSULA.stakes:
                click_config.emitter(
                    message=
                    f"Staking {str(URSULA.total_staked)} ~ Keep Ursula Online!",
                    color='blue',
                    bold=True)

            if not click_config.debug:
                stdio.StandardIO(UrsulaCommandProtocol(ursula=URSULA))

            if dry_run:
                return  # <-- ABORT -X (Last Chance)

            # Run - Step 3
            node_deployer = URSULA.get_deployer()
            node_deployer.addServices()
            node_deployer.catalogServers(node_deployer.hendrix)
            node_deployer.run()  # <--- Blocking Call (Reactor)

        # Handle Crash
        except Exception as e:
            ursula_config.log.critical(str(e))
            click_config.emitter(message="{} {}".format(
                e.__class__.__name__, str(e)),
                                 color='red',
                                 bold=True)
            raise  # Crash :-(

        # Graceful Exit / Crash
        finally:
            click_config.emitter(message="Stopping Ursula", color='green')
            ursula_config.cleanup()
            click_config.emitter(message="Ursula Stopped", color='red')
        return

    elif action == "save-metadata":
        """Manually save a node self-metadata file"""
        metadata_path = ursula.write_node_metadata(node=URSULA)
        return click_config.emitter(
            message="Successfully saved node metadata to {}.".format(
                metadata_path),
            color='green')

    elif action == "view":
        """Paint an existing configuration to the console"""
        response = UrsulaConfiguration._read_configuration_file(
            filepath=config_file or ursula_config.config_file_location)
        return click_config.emitter(response=response)

    elif action == "forget":
        actions.forget(configuration=ursula_config)
        return

    elif action == "destroy":
        """Delete all configuration files from the disk"""

        if dev:
            message = "'nucypher ursula destroy' cannot be used in --dev mode"
            raise click.BadOptionUsage(option_name='--dev', message=message)

        destroyed_filepath = destroy_system_configuration(
            config_class=UrsulaConfiguration,
            config_file=config_file,
            network=network,
            config_root=ursula_config.config_file_location,
            force=force)

        return click_config.emitter(message=f"Destroyed {destroyed_filepath}",
                                    color='green')

    elif action == 'stake':

        # List Only
        if list_:
            if not URSULA.stakes:
                click.echo(
                    f"There are no existing stakes for {URSULA.checksum_public_address}"
                )
            painting.paint_stakes(stakes=URSULA.stakes)
            return

        # Divide Only
        if divide:
            """Divide an existing stake by specifying the new target value and end period"""

            # Validate
            if len(URSULA.stakes) == 0:
                click.secho("There are no active stakes for {}".format(
                    URSULA.checksum_public_address))
                return

            # Selection
            if index is None:
                painting.paint_stakes(stakes=URSULA.stakes)
                index = click.prompt("Select a stake to divide",
                                     type=click.IntRange(
                                         min=0, max=len(URSULA.stakes) - 1))

            # Lookup the stake
            current_stake = URSULA.stakes[index]

            # Value
            if not value:
                value = click.prompt(
                    f"Enter target value (must be less than {str(current_stake.value)})",
                    type=STAKE_VALUE)
            value = NU(value, 'NU')

            # Duration
            if not duration:
                extension = click.prompt("Enter number of periods to extend",
                                         type=STAKE_EXTENSION)
            else:
                extension = duration

            if not force:
                painting.paint_staged_stake_division(
                    ursula=URSULA,
                    original_index=index,
                    original_stake=current_stake,
                    target_value=value,
                    extension=extension)

                click.confirm("Is this correct?", abort=True)

            txhash_bytes = URSULA.divide_stake(stake_index=index,
                                               target_value=value,
                                               additional_periods=extension)

            if not quiet:
                click.secho('Successfully divided stake', fg='green')
                click.secho(
                    f'Transaction Hash ........... {txhash_bytes.hex()}')

            # Show the resulting stake list
            painting.paint_stakes(stakes=URSULA.stakes)

            return

        # Confirm new stake init
        if not force:
            click.confirm("Stage a new stake?", abort=True)

        # Validate balance
        balance = URSULA.token_balance
        if balance == 0:
            click.secho(f"{ursula.checksum_public_address} has 0 NU.")
            raise click.Abort
        if not quiet:
            click.echo(f"Current balance: {balance}")

        # Gather stake value
        if not value:
            value = click.prompt(f"Enter stake value",
                                 type=STAKE_VALUE,
                                 default=NU(MIN_ALLOWED_LOCKED, 'NuNit'))
        else:
            value = NU(int(value), 'NU')

        # Duration
        if not quiet:
            message = "Minimum duration: {} | Maximum Duration: {}".format(
                MIN_LOCKED_PERIODS, MAX_MINTING_PERIODS)
            click.echo(message)
        if not duration:
            duration = click.prompt(
                "Enter stake duration in periods (1 Period = 24 Hours)",
                type=STAKE_DURATION)
        start_period = URSULA.miner_agent.get_current_period()
        end_period = start_period + duration

        # Review
        if not force:
            painting.paint_staged_stake(ursula=URSULA,
                                        stake_value=value,
                                        duration=duration,
                                        start_period=start_period,
                                        end_period=end_period)

            if not dev:
                actions.confirm_staged_stake(ursula=URSULA,
                                             value=value,
                                             duration=duration)

        # Last chance to bail
        if not force:
            click.confirm("Publish staged stake to the blockchain?",
                          abort=True)

        staking_transactions = URSULA.initialize_stake(amount=int(value),
                                                       lock_periods=duration)
        painting.paint_staking_confirmation(ursula=URSULA,
                                            transactions=staking_transactions)
        return

    elif action == 'confirm-activity':
        if not URSULA.stakes:
            click.secho("There are no active stakes for {}".format(
                URSULA.checksum_public_address))
            return
        URSULA.miner_agent.confirm_activity(
            node_address=URSULA.checksum_public_address)
        return

    elif action == 'collect-reward':
        """Withdraw staking reward to the specified wallet address"""
        if not force:
            click.confirm(
                f"Send {URSULA.calculate_reward()} to {URSULA.checksum_public_address}?"
            )

        URSULA.collect_policy_reward(
            collector_address=withdraw_address or checksum_address)
        URSULA.collect_staking_reward()

    else:
        raise click.BadArgumentUsage("No such argument {}".format(action))