def packages(ctx, opts, owner_repo, page, page_size, query):
    """
    List packages for a repository.

    OWNER/REPO: Specify the OWNER namespace (i.e. user or org), and the
    REPO name to list packages for that namespace and repository. All separated
    by a slash.

    You can use the search query (-q|--query) to filter packages:

      - By name: 'my-package' (implicit) or 'name:my-package'

      - By filename: 'pkg.ext' (implicit) or 'filename:pkg.ext' (explicit)

      - By version: '1.0.0' (implicit) or 'version:1.0.0' (explicit)

      - By arch: 'x86_64' (implicit) or 'architecture:x86_64' (explicit)

      - By disto: 'el' (implicit) or 'distribution:el' (explicit)

    You can also modify the search terms:

      - '^foo' to anchor to start of term

      - 'foo$' to anchor to end of term

      - 'foo*bar' for fuzzy matching

      - '~foo' for negation of the term (explicit only, e.g. name:~foo)

    Multiple search terms are conjunctive (AND).

    Examples, to find packages named exactly foo, with a zip filename, that are
    NOT the x86 architecture, use something like this:

    --query 'name:^foo$ filename:.zip$ architecture:~x86'

    """
    owner, repo = owner_repo

    # Use stderr for messages if the output is something else (e.g.  # JSON)
    use_stderr = opts.output != "pretty"

    click.echo("Getting list of packages ... ", nl=False, err=use_stderr)

    context_msg = "Failed to get list of packages!"
    with handle_api_exceptions(ctx, opts=opts, context_msg=context_msg):
        with maybe_spinner(opts):
            packages_, page_info = list_packages(
                owner=owner, repo=repo, page=page, page_size=page_size, query=query
            )

    click.secho("OK", fg="green", err=use_stderr)

    if utils.maybe_print_as_json(opts, packages_, page_info):
        return

    headers = ["Name", "Version", "Status", "Owner / Repository (Identifier)"]
    rows = []
    for package in sorted(packages_, key=itemgetter("namespace", "slug")):
        rows.append(
            [
                click.style(_get_package_name(package), fg="cyan"),
                click.style(_get_package_version(package), fg="yellow"),
                click.style(_get_package_status(package), fg="blue"),
                "%(owner_slug)s/%(repo_slug)s/%(slug)s"
                % {
                    "owner_slug": click.style(package["namespace"], fg="magenta"),
                    "repo_slug": click.style(package["repository"], fg="magenta"),
                    "slug": click.style(package["slug"], fg="green"),
                },
            ]
        )

    if packages_:
        click.echo()
        utils.pretty_print_table(headers, rows)

    click.echo()

    num_results = len(packages_)
    list_suffix = "package%s visible" % ("s" if num_results != 1 else "")
    utils.pretty_print_list_info(
        num_results=num_results, page_info=page_info, suffix=list_suffix
    )
List packages for a repository.

    OWNER/REPO: Specify the OWNER namespace (i.e. user or org), and the
    REPO name to list packages for that namespace and repository. All separated
    by a slash.

    You can use the search query (-q|--query) to filter packages:

      - By name: 'my-package' (implicit) or 'name:my-package'

      - By filename: 'pkg.ext' (implicit) or 'filename:pkg.ext' (explicit)

      - By version: '1.0.0' (implicit) or 'version:1.0.0' (explicit)

      - By arch: 'x86_64' (implicit) or 'architecture:x86_64' (explicit)

      - By disto: 'el' (implicit) or 'distribution:el' (explicit)

    You can also modify the search terms:

      - '^foo' to anchor to start of term

      - 'foo$' to anchor to end of term

      - 'foo*bar' for fuzzy matching

      - '~foo' for negation of the term (explicit only, e.g. name:~foo)

    Multiple search terms are conjunctive (AND).

    Examples, to find packages named exactly foo, with a zip filename, that are
    NOT the x86 architecture, use something like this:

    --query 'name:^foo$ filename:.zip$ architecture:~x86'