No description
  • C 87.7%
  • Shell 6.7%
  • Makefile 3.3%
  • Batchfile 2.2%
Find a file
xo corvus 4e6b62ae5e
All checks were successful
/ linux, tests and entries (push) Successful in 27s
/ windows, tests under wine (push) Successful in 27s
stub for the download bar the tests link against
2026-10-22 13:35:41 -07:00
.forgejo/workflows entry.pcat and index.pcat, paradise's line reader, album icons as one .pxt for every skin 2026-10-19 09:49:40 -07:00
entries/album-icons entry.pcat and index.pcat, paradise's line reader, album icons as one .pxt for every skin 2026-10-19 09:49:40 -07:00
src tests for the catalog's limits and the signed index against paradise's reader 2026-10-20 19:45:04 -07:00
test stub for the download bar the tests link against 2026-10-22 13:35:41 -07:00
.clang-format initial commit - the index tool, its tests and CI. No entries yet. 2026-10-13 14:21:48 -07:00
.gitattributes entry.pcat and index.pcat, paradise's line reader, album icons as one .pxt for every skin 2026-10-19 09:49:40 -07:00
.gitignore initial commit - the index tool, its tests and CI. No entries yet. 2026-10-13 14:21:48 -07:00
build-darwin.bash initial commit - the index tool, its tests and CI. No entries yet. 2026-10-13 14:21:48 -07:00
build-linux.bash entry.pcat and index.pcat, paradise's line reader, album icons as one .pxt for every skin 2026-10-19 09:49:40 -07:00
build-win32.cmd entry.pcat and index.pcat, paradise's line reader, album icons as one .pxt for every skin 2026-10-19 09:49:40 -07:00
catalog.pub initial commit - the index tool, its tests and CI. No entries yet. 2026-10-13 14:21:48 -07:00
index.pcat index 10 2026-10-19 16:38:39 -07:00
index.pcat.sig index 10 2026-10-19 16:38:39 -07:00
LICENSE initial commit - the index tool, its tests and CI. No entries yet. 2026-10-13 14:21:48 -07:00
README.md entry.pcat and index.pcat, paradise's line reader, album icons as one .pxt for every skin 2026-10-19 09:49:40 -07:00

paradise-plugins

The online catalog for paradise: theme packs and plugins from people other than the paradise repo, and the tool that indexes them. paradise only looks at it when the user switches Online catalog on.

Nothing here runs inside paradise. Entries are data - skins, variants, and add-ons that draw into the places a skin keeps for them - and the index lists every file in them with its SHA-512. xo merges, builds the index and signs it on her own machine. The key never goes near CI.

Layout

entries/<id>/entry.pcat
entries/<id>/...         the entry's files, as they install
drafts/<id>/...          entries not published yet, which the index never reads
index.pcat
index.pcat.sig
catalog.pub              the public key the index is signed with

The folder name is the id: lowercase letters, digits, - and _, starting with a letter or digit, 48 bytes at most, and not a name Windows keeps for itself (con, nul, com1 and so on). It can't be the id of a skin paradise ships (the folders in paradise-skins, compared without regard to case).

File and folder names in an entry are letters, digits, ., _ and -, up to 64 bytes each, 160 for the whole path, 8 folders deep. Nothing starts or ends with a dot, nothing is a name Windows keeps for itself (con, nul, com1 and so on), and no two differ only in case. No links. entry.pcat isn't part of what installs and isn't listed in the index. An entry.txt left at an entry's top is refused: that was its name before.

entry.pcat

The same line format as index.pcat, so the same reader does both: paradise's src/lines.c.

paradise_entry 2
kind skin                 // skin, variant or addon
name "Night Shift"
version 3                 // a whole number, up by one per change
author "someone"          // the credit CC BY-SA asks for
for paradise              // variants only: the skins they're for
paradise 1.2.0            // the oldest paradise it works on
skin_language 1           // the skin language's version it's written in

All of them once, in any order. paradise_entry 1 is the old entry.txt's and is refused. for is required for a variant and refused on a skin and an add-on. It names one skin or more, by id, each once: for paradise paradise-phone. skin_language is required for every kind, add-ons too, since they are written in it. paradise is major.minor.patch with minor and patch under 100. name is 80 bytes at most and author 120, UTF-8, no control characters. Any other line is refused.

A skin has a skin.pss. A variant's files go in a folder for each skin for names, entries/<id>/<skin>/, holding what goes in that skin's variants/ folder, and nothing goes outside them. paradise puts them in variants/<skin>/ in its data folder, and a file a variant names under variants/ is looked for there, so a variant's variants/dusk/frame.png is entries/<id>/<skin>/dusk/frame.png here. check puts each folder in its skin's variants/ folder and checks every .pss at its top over that skin, and there has to be one.

An add-on goes on every skin, drawing only into the places a skin keeps for it, so it has one <id>.pxt at its top and its pictures wherever it likes. paradise puts them in addons/<id>/ in its data folder. check runs skin-check on the .pxt over each skin in paradise-skins.

