Exemple #1
0
def connection(ctx: Context, connection_name):
    """Remove a connection from the agent."""
    agent_name = ctx.agent_config.agent_name
    logger.info(
        "Removing connection {connection_name} from the agent {agent_name}...".
        format(agent_name=agent_name, connection_name=connection_name))

    if connection_name not in ctx.agent_config.connections:
        logger.error("Connection '{}' not found.".format(connection_name))
        exit(-1)

    connection_folder = os.path.join("connections", connection_name)
    try:
        shutil.rmtree(connection_folder)
    except BaseException:
        logger.exception(
            "An error occurred while deleting '{}'.".format(connection_folder))
        exit(-1)

    # removing the connection to the configurations.
    logger.debug(
        "Removing the connection from {}".format(DEFAULT_AEA_CONFIG_FILE))
    if connection_name in ctx.agent_config.connections:
        ctx.agent_config.connections.remove(connection_name)
        ctx.agent_loader.dump(ctx.agent_config,
                              open(DEFAULT_AEA_CONFIG_FILE, "w"))
Exemple #2
0
def protocol(ctx: Context, protocol_name):
    """Remove a protocol from the agent."""
    agent_name = ctx.agent_config.agent_name
    logger.info(
        "Removing protocol {protocol_name} from the agent {agent_name}...".
        format(agent_name=agent_name, protocol_name=protocol_name))

    if protocol_name not in ctx.agent_config.protocols:
        logger.error("Protocol '{}' not found.".format(protocol_name))
        exit(-1)

    protocol_folder = os.path.join("protocols", protocol_name)
    try:
        shutil.rmtree(protocol_folder)
    except BaseException:
        logger.exception("An error occurred.")
        exit(-1)

    # removing the protocol to the configurations.
    logger.debug(
        "Removing the protocol from {}".format(DEFAULT_AEA_CONFIG_FILE))
    if protocol_name in ctx.agent_config.protocols:
        ctx.agent_config.protocols.remove(protocol_name)
        ctx.agent_loader.dump(ctx.agent_config,
                              open(DEFAULT_AEA_CONFIG_FILE, "w"))
Exemple #3
0
def _remove_item(ctx: Context, item_type, item_id: PublicId):
    """Remove an item from the configuration file and agent, given the public id."""
    item_name = item_id.name
    item_type_plural = "{}s".format(item_type)
    existing_item_ids = getattr(ctx.agent_config, item_type_plural)
    existing_items_name_to_ids = {
        public_id.name: public_id for public_id in existing_item_ids
    }

    agent_name = ctx.agent_config.agent_name
    click.echo(
        "Removing {item_type} '{item_name}' from the agent '{agent_name}'...".format(
            agent_name=agent_name, item_type=item_type, item_name=item_name
        )
    )

    if (
        item_id not in existing_items_name_to_ids.keys()
        and item_id not in existing_item_ids
    ):
        logger.error("The {} '{}' is not supported.".format(item_type, item_id))
        sys.exit(1)

    # TODO we assume the item in the agent config are necessarily in the agent projects.
    item_folder = Path("vendor", item_id.author, item_type_plural, item_name)
    if not item_folder.exists():
        # check if it is present in custom packages.
        item_folder = Path(item_type_plural, item_name)
        if not item_folder.exists():
            raise click.ClickException(
                "{} {} not found. Aborting.".format(item_type.title(), item_name)
            )
        elif (
            item_folder.exists() and not ctx.agent_config.author == item_id.author
        ):  # pragma: no cover
            raise click.ClickException(
                "{} {} author is different from {} agent author. "
                "Please fix the author field.".format(item_name, item_type, agent_name)
            )
        else:
            logger.debug(
                "Removing local {} {}.".format(item_type, item_name)
            )  # pragma: no cover

    try:
        shutil.rmtree(item_folder)
    except BaseException:
        logger.exception("An error occurred.")
        sys.exit(1)

    # removing the protocol to the configurations.
    item_public_id = existing_items_name_to_ids[item_name]
    logger.debug("Removing the {} from {}".format(item_type, DEFAULT_AEA_CONFIG_FILE))
    existing_item_ids.remove(item_public_id)
    ctx.agent_loader.dump(ctx.agent_config, open(DEFAULT_AEA_CONFIG_FILE, "w"))
