759d4a6e23
pCloud was never a hard dependency - the tool writes to any local directory. Renaming makes the tool clearly generic before publishing. - PCLOUD_TARGET → TARGET_DIR - probe_pcloud → probe_target - place_into_pcloud → place_into_target - pcloud_target config key → target_dir - COE_MIRROR_PCLOUD_TARGET env var → COE_MIRROR_TARGET_DIR - Hardcoded default: ~/pCloudDrive/Hacking/ChurchOfMalware → ~/coe-mirror - Log messages and docstrings updated - Tests updated to match DevTrack #1286
118 lines
4.1 KiB
Markdown
118 lines
4.1 KiB
Markdown
# coe-mirror
|
|
|
|
Mirror repos from a Forgejo/Gitea instance to a local directory. Built for `git.churchofmalware.org` but usable against any Forgejo/Gitea host.
|
|
|
|
## What it does
|
|
|
|
For every owner in your config, it fetches the repo list, downloads a zip of the current HEAD of the default branch, and writes it to `<target>/<owner>/<repo>_<sha8>.zip`. Old snapshots stay as history — new commits produce new files. Runs unattended via a systemd user timer.
|
|
|
|
## Requirements
|
|
|
|
- Python 3.11+ (uses stdlib `tomllib`)
|
|
- `pip install -r requirements.txt`
|
|
|
|
## Quick start
|
|
|
|
```
|
|
git clone <this repo>
|
|
cd coe-mirror
|
|
python3 -m venv .venv && source .venv/bin/activate
|
|
pip install -r requirements.txt
|
|
|
|
python coe_mirror.py config init # writes ~/.config/coe-mirror/config.toml
|
|
$EDITOR ~/.config/coe-mirror/config.toml # edit owners + target dir
|
|
python coe_mirror.py run # first mirror
|
|
```
|
|
|
|
Add or remove owners any time by editing the `owners = [...]` list in the config file.
|
|
|
|
## Configuration
|
|
|
|
**Precedence** (uniform for every key): env var > config file > hardcoded default.
|
|
|
|
**Config file** location: `~/.config/coe-mirror/config.toml` (override with `COE_MIRROR_CONFIG=/path/to/file.toml`).
|
|
|
|
Full schema:
|
|
|
|
```toml
|
|
api_base = "https://git.churchofmalware.org"
|
|
target_dir = "~/coe-mirror"
|
|
owners = ["Nightmare_Eclipse", "shai_hulud"]
|
|
# pending_dir = "~/.local/share/coe-mirror/pending" # optional
|
|
|
|
[matrix] # optional; leave blank to disable notifications
|
|
homeserver = ""
|
|
room = ""
|
|
```
|
|
|
|
**Env-var overrides** (all optional; each beats the config file):
|
|
|
|
| Var | Purpose |
|
|
|---|---|
|
|
| `COE_MIRROR_CONFIG` | Alternate path to config.toml |
|
|
| `COE_MIRROR_API_BASE` | Forgejo/Gitea base URL |
|
|
| `COE_MIRROR_OWNERS` | Comma-separated owners (`"a,b,c"`) |
|
|
| `COE_MIRROR_TARGET_DIR` | Target directory |
|
|
| `COE_MIRROR_PENDING_DIR` | Local staging dir |
|
|
| `COE_MIRROR_MATRIX_HOMESERVER` | Matrix homeserver URL |
|
|
| `COE_MIRROR_MATRIX_ROOM` | Matrix room ID |
|
|
| `COE_MIRROR_MATRIX_USER` | Matrix bot user (fallback if `creds` binary unavailable) |
|
|
| `COE_MIRROR_MATRIX_PASSWORD` | Matrix bot password (fallback) |
|
|
|
|
## CLI
|
|
|
|
```
|
|
python coe_mirror.py # run the mirror (default)
|
|
python coe_mirror.py run # same
|
|
python coe_mirror.py config init # write example config (won't overwrite)
|
|
python coe_mirror.py config path # print config file path
|
|
python coe_mirror.py --help
|
|
```
|
|
|
|
## Install as a systemd user timer
|
|
|
|
```
|
|
bash install.sh
|
|
```
|
|
|
|
Timer defaults to 00:00 and 12:00 daily with boot catch-up (`Persistent=true`). Missed windows run on next boot.
|
|
|
|
## Matrix notifications (optional)
|
|
|
|
- **Disabled by default.** Leave `[matrix]` blank to skip.
|
|
- If both `homeserver` and `room` are configured, the tool posts a summary after every run that lands at least one new zip (or reports any owner whose fetch failed).
|
|
- Credential lookup order: `creds get COE_MIRROR_BOT_USER matrix` / `COE_MIRROR_BOT_PASSWORD matrix` (Infisical CLI, if you use it), then `COE_MIRROR_MATRIX_USER` / `COE_MIRROR_MATRIX_PASSWORD` env vars. Tokens cached at `~/.local/share/coe-mirror/matrix-token.json` (mode 0600), auto-refreshed on expiry or 401.
|
|
- Matrix failures are non-fatal — a warning is logged and the run proceeds.
|
|
|
|
## Filename convention
|
|
|
|
- Final: `<target>/<owner>/<repo>_<sha8>.zip`
|
|
- Staging (while pending flush): `<pending_dir>/<owner>__<repo>_<sha8>.zip` — owner prefix prevents cross-owner collisions when two owners have identically-named repos.
|
|
|
|
## Behavior when the target is unavailable
|
|
|
|
Downloads land in `pending_dir`. Next run (or any subsequent invocation) flushes them to the target once it's healthy. Owner-scoped: one owner's fetch failure logs and continues; the next run retries.
|
|
|
|
## Logs
|
|
|
|
- File: `~/.local/share/coe-mirror/coe-mirror.log` (rotated at 5 MB, 3 backups)
|
|
- Journal: `journalctl --user -u coe-mirror.service -n 100`
|
|
|
|
## Storage
|
|
|
|
Old snapshots accumulate — no automatic pruning. Prune the target directory manually if you need to reclaim space.
|
|
|
|
## Testing
|
|
|
|
```
|
|
python -m pytest tests/ -v
|
|
```
|
|
|
|
## Uninstall
|
|
|
|
```
|
|
systemctl --user disable --now coe-mirror.timer
|
|
rm ~/.config/systemd/user/coe-mirror.{service,timer}
|
|
systemctl --user daemon-reload
|
|
```
|