index.pcat

paradise_index 2
sequence 12
commit 3f2c9a0d5b7e41c8a6d2f19e0b4c7a85d3e6f1b2

entry night-shift {
    kind skin
    name "Night Shift"
    version 3
    author "someone"
    paradise 1.2.0
    skin_language 1
    file images/frame.png 5678 <128 hex digits, the SHA-512>
    file skin.pss 1234 <128 hex digits>
}

The same line format again. The first line is the version, the second the sequence number and the third the commit the files are at, in that order. Then a block per entry, sorted by id, with the entry's fields and a file line per file: path from the entry's folder, size in bytes and SHA-512 in lowercase hex. Files are sorted by path. for and skin_language are there when the entry has them. name and author are quoted, with \" and \\ as the only escapes; everything else is a bare word. With no entries there are the three lines and nothing after.

The sequence number is one above the one in the index.pcat already in the repo, or 1 if there isn't one. A previous index the tool can't read is an error rather than a restart at 1, and so is one in the old format, paradise_index 1. The first index.pcat goes on from the last index.txt's number: while HEAD has no index.pcat, the scripts take it from HEAD's index.txt and pass it with --sequence.

A client fetches each file by its raw URL at that commit, so the commit is the one the files are at, which is the one before the commit that adds index.pcat.

Building the index

paradise-plugins builds on ../xo-app and checks ids against ../paradise-skins, the way paradise builds on ../xo-app. Its line reader is ../paradise/src/lines.c, and skins, variants and add-ons are checked with skin-check from ../paradise, so all four sit beside each other.

build-win32.cmd test       build and run the tests
build-win32.cmd index      write index.pcat
build-win32.cmd check      the same, writing nothing
build-win32.cmd format-check

build-linux.bash takes the same words, win32 for a cross-build run under Wine, and check there also runs every skin, variant and add-on through skin-check. check does all of it for drafts/ too, as if they were entries; index never looks there. test on Linux runs asan, tsan and test-release as well. Like every xo-app program the tool wants a display; build-linux.bash puts one up with xvfb-desktop when there isn't one.

Both scripts compile in parallel, a job to each CPU. --serial in the arguments, or XA_JOBS=1 in the environment, builds one file at a time; XA_JOBS=N sets the count.

index refuses to run with anything under entries/ that's changed, new, or ignored by git, since the index names a commit and the files have to be at it, and an ignored Thumbs.db would be in the index and not in the commit. The sequence number it passes with --sequence is one above the one in HEAD's index.pcat, not the working copy's, so running it twice before committing gives the same index twice. The tool itself (catalog-index, in out/<platform>-debug/) reads the commit from .git, or from --commit. It prints each problem as PATH:LINE: error: WHAT and exits 1, writing nothing. Options are --check, --verify, --list (each entry's id, kind and a variant's skins, which check reads to decide what to run skin-check on), --drafts (read drafts/ in place of entries/, with --check or --list only), --root, --skins, --commit, --sequence and --max-total.

It refuses:

  • an id that's a shipped skin's
  • an entry.pcat that is missing or wrong, an entry.txt beside it, a skin with no skin.pss, an add-on with no <id>.pxt at its top, an entry with no files
  • a font with no OFL.txt that isn't empty in its own folder. A font is a file named .ttf, .otf, .ttc, .woff or .woff2, or one that starts like one (00 01 00 00, OTTO, ttcf, true, wOFF, wOF2), since a skin's @font loads any file name
  • files that come to more than 1 GiB all together
  • any name above that won't do

All problems are listed, not just the first.

Signing

The tool never touches a key. Signing is xo-app's sign, built with xo-app (xo-app/out/<platform>-debug/tools/sign), on the machine that has the secret key:

sign sign SECRET index.pcat      writes index.pcat.sig
sign verify PUBLIC index.pcat

Then commit index.pcat and index.pcat.sig together, right on top of the commit the index names. CI, when there's an index.pcat, checks the signature against catalog.pub and fails without one. When the commit brings in a new index.pcat it also builds the index again from the entries of the parent commit with catalog-index --verify, and wants the same text, with the parent as its commit and a sequence one above the parent's index (its index.txt's, before there was an index.pcat). A commit that leaves index.pcat alone, a merged PR for one, only gets the signature check. .gitattributes leaves entries/, index.pcat and the signature alone, with no line ending changes, because what's hashed and signed is those exact bytes.

Licence

Every entry is CC BY-SA 4.0, the same as paradise-skins, licensed in by its author and credited in author. Nothing is assigned. The one exception is a font under the SIL OFL, which comes with its OFL.txt beside it; a font with no OFL.txt is refused, which is how one under another licence is caught. LICENSE is the CC BY-SA 4.0 text.

Send an entry as a PR.

Warnings

  • An add-on only draws, into a row's badge, an icon's badge and the status bar. Plugins that do more than that are built into paradise and aren't in the catalog.