Exemple #4
0
def run(click_context, connection_names: List[str], env_file: str,
        install_deps: bool):
    """Run the agent."""
    ctx = cast(Context, click_context.obj)
    _try_to_load_agent_config(ctx)
    _load_env_file(env_file)
    agent_name = cast(str, ctx.agent_config.agent_name)

    _verify_or_create_private_keys(ctx)
    _verify_ledger_apis_access()
    private_key_paths = dict([(identifier, config.path)
                              for identifier, config in
                              ctx.agent_config.private_key_paths.read_all()])
    ledger_api_configs = dict([
        (identifier, (config.addr, config.port))
        for identifier, config in ctx.agent_config.ledger_apis.read_all()
    ])

    wallet = Wallet(private_key_paths)
    ledger_apis = LedgerApis(ledger_api_configs)

    connection_names = [ctx.agent_config.default_connection
                        ] if connection_names is None else connection_names
    connections = []
    _try_to_load_protocols(ctx)
    try:
        for connection_name in connection_names:
            connection = _setup_connection(connection_name,
                                           wallet.public_keys[FETCHAI], ctx)
            connections.append(connection)
    except AEAConfigException as e:
        logger.error(str(e))
        sys.exit(1)

    if install_deps:
        if Path("requirements.txt").exists():
            click_context.invoke(install, requirement="requirements.txt")
        else:
            click_context.invoke(install)

    agent = AEA(agent_name,
                connections,
                wallet,
                ledger_apis,
                resources=Resources(str(Path("."))))
    try:
        agent.start()
    except KeyboardInterrupt:
        logger.info("Interrupted.")  # pragma: no cover
    except Exception as e:
        logger.exception(e)
        sys.exit(1)
    finally:
        agent.stop()
Exemple #5
0
def _run_aea(aea: AEA) -> None:
    click.echo(AEA_LOGO + "v" + __version__ + "\n")
    click.echo("{} starting ...".format(aea.name))
    try:
        aea.start()
    except KeyboardInterrupt:
        click.echo(" {} interrupted!".format(aea.name))  # pragma: no cover
    except Exception as e:
        logger.exception(e)
        sys.exit(1)
    finally:
        click.echo("{} stopping ...".format(aea.name))
        aea.stop()
