Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement linksmith inventory and linksmith output-formats #4

Merged
merged 1 commit into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.inv binary
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
## Unreleased

## v0.0.0 - 2024-xx-xx

- Implement `linksmith inventory` and `linksmith output-formats`
subcommands, based on `sphobjinv` and others. Thanks, @bskinn.
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,19 @@ pip install 'linksmith @ git+https://github.com/tech-writing/linksmith.git'


## Usage
Nothing works yet. All just sketched out.

sphobjinv call delegation ftw.
```shell
linksmith inventory https://linksmith.readthedocs.io/en/latest/objects.inv
```
# Shorthand command ...
anansi suggest matplotlib draw

# ... for:
sphobjinv suggest -u https://matplotlib.org/stable/ draw
```
Read more at the [Linksmith Usage] documentation.

The `linksmith inventory` subsystem is heavily based on
`sphinx.ext.intersphinx` and `sphobjinv`.

> [!WARNING]
> Here be dragons. Please note the program is pre-alpha, and a work in
> progress, so everything may change while we go.


## Development
Expand Down Expand Up @@ -89,7 +91,7 @@ please let us know._

## Acknowledgements

Kudos to [Sviatoslav Sydorenko], [Brian Skinn], [Chris Sewell], and all other
Kudos to [Brian Skinn], [Sviatoslav Sydorenko], [Chris Sewell], and all other
lovely people around Sphinx and Read the Docs.


Expand All @@ -103,6 +105,7 @@ lovely people around Sphinx and Read the Docs.
[Hyperlinks]: https://en.wikipedia.org/wiki/Hyperlink
[linksmith]: https://linksmith.readthedocs.io/
[`linksmith`]: https://pypi.org/project/linksmith/
[Linksmith Usage]: https://linksmith.readthedocs.io/en/latest/usage.html
[rfc]: https://linksmith.readthedocs.io/en/latest/rfc.html
[Sphinx]: https://www.sphinx-doc.org/
[sphobjinv]: https://sphobjinv.readthedocs.io/
Expand Down
19 changes: 19 additions & 0 deletions docs/backlog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Backlog

## Iteration +1
- Docs: Based on sphobjinv.
- Response caching to buffer subsequent invocations
- Add output flavor, like `--details=compact,full`.
**Full details**, well, should display **full URLs**, ready for
navigational consumption (clicking).
- Improve HTML output. (sticky breadcrumb/navbar, etc.)

## Iteration +2
sphobjinv call delegation ftw.
```
# Shorthand command ...
anansi suggest matplotlib draw

