commit local changes.

This commit is contained in:
2026-10-02 15:29:35 +02:00
parent 92e5b6e363
commit 95af3a84af
24 changed files with 3187 additions and 78 deletions
+201
View File
@@ -0,0 +1,201 @@
# sjaur
Fast, fuzzy **TUI search for the [Arch User Repository](https://aur.archlinux.org) and the official Arch Linux repositories** — with real package installation, built on the official AUR metadata dump and your local pacman sync databases.
```
┌ Search: firfox ────────────────────────────────────────────────────────┐
├──────────────────────────────────────┬─────────────────────────────────┤
│ firefox 130.0-1 +3500 │ Name firefox │
│ firefox-nightly 131.0b1 +120 │ Version 130.0-1 │
│ firefox-wayland 129.0 +90 │ Maintainer jonas │
│ … │ Votes 3500 │
│ │ Popularity 214.53 │
│ │ … │
├──────────────────────────────────────┴─────────────────────────────────┤
│ 9 results · 24 ms · cache 2.1 hours old │
└────────────────────────────────────────────────────────────────────────┘
```
Typo-tolerant ranking across name, description, maintainer, keywords,
provides, and dependency fields — all served from a local snapshot, so
searching never touches the network.
## Install
```bash
cd sjaur
python -m venv .venv
.venv/bin/pip install .
```
Then link the executable onto your `PATH` (or copy it):
```bash
sudo ln -s "$(pwd)/.venv/bin/sjaur" /usr/local/bin/sjaur
# or, without root:
mkdir -p ~/.local/bin && ln -s "$(pwd)/.venv/bin/sjaur" ~/.local/bin/sjaur
```
Requirements: Python ≥ 3.10 and Linux (deps: `rapidfuzz`, `textual`).
## Usage
```bash
sjaur # launch the TUI
sjaur --update # force a metadata refresh, then exit
sjaur --version
sjaur --help
```
Optional:
- `--cache-dir <dir>` overrides the cache location (default `~/.cache/sjaur`)
- `--no-repos` searches the AUR only (skip official repository packages)
- `--repos-dir <dir>` overrides the pacman sync database directory
(default `/var/lib/pacman/sync`)
## Official repository packages
By default, sjaur merges the packages of your **local pacman sync databases**
(`core`, `extra`, …) into the search index. They appear with a repository
badge (`firefox [extra]`), can be installed directly via
`sudo pacman -S <name>` (`i` in the TUI — no build step, pacman asks for
confirmation), and work with all search features including `@maintainer`
(the packager email is used, e.g. `@heftig`). Votes, popularity, and
out-of-date status are AUR-only concepts and are hidden for repo packages.
The databases are read-only and stay where pacman manages them; run
`pacman -Sy` as usual to refresh them. On systems without sync databases,
sjaur falls back to AUR-only search with a warning.
## Search syntax
| Query | Meaning |
| --------------------------- | ---------------------------------------------------------------- |
| `firefox` | fuzzy search across all package fields |
| `@max_musterman` | fuzzy-search the **maintainer** field |
| `@max_musterman firefox` | maintainer search combined with a normal search |
| `@john python editor` | maintainer query is `john`; `python editor` is the normal query |
Rules:
- Only the **first whitespace-delimited word** after `@` is the maintainer
query; everything after it is the normal search.
- Matching stays fuzzy: `@max_musterman` also finds `max_mustermann`,
`max-musterman` or `max_musterman123` — no exact match required.
- With `@`, the result score is
`maintainer_similarity × 0.65 + package_score × 0.35`, so maintainer matches
dominate while the text query still orders the results.
- The parser is table-driven, so future operators (e.g. `#keyword`,
`depends:python`) can be added without touching the search engine.
### Live search
Results update **while you type** — no Enter needed:
1. On every keystroke the current list is instantly narrowed client-side
(packages that no longer match disappear immediately).
2. After a short pause (0.18 s), the full fuzzy search over all fields runs
in the background and refines the list.
Editing or retyping a recent query restores its result set instantly from an
in-memory cache; the status line shows `live` while you are typing and the
measured search time once the background search has finished.
## Keys
| Key | Action |
| ---------------------- | ----------------------------------------- |
| typing | **live search** — results update on every keystroke |
| `↑` / `↓` | navigate results |
| `enter` | open package details (`esc` returns) |
| `i` / `ctrl+i` | install the selected package |
| `tab` / `shift+tab` | switch between search field and results |
| `page up` / `page down`, `home` / `end` | scroll / jump |
| `ctrl+r` | reload AUR metadata now |
| `f1` | help overlay |
| `esc` | clear search / leave current view |
| `ctrl+c` | quit |
## Installing packages
With a package highlighted, press `i` (or `ctrl+i`) and confirm with `y`.
sjaur then runs the classic AUR workflow with plain system tools:
1. **Clone** the package repository from
`https://aur.archlinux.org/<name>.git` into `~/.cache/sjaur/build/<name>`
(an existing clone is **reused**; confirm with `u` instead of `y` to
hard-reset and update it first).
2. **Review** the PKGBUILD — it is printed to the terminal, and you can open
it in `$EDITOR` before deciding. **Always read it**: the AUR ships
user-produced build scripts.
3. **Build & install** via `makepkg --syncdeps --install`. pacman's
confirmation, the sudo password prompt, and the whole build output appear
directly in your terminal; the TUI suspends and resumes afterwards.
The result is reported in the terminal; press Enter to return to sjaur.
If anything fails (clone error, dependency problem, aborted build), the
message explains what happened and the TUI keeps running.
> **Security note:** AUR packages are user-produced content. sjaur shows the
> PKGBUILD (and any bundled install scripts) before building — never install
> packages whose build steps you do not understand.
## Package details
Selecting a package shows everything the local snapshot knows — name,
version, description, maintainer, votes, popularity, last modified,
out-of-date status, upstream URL, AUR page, licenses, groups, keywords,
depends, makedepends, checkdepends, optdepends, provides, conflicts, replaces
— without any additional network request.
## Cache behavior
`sjaur` keeps a decompressed copy of the official extended metadata dump
(`https://aur.archlinux.org/packages-meta-ext-v1.json.gz`) in:
```
~/.cache/sjaur/packages-meta-ext-v1.json
```
- At startup the cache's **modification time** is checked; if it is younger
than **24 hours** it is used as-is, otherwise a fresh dump is downloaded.
- The replacement is **atomic**: the dump is downloaded to a temporary file,
decompressed, validated as JSON, and only then swapped in with
`os.replace`. A failed download never destroys a working cache.
- If the download fails but a (stale) cache exists, the old cache is used and
a warning is shown. If there is no usable cache at all, `sjaur` exits with
a clear error.
- `SJAUR_CACHE_DIR` overrides the cache directory (XDG `XDG_CACHE_HOME` is
respected).
## Development
```bash
python -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest # run the test suite
.venv/bin/mypy src # type-check
```
Project layout:
```
sjaur/
├── src/sjaur/
│ ├── cli.py argument parsing and startup flow
│ ├── cache.py download / decompress / validate / atomic replace
│ ├── metadata.py typed Package model, tolerant dump parsing
│ ├── repodb.py local pacman sync database reader
│ ├── query.py extensible query parser (@maintainer, …)
│ ├── search.py fuzzy scoring and ranking engine
│ ├── installer.py clone / review / makepkg / pacman install workflow
│ ├── config.py paths and constants
│ ├── errors.py user-facing error types
│ └── tui/ Textual application, detail view
└── tests/
```
## License
MIT — see [LICENSE](LICENSE).