Exemple #6
0
def protocol(ctx: Context, protocol_name: str):
    """Add a protocol scaffolding to the configuration file and agent."""
    # check if we already have a protocol with the same name
    logger.debug("Protocols already supported by the agent: {}".format(
        ctx.agent_config.protocols))
    if protocol_name in ctx.agent_config.protocols:
        logger.error(
            "A protocol with name '{}' already exists. Aborting...".format(
                protocol_name))
        exit(-1)
        return

    try:
        # create the 'protocols' folder if it doesn't exist:
        if not os.path.exists("protocols"):
            os.makedirs("protocols")

        # create the protocol folder
        dest = Path(os.path.join("protocols", protocol_name))

        # copy the skill package into the agent's supported skills.
        src = Path(os.path.join(AEA_DIR, "protocols", "scaffold"))
        logger.info("Copying protocol modules. src={} dst={}".format(
            src, dest))
        try:
            shutil.copytree(src, dest)
        except Exception as e:
            logger.error(e)
            exit(-1)

        # add the protocol to the configurations.
        logger.info(
            "Registering the protocol into {}".format(DEFAULT_AEA_CONFIG_FILE))
        ctx.agent_config.protocols.add(protocol_name)
        ctx.agent_loader.dump(
            ctx.agent_config,
            open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))

    except OSError:
        logger.error("Directory already exist. Aborting...")
        exit(-1)
    except ValidationError as e:
        logger.error(str(e))
        shutil.rmtree(protocol_name, ignore_errors=True)
        exit(-1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(protocol_name, ignore_errors=True)
        exit(-1)
Exemple #7
0
def create(click_context, agent_name):
    """Create an agent."""
    ctx = cast(Context, click_context.obj)
    path = Path(agent_name)
    logger.info("Initializing AEA project '{}'".format(agent_name))
    logger.info("Creating project directory '/{}'".format(agent_name))

    # create the agent's directory
    try:
        path.mkdir(exist_ok=False)

        # create a config file inside it
        logger.info("Creating config file {}".format(DEFAULT_AEA_CONFIG_FILE))
        config_file = open(os.path.join(agent_name, DEFAULT_AEA_CONFIG_FILE),
                           "w")
        agent_config = AgentConfig(agent_name=agent_name,
                                   aea_version=aea.__version__,
                                   authors="",
                                   version="v1",
                                   license="",
                                   url="",
                                   registry_path=DEFAULT_REGISTRY_PATH,
                                   description="")
        agent_config.default_connection = DEFAULT_CONNECTION
        ctx.agent_loader.dump(agent_config, config_file)

        # next commands must be done from the agent's directory -> overwrite ctx.cwd
        ctx.agent_config = agent_config
        ctx.cwd = agent_config.agent_name

        logger.info("Default connections:")
        click_context.invoke(connection, connection_name=DEFAULT_CONNECTION)

        logger.info("Default skills:")
        click_context.invoke(skill, skill_name=DEFAULT_SKILL)

    except OSError:
        logger.error("Directory already exist. Aborting...")
        sys.exit(1)
    except ValidationError as e:
        logger.error(str(e))
        shutil.rmtree(agent_name, ignore_errors=True)
        sys.exit(1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(agent_name, ignore_errors=True)
        sys.exit(1)
Exemple #8
0
def run(ctx: Context, connection_name: str):
    """Run the agent."""
    _try_to_load_agent_config(ctx)
    agent_name = cast(str, ctx.agent_config.agent_name)
    private_key_pem_path = cast(str, ctx.agent_config.private_key_pem_path)
    if private_key_pem_path == "":
        private_key_pem_path = _create_temporary_private_key_pem_path()
    else:
        _try_validate_private_key_pem_path(private_key_pem_path)
    crypto = Crypto(private_key_pem_path=private_key_pem_path)
    public_key = crypto.public_key
    connection_name = ctx.agent_config.default_connection if connection_name is None else connection_name
    _try_to_load_protocols(ctx)
    try:
        connection = _setup_connection(connection_name, public_key, ctx)
    except AEAConfigException as e:
        logger.error(str(e))
        exit(-1)
        return

    logger.debug("Installing all the dependencies...")
    for d in ctx.get_dependencies():
        logger.debug("Installing {}...".format(d))
        try:
            subp = subprocess.Popen(
                [sys.executable, "-m", "pip", "install", d])
            subp.wait(30.0)
        except Exception:
            logger.error(
                "An error occurred while installing {}. Stopping...".format(d))
            exit(-1)

    mailbox = MailBox(connection)
    agent = AEA(agent_name,
                mailbox,
                private_key_pem_path=private_key_pem_path,
                directory=str(Path(".")))
    try:
        agent.start()
    except KeyboardInterrupt:
        logger.info("Interrupted.")
    except Exception as e:
        logger.exception(e)
    finally:
        agent.stop()
Exemple #9
0
def launch(click_context, agents: List[str]):
    """Launch many agents."""
    agents_directories = list(map(Path, list(OrderedDict.fromkeys(agents))))
    agent_processes = [
        Process(target=_run_agent, args=(click_context, agent_directory))
        for agent_directory in agents_directories
    ]

    failed = 0
    try:
        for agent_directory, agent_process in zip(agents_directories,
                                                  agent_processes):
            agent_process.start()
            logger.info("Agent {} started...".format(agent_directory.name))
        for agent_process in agent_processes:
            agent_process.join()
            failed |= (agent_process.exitcode
                       if agent_process.exitcode is not None else 1)
    except KeyboardInterrupt:
        # at this point, the keyboard interrupt has been propagated
        # to all the child process, hence we just need to 'join' the processes.
        for agent_directory, agent_process in zip(agents_directories,
                                                  agent_processes):
            logger.info("Waiting for agent {} to shut down...".format(
                agent_directory.name))
            agent_process.join(5.0)
            if agent_process.is_alive():
                logger.info("Killing agent {}...".format(agent_directory.name))
                agent_process.kill()
                failed = 1
            else:
                logger.info("Agent {} terminated with exit code {}".format(
                    agent_directory.name, agent_process.exitcode))
                failed |= (agent_process.exitcode
                           if agent_process.exitcode is not None else 1)
    except Exception as e:
        logger.exception(e)
        sys.exit(1)

    sys.exit(1) if failed else sys.exit(0)
Exemple #10
0
def _fingerprint_item(click_context, item_type, item_public_id) -> None:
    """
    Fingerprint components of an item.

    :param click_context: the click context.
    :param item_type: the item type.
    :param item_public_id: the item public id.
    :return: None
    """
    ctx = cast(Context, click_context.obj)
    item_type_plural = item_type + "s"

    click.echo("Fingerprinting {} components of '{}' ...".format(
        item_type, item_public_id))

    # create fingerprints
    package_dir = Path(ctx.cwd, item_type_plural, item_public_id.name)
    try:
        default_config_file_name = _get_default_configuration_file_name_from_type(
            item_type)
        config_loader = ConfigLoader.from_configuration_type(item_type)
        config_file_path = Path(package_dir, default_config_file_name)
        config = config_loader.load(config_file_path.open())

        if not package_dir.exists():
            # we only permit non-vendorized packages to be fingerprinted
            logger.error("Package not found at path {}".format(package_dir))
            sys.exit(1)

        fingerprints_dict = _compute_fingerprint(
            package_dir, ignore_patterns=config.fingerprint_ignore_patterns
        )  # type: Dict[str, str]

        # Load item specification yaml file and add fingerprints
        config.fingerprint = fingerprints_dict
        config_loader.dump(config, open(config_file_path, "w"))
    except Exception as e:
        logger.exception(e)
        sys.exit(1)
Exemple #11
0
def skill(ctx: Context, skill_name):
    """Remove a skill from the agent."""
    agent_name = ctx.agent_config.agent_name
    logger.info("Removing skill '{skill_name}' from the agent '{agent_name}'..."
                .format(agent_name=agent_name, skill_name=skill_name))

    if skill_name not in ctx.agent_config.skills:
        logger.error("The skill '{}' is not supported.".format(skill_name))
        sys.exit(1)

    skill_folder = os.path.join("skills", skill_name)
    try:
        shutil.rmtree(skill_folder)
    except BaseException:
        logger.exception("An error occurred.")
        sys.exit(1)

    # removing the protocol to the configurations.
    logger.debug("Removing the skill from {}".format(DEFAULT_AEA_CONFIG_FILE))
    if skill_name in ctx.agent_config.skills:
        ctx.agent_config.skills.remove(skill_name)
        ctx.agent_loader.dump(ctx.agent_config, open(DEFAULT_AEA_CONFIG_FILE, "w"))
Exemple #12
0
def create(click_context, agent_name):
    """Create an agent."""
    ctx = cast(Context, click_context.obj)
    path = Path(agent_name)
    logger.info("Creating agent's directory in '{}'".format(path))

    # create the agent's directory
    try:
        path.mkdir(exist_ok=False)

        # create a config file inside it
        config_file = open(os.path.join(agent_name, DEFAULT_AEA_CONFIG_FILE), "w")
        agent_config = AgentConfig(agent_name=agent_name, aea_version=aea.__version__, authors="", version="v1", license="", url="", registry_path="../packages", private_key_pem_path="")
        agent_config.default_connection = DEFAULT_CONNECTION
        ctx.agent_loader.dump(agent_config, config_file)
        logger.info("Created config file {}".format(DEFAULT_AEA_CONFIG_FILE))

        # next commands must be done from the agent's directory -> overwrite ctx.cwd
        ctx.agent_config = agent_config
        ctx.cwd = agent_config.agent_name

        logger.info("Adding default connection '{}' to the agent...".format(DEFAULT_CONNECTION))
        click_context.invoke(connection, connection_name=DEFAULT_CONNECTION)

        logger.info("Adding default skill '{}' to the agent...".format(DEFAULT_SKILL))
        click_context.invoke(skill, skill_name=DEFAULT_SKILL)

    except OSError:
        logger.error("Directory already exist. Aborting...")
        exit(-1)
    except ValidationError as e:
        logger.error(str(e))
        shutil.rmtree(agent_name, ignore_errors=True)
        exit(-1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(agent_name, ignore_errors=True)
        exit(-1)
Exemple #13
0
def run(click_context, connection_ids: List[PublicId], env_file: str,
        is_install_deps: bool):
    """Run the agent."""
    ctx = cast(Context, click_context.obj)

    _validate_aea(ctx)

    _prepare_environment(click_context, env_file, is_install_deps)

    aea = _build_aea(ctx, connection_ids)

    click.echo(AEA_LOGO + "v" + __version__ + "\n")
    click.echo("{} starting ...".format(ctx.agent_config.agent_name))
    try:
        aea.start()
    except KeyboardInterrupt:
        click.echo(" {} interrupted!".format(
            ctx.agent_config.agent_name))  # pragma: no cover
    except Exception as e:
        logger.exception(e)
        sys.exit(1)
    finally:
        click.echo("{} stopping ...".format(ctx.agent_config.agent_name))
        aea.stop()
Exemple #14
0
def _scaffold_item(ctx: Context, item_type, item_name):
    """Add an item scaffolding to the configuration file and agent."""
    existing_item_list = getattr(ctx.agent_config, "{}s".format(item_type))
    loader = getattr(ctx, "{}_loader".format(item_type))
    default_config_filename = globals()["DEFAULT_{}_CONFIG_FILE".format(
        item_type.upper())]

    item_type_plural = item_type + "s"

    # check if we already have an item with the same name
    logger.debug("{} already supported by the agent: {}".format(
        item_type_plural, existing_item_list))
    if item_name in existing_item_list:
        logger.error("A {} with name '{}' already exists. Aborting...".format(
            item_type, item_name))
        sys.exit(1)

    try:
        agent_name = ctx.agent_config.agent_name
        logger.info("Adding {} scaffold '{}' to the agent '{}'...".format(
            item_type, item_name, agent_name))

        Path(item_type_plural).mkdir(exist_ok=True)

        # create the connection folder
        dest = Path(os.path.join(item_type_plural, item_name))

        # copy the skill package into the agent's supported skills.
        src = Path(os.path.join(AEA_DIR, item_type_plural, "scaffold"))
        logger.debug("Copying {} modules. src={} dst={}".format(
            item_type, src, dest))

        shutil.copytree(src, dest)

        # add the connection to the configurations.
        logger.debug("Registering the {} into {}".format(
            item_type, DEFAULT_AEA_CONFIG_FILE))
        existing_item_list.add(item_name)
        ctx.agent_loader.dump(
            ctx.agent_config,
            open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))

        # ensure the name in the yaml and the name of the folder are the same
        config_filepath = os.path.join(ctx.cwd, item_type_plural, item_name,
                                       default_config_filename)
        config = loader.load(open(str(config_filepath)))
        config.name = item_name
        loader.dump(config, open(config_filepath, "w"))

    except FileExistsError:
        logger.error(
            "A {} with this name already exists. Please choose a different name and try again."
            .format(item_type))
        sys.exit(1)
    except ValidationError:
        logger.error("Error when validating the skill configuration file.")
        shutil.rmtree(os.path.join(item_type_plural, item_name),
                      ignore_errors=True)
        sys.exit(1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(os.path.join(item_type_plural, item_name),
                      ignore_errors=True)
        sys.exit(1)
Exemple #15
0
def _generate_item(ctx: Context, item_type, specification_path):
    """Generate an item based on a specification and add it to the configuration file and agent."""
    # # check protocol buffer compiler is installed
    # res = shutil.which("protoc")
    # if res is None:
    #     print(
    #         "Please install protocol buffer first! See the following link: https://developers.google.com/protocol-buffers/"
    #     )
    #     sys.exit(1)

    # Get existing items
    existing_id_list = getattr(ctx.agent_config, "{}s".format(item_type))
    existing_item_list = [public_id.name for public_id in existing_id_list]

    item_type_plural = item_type + "s"

    # Load item specification yaml file
    try:
        config_loader = ConfigLoader(
            "protocol-specification_schema.json", ProtocolSpecification
        )
        protocol_spec = config_loader.load_protocol_specification(
            open(specification_path)
        )
    except Exception as e:
        logger.exception(e)
        sys.exit(1)

    protocol_directory_path = os.path.join(
        ctx.cwd, item_type_plural, protocol_spec.name
    )

    # Check if we already have an item with the same name in the agent config
    logger.debug(
        "{} already supported by the agent: {}".format(
            item_type_plural, existing_item_list
        )
    )
    if protocol_spec.name in existing_item_list:
        logger.error(
            "A {} with name '{}' already exists. Aborting...".format(
                item_type, protocol_spec.name
            )
        )
        sys.exit(1)
    # Check if we already have a directory with the same name in the resource directory (e.g. protocols) of the agent's directory
    if os.path.exists(protocol_directory_path):
        logger.error(
            "A directory with name '{}' already exists. Aborting...".format(
                protocol_spec.name
            )
        )
        sys.exit(1)

    try:
        agent_name = ctx.agent_config.agent_name
        click.echo(
            "Generating {} '{}' and adding it to the agent '{}'...".format(
                item_type, protocol_spec.name, agent_name
            )
        )

        output_path = os.path.join(ctx.cwd, item_type_plural)
        protocol_generator = ProtocolGenerator(protocol_spec, output_path)
        protocol_generator.generate()

        # Add the item to the configurations
        logger.debug(
            "Registering the {} into {}".format(item_type, DEFAULT_AEA_CONFIG_FILE)
        )
        existing_id_list.add(PublicId("fetchai", protocol_spec.name, DEFAULT_VERSION))
        ctx.agent_loader.dump(
            ctx.agent_config, open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w")
        )
    except FileExistsError:
        logger.error(
            "A {} with this name already exists. Please choose a different name and try again.".format(
                item_type
            )
        )
        sys.exit(1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(
            os.path.join(item_type_plural, protocol_spec.name), ignore_errors=True
        )
        sys.exit(1)
Exemple #16
0
def create(click_context, agent_name, author, local):
    """Create an agent."""
    try:
        _check_is_parent_folders_are_aea_projects_recursively()
    except Exception:
        logger.error(
            "The current folder is already an AEA project. Please move to the parent folder."
        )
        sys.exit(1)

    if author is not None:
        if local:
            do_init(author, False, False)
        else:
            raise click.ClickException(
                "Author is not set up. Please use 'aea init' to initialize.")

    config = _get_or_create_cli_config()
    set_author = config.get(AUTHOR, None)
    if set_author is None:
        click.echo(
            "The AEA configurations are not initialized. Uses `aea init` before continuing or provide optional argument `--author`."
        )
        sys.exit(1)

    ctx = cast(Context, click_context.obj)
    path = Path(agent_name)

    click.echo("Initializing AEA project '{}'".format(agent_name))
    click.echo("Creating project directory './{}'".format(agent_name))

    # create the agent's directory
    try:
        path.mkdir(exist_ok=False)

        # set up packages directories.
        _setup_package_folder(Path(agent_name, "protocols"))
        _setup_package_folder(Path(agent_name, "contracts"))
        _setup_package_folder(Path(agent_name, "connections"))
        _setup_package_folder(Path(agent_name, "skills"))

        # set up a vendor directory
        Path(agent_name, "vendor").mkdir(exist_ok=False)
        Path(agent_name, "vendor", "__init__.py").touch(exist_ok=False)

        # create a config file inside it
        click.echo("Creating config file {}".format(DEFAULT_AEA_CONFIG_FILE))
        config_file = open(os.path.join(agent_name, DEFAULT_AEA_CONFIG_FILE),
                           "w")
        agent_config = AgentConfig(
            agent_name=agent_name,
            aea_version=aea.__version__,
            author=set_author,
            version=DEFAULT_VERSION,
            license=DEFAULT_LICENSE,
            registry_path=os.path.join("..", DEFAULT_REGISTRY_PATH),
            description="",
        )
        agent_config.default_connection = DEFAULT_CONNECTION
        agent_config.default_ledger = DEFAULT_LEDGER
        ctx.agent_loader.dump(agent_config, config_file)

        # next commands must be done from the agent's directory -> overwrite ctx.cwd
        ctx.agent_config = agent_config
        ctx.cwd = agent_config.agent_name

        click.echo("Adding default packages ...")
        if local:
            ctx.set_config("is_local", True)
        _add_item(click_context, "connection", DEFAULT_CONNECTION)
        _add_item(click_context, "skill", DEFAULT_SKILL)

    except OSError:
        logger.error("Directory already exist. Aborting...")
        sys.exit(1)
    except ValidationError as e:
        logger.error(str(e))
        shutil.rmtree(agent_name, ignore_errors=True)
        sys.exit(1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(agent_name, ignore_errors=True)
        sys.exit(1)
Exemple #17
0
def _scaffold_item(ctx: Context, item_type, item_name):
    """Add an item scaffolding to the configuration file and agent."""
    _validate_package_name(item_name)
    author_name = ctx.agent_config.author
    loader = getattr(ctx, "{}_loader".format(item_type))
    default_config_filename = globals()["DEFAULT_{}_CONFIG_FILE".format(
        item_type.upper())]

    item_type_plural = item_type + "s"
    existing_ids = getattr(ctx.agent_config, "{}s".format(item_type))
    existing_ids_only_author_and_name = map(lambda x: (x.author, x.name),
                                            existing_ids)
    # check if we already have an item with the same public id
    if (author_name, item_name) in existing_ids_only_author_and_name:
        logger.error("A {} with name '{}' already exists. Aborting...".format(
            item_type, item_name))
        sys.exit(1)

    try:
        agent_name = ctx.agent_config.agent_name
        click.echo("Adding {} scaffold '{}' to the agent '{}'...".format(
            item_type, item_name, agent_name))

        # create the item folder
        Path(item_type_plural).mkdir(exist_ok=True)
        dest = Path(os.path.join(item_type_plural, item_name))

        # copy the item package into the agent project.
        src = Path(os.path.join(AEA_DIR, item_type_plural, "scaffold"))
        logger.debug("Copying {} modules. src={} dst={}".format(
            item_type, src, dest))
        shutil.copytree(src, dest)

        # add the item to the configurations.
        logger.debug("Registering the {} into {}".format(
            item_type, DEFAULT_AEA_CONFIG_FILE))
        existing_ids.add(PublicId(author_name, item_name, DEFAULT_VERSION))
        ctx.agent_loader.dump(
            ctx.agent_config,
            open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))

        # ensure the name in the yaml and the name of the folder are the same
        config_filepath = Path(ctx.cwd, item_type_plural, item_name,
                               default_config_filename)
        config = loader.load(config_filepath.open())
        config.name = item_name
        config.author = author_name
        loader.dump(config, open(config_filepath, "w"))

    except FileExistsError:
        logger.error(
            "A {} with this name already exists. Please choose a different name and try again."
            .format(item_type))
        sys.exit(1)
    except ValidationError:
        logger.error("Error when validating the {} configuration file.".format(
            item_type))
        shutil.rmtree(os.path.join(item_type_plural, item_name),
                      ignore_errors=True)
        sys.exit(1)
    except Exception as e:
        logger.exception(e)
        shutil.rmtree(os.path.join(item_type_plural, item_name),
                      ignore_errors=True)
        sys.exit(1)
Exemple #18
0
def _generate_item(click_context, item_type, specification_path):
    """Generate an item based on a specification and add it to the configuration file and agent."""
    # check protocol buffer compiler is installed
    ctx = cast(Context, click_context.obj)
    res = shutil.which("protoc")
    if res is None:
        logger.error(
            "Please install protocol buffer first! See the following link: https://developers.google.com/protocol-buffers/"
        )
        sys.exit(1)

    # check black code formatter is installed
    res = shutil.which("black")
    if res is None:
        logger.error(
            "Please install black code formater first! See the following link: https://black.readthedocs.io/en/stable/installation_and_usage.html"
        )
        sys.exit(1)

    # Get existing items
    existing_id_list = getattr(ctx.agent_config, "{}s".format(item_type))
    existing_item_list = [public_id.name for public_id in existing_id_list]

    item_type_plural = item_type + "s"

    # Load item specification yaml file
    try:
        config_loader = ConfigLoader("protocol-specification_schema.json",
                                     ProtocolSpecification)
        protocol_spec = config_loader.load_protocol_specification(
            open(specification_path))
    except Exception as e:
        logger.exception(e)
        sys.exit(1)

    protocol_directory_path = os.path.join(ctx.cwd, item_type_plural,
                                           protocol_spec.name)

    # Check if we already have an item with the same name in the agent config
    logger.debug("{} already supported by the agent: {}".format(
        item_type_plural, existing_item_list))
    if protocol_spec.name in existing_item_list:
        logger.error("A {} with name '{}' already exists. Aborting...".format(
            item_type, protocol_spec.name))
        sys.exit(1)
    # Check if we already have a directory with the same name in the resource directory (e.g. protocols) of the agent's directory
    if os.path.exists(protocol_directory_path):
        logger.error(
            "A directory with name '{}' already exists. Aborting...".format(
                protocol_spec.name))
        sys.exit(1)

    try:
        agent_name = ctx.agent_config.agent_name
        click.echo(
            "Generating {} '{}' and adding it to the agent '{}'...".format(
                item_type, protocol_spec.name, agent_name))

        output_path = os.path.join(ctx.cwd, item_type_plural)
        protocol_generator = ProtocolGenerator(protocol_spec, output_path)
        protocol_generator.generate()

        # Add the item to the configurations
        logger.debug("Registering the {} into {}".format(
            item_type, DEFAULT_AEA_CONFIG_FILE))
        existing_id_list.add(
            PublicId("fetchai", protocol_spec.name, DEFAULT_VERSION))
        ctx.agent_loader.dump(
            ctx.agent_config,
            open(os.path.join(ctx.cwd, DEFAULT_AEA_CONFIG_FILE), "w"))
    except FileExistsError:
        logger.error(
            "A {} with this name already exists. Please choose a different name and try again."
            .format(item_type))
        sys.exit(1)
    except ProtocolSpecificationParseError as e:
        logger.error(
            "The following error happened while parsing the protocol specification: "
            + str(e))
        shutil.rmtree(os.path.join(item_type_plural, protocol_spec.name),
                      ignore_errors=True)
        sys.exit(1)
    except Exception as e:
        logger.debug("Exception thrown: " + str(e))
        logger.error(
            "There was an error while generating the protocol. The protocol is NOT generated."
        )
        shutil.rmtree(os.path.join(item_type_plural, protocol_spec.name),
                      ignore_errors=True)
        sys.exit(1)

    # Run black code formatting
    try:
        subp = subprocess.Popen(  # nosec
            [
                sys.executable,
                "-m",
                "black",
                os.path.join(item_type_plural, protocol_spec.name),
                "--quiet",
            ])
        subp.wait(10.0)
    finally:
        poll = subp.poll()
        if poll is None:  # pragma: no cover
            subp.terminate()
            subp.wait(5)

    _fingerprint_item(click_context, "protocol", protocol_spec.public_id)