# ... for:
sphobjinv suggest -u https://matplotlib.org/stable/ draw
```
32 changes: 29 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A program for processing Hyperlinks, Sphinx references, and inventories.

:::::{grid} 1 3 3 3
::::::{grid} 1 3 3 3
:margin: 4 4 0 0
:padding: 0
:gutter: 2
Expand All @@ -26,15 +26,41 @@ Just the proposal, nothing more.
- [](#rfc-community-operations)
::::

:::::
::::{grid-item}
:::{card} Setup
:margin: 0 2 0 0
:link: setup
:link-type: ref
`pip install ...`
:::
:::{card} Usage
:margin: 0 2 0 0
:link: usage
:link-type: ref
`linksmith inventory ...`
:::
::::

::::::


:::{toctree}
:caption: Handbook
:hidden:

rfc
sandbox
setup
usage
:::


:::{toctree}
:caption: Workbench
:hidden:

project
sandbox
backlog
:::


Expand Down
12 changes: 12 additions & 0 deletions docs/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(setup)=
# Setup

Up until published on PyPI, please install the package that way. Thank you.

```bash
pip install 'linksmith @ git+https://github.com/tech-writing/linksmith.git'
```

:::{note}
This command will need an installation of Git on your system.
:::
48 changes: 48 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
(usage)=
# Usage

Linksmith provides the `linksmith` command line program. It harbours
different subsystems, accessible by using corresponding subcommands,
like `linksmith inventory`.

:::{warning}
Here be dragons. Please note the program is pre-alpha, and a work in
progress, so everything may change while we go.
:::


## Output Formats
Display all the available output formats at a glance.
```shell
linksmith output-formats
```


## Sphinx Inventories
The `linksmith inventory` subsystem supports working with Sphinx inventories,
it is heavily based on `sphinx.ext.intersphinx` and `sphobjinv`.

:::{rubric} Single Inventory
:::
Refer to `objects.inv` on the local filesystem or on a remote location.
```shell
linksmith inventory /path/to/objects.inv
```
```shell
linksmith inventory https://linksmith.readthedocs.io/en/latest/objects.inv
```

```shell
linksmith inventory \
https://linksmith.readthedocs.io/en/latest/objects.inv \
--format=markdown+table
```

:::{rubric} Multiple Inventories
:::
Refer to multiple `objects.inv` resources.
```shell
linksmith inventory \
https://github.com/crate/crate-docs/raw/main/registry/sphinx-inventories.txt \
--format=html+table
```
33 changes: 33 additions & 0 deletions linksmith/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import json

import rich_click as click
from pueblo.util.cli import boot_click

from linksmith.settings import help_config

from .model import OutputFormatRegistry
from .sphinx.cli import cli as inventory_cli


@click.group()
@click.rich_config(help_config=help_config)
@click.option("--verbose", is_flag=True, required=False, help="Turn on logging")
@click.option("--debug", is_flag=True, required=False, help="Turn on logging with debug level")
@click.version_option()
@click.pass_context
def cli(ctx: click.Context, verbose: bool, debug: bool):
return boot_click(ctx, verbose, debug)


@click.command()
@click.rich_config(help_config=help_config)
@click.pass_context
def output_formats(ctx: click.Context): # noqa: ARG001
"""
Display available output format aliases.
"""
print(json.dumps(sorted(OutputFormatRegistry.aliases()), indent=2))


cli.add_command(output_formats, name="output-formats")
cli.add_command(inventory_cli, name="inventory")
70 changes: 70 additions & 0 deletions linksmith/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import dataclasses
import io
import typing as t
from enum import auto
from pathlib import Path

from linksmith.util.python import AutoStrEnum


class OutputFormat(AutoStrEnum):
TEXT_INSPECT = auto()
TEXT_PLAIN = auto()
MARKDOWN = auto()
MARKDOWN_TABLE = auto()
RESTRUCTUREDTEXT = auto()
HTML = auto()
HTML_TABLE = auto()
JSON = auto()
YAML = auto()


@dataclasses.dataclass
class OutputFormatRule:
format: OutputFormat
aliases: t.List[str]


class OutputFormatRegistry:
rules = [
OutputFormatRule(format=OutputFormat.TEXT_INSPECT, aliases=["text"]),
OutputFormatRule(format=OutputFormat.TEXT_PLAIN, aliases=["text+plain"]),
OutputFormatRule(format=OutputFormat.MARKDOWN, aliases=["markdown", "md"]),
OutputFormatRule(format=OutputFormat.MARKDOWN_TABLE, aliases=["markdown+table", "md+table"]),
OutputFormatRule(format=OutputFormat.RESTRUCTUREDTEXT, aliases=["restructuredtext", "rst"]),
OutputFormatRule(format=OutputFormat.HTML, aliases=["html", "html+table"]),
OutputFormatRule(format=OutputFormat.JSON, aliases=["json"]),
OutputFormatRule(format=OutputFormat.YAML, aliases=["yaml"]),
]

@classmethod
def resolve(cls, format_: str) -> OutputFormat:
for rule in cls.rules:
if format_ in rule.aliases:
return rule.format
raise NotImplementedError(f"Output format not implemented: {format_}")

@classmethod
def aliases(cls) -> t.List[str]:
data = []
for rule in cls.rules:
data += rule.aliases
return data


class ResourceType(AutoStrEnum):
BUFFER = auto()
PATH = auto()
URL = auto()

@classmethod
def detect(cls, location):
if isinstance(location, io.IOBase):
return cls.BUFFER
path = Path(location)
if path.exists():
return cls.PATH
elif location.startswith("http://") or location.startswith("https://"):
return cls.URL
else:
raise NotImplementedError(f"Resource type not implemented: {location}")
10 changes: 10 additions & 0 deletions linksmith/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import rich_click as click

help_config = click.RichHelpConfiguration(
use_markdown=True,
width=100,
style_option="bold white",
style_argument="dim cyan",
style_command="bold yellow",
style_errors_suggestion_command="bold magenta",
)
Empty file added linksmith/sphinx/__init__.py
Empty file.
47 changes: 47 additions & 0 deletions linksmith/sphinx/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import typing as t

import rich_click as click
from click import ClickException

from linksmith.settings import help_config
from linksmith.sphinx.core import inventories_to_text, inventory_to_text


@click.command()
@click.rich_config(help_config=help_config)
@click.argument("infiles", nargs=-1)
@click.option("--format", "format_", type=str, default="text", help="Output format")
@click.pass_context
def cli(ctx: click.Context, infiles: t.List[str], format_: str):
"""
Decode one or multiple intersphinx inventories and output in different formats.

Use `linksmith output-formats` to learn about available output formats.

Examples:

Refer to `objects.inv` on the local filesystem or on a remote location:
```bash
linksmith inventory /path/to/objects.inv --format=html
linksmith inventory https://linksmith.readthedocs.io/en/latest/objects.inv --format=markdown
```

Refer to **multiple** `objects.inv` resources:
```bash
linksmith inventory https://github.com/crate/crate-docs/raw/main/registry/sphinx-inventories.txt
```
"""
if not infiles:
raise click.ClickException("No input")
for infile in infiles:
try:
if infile.endswith(".inv"):
inventory_to_text(infile, format_=format_)
elif infile.endswith(".txt"):
inventories_to_text(infile, format_=format_)
else:
raise NotImplementedError(f"Unknown input file type: {infile}")
except Exception as ex:
if ctx.parent and ctx.parent.params.get("debug"):
raise
raise ClickException(f"{ex.__class__.__name__}: {ex}")
Loading